12449e17fSsherrym /* 22449e17fSsherrym * CDDL HEADER START 32449e17fSsherrym * 42449e17fSsherrym * The contents of this file are subject to the terms of the 52449e17fSsherrym * Common Development and Distribution License (the "License"). 62449e17fSsherrym * You may not use this file except in compliance with the License. 72449e17fSsherrym * 82449e17fSsherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 92449e17fSsherrym * or http://www.opensolaris.org/os/licensing. 102449e17fSsherrym * See the License for the specific language governing permissions 112449e17fSsherrym * and limitations under the License. 122449e17fSsherrym * 132449e17fSsherrym * When distributing Covered Code, include this CDDL HEADER in each 142449e17fSsherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 152449e17fSsherrym * If applicable, add the following below this CDDL HEADER, with the 162449e17fSsherrym * fields enclosed by brackets "[]" replaced with your own identifying 172449e17fSsherrym * information: Portions Copyright [yyyy] [name of copyright owner] 182449e17fSsherrym * 192449e17fSsherrym * CDDL HEADER END 202449e17fSsherrym */ 212449e17fSsherrym 222449e17fSsherrym /* 23*adc586deSMark Johnson * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 242449e17fSsherrym * Use is subject to license terms. 252449e17fSsherrym */ 262449e17fSsherrym 272449e17fSsherrym #include <sys/types.h> 282449e17fSsherrym #include <sys/ucode.h> 292449e17fSsherrym #ifdef _KERNEL 302449e17fSsherrym #include <sys/systm.h> 312449e17fSsherrym #else 322449e17fSsherrym #include <strings.h> 332449e17fSsherrym #endif 342449e17fSsherrym 352449e17fSsherrym /* 362449e17fSsherrym * Refer to 372449e17fSsherrym * Intel 64 and IA-32 Architectures Software Developers's Manual 382449e17fSsherrym * Chapter 9.11 Microcode Update Facilities 392449e17fSsherrym * for details. 402449e17fSsherrym */ 412449e17fSsherrym 422449e17fSsherrym /* 432449e17fSsherrym * Validates the microcode header. 442449e17fSsherrym * Returns EM_OK on success, EM_HEADER on failure. 452449e17fSsherrym */ 462449e17fSsherrym ucode_errno_t 47*adc586deSMark Johnson ucode_header_validate_intel(ucode_header_intel_t *uhp) 482449e17fSsherrym { 492449e17fSsherrym uint32_t header_size, body_size, total_size; 502449e17fSsherrym 512449e17fSsherrym if (uhp == NULL) 522449e17fSsherrym return (EM_HEADER); 532449e17fSsherrym 542449e17fSsherrym /* 552449e17fSsherrym * The only header version number supported is 1. 562449e17fSsherrym */ 572449e17fSsherrym if (uhp->uh_header_ver != 0x1) 582449e17fSsherrym return (EM_HEADER); 592449e17fSsherrym 60*adc586deSMark Johnson header_size = UCODE_HEADER_SIZE_INTEL; 61*adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 62*adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 632449e17fSsherrym 642449e17fSsherrym /* 652449e17fSsherrym * The body size field of the microcode code header specifies the size 662449e17fSsherrym * of the encrypted data section, its value must be a multiple of the 672449e17fSsherrym * size of DWORD. The total size field must be in multiples of 1K 682449e17fSsherrym * bytes. 692449e17fSsherrym */ 702449e17fSsherrym if ((body_size % sizeof (int)) || 712449e17fSsherrym (total_size < (header_size + body_size)) || 722449e17fSsherrym (total_size % UCODE_KB(1))) 732449e17fSsherrym 742449e17fSsherrym return (EM_HEADER); 752449e17fSsherrym 762449e17fSsherrym /* 772449e17fSsherrym * Sanity check to avoid reading bogus files 782449e17fSsherrym */ 792449e17fSsherrym if (total_size < UCODE_MIN_SIZE || total_size > UCODE_MAX_SIZE) 802449e17fSsherrym return (EM_HEADER); 812449e17fSsherrym 822449e17fSsherrym /* 832449e17fSsherrym * If there is extended signature table, total_size is the sum of 842449e17fSsherrym * header_size 852449e17fSsherrym * body_size 862449e17fSsherrym * sizeof (struct ucode_ext_table) 872449e17fSsherrym * n * sizeof (struct ucode_ext_sig) 882449e17fSsherrym * where n is indicated by uet_count in struct ucode_ext_table. 892449e17fSsherrym */ 902449e17fSsherrym if (total_size > (header_size + body_size)) { 912449e17fSsherrym if ((total_size - body_size - header_size - 92*adc586deSMark Johnson UCODE_EXT_TABLE_SIZE_INTEL) % UCODE_EXT_SIG_SIZE_INTEL) { 932449e17fSsherrym 942449e17fSsherrym return (EM_HEADER); 952449e17fSsherrym } 962449e17fSsherrym } 972449e17fSsherrym 982449e17fSsherrym return (EM_OK); 992449e17fSsherrym } 1002449e17fSsherrym 1012449e17fSsherrym /* 1022449e17fSsherrym * Returns checksum. 1032449e17fSsherrym */ 1042449e17fSsherrym uint32_t 105*adc586deSMark Johnson ucode_checksum_intel(uint32_t sum, uint32_t size, uint8_t *code) 1062449e17fSsherrym { 1072449e17fSsherrym int i; 1082449e17fSsherrym uint32_t *lcode = (uint32_t *)(intptr_t)code; 1092449e17fSsherrym 1102449e17fSsherrym i = size >> 2; 1112449e17fSsherrym while (i--) 1122449e17fSsherrym sum += lcode[i]; 1132449e17fSsherrym 1142449e17fSsherrym return (sum); 1152449e17fSsherrym } 1162449e17fSsherrym 1172449e17fSsherrym ucode_errno_t 118*adc586deSMark Johnson ucode_validate_amd(uint8_t *ucodep, int size) 1192449e17fSsherrym { 120*adc586deSMark Johnson /* LINTED: pointer alignment */ 121*adc586deSMark Johnson uint32_t *ptr = (uint32_t *)ucodep; 122*adc586deSMark Johnson uint32_t count; 123*adc586deSMark Johnson 124*adc586deSMark Johnson if (ucodep == NULL || size <= 0) 125*adc586deSMark Johnson return (EM_INVALIDARG); 126*adc586deSMark Johnson 127*adc586deSMark Johnson /* Magic Number: "AMD\0" */ 128*adc586deSMark Johnson size -= 4; 129*adc586deSMark Johnson if (*ptr++ != 0x00414d44) 130*adc586deSMark Johnson return (EM_FILEFORMAT); 131*adc586deSMark Johnson 132*adc586deSMark Johnson /* equivalence table */ 133*adc586deSMark Johnson size -= 4; 134*adc586deSMark Johnson if (*ptr++) 135*adc586deSMark Johnson return (EM_FILEFORMAT); 136*adc586deSMark Johnson 137*adc586deSMark Johnson size -= 4; 138*adc586deSMark Johnson if (((count = *ptr++) > size) || (count % 16)) 139*adc586deSMark Johnson return (EM_FILEFORMAT); 140*adc586deSMark Johnson 141*adc586deSMark Johnson /* LINTED: pointer alignment */ 142*adc586deSMark Johnson ptr = (uint32_t *)(((uint8_t *)ptr) + count); 143*adc586deSMark Johnson size -= count; 144*adc586deSMark Johnson 145*adc586deSMark Johnson /* 146*adc586deSMark Johnson * minimum valid size: 147*adc586deSMark Johnson * - type and size fields (8 bytes) 148*adc586deSMark Johnson * - patch header (64 bytes) 149*adc586deSMark Johnson * - one patch triad (28 bytes) 150*adc586deSMark Johnson */ 151*adc586deSMark Johnson while (size >= 100) { 152*adc586deSMark Johnson /* microcode patch */ 153*adc586deSMark Johnson size -= 4; 154*adc586deSMark Johnson if (*ptr++ != 1) 155*adc586deSMark Johnson return (EM_FILEFORMAT); 156*adc586deSMark Johnson 157*adc586deSMark Johnson size -= 4; 158*adc586deSMark Johnson if (((count = *ptr++) > size) || 159*adc586deSMark Johnson ((count - sizeof (ucode_header_amd_t)) % 28)) 160*adc586deSMark Johnson return (EM_FILEFORMAT); 161*adc586deSMark Johnson 162*adc586deSMark Johnson /* LINTED: pointer alignment */ 163*adc586deSMark Johnson ptr = (uint32_t *)(((uint8_t *)ptr) + count); 164*adc586deSMark Johnson size -= count; 165*adc586deSMark Johnson } 166*adc586deSMark Johnson 167*adc586deSMark Johnson if (size) 168*adc586deSMark Johnson return (EM_FILEFORMAT); 169*adc586deSMark Johnson 170*adc586deSMark Johnson return (EM_OK); 171*adc586deSMark Johnson } 172*adc586deSMark Johnson 173*adc586deSMark Johnson ucode_errno_t 174*adc586deSMark Johnson ucode_validate_intel(uint8_t *ucodep, int size) 175*adc586deSMark Johnson { 176*adc586deSMark Johnson uint32_t header_size = UCODE_HEADER_SIZE_INTEL; 1772449e17fSsherrym int remaining; 1782449e17fSsherrym 1792449e17fSsherrym if (ucodep == NULL || size <= 0) 1802449e17fSsherrym return (EM_INVALIDARG); 1812449e17fSsherrym 1822449e17fSsherrym for (remaining = size; remaining > 0; ) { 1832449e17fSsherrym uint32_t total_size, body_size, ext_size; 184*adc586deSMark Johnson ucode_header_intel_t *uhp; 1852449e17fSsherrym uint8_t *curbuf = &ucodep[size - remaining]; 1862449e17fSsherrym ucode_errno_t rc; 1872449e17fSsherrym 188*adc586deSMark Johnson uhp = (ucode_header_intel_t *)(intptr_t)curbuf; 1892449e17fSsherrym 190*adc586deSMark Johnson if ((rc = ucode_header_validate_intel(uhp)) != EM_OK) 1912449e17fSsherrym return (rc); 1922449e17fSsherrym 193*adc586deSMark Johnson total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 1942449e17fSsherrym 195*adc586deSMark Johnson if (ucode_checksum_intel(0, total_size, curbuf)) 1962449e17fSsherrym return (EM_CHECKSUM); 1972449e17fSsherrym 198*adc586deSMark Johnson body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 1992449e17fSsherrym ext_size = total_size - (header_size + body_size); 2002449e17fSsherrym 2012449e17fSsherrym if (ext_size > 0) { 2022449e17fSsherrym uint32_t i; 2032449e17fSsherrym 204*adc586deSMark Johnson if (ucode_checksum_intel(0, ext_size, 2052449e17fSsherrym &curbuf[header_size + body_size])) { 2062449e17fSsherrym return (EM_CHECKSUM); 2072449e17fSsherrym } 2082449e17fSsherrym 209*adc586deSMark Johnson ext_size -= UCODE_EXT_TABLE_SIZE_INTEL; 210*adc586deSMark Johnson for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE_INTEL; 211*adc586deSMark Johnson i++) { 212*adc586deSMark Johnson if (ucode_checksum_intel(0, 213*adc586deSMark Johnson UCODE_EXT_SIG_SIZE_INTEL, 2142449e17fSsherrym &curbuf[total_size - ext_size + 215*adc586deSMark Johnson i * UCODE_EXT_SIG_SIZE_INTEL])) { 2162449e17fSsherrym 2172449e17fSsherrym return (EM_CHECKSUM); 2182449e17fSsherrym } 2192449e17fSsherrym } 2202449e17fSsherrym } 2212449e17fSsherrym 2222449e17fSsherrym remaining -= total_size; 2232449e17fSsherrym } 2242449e17fSsherrym return (EM_OK); 2252449e17fSsherrym } 226