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