1*4581Ssherrym /* 2*4581Ssherrym * CDDL HEADER START 3*4581Ssherrym * 4*4581Ssherrym * The contents of this file are subject to the terms of the 5*4581Ssherrym * Common Development and Distribution License (the "License"). 6*4581Ssherrym * You may not use this file except in compliance with the License. 7*4581Ssherrym * 8*4581Ssherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4581Ssherrym * or http://www.opensolaris.org/os/licensing. 10*4581Ssherrym * See the License for the specific language governing permissions 11*4581Ssherrym * and limitations under the License. 12*4581Ssherrym * 13*4581Ssherrym * When distributing Covered Code, include this CDDL HEADER in each 14*4581Ssherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4581Ssherrym * If applicable, add the following below this CDDL HEADER, with the 16*4581Ssherrym * fields enclosed by brackets "[]" replaced with your own identifying 17*4581Ssherrym * information: Portions Copyright [yyyy] [name of copyright owner] 18*4581Ssherrym * 19*4581Ssherrym * CDDL HEADER END 20*4581Ssherrym */ 21*4581Ssherrym 22*4581Ssherrym /* 23*4581Ssherrym * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*4581Ssherrym * Use is subject to license terms. 25*4581Ssherrym */ 26*4581Ssherrym 27*4581Ssherrym #pragma ident "%Z%%M% %I% %E% SMI" 28*4581Ssherrym 29*4581Ssherrym #include <sys/types.h> 30*4581Ssherrym #include <sys/ucode.h> 31*4581Ssherrym #ifdef _KERNEL 32*4581Ssherrym #include <sys/systm.h> 33*4581Ssherrym #else 34*4581Ssherrym #include <strings.h> 35*4581Ssherrym #endif 36*4581Ssherrym 37*4581Ssherrym /* 38*4581Ssherrym * Refer to 39*4581Ssherrym * Intel 64 and IA-32 Architectures Software Developers's Manual 40*4581Ssherrym * Chapter 9.11 Microcode Update Facilities 41*4581Ssherrym * for details. 42*4581Ssherrym */ 43*4581Ssherrym 44*4581Ssherrym /* 45*4581Ssherrym * Validates the microcode header. 46*4581Ssherrym * Returns EM_OK on success, EM_HEADER on failure. 47*4581Ssherrym */ 48*4581Ssherrym ucode_errno_t 49*4581Ssherrym ucode_header_validate(ucode_header_t *uhp) 50*4581Ssherrym { 51*4581Ssherrym uint32_t header_size, body_size, total_size; 52*4581Ssherrym 53*4581Ssherrym if (uhp == NULL) 54*4581Ssherrym return (EM_HEADER); 55*4581Ssherrym 56*4581Ssherrym /* 57*4581Ssherrym * The only header version number supported is 1. 58*4581Ssherrym */ 59*4581Ssherrym if (uhp->uh_header_ver != 0x1) 60*4581Ssherrym return (EM_HEADER); 61*4581Ssherrym 62*4581Ssherrym header_size = UCODE_HEADER_SIZE; 63*4581Ssherrym total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); 64*4581Ssherrym body_size = UCODE_BODY_SIZE(uhp->uh_body_size); 65*4581Ssherrym 66*4581Ssherrym /* 67*4581Ssherrym * The body size field of the microcode code header specifies the size 68*4581Ssherrym * of the encrypted data section, its value must be a multiple of the 69*4581Ssherrym * size of DWORD. The total size field must be in multiples of 1K 70*4581Ssherrym * bytes. 71*4581Ssherrym */ 72*4581Ssherrym if ((body_size % sizeof (int)) || 73*4581Ssherrym (total_size < (header_size + body_size)) || 74*4581Ssherrym (total_size % UCODE_KB(1))) 75*4581Ssherrym 76*4581Ssherrym return (EM_HEADER); 77*4581Ssherrym 78*4581Ssherrym /* 79*4581Ssherrym * Sanity check to avoid reading bogus files 80*4581Ssherrym */ 81*4581Ssherrym if (total_size < UCODE_MIN_SIZE || total_size > UCODE_MAX_SIZE) 82*4581Ssherrym return (EM_HEADER); 83*4581Ssherrym 84*4581Ssherrym /* 85*4581Ssherrym * If there is extended signature table, total_size is the sum of 86*4581Ssherrym * header_size 87*4581Ssherrym * body_size 88*4581Ssherrym * sizeof (struct ucode_ext_table) 89*4581Ssherrym * n * sizeof (struct ucode_ext_sig) 90*4581Ssherrym * where n is indicated by uet_count in struct ucode_ext_table. 91*4581Ssherrym */ 92*4581Ssherrym if (total_size > (header_size + body_size)) { 93*4581Ssherrym if ((total_size - body_size - header_size - 94*4581Ssherrym UCODE_EXT_TABLE_SIZE) % UCODE_EXT_SIG_SIZE) { 95*4581Ssherrym 96*4581Ssherrym return (EM_HEADER); 97*4581Ssherrym } 98*4581Ssherrym } 99*4581Ssherrym 100*4581Ssherrym return (EM_OK); 101*4581Ssherrym } 102*4581Ssherrym 103*4581Ssherrym /* 104*4581Ssherrym * Returns checksum. 105*4581Ssherrym */ 106*4581Ssherrym uint32_t 107*4581Ssherrym ucode_checksum(uint32_t sum, uint32_t size, uint8_t *code) 108*4581Ssherrym { 109*4581Ssherrym int i; 110*4581Ssherrym uint32_t *lcode = (uint32_t *)(intptr_t)code; 111*4581Ssherrym 112*4581Ssherrym i = size >> 2; 113*4581Ssherrym while (i--) 114*4581Ssherrym sum += lcode[i]; 115*4581Ssherrym 116*4581Ssherrym return (sum); 117*4581Ssherrym } 118*4581Ssherrym 119*4581Ssherrym ucode_errno_t 120*4581Ssherrym ucode_validate(uint8_t *ucodep, int size) 121*4581Ssherrym { 122*4581Ssherrym uint32_t header_size = UCODE_HEADER_SIZE; 123*4581Ssherrym int remaining; 124*4581Ssherrym 125*4581Ssherrym if (ucodep == NULL || size <= 0) 126*4581Ssherrym return (EM_INVALIDARG); 127*4581Ssherrym 128*4581Ssherrym for (remaining = size; remaining > 0; ) { 129*4581Ssherrym uint32_t total_size, body_size, ext_size; 130*4581Ssherrym ucode_header_t *uhp; 131*4581Ssherrym uint8_t *curbuf = &ucodep[size - remaining]; 132*4581Ssherrym ucode_errno_t rc; 133*4581Ssherrym 134*4581Ssherrym uhp = (ucode_header_t *)(intptr_t)curbuf; 135*4581Ssherrym 136*4581Ssherrym if ((rc = ucode_header_validate(uhp)) != EM_OK) 137*4581Ssherrym return (rc); 138*4581Ssherrym 139*4581Ssherrym total_size = UCODE_TOTAL_SIZE(uhp->uh_total_size); 140*4581Ssherrym 141*4581Ssherrym if (ucode_checksum(0, total_size, curbuf)) 142*4581Ssherrym return (EM_CHECKSUM); 143*4581Ssherrym 144*4581Ssherrym body_size = UCODE_BODY_SIZE(uhp->uh_body_size); 145*4581Ssherrym ext_size = total_size - (header_size + body_size); 146*4581Ssherrym 147*4581Ssherrym if (ext_size > 0) { 148*4581Ssherrym uint32_t i; 149*4581Ssherrym 150*4581Ssherrym if (ucode_checksum(0, ext_size, 151*4581Ssherrym &curbuf[header_size + body_size])) { 152*4581Ssherrym return (EM_CHECKSUM); 153*4581Ssherrym } 154*4581Ssherrym 155*4581Ssherrym ext_size -= UCODE_EXT_TABLE_SIZE; 156*4581Ssherrym for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE; i++) { 157*4581Ssherrym if (ucode_checksum(0, UCODE_EXT_SIG_SIZE, 158*4581Ssherrym &curbuf[total_size - ext_size + 159*4581Ssherrym i * UCODE_EXT_SIG_SIZE])) { 160*4581Ssherrym 161*4581Ssherrym return (EM_CHECKSUM); 162*4581Ssherrym } 163*4581Ssherrym } 164*4581Ssherrym } 165*4581Ssherrym 166*4581Ssherrym remaining -= total_size; 167*4581Ssherrym } 168*4581Ssherrym return (EM_OK); 169*4581Ssherrym } 170