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