1*9e66506dSSimon Glass /* 2*9e66506dSSimon Glass * Copyright (c) 2014 Google, Inc 3*9e66506dSSimon Glass * Copyright (C) 2000 Ronald G. Minnich 4*9e66506dSSimon Glass * 5*9e66506dSSimon Glass * Microcode update for Intel PIII and later CPUs 6*9e66506dSSimon Glass * 7*9e66506dSSimon Glass * SPDX-License-Identifier: GPL-2.0 8*9e66506dSSimon Glass */ 9*9e66506dSSimon Glass 10*9e66506dSSimon Glass #include <common.h> 11*9e66506dSSimon Glass #include <errno.h> 12*9e66506dSSimon Glass #include <fdtdec.h> 13*9e66506dSSimon Glass #include <libfdt.h> 14*9e66506dSSimon Glass #include <asm/cpu.h> 15*9e66506dSSimon Glass #include <asm/microcode.h> 16*9e66506dSSimon Glass #include <asm/msr.h> 17*9e66506dSSimon Glass #include <asm/msr-index.h> 18*9e66506dSSimon Glass #include <asm/processor.h> 19*9e66506dSSimon Glass 20*9e66506dSSimon Glass DECLARE_GLOBAL_DATA_PTR; 21*9e66506dSSimon Glass 22*9e66506dSSimon Glass /** 23*9e66506dSSimon Glass * struct microcode_update - standard microcode header from Intel 24*9e66506dSSimon Glass * 25*9e66506dSSimon Glass * We read this information out of the device tree and use it to determine 26*9e66506dSSimon Glass * whether the update is applicable or not. We also use the same structure 27*9e66506dSSimon Glass * to read information from the CPU. 28*9e66506dSSimon Glass */ 29*9e66506dSSimon Glass struct microcode_update { 30*9e66506dSSimon Glass uint header_version; 31*9e66506dSSimon Glass uint update_revision; 32*9e66506dSSimon Glass uint date_code; 33*9e66506dSSimon Glass uint processor_signature; 34*9e66506dSSimon Glass uint checksum; 35*9e66506dSSimon Glass uint loader_revision; 36*9e66506dSSimon Glass uint processor_flags; 37*9e66506dSSimon Glass const void *data; 38*9e66506dSSimon Glass int size; 39*9e66506dSSimon Glass }; 40*9e66506dSSimon Glass 41*9e66506dSSimon Glass static int microcode_decode_node(const void *blob, int node, 42*9e66506dSSimon Glass struct microcode_update *update) 43*9e66506dSSimon Glass { 44*9e66506dSSimon Glass update->data = fdt_getprop(blob, node, "data", &update->size); 45*9e66506dSSimon Glass if (!update->data) 46*9e66506dSSimon Glass return -EINVAL; 47*9e66506dSSimon Glass update->data += UCODE_HEADER_LEN; 48*9e66506dSSimon Glass update->size -= UCODE_HEADER_LEN; 49*9e66506dSSimon Glass 50*9e66506dSSimon Glass update->header_version = fdtdec_get_int(blob, node, 51*9e66506dSSimon Glass "intel,header-version", 0); 52*9e66506dSSimon Glass update->update_revision = fdtdec_get_int(blob, node, 53*9e66506dSSimon Glass "intel,update-revision", 0); 54*9e66506dSSimon Glass update->date_code = fdtdec_get_int(blob, node, 55*9e66506dSSimon Glass "intel,date-code", 0); 56*9e66506dSSimon Glass update->processor_signature = fdtdec_get_int(blob, node, 57*9e66506dSSimon Glass "intel,processor-signature", 0); 58*9e66506dSSimon Glass update->checksum = fdtdec_get_int(blob, node, "intel,checksum", 0); 59*9e66506dSSimon Glass update->loader_revision = fdtdec_get_int(blob, node, 60*9e66506dSSimon Glass "intel,loader-revision", 0); 61*9e66506dSSimon Glass update->processor_flags = fdtdec_get_int(blob, node, 62*9e66506dSSimon Glass "intel,processor-flags", 0); 63*9e66506dSSimon Glass 64*9e66506dSSimon Glass return 0; 65*9e66506dSSimon Glass } 66*9e66506dSSimon Glass 67*9e66506dSSimon Glass static inline uint32_t microcode_read_rev(void) 68*9e66506dSSimon Glass { 69*9e66506dSSimon Glass /* 70*9e66506dSSimon Glass * Some Intel CPUs can be very finicky about the CPUID sequence used. 71*9e66506dSSimon Glass * So this is implemented in assembly so that it works reliably. 72*9e66506dSSimon Glass */ 73*9e66506dSSimon Glass uint32_t low, high; 74*9e66506dSSimon Glass 75*9e66506dSSimon Glass asm volatile ( 76*9e66506dSSimon Glass "xorl %%eax, %%eax\n" 77*9e66506dSSimon Glass "xorl %%edx, %%edx\n" 78*9e66506dSSimon Glass "movl %2, %%ecx\n" 79*9e66506dSSimon Glass "wrmsr\n" 80*9e66506dSSimon Glass "movl $0x01, %%eax\n" 81*9e66506dSSimon Glass "cpuid\n" 82*9e66506dSSimon Glass "movl %2, %%ecx\n" 83*9e66506dSSimon Glass "rdmsr\n" 84*9e66506dSSimon Glass : /* outputs */ 85*9e66506dSSimon Glass "=a" (low), "=d" (high) 86*9e66506dSSimon Glass : /* inputs */ 87*9e66506dSSimon Glass "i" (MSR_IA32_UCODE_REV) 88*9e66506dSSimon Glass : /* clobbers */ 89*9e66506dSSimon Glass "ebx", "ecx" 90*9e66506dSSimon Glass ); 91*9e66506dSSimon Glass 92*9e66506dSSimon Glass return high; 93*9e66506dSSimon Glass } 94*9e66506dSSimon Glass 95*9e66506dSSimon Glass static void microcode_read_cpu(struct microcode_update *cpu) 96*9e66506dSSimon Glass { 97*9e66506dSSimon Glass /* CPUID sets MSR 0x8B iff a microcode update has been loaded. */ 98*9e66506dSSimon Glass unsigned int x86_model, x86_family; 99*9e66506dSSimon Glass struct cpuid_result result; 100*9e66506dSSimon Glass uint32_t low, high; 101*9e66506dSSimon Glass 102*9e66506dSSimon Glass wrmsr(MSR_IA32_UCODE_REV, 0, 0); 103*9e66506dSSimon Glass result = cpuid(1); 104*9e66506dSSimon Glass rdmsr(MSR_IA32_UCODE_REV, low, cpu->update_revision); 105*9e66506dSSimon Glass x86_model = (result.eax >> 4) & 0x0f; 106*9e66506dSSimon Glass x86_family = (result.eax >> 8) & 0x0f; 107*9e66506dSSimon Glass cpu->processor_signature = result.eax; 108*9e66506dSSimon Glass 109*9e66506dSSimon Glass cpu->processor_flags = 0; 110*9e66506dSSimon Glass if ((x86_model >= 5) || (x86_family > 6)) { 111*9e66506dSSimon Glass rdmsr(0x17, low, high); 112*9e66506dSSimon Glass cpu->processor_flags = 1 << ((high >> 18) & 7); 113*9e66506dSSimon Glass } 114*9e66506dSSimon Glass debug("microcode: sig=%#x pf=%#x revision=%#x\n", 115*9e66506dSSimon Glass cpu->processor_signature, cpu->processor_flags, 116*9e66506dSSimon Glass cpu->update_revision); 117*9e66506dSSimon Glass } 118*9e66506dSSimon Glass 119*9e66506dSSimon Glass /* Get a microcode update from the device tree and apply it */ 120*9e66506dSSimon Glass int microcode_update_intel(void) 121*9e66506dSSimon Glass { 122*9e66506dSSimon Glass struct microcode_update cpu, update; 123*9e66506dSSimon Glass const void *blob = gd->fdt_blob; 124*9e66506dSSimon Glass int skipped; 125*9e66506dSSimon Glass int count; 126*9e66506dSSimon Glass int node; 127*9e66506dSSimon Glass int ret; 128*9e66506dSSimon Glass int rev; 129*9e66506dSSimon Glass 130*9e66506dSSimon Glass microcode_read_cpu(&cpu); 131*9e66506dSSimon Glass node = 0; 132*9e66506dSSimon Glass count = 0; 133*9e66506dSSimon Glass skipped = 0; 134*9e66506dSSimon Glass do { 135*9e66506dSSimon Glass node = fdtdec_next_compatible(blob, node, 136*9e66506dSSimon Glass COMPAT_INTEL_MICROCODE); 137*9e66506dSSimon Glass if (node < 0) { 138*9e66506dSSimon Glass debug("%s: Found %d updates\n", __func__, count); 139*9e66506dSSimon Glass return count ? 0 : skipped ? -EEXIST : -ENOENT; 140*9e66506dSSimon Glass } 141*9e66506dSSimon Glass 142*9e66506dSSimon Glass ret = microcode_decode_node(blob, node, &update); 143*9e66506dSSimon Glass if (ret) { 144*9e66506dSSimon Glass debug("%s: Unable to decode update: %d\n", __func__, 145*9e66506dSSimon Glass ret); 146*9e66506dSSimon Glass return ret; 147*9e66506dSSimon Glass } 148*9e66506dSSimon Glass if (!(update.processor_signature == cpu.processor_signature && 149*9e66506dSSimon Glass (update.processor_flags & cpu.processor_flags))) { 150*9e66506dSSimon Glass debug("%s: Skipping non-matching update, sig=%x, pf=%x\n", 151*9e66506dSSimon Glass __func__, update.processor_signature, 152*9e66506dSSimon Glass update.processor_flags); 153*9e66506dSSimon Glass skipped++; 154*9e66506dSSimon Glass continue; 155*9e66506dSSimon Glass } 156*9e66506dSSimon Glass wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0); 157*9e66506dSSimon Glass rev = microcode_read_rev(); 158*9e66506dSSimon Glass debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n", 159*9e66506dSSimon Glass rev, update.date_code & 0xffff, 160*9e66506dSSimon Glass (update.date_code >> 24) & 0xff, 161*9e66506dSSimon Glass (update.date_code >> 16) & 0xff); 162*9e66506dSSimon Glass if (update.update_revision != rev) { 163*9e66506dSSimon Glass printf("Microcode update failed\n"); 164*9e66506dSSimon Glass return -EFAULT; 165*9e66506dSSimon Glass } 166*9e66506dSSimon Glass count++; 167*9e66506dSSimon Glass } while (1); 168*9e66506dSSimon Glass } 169