Intel Microcode Updating

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Intel Microcode Updating

Post by johnsa »

Hey all,

For anyone that is interested. I found the latest Microcode update file from Intel specifically for Linux. It was in a a text file format so I write a small proggy to extract out the data and write out the respective binary files for each update.
Each bin file is a multiple of 2kb (most are exactly 2kb) and conform to the specification in the Intel manuals. The process to apply the update is fairly trivial save that you need to apply it for every logical processor (IE: in your trampoline code for smp). In any event I hope someone finds this useful. Refer to Intel manual system programming guide 3a - microcode update facilities.

Link for the original DAT file from Intel:
http://www.johnoconnor.co.za/microcode-20090330.tgz

Link to a RAR of all the extracted BIN files:
http://www.johnoconnor.co.za/Bins.rar

C#.NET 3.5 App to do the extraction:
http://www.johnoconnor.co.za/LXCode2Bin.rar

Let me know if this is helpful, or if you want to share any code for applying the updates etc. This is all towards my system-startup tutorial as mentioned in another thread.

John
johnsa
Member
Member
Posts: 296
Joined: Mon Oct 15, 2007 3:04 pm

Re: Intel Microcode Updating

Post by johnsa »

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
Post Reply