1/* SPDX-License-Identifier: GPL-2.0-only */ 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> 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) 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 46.code32 47.section .init 48.global update_bsp_microcode 49 50update_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 581: 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 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 99 100 /* Processor family+model signature=cpuid_eax(1) */ 101 movl %eax, %ebx 102 103 movl $IA32_BIOS_SIGN_ID, %ecx 104 rdmsr 105 106check_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 */ 116 test PROCESSOR_FLAG(%esi), %ebp 117 jz next_entry 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 133next_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 1411: 142 addl %eax, %esi 143 144check_end: 145 cmpl %esi, %edi 146 ja check_microcode_entry 147 148end_microcode_update: 149 jmp *%esp 150 151microcode_name: 152 .string "cpu_microcode_blob.bin" 153 154_update_bsp_microcode_end: 155