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