blob: 783675d953004baedd16cb9f4f31009904e64dd4 [file] [log] [blame]
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Marc Jones2006b382007-12-19 00:47:09 +00003 *
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
Audrey Pearson83e4c562015-10-08 12:47:24 -05005 * Copyright (C) 2015 Raptor Engineering
Marc Jones2006b382007-12-19 00:47:09 +00006 *
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.
Marc Jones2006b382007-12-19 00:47:09 +000015 */
16
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000017#include <stdint.h>
18#include <console/console.h>
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000019#include <cpu/x86/msr.h>
Elyes HAOUAS1a5f1c82018-10-31 08:06:12 +010020#include <cpu/amd/msr.h>
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000021#include <cpu/amd/microcode.h>
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020022#include <cbfs.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020023#include <device/mmio.h>
Timothy Pearsonc764c742015-08-28 20:48:17 -050024#include <smp/spinlock.h>
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +020025
26#define UCODE_DEBUG(fmt, args...) \
Elyes HAOUAScbe7464c2016-08-23 21:07:28 +020027 do { printk(BIOS_DEBUG, "[microcode] "fmt, ##args); } while (0)
Marc Jones8ae8c882007-12-19 01:32:08 +000028
Audrey Pearson83e4c562015-10-08 12:47:24 -050029#define UCODE_MAGIC 0x00414d44
30#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
31#define UCODE_SECTION_START_ID 0x00000001
32#define UCODE_MAGIC 0x00414d44
33
Elyes HAOUAS9d759572018-05-28 15:41:12 +020034#define F1XH_MPB_MAX_SIZE 2048
35#define F15H_MPB_MAX_SIZE 4096
36#define CONT_HDR 12
Audrey Pearson83e4c562015-10-08 12:47:24 -050037#define SECT_HDR 8
38
39/*
40 * STRUCTURE OF A MICROCODE (UCODE) FILE
41 * Container Header
42 * Section Header
43 * Microcode Header
44 * Microcode "Blob"
45 * Section Header
46 * Microcode Header
47 * Microcode "Blob"
48 * ...
49 * ...
50 * (end of file)
51 *
52 *
53 * CONTAINER HEADER (offset 0 bytes from start of file)
54 * Total size = fixed size (12 bytes) + variable size
55 * [0:3] 32-bit unique ID
56 * [4:7] don't-care
57 * [8-11] Size (n) in bytes of variable portion of container header
58 * [12-n] don't-care
59 *
60 * SECTION HEADER (offset += 12+n)
61 * Total size = 8 bytes
62 * [0:3] Unique identifier signaling start of section (0x00000001)
63 * [4:7] Total size (m) of following microcode section, including microcode header
64 *
65 * MICROCODE HEADER (offset += 8)
66 * Total size = 64 bytes
67 * [0:3] Data code (32 bits)
68 * [4:7] Patch ID (32 bits)
69 * [8:9] Microcode patch data ID (16 bits)
70 * [10] c patch data length (8 bits)
71 * [11] init flag (8 bits)
72 * [12:15] ucode patch data cksum (32 bits)
73 * [16:19] nb dev ID (32 bits)
74 * [20:23] sb dev ID (32 bits)
75 * [24:25] Processor rev ID (16 bits)
76 * [26] nb revision ID (8 bits)
77 * [27] sb revision ID (8 bits)
78 * [28] BIOS API revision (8 bits)
79 * [29-31] Reserved 1 (array of three 8-bit values)
80 * [32-63] Match reg (array of eight 32-bit values)
81 *
82 * MICROCODE BLOB (offset += 64)
83 * Total size = m bytes
84 *
85 */
86
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000087struct microcode {
Audrey Pearson83e4c562015-10-08 12:47:24 -050088 uint32_t data_code;
89 uint32_t patch_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000090
Audrey Pearson83e4c562015-10-08 12:47:24 -050091 uint16_t mc_patch_data_id;
92 uint8_t mc_patch_data_len;
93 uint8_t init_flag;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000094
Audrey Pearson83e4c562015-10-08 12:47:24 -050095 uint32_t mc_patch_data_checksum;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000096
Audrey Pearson83e4c562015-10-08 12:47:24 -050097 uint32_t nb_dev_id;
98 uint32_t sb_dev_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +000099
Audrey Pearson83e4c562015-10-08 12:47:24 -0500100 uint16_t processor_rev_id;
101 uint8_t nb_rev_id;
102 uint8_t sb_rev_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000103
Audrey Pearson83e4c562015-10-08 12:47:24 -0500104 uint8_t bios_api_rev;
105 uint8_t reserved1[3];
Marc Jones2006b382007-12-19 00:47:09 +0000106
Audrey Pearson83e4c562015-10-08 12:47:24 -0500107 uint32_t match_reg[8];
Marc Jones2006b382007-12-19 00:47:09 +0000108
Audrey Pearson83e4c562015-10-08 12:47:24 -0500109 uint8_t m_patch_data[896];
110 uint8_t resv2[896];
Marc Jones2006b382007-12-19 00:47:09 +0000111
Audrey Pearson83e4c562015-10-08 12:47:24 -0500112 uint8_t x86_code_present;
113 uint8_t x86_code_entry[191];
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000114};
115
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200116static void apply_microcode_patch(const struct microcode *m)
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000117{
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200118 uint32_t new_patch_id;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000119 msr_t msr;
Marc Jones2006b382007-12-19 00:47:09 +0000120
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200121 /* apply patch */
122 msr.hi = 0;
123 msr.lo = (uint32_t)m;
124
Elyes HAOUAS1a5f1c82018-10-31 08:06:12 +0100125 wrmsr(MSR_PATCH_LOADER, msr);
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200126
127 UCODE_DEBUG("patch id to apply = 0x%08x\n", m->patch_id);
128
129 /* read the patch_id again */
Elyes HAOUASa9473ec2018-10-24 15:55:53 +0200130 msr = rdmsr(IA32_BIOS_SIGN_ID);
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200131 new_patch_id = msr.lo;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000132
Elyes HAOUASa342f392018-10-17 10:56:26 +0200133 UCODE_DEBUG("updated to patch id = 0x%08x %s\n", new_patch_id,
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200134 (new_patch_id == m->patch_id) ? "success" : "fail");
135}
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000136
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200137static void amd_update_microcode(const void *ucode, size_t ucode_len,
138 uint32_t equivalent_processor_rev_id)
139{
140 const struct microcode *m;
Kyösti Mälkki1608f362013-12-16 07:19:09 +0200141 const uint8_t *c = ucode;
142 const uint8_t *ucode_end = (uint8_t*)ucode + ucode_len;
Audrey Pearson83e4c562015-10-08 12:47:24 -0500143 const uint8_t *cur_section_hdr;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000144
Audrey Pearson83e4c562015-10-08 12:47:24 -0500145 uint32_t container_hdr_id;
146 uint32_t container_hdr_size;
147 uint32_t blob_size;
148 uint32_t sec_hdr_id;
149
150 /* Container Header */
151 container_hdr_id = read32(c);
152 if (container_hdr_id != UCODE_MAGIC) {
153 UCODE_DEBUG("Invalid container header ID\n");
154 return;
155 }
156
157 container_hdr_size = read32(c + 8);
158 cur_section_hdr = c + CONT_HDR + container_hdr_size;
159
160 /* Read in first section header ID */
161 sec_hdr_id = read32(cur_section_hdr);
162 c = cur_section_hdr + 4;
163
164 /* Loop through sections */
165 while (sec_hdr_id == UCODE_SECTION_START_ID &&
166 c <= (ucode_end - F15H_MPB_MAX_SIZE)) {
167
168 blob_size = read32(c);
169
170 m = (struct microcode *)(c + 4);
171
Kyösti Mälkki75b68d82013-12-12 06:53:05 +0200172 if (m->processor_rev_id == equivalent_processor_rev_id) {
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200173 apply_microcode_patch(m);
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000174 break;
175 }
Audrey Pearson83e4c562015-10-08 12:47:24 -0500176
177 cur_section_hdr = c + 4 + blob_size;
178 sec_hdr_id = read32(cur_section_hdr);
Elyes HAOUASb67cfbb2018-03-27 19:57:51 +0200179 c = cur_section_hdr + 4;
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000180 }
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200181}
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000182
Audrey Pearson83e4c562015-10-08 12:47:24 -0500183static const char *microcode_cbfs_file[] = {
184 "microcode_amd.bin",
185 "microcode_amd_fam15h.bin",
186};
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200187
Audrey Pearson83e4c562015-10-08 12:47:24 -0500188void amd_update_microcode_from_cbfs(uint32_t equivalent_processor_rev_id)
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200189{
190 const void *ucode;
191 size_t ucode_len;
192
Audrey Pearson83e4c562015-10-08 12:47:24 -0500193 uint32_t i;
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200194
Audrey Pearson83e4c562015-10-08 12:47:24 -0500195 for (i = 0; i < ARRAY_SIZE(microcode_cbfs_file); i++)
196 {
197 if (equivalent_processor_rev_id == 0) {
198 UCODE_DEBUG("rev id not found. Skipping microcode patch!\n");
199 return;
200 }
Kyösti Mälkki5fe1fb7a2013-12-08 07:21:05 +0200201
Timothy Pearsonc764c742015-08-28 20:48:17 -0500202#ifdef __PRE_RAM__
203#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
204 spin_lock(romstage_microcode_cbfs_lock());
205#endif
206#endif
207
Audrey Pearson83e4c562015-10-08 12:47:24 -0500208 ucode = cbfs_boot_map_with_leak(microcode_cbfs_file[i],
209 CBFS_TYPE_MICROCODE, &ucode_len);
210 if (!ucode) {
211 UCODE_DEBUG("microcode file not found. Skipping updates.\n");
Timothy Pearsonc764c742015-08-28 20:48:17 -0500212#ifdef __PRE_RAM__
213#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
214 spin_unlock(romstage_microcode_cbfs_lock());
215#endif
216#endif
Audrey Pearson83e4c562015-10-08 12:47:24 -0500217 return;
218 }
219
220 amd_update_microcode(ucode, ucode_len, equivalent_processor_rev_id);
Timothy Pearsonc764c742015-08-28 20:48:17 -0500221
222#ifdef __PRE_RAM__
223#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
224 spin_unlock(romstage_microcode_cbfs_lock());
225#endif
226#endif
Audrey Pearson83e4c562015-10-08 12:47:24 -0500227 }
Ronald G. Minnich9b6b3d22005-11-23 04:56:36 +0000228}