xref: /onnv-gate/usr/src/common/ucode/ucode_utils.c (revision 7605:b4a19682e632)
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