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 int microcode_read_rev(void) 68 { 69 /* Quark does not have microcode MSRs */ 70 #ifdef CONFIG_INTEL_QUARK 71 return 0; 72 #else 73 /* 74 * Some Intel CPUs can be very finicky about the CPUID sequence used. 75 * So this is implemented in assembly so that it works reliably. 76 */ 77 uint32_t low, high; 78 79 asm volatile ( 80 "xorl %%eax, %%eax\n" 81 "xorl %%edx, %%edx\n" 82 "movl %2, %%ecx\n" 83 "wrmsr\n" 84 "movl $0x01, %%eax\n" 85 "cpuid\n" 86 "movl %2, %%ecx\n" 87 "rdmsr\n" 88 : /* outputs */ 89 "=a" (low), "=d" (high) 90 : /* inputs */ 91 "i" (MSR_IA32_UCODE_REV) 92 : /* clobbers */ 93 "ebx", "ecx" 94 ); 95 96 return high; 97 #endif 98 } 99 100 static void microcode_read_cpu(struct microcode_update *cpu) 101 { 102 /* CPUID sets MSR 0x8B iff a microcode update has been loaded. */ 103 unsigned int x86_model, x86_family; 104 struct cpuid_result result; 105 uint32_t low, high; 106 107 wrmsr(MSR_IA32_UCODE_REV, 0, 0); 108 result = cpuid(1); 109 rdmsr(MSR_IA32_UCODE_REV, low, cpu->update_revision); 110 x86_model = (result.eax >> 4) & 0x0f; 111 x86_family = (result.eax >> 8) & 0x0f; 112 cpu->processor_signature = result.eax; 113 114 cpu->processor_flags = 0; 115 if ((x86_model >= 5) || (x86_family > 6)) { 116 rdmsr(0x17, low, high); 117 cpu->processor_flags = 1 << ((high >> 18) & 7); 118 } 119 debug("microcode: sig=%#x pf=%#x revision=%#x\n", 120 cpu->processor_signature, cpu->processor_flags, 121 cpu->update_revision); 122 } 123 124 /* Get a microcode update from the device tree and apply it */ 125 int microcode_update_intel(void) 126 { 127 struct microcode_update cpu, update; 128 const void *blob = gd->fdt_blob; 129 int skipped; 130 int count; 131 int node; 132 int ret; 133 int rev; 134 135 microcode_read_cpu(&cpu); 136 node = 0; 137 count = 0; 138 skipped = 0; 139 do { 140 node = fdtdec_next_compatible(blob, node, 141 COMPAT_INTEL_MICROCODE); 142 if (node < 0) { 143 debug("%s: Found %d updates\n", __func__, count); 144 return count ? 0 : skipped ? -EEXIST : -ENOENT; 145 } 146 147 ret = microcode_decode_node(blob, node, &update); 148 if (ret) { 149 debug("%s: Unable to decode update: %d\n", __func__, 150 ret); 151 return ret; 152 } 153 if (!(update.processor_signature == cpu.processor_signature && 154 (update.processor_flags & cpu.processor_flags))) { 155 debug("%s: Skipping non-matching update, sig=%x, pf=%x\n", 156 __func__, update.processor_signature, 157 update.processor_flags); 158 skipped++; 159 continue; 160 } 161 wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0); 162 rev = microcode_read_rev(); 163 debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n", 164 rev, update.date_code & 0xffff, 165 (update.date_code >> 24) & 0xff, 166 (update.date_code >> 16) & 0xff); 167 if (update.update_revision != rev) { 168 printf("Microcode update failed\n"); 169 return -EFAULT; 170 } 171 count++; 172 } while (1); 173 } 174