mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
3bcc686023
Drop the unneded register preserving of RBX, RSI and RDI. It's no longer
needed since commit 5c943b8f38 ("Changes to windows helper and driver
to support return values") refactored the code to just work with the
passed SMI_CTX buffer as scratch space.
Also clobber only the lower 16 bits of RAX with 'smi_code_data', as
documented and assumed by callers.
Last, but not least, drop the misleading comment about clobbering DX as
that doesn't happen any more. Also update all other comments to mirror
the current implementation.
This brings the Windows implementation in line with the Linux one.
Signed-off-by: Mathias Krause <minipli@grsecurity.net>
702 lines
17 KiB
NASM
702 lines
17 KiB
NASM
TITLE cpu.asm: Assembly code for the x64 resources
|
|
|
|
.CODE chipsec_code$__a
|
|
|
|
PUBLIC DisableInterrupts
|
|
PUBLIC WritePortDword
|
|
PUBLIC WritePortWord
|
|
PUBLIC WritePortByte
|
|
PUBLIC ReadPortDword
|
|
PUBLIC ReadPortWord
|
|
PUBLIC ReadPortByte
|
|
PUBLIC WriteHighCMOSByte
|
|
PUBLIC WriteLowCMOSByte
|
|
PUBLIC SendAPMSMI
|
|
PUBLIC WritePCIByte
|
|
PUBLIC WritePCIWord
|
|
PUBLIC WritePCIDword
|
|
PUBLIC ReadPCIByte
|
|
PUBLIC ReadPCIWord
|
|
PUBLIC ReadPCIDword
|
|
PUBLIC _rdmsr
|
|
PUBLIC _wrmsr
|
|
PUBLIC _load_gdt
|
|
PUBLIC _rflags
|
|
PUBLIC ReadCR0
|
|
PUBLIC ReadCR2
|
|
PUBLIC ReadCR3
|
|
PUBLIC ReadCR4
|
|
PUBLIC ReadCR8
|
|
PUBLIC WriteCR0
|
|
PUBLIC WriteCR2
|
|
PUBLIC WriteCR3
|
|
PUBLIC WriteCR4
|
|
PUBLIC WriteCR8
|
|
PUBLIC hypercall
|
|
PUBLIC hypercall_page
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; UINT64 _rflags()
|
|
;------------------------------------------------------------------------------
|
|
_rflags PROC
|
|
pushfq
|
|
pop rax
|
|
ret
|
|
_rflags ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _store_idtr(
|
|
; unsigned char *address // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_store_idtr PROC
|
|
sidt fword ptr [rcx]
|
|
ret
|
|
_store_idtr ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _load_idtr(
|
|
; unsigned char *address // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_idtr PROC
|
|
lidt fword ptr [rcx]
|
|
ret
|
|
_load_idtr ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _store_gdtr(
|
|
; unsigned char *address // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_store_gdtr PROC
|
|
sgdt fword ptr [rcx]
|
|
ret
|
|
_store_gdtr ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _load_gdtr(
|
|
; unsigned char *address // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_gdtr PROC
|
|
lgdt fword ptr [rcx]
|
|
ret
|
|
_load_gdtr ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _store_ldtr(
|
|
; unsigned char *address // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_store_ldtr PROC
|
|
;sldt fword ptr [rcx]
|
|
ret
|
|
_store_ldtr ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _load_ldtr(
|
|
; unsigned char *address // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_ldtr PROC
|
|
;lldt fword ptr [rcx]
|
|
ret
|
|
_load_ldtr ENDP
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _load_gdt(
|
|
; unsigned char *value // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_gdt PROC
|
|
|
|
sgdt fword ptr [rcx]
|
|
lgdt fword ptr [rcx]
|
|
|
|
ret
|
|
_load_gdt ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _rdmsr(
|
|
; unsigned int msr_num, // rcx
|
|
; unsigned int* msr_lo, // rdx
|
|
; unsigned int* msr_hi // r8
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_rdmsr PROC FRAME
|
|
push r10
|
|
.ALLOCSTACK 8
|
|
push r11
|
|
.ALLOCSTACK 8
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
mov r10, rdx ; msr_lo
|
|
mov r11, r8 ; msr_hi
|
|
|
|
; rcx has msr_num
|
|
rdmsr
|
|
|
|
; Write MSR results in edx:eax
|
|
mov dword ptr [r10], eax
|
|
mov dword ptr [r11], edx
|
|
|
|
pop rdx
|
|
pop rax
|
|
pop r11
|
|
pop r10
|
|
|
|
ret
|
|
_rdmsr ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void _wrmsr(
|
|
; unsigned int msr_num, // rcx
|
|
; unsigned int msr_hi, // rdx
|
|
; unsigned int msr_lo // r8
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_wrmsr PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
; rcx has msr_num
|
|
; rdx has msr_hi
|
|
; move msr_lo from r8 to rax
|
|
mov rax, r8
|
|
wrmsr
|
|
|
|
pop rax
|
|
ret
|
|
_wrmsr ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; DisableInterrupts (
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
DisableInterrupts PROC
|
|
cli
|
|
ret
|
|
DisableInterrupts ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePortDword (
|
|
; unsigned int out_value // rcx
|
|
; unsigned short port_num // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePortDword PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
mov rax, rcx
|
|
out dx, rax
|
|
|
|
pop rax
|
|
ret
|
|
WritePortDword ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePortWord (
|
|
; unsigned short out_value // rcx
|
|
; unsigned short port_num // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePortWord PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
mov rax, rcx
|
|
out dx, ax
|
|
|
|
pop rax
|
|
ret
|
|
WritePortWord ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePortByte (
|
|
; unsigned char out_value // rcx
|
|
; unsigned short port_num // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePortByte PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
mov rax, rcx
|
|
out dx, al
|
|
|
|
pop rax
|
|
ret
|
|
WritePortByte ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; unsigned int
|
|
; ReadPortDword (
|
|
; unsigned short port_num // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPortDword PROC FRAME
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
xor rax, rax
|
|
mov rdx, rcx
|
|
in eax, dx
|
|
|
|
pop rdx
|
|
ret
|
|
ReadPortDword ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; unsigned short
|
|
; ReadPortWord (
|
|
; unsigned short port_num // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPortWord PROC FRAME
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
xor rax, rax
|
|
mov rdx, rcx
|
|
in ax, dx
|
|
|
|
pop rdx
|
|
ret
|
|
ReadPortWord ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; unsigned char
|
|
; ReadPortByte (
|
|
; unsigned short port_num // rcx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPortByte PROC FRAME
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
xor rax, rax
|
|
mov rdx, rcx
|
|
in al, dx
|
|
|
|
pop rdx
|
|
ret
|
|
ReadPortByte ENDP
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WriteHighCMOSByte (
|
|
; unsigned char cmos_off // rcx
|
|
; unsigned char val // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WriteHighCMOSByte PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
mov rax, rcx
|
|
out 72h, al
|
|
mov rax, rdx
|
|
out 73h, al
|
|
|
|
pop rax
|
|
ret
|
|
WriteHighCMOSByte ENDP
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WriteLowCMOSByte (
|
|
; unsigned char cmos_off // rcx
|
|
; unsigned char val // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WriteLowCMOSByte PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
mov rax, rcx
|
|
or al, 80h
|
|
out 70h, al
|
|
mov rax, rdx
|
|
out 71h, al
|
|
|
|
pop rax
|
|
ret
|
|
WriteLowCMOSByte ENDP
|
|
|
|
|
|
; @TODO: looks incorrect
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; SendAPMSMI (
|
|
; unsigned int apm_port_value // rcx
|
|
; IN UINT64 rax_value // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
SendAPMSMI PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
mov rax, rcx
|
|
mov dx, 0B2h
|
|
out dx, rax
|
|
|
|
pop rdx
|
|
pop rax
|
|
ret
|
|
SendAPMSMI ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
;This function has one argument: swsmi_msg_t structure pointer which contain SMI code and data values and 6 regs: rax, rbx, rcx, rdx, rsi, rdi:
|
|
; IN UINT64 code_data (only lower 16 bit used)
|
|
; IN/OUT UINT64 rax_value
|
|
; IN/OUT UINT64 rbx_value
|
|
; IN/OUT UINT64 rcx_value
|
|
; IN/OUT UINT64 rdx_value
|
|
; IN/OUT UINT64 rsi_value
|
|
; IN/OUT UINT64 rdi_value
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; _swsmi (
|
|
; swsmi_msg_t*
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_swsmi PROC
|
|
; setting up GPR (arguments) to SMI handler call
|
|
; notes:
|
|
; RAX will get partially overwritten (AX) by code_data
|
|
mov r10, rcx ; //pointer for struct into r10
|
|
xchg rax, [r10+08h] ; //rax_value (partially overwritten by code_data)
|
|
mov ax, [r10] ; //code_data
|
|
xchg rbx, [r10+10h] ; //rbx value
|
|
xchg rcx, [r10+18h] ; //rcx value
|
|
xchg rdx, [r10+20h] ; //rdx value
|
|
xchg rsi, [r10+28h] ; //rsi value
|
|
xchg rdi, [r10+30h] ; //rdi value
|
|
|
|
; Output smi_code_data split up to their designated ports, SW SMI data
|
|
; (0xB3) and SW SMI control (0xB2), respectively.
|
|
;
|
|
; Resist from outputting both at once as a single word, as some systems
|
|
; reject the request if the i/o spans more than a byte, e.g.:
|
|
; https://github.com/tianocore/edk2-platforms/blob/aa3f6fd542e99dde4206537b095f1a2201275e75/Silicon/Intel/CoffeelakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c#L314
|
|
ror ax, 8
|
|
out 0B3h, al ; SW SMI data
|
|
ror ax, 8
|
|
out 0B2h, al ; SW SMI control
|
|
|
|
; some SMI handlers return data/errorcode in GPRs, need to return this to the caller
|
|
xchg [r10+08h], rax ; //rax value
|
|
xchg [r10+10h], rbx ; //rbx value
|
|
xchg [r10+18h], rcx ; //rcx value
|
|
xchg [r10+20h], rdx ; //rdx value
|
|
xchg [r10+28h], rsi ; //rsi value
|
|
xchg [r10+30h], rdi ; //rdi value
|
|
|
|
ret
|
|
_swsmi ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePCIByte (
|
|
; unsigned int pci_reg // rcx
|
|
; unsigned short cfg_data_port // rdx
|
|
; unsigned char byte_value // r8
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePCIByte PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
cli
|
|
mov rax, rcx ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, rax
|
|
|
|
mov rax, r8 ; byte_value
|
|
pop rdx ; cfg_data_port
|
|
out dx, al
|
|
sti
|
|
|
|
pop rax
|
|
ret
|
|
WritePCIByte ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePCIWord (
|
|
; unsigned int pci_reg // rcx
|
|
; unsigned short cfg_data_port // rdx
|
|
; unsigned short word_value // r8
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePCIWord PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
cli
|
|
mov rax, rcx ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, rax
|
|
|
|
mov rax, r8 ; byte_value
|
|
pop rdx ; cfg_data_port
|
|
out dx, ax
|
|
sti
|
|
|
|
pop rax
|
|
ret
|
|
WritePCIWord ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePCIDword (
|
|
; unsigned int pci_reg // rcx
|
|
; unsigned short cfg_data_port // rdx
|
|
; unsigned int dword_value // r8
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePCIDword PROC FRAME
|
|
push rax
|
|
.ALLOCSTACK 8
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
cli
|
|
mov rax, rcx ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, rax
|
|
|
|
mov rax, r8 ; byte_value
|
|
pop rdx ; cfg_data_port
|
|
out dx, eax
|
|
sti
|
|
|
|
pop rax
|
|
ret
|
|
WritePCIDword ENDP
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; unsigned char
|
|
; ReadPCIByte (
|
|
; unsigned int pci_reg // rcx
|
|
; unsigned short cfg_data_port // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPCIByte PROC FRAME
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
cli
|
|
mov rax, rcx ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, rax
|
|
|
|
xor rax, rax
|
|
pop rdx ; cfg_data_port
|
|
in al, dx
|
|
sti
|
|
|
|
ret
|
|
ReadPCIByte ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; unsigned short
|
|
; ReadPCIWord (
|
|
; unsigned int pci_reg // rcx
|
|
; unsigned short cfg_data_port // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPCIWord PROC FRAME
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
cli
|
|
mov rax, rcx ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, rax
|
|
|
|
xor rax, rax
|
|
pop rdx ; cfg_data_port
|
|
in ax, dx
|
|
sti
|
|
|
|
ret
|
|
ReadPCIWord ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; unsigned int
|
|
; ReadPCIDword (
|
|
; unsigned int pci_reg // rcx
|
|
; unsigned short cfg_data_port // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPCIDword PROC FRAME
|
|
push rdx
|
|
.ALLOCSTACK 8
|
|
.endprolog
|
|
|
|
cli
|
|
mov rax, rcx ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, rax
|
|
|
|
xor rax, rax
|
|
pop rdx ; cfg_data_port
|
|
in eax, dx
|
|
sti
|
|
|
|
ret
|
|
ReadPCIDword ENDP
|
|
|
|
ReadCR0 PROC
|
|
xor rax, rax
|
|
mov rax, cr0
|
|
ret
|
|
ReadCR0 ENDP
|
|
|
|
ReadCR2 PROC
|
|
xor rax, rax
|
|
mov rax, cr2
|
|
ret
|
|
ReadCR2 ENDP
|
|
|
|
ReadCR3 PROC
|
|
xor rax, rax
|
|
mov rax, cr3
|
|
ret
|
|
ReadCR3 ENDP
|
|
|
|
ReadCR4 PROC
|
|
xor rax, rax
|
|
mov rax, cr4
|
|
ret
|
|
ReadCR4 ENDP
|
|
|
|
ReadCR8 PROC
|
|
xor rax, rax
|
|
mov rax, cr8
|
|
ret
|
|
ReadCR8 ENDP
|
|
|
|
WriteCR0 PROC
|
|
mov cr0, rcx
|
|
ret
|
|
WriteCR0 ENDP
|
|
|
|
WriteCR2 PROC
|
|
mov cr2, rcx
|
|
ret
|
|
WriteCR2 ENDP
|
|
|
|
WriteCR3 PROC
|
|
mov cr3, rcx
|
|
ret
|
|
WriteCR3 ENDP
|
|
|
|
WriteCR4 PROC
|
|
mov cr4, rcx
|
|
ret
|
|
WriteCR4 ENDP
|
|
|
|
WriteCR8 PROC
|
|
mov cr8, rcx
|
|
ret
|
|
WriteCR8 ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; CPU_REG_TYPE
|
|
; hypercall(
|
|
; CPU_REG_TYPE rcx_val, // rcx +08h
|
|
; CPU_REG_TYPE rdx_val, // rdx +10h
|
|
; CPU_REG_TYPE r8_val, // r8 +18h
|
|
; CPU_REG_TYPE r9_val, // r9 +20h
|
|
; CPU_REG_TYPE r10_val, // on stack +28h
|
|
; CPU_REG_TYPE r11_val, // on stack +30h
|
|
; CPU_REG_TYPE rax_val, // on stack +38h
|
|
; CPU_REG_TYPE rbx_val, // on stack +40h
|
|
; CPU_REG_TYPE rdi_val, // on stack +48h
|
|
; CPU_REG_TYPE rsi_val, // on stack +50h
|
|
; CPU_REG_TYPE xmm_buffer, // on stack +58h
|
|
; CPU_REG_TYPE hypercall_page // on stack +60h
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
|
|
hypercall PROC
|
|
push rsi
|
|
push rdi
|
|
push rbx
|
|
mov r11, qword ptr [rsp + 18h + 58h]
|
|
test r11, r11
|
|
jz hypercall_skip_xmm
|
|
pinsrq xmm0, qword ptr [r11 + 000h], 00h
|
|
pinsrq xmm0, qword ptr [r11 + 008h], 01h
|
|
pinsrq xmm1, qword ptr [r11 + 010h], 00h
|
|
pinsrq xmm1, qword ptr [r11 + 018h], 01h
|
|
pinsrq xmm2, qword ptr [r11 + 020h], 00h
|
|
pinsrq xmm2, qword ptr [r11 + 028h], 01h
|
|
pinsrq xmm3, qword ptr [r11 + 030h], 00h
|
|
pinsrq xmm3, qword ptr [r11 + 038h], 01h
|
|
pinsrq xmm4, qword ptr [r11 + 040h], 00h
|
|
pinsrq xmm4, qword ptr [r11 + 048h], 01h
|
|
pinsrq xmm5, qword ptr [r11 + 050h], 00h
|
|
pinsrq xmm5, qword ptr [r11 + 058h], 01h
|
|
hypercall_skip_xmm:
|
|
mov r10, qword ptr [rsp + 18h + 28h]
|
|
mov r11, qword ptr [rsp + 18h + 30h]
|
|
mov rax, qword ptr [rsp + 18h + 38h]
|
|
mov rbx, qword ptr [rsp + 18h + 40h]
|
|
mov rdi, qword ptr [rsp + 18h + 48h]
|
|
mov rsi, qword ptr [rsp + 18h + 50h]
|
|
call qword ptr [rsp + 18h + 60h]
|
|
pop rbx
|
|
pop rdi
|
|
pop rsi
|
|
ret
|
|
hypercall ENDP
|
|
|
|
;------------------------------------------------------------------------------
|
|
; CPU_REG_TYPE hypercall_page ( )
|
|
;------------------------------------------------------------------------------
|
|
|
|
hypercall_page PROC
|
|
vmcall
|
|
ret
|
|
hypercall_page ENDP
|
|
|
|
END
|