blob: 35eff160d56c0f5076d34b28c46bbe68750f4e42 [file] [log] [blame]
Stefan Reinauer3f8989e2012-04-25 22:58:23 +02001/*
2 * This file is part of the coreboot project.
3 *
Vadim Bendebury537b4e02012-06-19 12:56:57 -07004 * Copyright (C) 2012 The ChromiumOS Authors. All rights reserved.
Stefan Reinauer3f8989e2012-04-25 22:58:23 +02005 * Copyright (C) 2000 Ronald G. Minnich
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000015 */
16
Stefan Reinauer3f8989e2012-04-25 22:58:23 +020017/* Microcode update for Intel PIII and later CPUs */
18
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000019#include <stdint.h>
Vladimir Serbinenko2c88cc02013-03-30 12:04:23 +010020#include <stddef.h>
Stefan Reinauer252111d2012-05-01 16:53:22 -070021#if !defined(__ROMCC__)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000022#include <console/console.h>
Stefan Reinauer252111d2012-05-01 16:53:22 -070023#endif
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000024#include <cpu/cpu.h>
25#include <cpu/x86/msr.h>
26#include <cpu/intel/microcode.h>
Rizwan Qureshi30b755b2015-07-23 22:31:51 +053027#include <rules.h>
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000028
Alexandru Gagniuc2c38f502013-12-06 23:14:54 -060029#if !defined(__PRE_RAM__)
Vadim Bendebury537b4e02012-06-19 12:56:57 -070030#include <cbfs.h>
Stefan Reinauera42e2f42012-10-15 13:18:06 -070031#include <smp/spinlock.h>
32DECLARE_SPIN_LOCK(microcode_lock)
Alexandru Gagniuc2c38f502013-12-06 23:14:54 -060033#else
34#include <arch/cbfs.h>
Vadim Bendebury537b4e02012-06-19 12:56:57 -070035#endif
36
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000037struct microcode {
Stefan Reinauerc8f8a6c2010-05-26 12:53:43 +000038 u32 hdrver; /* Header Version */
Stefan Reinauer3f8989e2012-04-25 22:58:23 +020039 u32 rev; /* Update Revision */
40 u32 date; /* Date */
41 u32 sig; /* Processor Signature */
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000042
Stefan Reinauer3f8989e2012-04-25 22:58:23 +020043 u32 cksum; /* Checksum */
44 u32 ldrver; /* Loader Revision */
45 u32 pf; /* Processor Flags */
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000046
Stefan Reinauer3f8989e2012-04-25 22:58:23 +020047 u32 data_size; /* Data Size */
48 u32 total_size; /* Total Size */
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000049
Stefan Reinauerc8f8a6c2010-05-26 12:53:43 +000050 u32 reserved[3];
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000051};
52
Stefan Reinauerc8f8a6c2010-05-26 12:53:43 +000053static inline u32 read_microcode_rev(void)
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000054{
Stefan Reinauer3f8989e2012-04-25 22:58:23 +020055 /* Some Intel CPUs can be very finicky about the
Stefan Reinauerc8f8a6c2010-05-26 12:53:43 +000056 * CPUID sequence used. So this is implemented in
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000057 * assembly so that it works reliably.
58 */
59 msr_t msr;
Stefan Reinauer3f8989e2012-04-25 22:58:23 +020060 asm volatile (
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000061 "xorl %%eax, %%eax\n\t"
62 "xorl %%edx, %%edx\n\t"
63 "movl $0x8b, %%ecx\n\t"
64 "wrmsr\n\t"
65 "movl $0x01, %%eax\n\t"
66 "cpuid\n\t"
67 "movl $0x08b, %%ecx\n\t"
68 "rdmsr \n\t"
69 : /* outputs */
70 "=a" (msr.lo), "=d" (msr.hi)
71 : /* inputs */
72 : /* trashed */
Stefan Reinauer3b5a9ed2012-05-02 16:41:55 -070073 "ebx", "ecx"
Stefan Reinauerc8f8a6c2010-05-26 12:53:43 +000074 );
Eric Biedermanfcd5ace2004-10-14 19:29:29 +000075 return msr.hi;
76}
77
Aaron Durbin98ffb422013-01-15 15:15:32 -060078#define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin"
79
80void intel_microcode_load_unlocked(const void *microcode_patch)
81{
82 u32 current_rev;
83 msr_t msr;
84 const struct microcode *m = microcode_patch;
85
86 if (!m)
87 return;
88
89 current_rev = read_microcode_rev();
90
91 /* No use loading the same revision. */
92 if (current_rev == m->rev)
93 return;
94
Rizwan Qureshi30b755b2015-07-23 22:31:51 +053095#if ENV_RAMSTAGE
96 /*SoC specific check to update microcode*/
97 if (soc_skip_ucode_update(current_rev, m->rev)) {
98 printk(BIOS_DEBUG, "Skip microcode update\n");
99 return;
100 }
101#endif
102
Aaron Durbin98ffb422013-01-15 15:15:32 -0600103 msr.lo = (unsigned long)m + sizeof(struct microcode);
104 msr.hi = 0;
105 wrmsr(0x79, msr);
106
107#if !defined(__ROMCC__)
108 printk(BIOS_DEBUG, "microcode: updated to revision "
109 "0x%x date=%04x-%02x-%02x\n", read_microcode_rev(),
110 m->date & 0xffff, (m->date >> 24) & 0xff,
111 (m->date >> 16) & 0xff);
Vadim Bendebury537b4e02012-06-19 12:56:57 -0700112#endif
Aaron Durbin98ffb422013-01-15 15:15:32 -0600113}
114
115const void *intel_microcode_find(void)
116{
Aaron Durbine6767672014-01-27 15:52:47 -0600117 const struct microcode *ucode_updates;
Aaron Durbin899d13d2015-05-15 23:39:23 -0500118 size_t microcode_len;
119 u32 eax;
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600120 u32 pf, rev, sig, update_size;
Aaron Durbin98ffb422013-01-15 15:15:32 -0600121 unsigned int x86_model, x86_family;
Aaron Durbin98ffb422013-01-15 15:15:32 -0600122 msr_t msr;
123
124#ifdef __PRE_RAM__
Aaron Durbin899d13d2015-05-15 23:39:23 -0500125 struct cbfs_file *microcode_file;
Aaron Durbin98ffb422013-01-15 15:15:32 -0600126
Aaron Durbin899d13d2015-05-15 23:39:23 -0500127 microcode_file = walkcbfs_head((char *) MICROCODE_CBFS_FILE);
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600128 if (!microcode_file)
Vladimir Serbinenko2c88cc02013-03-30 12:04:23 +0100129 return NULL;
Aaron Durbin98ffb422013-01-15 15:15:32 -0600130
Aaron Durbine6767672014-01-27 15:52:47 -0600131 ucode_updates = CBFS_SUBHEADER(microcode_file);
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600132 microcode_len = ntohl(microcode_file->len);
Aaron Durbin899d13d2015-05-15 23:39:23 -0500133#else
134 ucode_updates = cbfs_boot_map_with_leak(MICROCODE_CBFS_FILE,
135 CBFS_TYPE_MICROCODE,
136 &microcode_len);
137 if (ucode_updates == NULL)
138 return NULL;
139#endif
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600140
Aaron Durbin98ffb422013-01-15 15:15:32 -0600141 /* CPUID sets MSR 0x8B iff a microcode update has been loaded. */
142 msr.lo = 0;
143 msr.hi = 0;
144 wrmsr(0x8B, msr);
145 eax = cpuid_eax(1);
146 msr = rdmsr(0x8B);
147 rev = msr.hi;
148 x86_model = (eax >>4) & 0x0f;
149 x86_family = (eax >>8) & 0x0f;
150 sig = eax;
151
152 pf = 0;
153 if ((x86_model >= 5)||(x86_family>6)) {
154 msr = rdmsr(0x17);
155 pf = 1 << ((msr.hi >> 18) & 7);
156 }
157#if !defined(__ROMCC__)
158 /* If this code is compiled with ROMCC we're probably in
159 * the bootblock and don't have console output yet.
160 */
161 printk(BIOS_DEBUG, "microcode: sig=0x%x pf=0x%x revision=0x%x\n",
162 sig, pf, rev);
163#endif
164
Aaron Durbine6767672014-01-27 15:52:47 -0600165 while (microcode_len >= sizeof(*ucode_updates)) {
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600166 /* Newer microcode updates include a size field, whereas older
167 * containers set it at 0 and are exactly 2048 bytes long */
Aaron Durbine6767672014-01-27 15:52:47 -0600168 if (ucode_updates->total_size) {
169 update_size = ucode_updates->total_size;
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600170 } else {
171 #if !defined(__ROMCC__)
Alexandru Gagniuc2c38f502013-12-06 23:14:54 -0600172 printk(BIOS_SPEW, "Microcode size field is 0\n");
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600173 #endif
174 update_size = 2048;
175 }
176
177 /* Checkpoint 1: The microcode update falls within CBFS */
178 if(update_size > microcode_len) {
179#if !defined(__ROMCC__)
180 printk(BIOS_WARNING, "Microcode header corrupted!\n");
181#endif
182 break;
183 }
184
Aaron Durbine6767672014-01-27 15:52:47 -0600185 if ((ucode_updates->sig == sig) && (ucode_updates->pf & pf))
186 return ucode_updates;
Aaron Durbin98ffb422013-01-15 15:15:32 -0600187
Aaron Durbine6767672014-01-27 15:52:47 -0600188 ucode_updates = (void *)((char *)ucode_updates + update_size);
Alexandru Gagniucb1ae0302013-12-08 16:30:07 -0600189 microcode_len -= update_size;
Aaron Durbin98ffb422013-01-15 15:15:32 -0600190 }
191
192 /* ROMCC doesn't like NULL. */
193 return (void *)0;
194}
195
196void intel_update_microcode_from_cbfs(void)
197{
198 const void *patch = intel_microcode_find();
199
200#if !defined(__ROMCC__) && !defined(__PRE_RAM__)
201 spin_lock(&microcode_lock);
202#endif
203
204 intel_microcode_load_unlocked(patch);
205
206#if !defined(__ROMCC__) && !defined(__PRE_RAM__)
207 spin_unlock(&microcode_lock);
208#endif
209}
Rizwan Qureshi30b755b2015-07-23 22:31:51 +0530210
211#if ENV_RAMSTAGE
212__attribute__((weak)) int soc_skip_ucode_update(u32 currrent_patch_id, u32 new_patch_id)
213{
214 return 0;
215}
216#endif