Angel Pons | f23ae0b | 2020-04-02 23:48:12 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Arthur Heymans | 2e658f8 | 2018-06-13 15:54:35 +0200 | [diff] [blame] | 2 | |
| 3 | /* |
| 4 | * input %esp: return address (not pointer to return address!) |
| 5 | * clobber the content of eax, ebx, ecx, edx, esi, edi, and ebp |
| 6 | */ |
| 7 | |
| 8 | #include <cpu/x86/post_code.h> |
| 9 | #include <cpu/x86/msr.h> |
Arthur Heymans | 0eb9c57 | 2019-01-05 18:21:47 +0100 | [diff] [blame] | 10 | |
| 11 | #define CBFS_FILE_MAGIC 0 |
| 12 | #define CBFS_FILE_LEN (CBFS_FILE_MAGIC + 8) |
| 13 | #define CBFS_FILE_TYPE (CBFS_FILE_LEN + 4) |
| 14 | #define CBFS_FILE_CHECKSUM (CBFS_FILE_TYPE + 4) |
| 15 | #define CBFS_FILE_OFFSET (CBFS_FILE_CHECKSUM + 4) |
Arthur Heymans | 2e658f8 | 2018-06-13 15:54:35 +0200 | [diff] [blame] | 16 | |
| 17 | #define HEADER_VER_OFFSET 0 |
| 18 | #define UPDATE_VER_OFFSET 4 |
| 19 | #define DATE_OFFSET 8 |
| 20 | #define PROCESSOR_SIG_OFFSET 12 |
| 21 | #define CHKSUM_OFFSET 16 |
| 22 | #define LOADER_REV_OFFSET 20 |
| 23 | #define PROCESSOR_FLAG 24 |
| 24 | #define DATA_SIZE_OFFSET 28 |
| 25 | #define TOTAL_OFFSET 32 |
| 26 | #define HEADER_SIZE 48 |
| 27 | |
| 28 | /* |
| 29 | * The microcode header is 48 bytes wide and has the following |
| 30 | * structure: |
| 31 | * Header Version : 32bit |
| 32 | * Update Revision : 32bit |
| 33 | * Date : 32bit |
| 34 | * Processor Signature : 32bit |
| 35 | * Checksum : 32bit |
| 36 | * Loader Revision : 32bit |
| 37 | * Processor Flags : 32bit |
| 38 | * Data Size : 32bit |
| 39 | * Total Size : 32bit |
| 40 | * Reserved : 96bit |
| 41 | * |
| 42 | * We only check if the Processor signature and flags match and check |
| 43 | * if the revision of the update is newer than what is installed |
| 44 | */ |
| 45 | |
Patrick Rudolph | 983ea18 | 2020-11-30 13:33:41 +0100 | [diff] [blame^] | 46 | .code32 |
Arthur Heymans | 2e658f8 | 2018-06-13 15:54:35 +0200 | [diff] [blame] | 47 | .section .text |
| 48 | .global update_bsp_microcode |
| 49 | |
| 50 | update_bsp_microcode: |
| 51 | /* Keep return address */ |
| 52 | movl %esp, %edx |
| 53 | /* find microcodes in cbfs */ |
| 54 | leal microcode_name, %esi |
| 55 | movl $1f, %esp |
| 56 | jmp walkcbfs_asm |
| 57 | |
| 58 | 1: |
| 59 | /* restore return address */ |
| 60 | movl %edx, %esp |
| 61 | |
| 62 | cmpl $0, %eax |
| 63 | je end_microcode_update |
| 64 | movl CBFS_FILE_OFFSET(%eax), %ebx |
| 65 | bswap %ebx |
| 66 | addl %eax, %ebx |
| 67 | movl %ebx, %esi |
| 68 | |
| 69 | movl CBFS_FILE_LEN(%eax), %edi |
| 70 | bswap %edi |
| 71 | addl %esi, %edi |
| 72 | |
| 73 | /* |
| 74 | * Microcode revision -> %ebx |
| 75 | * Processor flags -> %ebp |
| 76 | * Current installed microcode revision -> %edx |
| 77 | */ |
| 78 | |
Arthur Heymans | 2e658f8 | 2018-06-13 15:54:35 +0200 | [diff] [blame] | 79 | /* Processor flags |
| 80 | * rdmsr 0x17 |
| 81 | * pf = 1 << ((msr.hi >> 18) & 7) */ |
| 82 | movl $IA32_PLATFORM_ID, %ecx |
| 83 | rdmsr |
| 84 | shr $18, %edx |
| 85 | andl $7, %edx |
| 86 | movl $1, %eax |
| 87 | /* needs to be %cl for shl */ |
| 88 | movl %edx, %ecx |
| 89 | shl %cl, %eax |
| 90 | movl %eax, %ebp |
| 91 | |
| 92 | /* Fetch the current microcode revision*/ |
| 93 | xorl %eax, %eax |
| 94 | xorl %edx, %edx |
| 95 | movl $IA32_BIOS_SIGN_ID, %ecx |
| 96 | wrmsr |
| 97 | movl $0x1, %eax |
| 98 | cpuid |
Arthur Heymans | 8c70dd6 | 2019-01-05 17:20:11 +0100 | [diff] [blame] | 99 | |
| 100 | /* Processor family+model signature=cpuid_eax(1) */ |
| 101 | movl %eax, %ebx |
| 102 | |
Arthur Heymans | 2e658f8 | 2018-06-13 15:54:35 +0200 | [diff] [blame] | 103 | movl $IA32_BIOS_SIGN_ID, %ecx |
| 104 | rdmsr |
| 105 | |
| 106 | check_microcode_entry: |
| 107 | /* Test if header revision is non zero */ |
| 108 | cmpl $0, HEADER_VER_OFFSET(%esi) |
| 109 | je end_microcode_update |
| 110 | |
| 111 | /* Processor family+model signature=cpuid_eax(1) */ |
| 112 | cmpl PROCESSOR_SIG_OFFSET(%esi), %ebx |
| 113 | jne next_entry |
| 114 | |
| 115 | /* Processor flags */ |
Arthur Heymans | 8c70dd6 | 2019-01-05 17:20:11 +0100 | [diff] [blame] | 116 | test PROCESSOR_FLAG(%esi), %ebp |
| 117 | jz next_entry |
Arthur Heymans | 2e658f8 | 2018-06-13 15:54:35 +0200 | [diff] [blame] | 118 | |
| 119 | /* Check if revision is higher than current */ |
| 120 | cmpl UPDATE_VER_OFFSET(%esi), %edx |
| 121 | /* Don't upgrade if already greater or equal */ |
| 122 | jge end_microcode_update |
| 123 | |
| 124 | /* Do actual update */ |
| 125 | movl %esi, %eax |
| 126 | addl $HEADER_SIZE, %eax |
| 127 | xorl %edx, %edx |
| 128 | movl $IA32_BIOS_UPDT_TRIG, %ecx |
| 129 | wrmsr |
| 130 | |
| 131 | jmp end_microcode_update |
| 132 | |
| 133 | next_entry: |
| 134 | movl TOTAL_OFFSET(%esi), %eax |
| 135 | cmpl $0, %eax |
| 136 | jne 1f |
| 137 | /* Newer microcode updates include a size field, whereas older |
| 138 | * containers set it at 0 and are exactly 2048 bytes long */ |
| 139 | addl $2048, %esi |
| 140 | jmp check_end |
| 141 | 1: |
| 142 | addl %eax, %esi |
| 143 | |
| 144 | check_end: |
| 145 | cmpl %esi, %edi |
| 146 | ja check_microcode_entry |
| 147 | |
| 148 | end_microcode_update: |
| 149 | jmp *%esp |
| 150 | |
| 151 | microcode_name: |
| 152 | .string "cpu_microcode_blob.bin" |
| 153 | |
| 154 | _update_bsp_microcode_end: |