Home | History | Annotate | Line # | Download | only in x86
cpu_ucode_intel.c revision 1.15
      1  1.15  pgoyette /* $NetBSD: cpu_ucode_intel.c,v 1.15 2019/01/27 02:08:39 pgoyette Exp $ */
      2   1.1  drochner /*
      3   1.1  drochner  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      4   1.1  drochner  * All rights reserved.
      5   1.1  drochner  *
      6   1.1  drochner  * This code is derived from software contributed to The NetBSD Foundation
      7   1.1  drochner  * by Matthias Drochner.
      8   1.1  drochner  *
      9   1.1  drochner  * Redistribution and use in source and binary forms, with or without
     10   1.1  drochner  * modification, are permitted provided that the following conditions
     11   1.1  drochner  * are met:
     12   1.1  drochner  * 1. Redistributions of source code must retain the above copyright
     13   1.1  drochner  *    notice, this list of conditions and the following disclaimer.
     14   1.1  drochner  * 2. Redistributions in binary form must reproduce the above copyright
     15   1.1  drochner  *    notice, this list of conditions and the following disclaimer in the
     16   1.1  drochner  *    documentation and/or other materials provided with the distribution.
     17   1.1  drochner  *
     18   1.1  drochner  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19   1.1  drochner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20   1.1  drochner  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21   1.1  drochner  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22   1.1  drochner  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23   1.1  drochner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24   1.1  drochner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25   1.1  drochner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26   1.1  drochner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27   1.1  drochner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28   1.1  drochner  * POSSIBILITY OF SUCH DAMAGE.
     29   1.1  drochner  */
     30   1.1  drochner 
     31   1.1  drochner #include <sys/cdefs.h>
     32  1.15  pgoyette __KERNEL_RCSID(0, "$NetBSD: cpu_ucode_intel.c,v 1.15 2019/01/27 02:08:39 pgoyette Exp $");
     33   1.1  drochner 
     34  1.15  pgoyette #ifdef _KERNEL_OPT
     35   1.1  drochner #include "opt_xen.h"
     36   1.1  drochner #include "opt_cpu_ucode.h"
     37  1.15  pgoyette #endif
     38   1.1  drochner 
     39   1.1  drochner #include <sys/param.h>
     40   1.1  drochner #include <sys/conf.h>
     41   1.1  drochner #include <sys/cpuio.h>
     42   1.1  drochner #include <sys/cpu.h>
     43   1.1  drochner #include <sys/kmem.h>
     44   1.1  drochner 
     45   1.1  drochner #include <machine/cpufunc.h>
     46   1.1  drochner #include <machine/specialreg.h>
     47   1.1  drochner #include <x86/cpu_ucode.h>
     48   1.1  drochner 
     49   1.1  drochner static void
     50   1.1  drochner intel_getcurrentucode(uint32_t *ucodeversion, int *platformid)
     51   1.1  drochner {
     52   1.1  drochner 	unsigned int unneeded_ids[4];
     53   1.1  drochner 	uint64_t msr;
     54   1.1  drochner 
     55   1.1  drochner 	kpreempt_disable();
     56   1.1  drochner 
     57   1.6   msaitoh 	wrmsr(MSR_BIOS_SIGN, 0);
     58   1.1  drochner 	x86_cpuid(0, unneeded_ids);
     59   1.6   msaitoh 	msr = rdmsr(MSR_BIOS_SIGN);
     60   1.1  drochner 	*ucodeversion = msr >> 32;
     61   1.1  drochner 
     62   1.1  drochner 	kpreempt_enable();
     63   1.1  drochner 
     64   1.1  drochner 	msr = rdmsr(MSR_IA32_PLATFORM_ID);
     65   1.1  drochner 	*platformid = ((int)(msr >> 50)) & 7;
     66   1.1  drochner }
     67   1.1  drochner 
     68   1.1  drochner int
     69  1.13  christos cpu_ucode_intel_get_version(struct cpu_ucode_version *ucode,
     70  1.13  christos     void *ptr, size_t len)
     71   1.1  drochner {
     72   1.1  drochner 	struct cpu_info *ci = curcpu();
     73  1.13  christos 	struct cpu_ucode_version_intel1 *data = ptr;
     74   1.1  drochner 
     75   1.1  drochner 	if (ucode->loader_version != CPU_UCODE_LOADER_INTEL1 ||
     76   1.4   msaitoh 	    CPUID_TO_FAMILY(ci->ci_signature) < 6)
     77   1.1  drochner 		return EOPNOTSUPP;
     78   1.1  drochner 
     79  1.13  christos 	if (len < sizeof(*data))
     80  1.13  christos 		return ENOSPC;
     81   1.1  drochner 
     82  1.13  christos 	intel_getcurrentucode(&data->ucodeversion, &data->platformid);
     83  1.13  christos 	return 0;
     84   1.1  drochner }
     85   1.1  drochner 
     86   1.1  drochner int
     87   1.1  drochner cpu_ucode_intel_firmware_open(firmware_handle_t *fwh, const char *fwname)
     88   1.1  drochner {
     89   1.1  drochner 	const char *fw_path = "cpu_x86_intel1";
     90   1.1  drochner 	uint32_t ucodeversion, cpu_signature;
     91   1.1  drochner 	int platformid;
     92   1.1  drochner 	char cpuspec[11];
     93   1.1  drochner 
     94   1.1  drochner 	if (fwname != NULL && fwname[0] != '\0')
     95   1.1  drochner 		return firmware_open(fw_path, fwname, fwh);
     96   1.1  drochner 
     97   1.1  drochner 	cpu_signature = curcpu()->ci_signature;
     98   1.4   msaitoh 	if (CPUID_TO_FAMILY(cpu_signature) < 6)
     99   1.1  drochner 		return EOPNOTSUPP;
    100   1.1  drochner 
    101   1.1  drochner 	intel_getcurrentucode(&ucodeversion, &platformid);
    102   1.5  christos 	snprintf(cpuspec, sizeof(cpuspec), "%08x-%d", cpu_signature,
    103   1.5  christos 	    platformid);
    104   1.1  drochner 
    105   1.1  drochner 	return firmware_open(fw_path, cpuspec, fwh);
    106   1.1  drochner }
    107   1.1  drochner 
    108   1.1  drochner #ifndef XEN
    109  1.14   msaitoh /* Check header version and checksum */
    110  1.14   msaitoh static int
    111  1.14   msaitoh cpu_ucode_intel_verify(struct intel1_ucode_header *buf)
    112  1.14   msaitoh {
    113  1.14   msaitoh 	uint32_t data_size, total_size, payload_size, extended_table_size;
    114  1.14   msaitoh #if 0 /* not yet */
    115  1.14   msaitoh 	struct intel1_ucode_ext_table *ext_table;
    116  1.14   msaitoh 	struct intel1_ucode_proc_signature *ext_psig;
    117  1.14   msaitoh #endif
    118  1.14   msaitoh 	uint32_t sum;
    119  1.14   msaitoh 	int i;
    120  1.14   msaitoh 
    121  1.14   msaitoh 	if ((buf->uh_header_ver != 1) || (buf->uh_loader_rev != 1))
    122  1.14   msaitoh 		return EINVAL;
    123  1.14   msaitoh 
    124  1.14   msaitoh 	/* Data size */
    125  1.14   msaitoh 	if (buf->uh_data_size == 0)
    126  1.14   msaitoh 		data_size = 2000;
    127  1.14   msaitoh 	else
    128  1.14   msaitoh 		data_size = buf->uh_data_size;
    129  1.14   msaitoh 
    130  1.14   msaitoh 	if ((data_size % 4) != 0) {
    131  1.14   msaitoh 		/* Wrong size */
    132  1.14   msaitoh 		return EINVAL;
    133  1.14   msaitoh 	}
    134  1.14   msaitoh 
    135  1.14   msaitoh 	/* Total size */
    136  1.14   msaitoh 	if (buf->uh_total_size == 0)
    137  1.14   msaitoh 		total_size = data_size + 48;
    138  1.14   msaitoh 	else
    139  1.14   msaitoh 		total_size = buf->uh_total_size;
    140  1.14   msaitoh 
    141  1.14   msaitoh 	if ((total_size % 1024) != 0) {
    142  1.14   msaitoh 		/* Wrong size */
    143  1.14   msaitoh 		return EINVAL;
    144  1.14   msaitoh 	}
    145  1.14   msaitoh 
    146  1.14   msaitoh 	payload_size = data_size + 48;
    147  1.14   msaitoh 
    148  1.14   msaitoh 	/* Extended table size */
    149  1.14   msaitoh 	extended_table_size = total_size - payload_size;
    150  1.14   msaitoh 
    151  1.14   msaitoh 	/*
    152  1.14   msaitoh 	 * Verify checksum of update data and header
    153  1.14   msaitoh 	 * (exclude extended signature).
    154  1.14   msaitoh 	 */
    155  1.14   msaitoh 	sum = 0;
    156  1.14   msaitoh 	for (i = 0; i < (payload_size / sizeof(uint32_t)); i++)
    157  1.14   msaitoh 		sum += *((uint32_t *)buf + i);
    158  1.14   msaitoh 	if (sum != 0) {
    159  1.14   msaitoh 		/* Checksum mismatch */
    160  1.14   msaitoh 		return EINVAL;
    161  1.14   msaitoh 	}
    162  1.14   msaitoh 
    163  1.14   msaitoh 	if (extended_table_size == 0)
    164  1.14   msaitoh 		return 0;
    165  1.14   msaitoh 
    166  1.14   msaitoh #if 0
    167  1.14   msaitoh 	/* Verify extended signature's checksum */
    168  1.14   msaitoh 	ext_table = (void *)buf + payload_size;
    169  1.14   msaitoh 	ext_psig = (void *)ext_table + sizeof(struct intel1_ucode_ext_table);
    170  1.14   msaitoh 	printf("ext_table = %p, extsig = %p\n", ext_table, ext_psig);
    171  1.14   msaitoh #else
    172  1.14   msaitoh 	printf("This image has extended signature table.");
    173  1.14   msaitoh #endif
    174  1.14   msaitoh 
    175  1.14   msaitoh 	return 0;
    176  1.14   msaitoh }
    177  1.14   msaitoh 
    178   1.1  drochner int
    179   1.1  drochner cpu_ucode_intel_apply(struct cpu_ucode_softc *sc, int cpuno)
    180   1.1  drochner {
    181   1.1  drochner 	uint32_t ucodetarget, oucodeversion, nucodeversion;
    182  1.10       jym 	int platformid, cpuid;
    183   1.1  drochner 	struct intel1_ucode_header *uh;
    184   1.9       mrg 	void *uha;
    185   1.7   msaitoh 	size_t newbufsize = 0;
    186   1.7   msaitoh 	int rv = 0;
    187   1.1  drochner 
    188   1.1  drochner 	if (sc->loader_version != CPU_UCODE_LOADER_INTEL1
    189   1.1  drochner 	    || cpuno != CPU_UCODE_CURRENT_CPU)
    190   1.1  drochner 		return EINVAL;
    191   1.1  drochner 
    192   1.1  drochner 	uh = (struct intel1_ucode_header *)(sc->sc_blob);
    193  1.14   msaitoh 	rv = cpu_ucode_intel_verify(uh);
    194  1.14   msaitoh 	if (rv != 0)
    195   1.1  drochner 		return EINVAL;
    196  1.14   msaitoh 
    197   1.1  drochner 	ucodetarget = uh->uh_rev;
    198   1.1  drochner 
    199   1.7   msaitoh 	if ((uintptr_t)(sc->sc_blob) & 15) {
    200   1.7   msaitoh 		/* Make the buffer 16 byte aligned */
    201   1.7   msaitoh 		newbufsize = sc->sc_blobsize + 15;
    202   1.9       mrg 		uha = kmem_alloc(newbufsize, KM_SLEEP);
    203   1.9       mrg 		uh = (struct intel1_ucode_header *)roundup2((uintptr_t)uha, 16);
    204   1.7   msaitoh 		/* Copy to the new area */
    205   1.7   msaitoh 		memcpy(uh, sc->sc_blob, sc->sc_blobsize);
    206   1.7   msaitoh 	}
    207   1.7   msaitoh 
    208   1.1  drochner 	kpreempt_disable();
    209   1.1  drochner 
    210   1.1  drochner 	intel_getcurrentucode(&oucodeversion, &platformid);
    211   1.1  drochner 	if (oucodeversion >= ucodetarget) {
    212   1.1  drochner 		kpreempt_enable();
    213   1.7   msaitoh 		rv = EEXIST; /* ??? */
    214   1.7   msaitoh 		goto out;
    215   1.1  drochner 	}
    216   1.9       mrg 	wrmsr(MSR_BIOS_UPDT_TRIG, (uintptr_t)uh + 48);
    217   1.1  drochner 	intel_getcurrentucode(&nucodeversion, &platformid);
    218  1.10       jym 	cpuid = curcpu()->ci_index;
    219   1.1  drochner 
    220   1.1  drochner 	kpreempt_enable();
    221   1.1  drochner 
    222   1.7   msaitoh 	if (nucodeversion != ucodetarget) {
    223   1.7   msaitoh 		rv = EIO;
    224   1.7   msaitoh 		goto out;
    225   1.7   msaitoh 	}
    226   1.1  drochner 
    227  1.10       jym 	printf("cpu %d: ucode 0x%x->0x%x\n", cpuid,
    228   1.1  drochner 	       oucodeversion, nucodeversion);
    229   1.7   msaitoh out:
    230   1.7   msaitoh 	if (newbufsize != 0)
    231   1.9       mrg 		kmem_free(uha, newbufsize);
    232   1.7   msaitoh 	return rv;
    233   1.1  drochner }
    234   1.3       gdt #endif /* ! XEN */
    235