xref: /titanic_44/usr/src/common/ucode/ucode_utils.c (revision 2449e17f82f6097fd2c665b64723e31ceecbeca6)
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