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