Hey all,
Some more updates on this topic for anyone interested...
You don't have to do anything to support cpu's with hyper-threading, must be applied once per physical/logical cpu otherwise.
I've written some code (it assembles) but haven't had a chance to test it yet that should perform the entire update procedure, all that is needed is to have the bin's in memory and move through them using:
Code: Select all
;##############################################################################################################################
;
; VX Platform v1.0
; - Intel CPU Microcode update loader v1.0
; Author: John Hankinson
; Date: 2010-02-01
;
;##############################################################################################################################
_imc_update_checksum dd ?
_imc_update_datasize dd ?
_imc_update_totalsize dd ?
_imc_update_processorSignature dd ?
_imc_update_processorFlags dd ?
_imc_update_extsigSize dd ?
_imc_update_extsigCount dd ?
_imc_cpu_processorSignature dd ?
_imc_cpu_platformID dd ?
_imc_cpu_currentUpdateVer dd ?
;==============================================================================================================================
; Real Mode Microcode update loader.
; -> IN: ES:EDI points to update packet.
; -> OUT: EAX = 1[fail] or 0[success].
; -> Update packet cannot cross a segment boundary and must be 16byte aligned.
;==============================================================================================================================
cpu_microcode_update:
; Ensure all global values are reset.
mov dword [_imc_update_checksum],0
mov dword [_imc_update_datasize],0
mov dword [_imc_update_totalsize],0
mov dword [_imc_update_processorSignature],0
mov dword [_imc_update_processorFlags],0
mov dword [_imc_update_extsigSize],0
mov dword [_imc_update_extsigCount],0
; Get the current update version or 0 if none.
mov eax,01h
CPUID ; Ensure the MSR is loaded so we can read it.
mov ecx,MSR_IA32_BIOS_SIGN_ID
xor edx,edx
xor eax,eax
RDMSR
mov [_imc_cpu_currentUpdateVer],edx
; Ensure Update's Header Version is 00000001h.
mov eax,[es:edi]
.if eax <> 1
mov eax,1
ret ; If the update header is not 1 then return.
.endif
; Ensure that this update's revision is > than our CPUs current loaded one.
mov eax,[es:edi+4]
cmp eax,[_imc_cpu_currentUpdateVer]
jge short verOk
mov eax,1 ; Version is older - don't continue.
ret
; Get the update's size values.
verOk:
mov eax,[es:edi+16] ; Get the update checksum. this + all dwords of update should = 0.
mov ebx,[es:edi+28] ; Get the data size in bytes (if 0 then size is 2000 bytes).
mov ecx,[es:edi+32] ; Get total size of update in bytes (= head+data+optional ext. sig. table).
; If the data size is 0, then it's assumed to be 2000.
.if ebx = 0
mov ebx,2000
mov ecx,(2000+48)
.endif
mov [_imc_update_checksum],eax
mov [_imc_update_datasize],ebx
mov [_imc_update_totalsize],ecx
; Determine if there is an extended signature table and if so the count.
sub ecx,ebx
.if ecx > 48
mov [_imc_update_extsigSize],ecx
mov eax,[_imc_update_datasize]
add eax,48
mov eax,[es:edi+eax] ; Location of Extended Signature Count.
mov [_imc_update_extsigCount],eax
.endif
; Validate the update's checksum.
xor eax,eax
mov ecx,[_imc_update_totalsize]
shr ecx,2 ; Size in bytes now dwords.
push edi
validate_checksum:
add eax,[es:edi]
add edi,4
dec ecx
jnz short validate_checksum
pop edi
.if eax <> 0
mov eax,1 ; Checksum validation failed.
ret
.endif
; Get CPU type, family, model, stepping id.
mov eax,1 ; | 31 - 28 | 27 - 20 | 19 - 16 | 15 - 14 | 13 - 12 | 11 - 8 | 7 - 4 | 3 - 0 |
CPUID ; eax will contain: | | ext family id | ext model id | | | family id | model | stepping |
mov [_imc_cpu_processorSignature],eax
; Get the update data's Processor Signature.
mov ebx,[es:edi+12]
mov [_imc_update_processorSignature],ebx
; Ensure that we can find a matching signature between the update and our CPU.
.if eax <> ebx
mov ebx,[_imc_update_extsigSize]
.if ebx <> 0
mov ecx,[_imc_update_extsigCount]
xor ebx,ebx
push edi
add edi,[_imc_update_datasize]
add edi,(48+20)
checkExtSigs:
mov edx,[es:edi]
.if eax = edx
mov ebx,1 ; Found a matching signature.
.endif
add edi,12 ; Move to next extended signature entry.
dec ecx
jnz short checkExtSigs
pop edi
.if ebx = 1
jmp short processorSignaturesMatch
.endif
.endif
mov eax,1
ret ; If the processor signature of the update doesn't match our CPU then return.
.endif
; Read IA32_PLATFORM_ID MSR (bits 50-52).
processorSignaturesMatch:
mov ecx,MSR_IA32_PLATFORM_ID
RDMSR
mov [_imc_cpu_platformID],edx
; Read the Update's Processor Flags.
mov ebx,[es:edi+24] ; Read processor flags from the update.
mov [_imc_update_processorFlags],ebx
; Ensure that the processor flags match.
mov eax,1
mov ecx,[_imc_cpu_platformID]
and ecx,00000000000111000000000000000000b ; Keep bits 50-52 of the MSR.
shr ecx,18
shl eax,cl
mov ebx,eax
and eax,[_imc_update_processorFlags]
.if eax <> 0
jmp short load_update ; The primary processor flags match.
.endif
; Now loop through extended processorFlags and test.
mov eax,ebx
mov ebx,[_imc_update_extsigSize]
.if ebx <> 0
mov ecx,[_imc_update_extsigCount]
xor ebx,ebx
push edi
add edi,[_imc_update_datasize]
add edi,(48+20)
checkExtFlags:
mov edx,[es:edi+4]
and edx,eax
.if edx <> 0
mov ebx,1 ; Found a matching flags/platform id.
.endif
add edi,12 ; Move to next extended signature entry.
dec ecx
jnz short checkExtFlags
pop edi
.if ebx = 1
jmp short load_update
.endif
.endif
mov eax,1 ; No matching processor flags so fail.
ret
; Force processor to load the microcode update.
load_update:
xor eax,eax
mov ax,es
shl eax,4
add eax,edi
add eax,48 ; Skip the header (point straight at update data).
xor edx,edx
mov ecx,MSR_IA32_BIOS_UPDT_TRIG
WRMSR
; Confirm that the update revision matches the update.
mov eax,01h
CPUID
mov ecx,MSR_IA32_BIOS_SIGN_ID
xor edx,edx
xor eax,eax
RDMSR
.if edx <> dword [_imc_cpu_currentUpdateVer]
mov eax,1
ret ; Revision's differ / update must have failed.
.endif
xor eax,eax
ret
It's written for fasm using:
offset equ
and including the macro file to allow .if/.endif.
If anyone wants to try it out and has some feedback that would be great.
I'll get around to testing it when i'm not at work and update as necessary.
John