ucode_utils.c revision 5e53ed34920bc03b619b50f459f2475e7bf80b6f
c77a61a72b5ecdc507d6cf104142edd371a16c84yz/*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * CDDL HEADER START
c77a61a72b5ecdc507d6cf104142edd371a16c84yz *
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * The contents of this file are subject to the terms of the
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Common Development and Distribution License (the "License").
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * You may not use this file except in compliance with the License.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz *
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * or http://www.opensolaris.org/os/licensing.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * See the License for the specific language governing permissions
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * and limitations under the License.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz *
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * When distributing Covered Code, include this CDDL HEADER in each
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * If applicable, add the following below this CDDL HEADER, with the
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * fields enclosed by brackets "[]" replaced with your own identifying
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * information: Portions Copyright [yyyy] [name of copyright owner]
c77a61a72b5ecdc507d6cf104142edd371a16c84yz *
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * CDDL HEADER END
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz/*
489b7c4ab76ae8df137fbfcc2214f7baa52883a0Raymond Chen * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Use is subject to license terms.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
e2c88f0c2610f16de7b639746b40dea5f3e2256eGarrett D'Amore
e2c88f0c2610f16de7b639746b40dea5f3e2256eGarrett D'Amore#include <sys/types.h>
c77a61a72b5ecdc507d6cf104142edd371a16c84yz#include <sys/ucode.h>
c77a61a72b5ecdc507d6cf104142edd371a16c84yz#ifdef _KERNEL
c77a61a72b5ecdc507d6cf104142edd371a16c84yz#include <sys/systm.h>
c77a61a72b5ecdc507d6cf104142edd371a16c84yz#else
c77a61a72b5ecdc507d6cf104142edd371a16c84yz#include <strings.h>
c77a61a72b5ecdc507d6cf104142edd371a16c84yz#endif
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz/*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Refer to
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Intel 64 and IA-32 Architectures Software Developers's Manual
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Chapter 9.11 Microcode Update Facilities
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * for details.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz/*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Validates the microcode header.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Returns EM_OK on success, EM_HEADER on failure.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
c77a61a72b5ecdc507d6cf104142edd371a16c84yzucode_errno_t
c77a61a72b5ecdc507d6cf104142edd371a16c84yzucode_header_validate_intel(ucode_header_intel_t *uhp)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz{
c77a61a72b5ecdc507d6cf104142edd371a16c84yz uint32_t header_size, body_size, total_size;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (uhp == NULL)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_HEADER);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * The only header version number supported is 1.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (uhp->uh_header_ver != 0x1)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_HEADER);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz header_size = UCODE_HEADER_SIZE_INTEL;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * The body size field of the microcode code header specifies the size
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * of the encrypted data section, its value must be a multiple of the
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * size of DWORD. The total size field must be in multiples of 1K
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * bytes.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if ((body_size % sizeof (int)) ||
c77a61a72b5ecdc507d6cf104142edd371a16c84yz (total_size < (header_size + body_size)) ||
c77a61a72b5ecdc507d6cf104142edd371a16c84yz (total_size % UCODE_KB(1)))
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_HEADER);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Sanity check to avoid reading bogus files
7014882c6a3672fd0e5d60200af8643ae53c5928Richard Lowe */
7014882c6a3672fd0e5d60200af8643ae53c5928Richard Lowe if (total_size < UCODE_MIN_SIZE || total_size > UCODE_MAX_SIZE)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_HEADER);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * If there is extended signature table, total_size is the sum of
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * header_size
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * body_size
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * sizeof (struct ucode_ext_table)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * n * sizeof (struct ucode_ext_sig)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * where n is indicated by uet_count in struct ucode_ext_table.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (total_size > (header_size + body_size)) {
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if ((total_size - body_size - header_size -
c77a61a72b5ecdc507d6cf104142edd371a16c84yz UCODE_EXT_TABLE_SIZE_INTEL) % UCODE_EXT_SIG_SIZE_INTEL) {
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_HEADER);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz }
c77a61a72b5ecdc507d6cf104142edd371a16c84yz }
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_OK);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz}
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz/*
c77a61a72b5ecdc507d6cf104142edd371a16c84yz * Returns checksum.
c77a61a72b5ecdc507d6cf104142edd371a16c84yz */
c77a61a72b5ecdc507d6cf104142edd371a16c84yzuint32_t
c77a61a72b5ecdc507d6cf104142edd371a16c84yzucode_checksum_intel(uint32_t sum, uint32_t size, uint8_t *code)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz{
c77a61a72b5ecdc507d6cf104142edd371a16c84yz int i;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz uint32_t *lcode = (uint32_t *)(intptr_t)code;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz i = size >> 2;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz while (i--)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz sum += lcode[i];
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (sum);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz}
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yzucode_errno_t
c77a61a72b5ecdc507d6cf104142edd371a16c84yzucode_validate_amd(uint8_t *ucodep, int size)
e2c88f0c2610f16de7b639746b40dea5f3e2256eGarrett D'Amore{
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /* LINTED: pointer alignment */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz uint32_t *ptr = (uint32_t *)ucodep;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz uint32_t count;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (ucodep == NULL || size <= 0)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_INVALIDARG);
bf56214c0556fa6864189c826d39dbe156bb22a0stevel
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /* Magic Number: "AMD\0" */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz size -= 4;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (*ptr++ != 0x00414d44)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_FILEFORMAT);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /* equivalence table */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz size -= 4;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (*ptr++)
bf56214c0556fa6864189c826d39dbe156bb22a0stevel return (EM_FILEFORMAT);
bf56214c0556fa6864189c826d39dbe156bb22a0stevel
c77a61a72b5ecdc507d6cf104142edd371a16c84yz size -= 4;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (((count = *ptr++) > size) || (count % 16))
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_FILEFORMAT);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /* LINTED: pointer alignment */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz ptr = (uint32_t *)(((uint8_t *)ptr) + count);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz size -= count;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz while (size > 8) {
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /* microcode patch */
c77a61a72b5ecdc507d6cf104142edd371a16c84yz size -= 4;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (*ptr++ != 1)
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_FILEFORMAT);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz size -= 4;
c77a61a72b5ecdc507d6cf104142edd371a16c84yz if (((count = *ptr++) > size))
c77a61a72b5ecdc507d6cf104142edd371a16c84yz return (EM_FILEFORMAT);
c77a61a72b5ecdc507d6cf104142edd371a16c84yz
c77a61a72b5ecdc507d6cf104142edd371a16c84yz /* LINTED: pointer alignment */
ptr = (uint32_t *)(((uint8_t *)ptr) + count);
size -= count;
}
if (size)
return (EM_FILEFORMAT);
return (EM_OK);
}
ucode_errno_t
ucode_validate_intel(uint8_t *ucodep, int size)
{
uint32_t header_size = UCODE_HEADER_SIZE_INTEL;
int remaining;
if (ucodep == NULL || size <= 0)
return (EM_INVALIDARG);
for (remaining = size; remaining > 0; ) {
uint32_t total_size, body_size, ext_size;
ucode_header_intel_t *uhp;
uint8_t *curbuf = &ucodep[size - remaining];
ucode_errno_t rc;
uhp = (ucode_header_intel_t *)(intptr_t)curbuf;
if ((rc = ucode_header_validate_intel(uhp)) != EM_OK)
return (rc);
total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
if (ucode_checksum_intel(0, total_size, curbuf))
return (EM_CHECKSUM);
body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
ext_size = total_size - (header_size + body_size);
if (ext_size > 0) {
uint32_t i;
if (ucode_checksum_intel(0, ext_size,
&curbuf[header_size + body_size])) {
return (EM_CHECKSUM);
}
ext_size -= UCODE_EXT_TABLE_SIZE_INTEL;
for (i = 0; i < ext_size / UCODE_EXT_SIG_SIZE_INTEL;
i++) {
if (ucode_checksum_intel(0,
UCODE_EXT_SIG_SIZE_INTEL,
&curbuf[total_size - ext_size +
i * UCODE_EXT_SIG_SIZE_INTEL])) {
return (EM_CHECKSUM);
}
}
}
remaining -= total_size;
}
return (EM_OK);
}