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
ucode_header_validate_intel(ucode_header_intel_t * uhp)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
ucode_checksum_intel(uint32_t sum,uint32_t size,uint8_t * code)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
ucode_validate_amd(uint8_t * ucodep,int size)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
ucode_validate_intel(uint8_t * ucodep,int size)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