14581Ssherrym /* 24581Ssherrym * CDDL HEADER START 34581Ssherrym * 44581Ssherrym * The contents of this file are subject to the terms of the 54581Ssherrym * Common Development and Distribution License (the "License"). 64581Ssherrym * You may not use this file except in compliance with the License. 74581Ssherrym * 84581Ssherrym * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94581Ssherrym * or http://www.opensolaris.org/os/licensing. 104581Ssherrym * See the License for the specific language governing permissions 114581Ssherrym * and limitations under the License. 124581Ssherrym * 134581Ssherrym * When distributing Covered Code, include this CDDL HEADER in each 144581Ssherrym * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154581Ssherrym * If applicable, add the following below this CDDL HEADER, with the 164581Ssherrym * fields enclosed by brackets "[]" replaced with your own identifying 174581Ssherrym * information: Portions Copyright [yyyy] [name of copyright owner] 184581Ssherrym * 194581Ssherrym * CDDL HEADER END 204581Ssherrym */ 214581Ssherrym 224581Ssherrym /* 23*7605SMark.Johnson@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 244581Ssherrym * Use is subject to license terms. 254581Ssherrym */ 264581Ssherrym 274581Ssherrym #include <sys/types.h> 284581Ssherrym #include <sys/ucode.h> 294581Ssherrym #ifdef _KERNEL 304581Ssherrym #include <sys/systm.h> 314581Ssherrym #else 324581Ssherrym #include <strings.h> 334581Ssherrym #endif 344581Ssherrym 354581Ssherrym /* 364581Ssherrym * Refer to 374581Ssherrym * Intel 64 and IA-32 Architectures Software Developers's Manual 384581Ssherrym * Chapter 9.11 Microcode Update Facilities 394581Ssherrym * for details. 404581Ssherrym */ 414581Ssherrym 424581Ssherrym /* 434581Ssherrym * Validates the microcode header. 444581Ssherrym * Returns EM_OK on success, EM_HEADER on failure. 454581Ssherrym */ 464581Ssherrym ucode_errno_t 47*7605SMark.Johnson@Sun.COM ucode_header_validate_intel(ucode_header_intel_t *uhp) 484581Ssherrym { 494581Ssherrym uint32_t header_size, body_size, total_size; 504581Ssherrym 514581Ssherrym if (uhp == NULL) 524581Ssherrym return (EM_HEADER); 534581Ssherrym 544581Ssherrym /* 554581Ssherrym * The only header version number supported is 1. 564581Ssherrym */ 574581Ssherrym if (uhp->uh_header_ver != 0x1) 584581Ssherrym return (EM_HEADER); 594581Ssherrym 60*7605SMark.Johnson@Sun.COM header_size = UCODE_HEADER_SIZE_INTEL; 61*7605SMark.Johnson@Sun.COM total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 62*7605SMark.Johnson@Sun.COM body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 634581Ssherrym 644581Ssherrym /* 654581Ssherrym * The body size field of the microcode code header specifies the size 664581Ssherrym * of the encrypted data section, its value must be a multiple of the 674581Ssherrym * size of DWORD. The total size field must be in multiples of 1K 684581Ssherrym * bytes. 694581Ssherrym */ 704581Ssherrym if ((body_size % sizeof (int)) || 714581Ssherrym (total_size < (header_size + body_size)) || 724581Ssherrym (total_size % UCODE_KB(1))) 734581Ssherrym 744581Ssherrym return (EM_HEADER); 754581Ssherrym 764581Ssherrym /* 774581Ssherrym * Sanity check to avoid reading bogus files 784581Ssherrym */ 794581Ssherrym if (total_size < UCODE_MIN_SIZE || total_size > UCODE_MAX_SIZE) 804581Ssherrym return (EM_HEADER); 814581Ssherrym 824581Ssherrym /* 834581Ssherrym * If there is extended signature table, total_size is the sum of 844581Ssherrym * header_size 854581Ssherrym * body_size 864581Ssherrym * sizeof (struct ucode_ext_table) 874581Ssherrym * n * sizeof (struct ucode_ext_sig) 884581Ssherrym * where n is indicated by uet_count in struct ucode_ext_table. 894581Ssherrym */ 904581Ssherrym if (total_size > (header_size + body_size)) { 914581Ssherrym if ((total_size - body_size - header_size - 92*7605SMark.Johnson@Sun.COM UCODE_EXT_TABLE_SIZE_INTEL) % UCODE_EXT_SIG_SIZE_INTEL) { 934581Ssherrym 944581Ssherrym return (EM_HEADER); 954581Ssherrym } 964581Ssherrym } 974581Ssherrym 984581Ssherrym return (EM_OK); 994581Ssherrym } 1004581Ssherrym 1014581Ssherrym /* 1024581Ssherrym * Returns checksum. 1034581Ssherrym */ 1044581Ssherrym uint32_t 105*7605SMark.Johnson@Sun.COM ucode_checksum_intel(uint32_t sum, uint32_t size, uint8_t *code) 1064581Ssherrym { 1074581Ssherrym int i; 1084581Ssherrym uint32_t *lcode = (uint32_t *)(intptr_t)code; 1094581Ssherrym 1104581Ssherrym i = size >> 2; 1114581Ssherrym while (i--) 1124581Ssherrym sum += lcode[i]; 1134581Ssherrym 1144581Ssherrym return (sum); 1154581Ssherrym } 1164581Ssherrym 1174581Ssherrym ucode_errno_t 118*7605SMark.Johnson@Sun.COM ucode_validate_amd(uint8_t *ucodep, int size) 1194581Ssherrym { 120*7605SMark.Johnson@Sun.COM /* LINTED: pointer alignment */ 121*7605SMark.Johnson@Sun.COM uint32_t *ptr = (uint32_t *)ucodep; 122*7605SMark.Johnson@Sun.COM uint32_t count; 123*7605SMark.Johnson@Sun.COM 124*7605SMark.Johnson@Sun.COM if (ucodep == NULL || size <= 0) 125*7605SMark.Johnson@Sun.COM return (EM_INVALIDARG); 126*7605SMark.Johnson@Sun.COM 127*7605SMark.Johnson@Sun.COM /* Magic Number: "AMD\0" */ 128*7605SMark.Johnson@Sun.COM size -= 4; 129*7605SMark.Johnson@Sun.COM if (*ptr++ != 0x00414d44) 130*7605SMark.Johnson@Sun.COM return (EM_FILEFORMAT); 131*7605SMark.Johnson@Sun.COM 132*7605SMark.Johnson@Sun.COM /* equivalence table */ 133*7605SMark.Johnson@Sun.COM size -= 4; 134*7605SMark.Johnson@Sun.COM if (*ptr++) 135*7605SMark.Johnson@Sun.COM return (EM_FILEFORMAT); 136*7605SMark.Johnson@Sun.COM 137*7605SMark.Johnson@Sun.COM size -= 4; 138*7605SMark.Johnson@Sun.COM if (((count = *ptr++) > size) || (count % 16)) 139*7605SMark.Johnson@Sun.COM return (EM_FILEFORMAT); 140*7605SMark.Johnson@Sun.COM 141*7605SMark.Johnson@Sun.COM /* LINTED: pointer alignment */ 142*7605SMark.Johnson@Sun.COM ptr = (uint32_t *)(((uint8_t *)ptr) + count); 143*7605SMark.Johnson@Sun.COM size -= count; 144*7605SMark.Johnson@Sun.COM 145*7605SMark.Johnson@Sun.COM /* 146*7605SMark.Johnson@Sun.COM * minimum valid size: 147*7605SMark.Johnson@Sun.COM * - type and size fields (8 bytes) 148*7605SMark.Johnson@Sun.COM * - patch header (64 bytes) 149*7605SMark.Johnson@Sun.COM * - one patch triad (28 bytes) 150*7605SMark.Johnson@Sun.COM */ 151*7605SMark.Johnson@Sun.COM while (size >= 100) { 152*7605SMark.Johnson@Sun.COM /* microcode patch */ 153*7605SMark.Johnson@Sun.COM size -= 4; 154*7605SMark.Johnson@Sun.COM if (*ptr++ != 1) 155*7605SMark.Johnson@Sun.COM return (EM_FILEFORMAT); 156*7605SMark.Johnson@Sun.COM 157*7605SMark.Johnson@Sun.COM size -= 4; 158*7605SMark.Johnson@Sun.COM if (((count = *ptr++) > size) || 159*7605SMark.Johnson@Sun.COM ((count - sizeof (ucode_header_amd_t)) % 28)) 160*7605SMark.Johnson@Sun.COM return (EM_FILEFORMAT); 161*7605SMark.Johnson@Sun.COM 162*7605SMark.Johnson@Sun.COM /* LINTED: pointer alignment */ 163*7605SMark.Johnson@Sun.COM ptr = (uint32_t *)(((uint8_t *)ptr) + count); 164*7605SMark.Johnson@Sun.COM size -= count; 165*7605SMark.Johnson@Sun.COM } 166*7605SMark.Johnson@Sun.COM 167*7605SMark.Johnson@Sun.COM if (size) 168*7605SMark.Johnson@Sun.COM return (EM_FILEFORMAT); 169*7605SMark.Johnson@Sun.COM 170*7605SMark.Johnson@Sun.COM return (EM_OK); 171*7605SMark.Johnson@Sun.COM } 172*7605SMark.Johnson@Sun.COM 173*7605SMark.Johnson@Sun.COM ucode_errno_t 174*7605SMark.Johnson@Sun.COM ucode_validate_intel(uint8_t *ucodep, int size) 175*7605SMark.Johnson@Sun.COM { 176*7605SMark.Johnson@Sun.COM uint32_t header_size = UCODE_HEADER_SIZE_INTEL; 1774581Ssherrym int remaining; 1784581Ssherrym 1794581Ssherrym if (ucodep == NULL || size <= 0) 1804581Ssherrym return (EM_INVALIDARG); 1814581Ssherrym 1824581Ssherrym for (remaining = size; remaining > 0; ) { 1834581Ssherrym uint32_t total_size, body_size, ext_size; 184*7605SMark.Johnson@Sun.COM ucode_header_intel_t *uhp; 1854581Ssherrym uint8_t *curbuf = &ucodep[size - remaining]; 1864581Ssherrym ucode_errno_t rc; 1874581Ssherrym 188*7605SMark.Johnson@Sun.COM uhp = (ucode_header_intel_t *)(intptr_t)curbuf; 1894581Ssherrym 190*7605SMark.Johnson@Sun.COM if ((rc = ucode_header_validate_intel(uhp)) != EM_OK) 1914581Ssherrym return (rc); 1924581Ssherrym 193*7605SMark.Johnson@Sun.COM total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size); 1944581Ssherrym 195*7605SMark.Johnson@Sun.COM if (ucode_checksum_intel(0, total_size, curbuf)) 1964581Ssherrym return (EM_CHECKSUM); 1974581Ssherrym 198*7605SMark.Johnson@Sun.COM body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size); 1994581Ssherrym ext_size = total_size - (header_size + body_size); 2004581Ssherrym 2014581Ssherrym if (ext_size > 0) { 2024581Ssherrym uint32_t i; 2034581Ssherrym 204*7605SMark.Johnson@Sun.COM if (ucode_checksum_intel(0, ext_size, 2054581Ssherrym &curbuf[header_size + body_size])) { 2064581Ssherrym return (EM_CHECKSUM); 2074581Ssherrym } 2084581Ssherrym 209*7605SMark.Johnson@Sun.COM ext_size -= UCODE_EXT_TABLE_SIZE_INTEL; 210*7605SMark.Johnson@Sun.COM for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE_INTEL; 211*7605SMark.Johnson@Sun.COM i++) { 212*7605SMark.Johnson@Sun.COM if (ucode_checksum_intel(0, 213*7605SMark.Johnson@Sun.COM UCODE_EXT_SIG_SIZE_INTEL, 2144581Ssherrym &curbuf[total_size - ext_size + 215*7605SMark.Johnson@Sun.COM i * UCODE_EXT_SIG_SIZE_INTEL])) { 2164581Ssherrym 2174581Ssherrym return (EM_CHECKSUM); 2184581Ssherrym } 2194581Ssherrym } 2204581Ssherrym } 2214581Ssherrym 2224581Ssherrym remaining -= total_size; 2234581Ssherrym } 2244581Ssherrym return (EM_OK); 2254581Ssherrym } 226