Angel Pons | f23ae0b | 2020-04-02 23:48:12 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 2 | |
| 3 | #include <stdint.h> |
| 4 | #include <cpu/amd/microcode.h> |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 5 | #include <commonlib/helpers.h> |
| 6 | #include <console/console.h> |
| 7 | #include <cpu/x86/msr.h> |
| 8 | #include <cpu/amd/msr.h> |
| 9 | #include <cbfs.h> |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 10 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 11 | /* |
| 12 | * Values and header structure from: |
| 13 | * BKDG for AMD Family 16h Models 30h-3Fh Processors |
| 14 | * 52740 Rev 3.06 - March 18, 2016 |
| 15 | */ |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 16 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 17 | #define F16H_MPB_MAX_SIZE 3458 |
| 18 | #define F16H_MPB_DATA_OFFSET 32 |
| 19 | |
| 20 | /* |
| 21 | * STRUCTURE OF A MICROCODE (UCODE) FILE FOR FAM16h |
| 22 | * Microcode Patch Block |
| 23 | * Microcode Header |
| 24 | * Microcode "Blob" |
| 25 | * ... |
| 26 | * ... |
| 27 | * (end of file) |
| 28 | * |
| 29 | * |
| 30 | * MICROCODE HEADER (offset 0 bytes from start of file) |
| 31 | * Total size = 32 bytes |
| 32 | * [0:3] Date code (32 bits) |
| 33 | * [4:7] Patch level (32 bits) |
| 34 | * [8:9] Microcode patch data ID (16 bits) |
| 35 | * [10:15] Reserved (48 bits) |
| 36 | * [16:19] Chipset 1 device ID (32 bits) |
| 37 | * [20:23] Chipset 2 device ID (32 bits) |
| 38 | * [24:25] Processor Revisions ID (16 bits) |
| 39 | * [26] Chipset 1 revision ID (8 bits) |
| 40 | * [27] Chipset 2 revision ID (8 bits) |
| 41 | * [28:31] Reserved (32 bits) |
| 42 | * |
| 43 | * MICROCODE BLOB (offset += 32) |
| 44 | * Total size = m bytes |
| 45 | * |
| 46 | */ |
| 47 | |
| 48 | struct microcode { |
| 49 | uint32_t date_code; |
| 50 | uint32_t patch_id; |
| 51 | |
| 52 | uint16_t mc_patch_data_id; |
| 53 | uint8_t reserved1[6]; |
| 54 | |
| 55 | uint32_t chipset1_dev_id; |
| 56 | uint32_t chipset2_dev_id; |
| 57 | |
| 58 | uint16_t processor_rev_id; |
| 59 | |
| 60 | uint8_t chipset1_rev_id; |
| 61 | uint8_t chipset2_rev_id; |
| 62 | |
| 63 | uint8_t reserved2[4]; |
| 64 | |
| 65 | uint8_t m_patch_data[F16H_MPB_MAX_SIZE-F16H_MPB_DATA_OFFSET]; |
| 66 | } __packed; |
| 67 | |
| 68 | static void apply_microcode_patch(const struct microcode *m) |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 69 | { |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 70 | uint32_t new_patch_id; |
| 71 | msr_t msr; |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 72 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 73 | msr.hi = (uint64_t)(uintptr_t)m >> 32; |
| 74 | msr.lo = (uintptr_t)m & 0xffffffff; |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 75 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 76 | wrmsr(MSR_PATCH_LOADER, msr); |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 77 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 78 | printk(BIOS_DEBUG, "microcode: patch id to apply = 0x%08x\n", |
| 79 | m->patch_id); |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 80 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 81 | msr = rdmsr(MSR_PATCH_LEVEL); |
| 82 | new_patch_id = msr.lo; |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 83 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 84 | if (new_patch_id == m->patch_id) |
| 85 | printk(BIOS_INFO, "microcode: being updated to patch id = 0x%08x succeeded\n", |
| 86 | new_patch_id); |
| 87 | else |
| 88 | printk(BIOS_ERR, "microcode: being updated to patch id = 0x%08x failed\n", |
| 89 | new_patch_id); |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 90 | } |
| 91 | |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 92 | static uint16_t get_equivalent_processor_rev_id(void) |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 93 | { |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 94 | uint32_t cpuid_family = cpuid_eax(1); |
| 95 | |
| 96 | return (uint16_t)((cpuid_family & 0xff0000) >> 8 | (cpuid_family & 0xff)); |
| 97 | } |
| 98 | |
| 99 | static void amd_update_microcode(const void *ucode, size_t ucode_len, |
| 100 | uint16_t equivalent_processor_rev_id) |
| 101 | { |
| 102 | const struct microcode *m; |
| 103 | const uint8_t *c = ucode; |
| 104 | |
| 105 | m = (struct microcode *)c; |
| 106 | |
| 107 | /* Assume cpu_microcode_blob only contains one microcode. */ |
| 108 | if (m->processor_rev_id == equivalent_processor_rev_id) |
| 109 | apply_microcode_patch(m); |
| 110 | } |
| 111 | |
| 112 | void amd_update_microcode_from_cbfs(void) |
| 113 | { |
| 114 | const void *ucode; |
| 115 | size_t ucode_len; |
| 116 | uint16_t equivalent_processor_rev_id = get_equivalent_processor_rev_id(); |
| 117 | |
Julius Werner | 834b3ec | 2020-03-04 16:52:08 -0800 | [diff] [blame^] | 118 | ucode = cbfs_map("cpu_microcode_blob.bin", &ucode_len); |
Zheng Bao | b8c473e | 2020-06-09 09:30:39 +0800 | [diff] [blame] | 119 | if (!ucode) { |
| 120 | printk(BIOS_WARNING, "cpu_microcode_blob.bin not found. Skipping updates.\n"); |
| 121 | return; |
| 122 | } |
| 123 | |
| 124 | if (ucode_len > F16H_MPB_MAX_SIZE || |
| 125 | ucode_len < F16H_MPB_DATA_OFFSET) { |
| 126 | printk(BIOS_DEBUG, "microcode file invalid. Skipping updates.\n"); |
| 127 | return; |
| 128 | } |
| 129 | |
| 130 | amd_update_microcode(ucode, ucode_len, equivalent_processor_rev_id); |
Michał Żygowski | 319f037 | 2018-10-25 15:48:54 +0200 | [diff] [blame] | 131 | } |