mirror of
https://github.com/chipsec/chipsec
synced 2026-06-08 13:31:00 +00:00
08963cf024
Signed-off-by: Nathaniel Mitchell <nathaniel.p.mitchell@intel.com>
709 lines
19 KiB
NASM
709 lines
19 KiB
NASM
;TITLE cpu.asm: Assembly code for the x64 resources
|
|
|
|
global DisableInterrupts
|
|
global WritePortDword
|
|
global WritePortWord
|
|
global WritePortByte
|
|
global ReadPortDword
|
|
global ReadPortWord
|
|
global ReadPortByte
|
|
global WriteHighCMOSByte
|
|
global WriteLowCMOSByte
|
|
global SendAPMSMI
|
|
global WritePCIByte
|
|
global WritePCIWord
|
|
global WritePCIDword
|
|
global ReadPCIByte
|
|
global ReadPCIWord
|
|
global ReadPCIDword
|
|
global _rdmsr
|
|
global _wrmsr
|
|
global _load_gdt
|
|
global _store_idtr
|
|
global _store_gdtr
|
|
global _store_ldtr
|
|
global _rflags
|
|
|
|
global ReadCR0
|
|
global ReadCR2
|
|
global ReadCR3
|
|
global ReadCR4
|
|
global ReadCR8
|
|
global WriteCR0
|
|
global WriteCR2
|
|
global WriteCR3
|
|
global WriteCR4
|
|
global WriteCR8
|
|
global hypercall
|
|
global hypercall_page
|
|
|
|
global __cpuid__
|
|
global __swsmi__
|
|
global __swsmi_timed__
|
|
|
|
extern __x86_return_thunk
|
|
extern __x86_indirect_thunk_r11
|
|
|
|
section .text
|
|
|
|
%macro RET 0
|
|
jmp __x86_return_thunk
|
|
%endmacro
|
|
%macro SETCTX_CPUID 0
|
|
xchg rax, [rdi]
|
|
xchg rbx, [rdi+0x8]
|
|
xchg rcx, [rdi+0x10]
|
|
xchg rdx, [rdi+0x18]
|
|
%endmacro
|
|
|
|
;This function has one argument: CPUID_CTX structure which contain 4 regs: rax, rbx, rcx, rdx:
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; __cpuid__ (
|
|
; CPUID_CTX ctx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
|
|
__cpuid__:
|
|
|
|
SETCTX_CPUID
|
|
|
|
cpuid
|
|
|
|
SETCTX_CPUID
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; UINT64 _rflags()
|
|
;------------------------------------------------------------------------------
|
|
_rflags:
|
|
pushfq
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _store_idtr(
|
|
; unsigned char *address // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_store_idtr:
|
|
sidt [rdi]
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _load_idtr(
|
|
; unsigned char *address // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_idtr:
|
|
lidt [rdi]
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _store_gdtr(
|
|
; unsigned char *address // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_store_gdtr:
|
|
sgdt [rdi]
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _load_gdtr(
|
|
; unsigned char *address // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_gdtr:
|
|
lgdt [rdi]
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _store_ldtr(
|
|
; unsigned char *address // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_store_ldtr:
|
|
;sldt fword ptr [rdi]
|
|
sldt [rdi]
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _load_ldtr(
|
|
; unsigned char *address // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_ldtr:
|
|
;lldt fword ptr [rdi]
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _load_gdt(
|
|
; unsigned char *value // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_load_gdt:
|
|
|
|
sgdt [rdi]
|
|
lgdt [rdi]
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _rdmsr(
|
|
; unsigned int msr_num, // rdi
|
|
; unsigned int* msr_lo, // rsi
|
|
; unsigned int* msr_hi // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_rdmsr:
|
|
push r10
|
|
push r11
|
|
push rax
|
|
push rdx
|
|
|
|
|
|
mov rcx, rdi
|
|
mov r10, rsi ; msr_lo
|
|
mov r11, rdx ; msr_hi
|
|
|
|
; rcx has msr_num
|
|
rdmsr
|
|
|
|
; Write MSR results in edx:eax
|
|
mov [r10], eax
|
|
|
|
mov [r11], edx
|
|
|
|
pop rdx
|
|
pop rax
|
|
pop r11
|
|
pop r10
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void _wrmsr(
|
|
; unsigned int msr_num, // rdi
|
|
; unsigned int msr_hi, // rsi
|
|
; unsigned int msr_lo // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
_wrmsr:
|
|
push rax
|
|
push rcx
|
|
|
|
; move msr_num to rcx
|
|
mov rcx, rdi
|
|
; move msr_lo from rdx to rax
|
|
mov rax, rsi
|
|
; move msr_hi to rdx
|
|
wrmsr
|
|
|
|
pop rcx
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; DisableInterrupts (
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
DisableInterrupts:
|
|
cli
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePortDword (
|
|
; unsigned int out_value // rdi
|
|
; unsigned short port_num // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePortDword:
|
|
push rax
|
|
push rdx
|
|
|
|
mov rax, rdi
|
|
mov rdx, rsi
|
|
out dx, eax
|
|
|
|
pop rdx
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePortWord (
|
|
; unsigned short out_value // rdi
|
|
; unsigned short port_num // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePortWord:
|
|
push rax
|
|
push rdx
|
|
|
|
mov rax, rdi
|
|
mov rdx, rsi
|
|
out dx, ax
|
|
|
|
pop rdx
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePortByte (
|
|
; unsigned char out_value // rdi
|
|
; unsigned short port_num // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePortByte:
|
|
push rax
|
|
push rdx
|
|
|
|
mov rax, rdi
|
|
mov rdx, rsi
|
|
out dx, al
|
|
|
|
pop rdx
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; unsigned int
|
|
; ReadPortDword (
|
|
; unsigned short port_num // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPortDword:
|
|
push rdx
|
|
|
|
xor rax, rax
|
|
mov rdx, rdi
|
|
in eax, dx
|
|
|
|
pop rdx
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; unsigned short
|
|
; ReadPortWord (
|
|
; unsigned short port_num // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPortWord:
|
|
push rdx
|
|
|
|
xor rax, rax
|
|
mov rdx, rdi
|
|
in ax, dx
|
|
|
|
pop rdx
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; unsigned char
|
|
; ReadPortByte (
|
|
; unsigned short port_num // rdi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPortByte:
|
|
push rdx
|
|
|
|
xor rax, rax
|
|
mov rdx, rdi
|
|
in al, dx
|
|
|
|
pop rdx
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WriteHighCMOSByte (
|
|
; unsigned char cmos_off // rdi
|
|
; unsigned char val // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WriteHighCMOSByte:
|
|
push rax
|
|
|
|
mov rax, rdi
|
|
out 72h, al
|
|
mov rax, rsi
|
|
out 73h, al
|
|
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WriteLowCMOSByte (
|
|
; unsigned char cmos_off // rdi
|
|
; unsigned char val // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WriteLowCMOSByte:
|
|
push rax
|
|
|
|
mov rax, rdi
|
|
or al, 80h
|
|
out 70h, al
|
|
mov rax, rsi
|
|
out 71h, al
|
|
|
|
pop rax
|
|
RET
|
|
; @TODO: looks incorrect
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; SendAPMSMI (
|
|
; unsigned int apm_port_value // rdi
|
|
; IN UINT64 rax_value // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
SendAPMSMI:
|
|
push rax
|
|
push rdx
|
|
|
|
mov rax, rdi
|
|
mov rdx, rsi
|
|
mov dx, 0B2h
|
|
out dx, eax
|
|
|
|
pop rdx
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
;This function has one argument: SMI_CTX structure pointer which contain SMI code and data values and 6 regs: rax, rbx, rcx, rdx, rsi, rdi:
|
|
; IN UINT64 smi_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__ (
|
|
; SMI_CTX ctx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
__swsmi__:
|
|
mov r10, rdi
|
|
|
|
; setting up GPR (arguments) to SMI handler call
|
|
; notes:
|
|
; RAX will get partially overwritten (AX) by smi_code_data
|
|
xchg rax, [r10+08h] ; rax_value (partially overwritten with smi_code_data)
|
|
mov ax, [r10+0h] ; smi_code_data
|
|
xchg rbx, [r10+010h] ; rbx_value
|
|
xchg rcx, [r10+018h] ; rcx_value
|
|
xchg rdx, [r10+020h] ; rdx_value
|
|
xchg rsi, [r10+028h] ; rsi_value
|
|
xchg rdi, [r10+030h] ; 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
|
|
ror ax, 8
|
|
out 0B2h, al
|
|
|
|
; some SMI handlers return data/errorcode in GPRs, need to return this to the caller
|
|
xchg rax, [r10+08h] ; rax_value
|
|
xchg rbx, [r10+010h] ; rbx_value
|
|
xchg rcx, [r10+018h] ; rcx_value
|
|
xchg rdx, [r10+020h] ; rdx_value
|
|
xchg rsi, [r10+028h] ; rsi_value
|
|
xchg rdi, [r10+030h] ; rdi_value
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
;This function has two arguments: SMI_CTX structure pointer which contain SMI code and data values and 6 regs: rax, rbx, rcx, rdx, rsi, rdi:
|
|
; IN UINT64 smi_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
|
|
; The second argument is a pointer to an unsigned long to return the measured execution time
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; __swsmi_timed__ (
|
|
; SMI_CTX ctx // rdi
|
|
; unsigned long *time // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
__swsmi_timed__:
|
|
mov r10, rdi
|
|
push r12 ; callee-saved register
|
|
mov r12, rsi
|
|
|
|
; setting up GPR (arguments) to SMI handler call
|
|
; notes:
|
|
; RAX will get partially overwritten (AX) by smi_code_data
|
|
xchg rax, [r10+08h] ; rax_value (partially overwritten with smi_code_data)
|
|
mov ax, [r10+0h] ; smi_code_data
|
|
xchg rbx, [r10+010h] ; rbx_value
|
|
xchg rcx, [r10+018h] ; rcx_value
|
|
xchg rdx, [r10+020h] ; rdx_value
|
|
xchg rsi, [r10+028h] ; rsi_value
|
|
xchg rdi, [r10+030h] ; 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
|
|
|
|
wbinvd
|
|
mfence
|
|
; read time-stamp counter
|
|
mov r9, rax
|
|
mov r11, rdx
|
|
rdtsc
|
|
shl rdx, 32
|
|
or rax, rdx
|
|
mov r8, rax
|
|
mov rax, r9
|
|
mov rdx, r11
|
|
|
|
; trigger SMI
|
|
ror ax, 8
|
|
out 0B2h, al
|
|
|
|
; measure SMI execution time
|
|
mov r9, rax
|
|
mov r11, rdx
|
|
rdtsc
|
|
shl rdx, 32
|
|
or rax, rdx
|
|
sub rax, r8
|
|
mov [r12], rax
|
|
mov rax, r9
|
|
mov rdx, r11
|
|
|
|
; some SMI handlers return data/errorcode in GPRs, need to return this to the caller
|
|
xchg rax, [r10+08h] ; rax_value
|
|
xchg rbx, [r10+010h] ; rbx_value
|
|
xchg rcx, [r10+018h] ; rcx_value
|
|
xchg rdx, [r10+020h] ; rdx_value
|
|
xchg rsi, [r10+028h] ; rsi_value
|
|
xchg rdi, [r10+030h] ; rdi_value
|
|
|
|
pop r12
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePCIByte (
|
|
; unsigned int pci_reg // rdi
|
|
; unsigned short cfg_data_port // rsi
|
|
; unsigned char byte_value // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePCIByte:
|
|
push rax
|
|
push rsi
|
|
push rdx
|
|
|
|
cli
|
|
mov rax, rdi ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, eax
|
|
|
|
pop rax ; byte_value
|
|
pop rdx ; cfg_data_port
|
|
out dx, al
|
|
sti
|
|
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePCIWord (
|
|
; unsigned int pci_reg // rdi
|
|
; unsigned short cfg_data_port // rsi
|
|
; unsigned short word_value // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePCIWord:
|
|
push rax
|
|
push rsi
|
|
push rdx
|
|
|
|
cli
|
|
mov rax, rdi ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, eax
|
|
|
|
pop rax ; byte_value
|
|
pop rdx ; cfg_data_port
|
|
out dx, ax
|
|
sti
|
|
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; void
|
|
; WritePCIDword (
|
|
; unsigned int pci_reg // rdi
|
|
; unsigned short cfg_data_port // rsi
|
|
; unsigned int dword_value // rdx
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
WritePCIDword:
|
|
push rax
|
|
push rsi
|
|
push rdx
|
|
|
|
cli
|
|
mov rax, rdi ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, eax
|
|
|
|
pop rax ; byte_value
|
|
pop rdx ; cfg_data_port
|
|
out dx, eax
|
|
sti
|
|
|
|
pop rax
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; unsigned char
|
|
; ReadPCIByte (
|
|
; unsigned int pci_reg // rdi
|
|
; unsigned short cfg_data_port // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPCIByte:
|
|
|
|
cli
|
|
mov rax, rdi ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, eax
|
|
|
|
xor rax, rax
|
|
mov rdx, rsi ; cfg_data_port
|
|
in al, dx
|
|
sti
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; unsigned short
|
|
; ReadPCIWord (
|
|
; unsigned int pci_reg // rdi
|
|
; unsigned short cfg_data_port // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPCIWord:
|
|
|
|
cli
|
|
mov rax, rdi ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, eax
|
|
|
|
xor rax, rax
|
|
mov rdx, rsi ; cfg_data_port
|
|
in ax, dx
|
|
sti
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; unsigned int
|
|
; ReadPCIDword (
|
|
; unsigned int pci_reg // rdi
|
|
; unsigned short cfg_data_port // rsi
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
ReadPCIDword:
|
|
|
|
cli
|
|
mov rax, rdi ; pci_reg
|
|
mov dx, 0CF8h
|
|
out dx, eax
|
|
|
|
xor rax, rax
|
|
mov rdx, rsi ; cfg_data_port
|
|
in eax, dx
|
|
sti
|
|
RET
|
|
ReadCR0:
|
|
xor rax, rax
|
|
mov rax, cr0
|
|
RET
|
|
ReadCR2:
|
|
xor rax, rax
|
|
mov rax, cr2
|
|
RET
|
|
ReadCR3:
|
|
xor rax, rax
|
|
mov rax, cr3
|
|
RET
|
|
ReadCR4:
|
|
xor rax, rax
|
|
mov rax, cr4
|
|
RET
|
|
ReadCR8:
|
|
xor rax, rax
|
|
mov rax, cr8
|
|
RET
|
|
WriteCR0:
|
|
mov cr0, rdi
|
|
RET
|
|
WriteCR2:
|
|
mov cr2, rdi
|
|
RET
|
|
WriteCR3:
|
|
mov cr3, rdi
|
|
RET
|
|
WriteCR4:
|
|
mov cr4, rdi
|
|
RET
|
|
WriteCR8:
|
|
mov cr8, rdi
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; UINT64
|
|
; hypercall(
|
|
; UINT64 rcx_val, // rdi
|
|
; UINT64 rdx_val, // rsi
|
|
; UINT64 r8_val, // rdx
|
|
; UINT64 r9_val, // rcx
|
|
; UINT64 r10_val, // r8
|
|
; UINT64 r11_val, // r9
|
|
; UINT64 rax_val, // on stack +10h
|
|
; UINT64 rbx_val, // on stack +18h
|
|
; UINT64 rdi_val, // on stack +20h
|
|
; UINT64 rsi_val, // on stack +28h
|
|
; UINT64 xmm_buffer, // on stack +30h
|
|
; UINT64 hypercall_page // on stack +38h
|
|
; )
|
|
;------------------------------------------------------------------------------
|
|
|
|
hypercall:
|
|
push rbp
|
|
mov rbp, rsp
|
|
push rbx
|
|
mov rax, qword [rbp + 30h]
|
|
test rax, rax
|
|
jz hypercall_skip_xmm
|
|
pinsrq xmm0, qword [rax + 000h], 00h
|
|
pinsrq xmm0, qword [rax + 008h], 01h
|
|
pinsrq xmm1, qword [rax + 010h], 00h
|
|
pinsrq xmm1, qword [rax + 018h], 01h
|
|
pinsrq xmm2, qword [rax + 020h], 00h
|
|
pinsrq xmm2, qword [rax + 028h], 01h
|
|
pinsrq xmm3, qword [rax + 030h], 00h
|
|
pinsrq xmm3, qword [rax + 038h], 01h
|
|
pinsrq xmm4, qword [rax + 040h], 00h
|
|
pinsrq xmm4, qword [rax + 048h], 01h
|
|
pinsrq xmm5, qword [rax + 050h], 00h
|
|
pinsrq xmm5, qword [rax + 058h], 01h
|
|
hypercall_skip_xmm:
|
|
mov r11, r9
|
|
mov r10, r8
|
|
mov r9, rcx
|
|
mov r8, rdx
|
|
mov rdx, rsi
|
|
mov rcx, rdi
|
|
mov rdi, qword [rbp + 20h]
|
|
mov rsi, qword [rbp + 28h]
|
|
mov rax, qword [rbp + 10h]
|
|
mov rbx, qword [rbp + 18h]
|
|
mov r11, qword [rbp + 38h]
|
|
call __x86_indirect_thunk_r11
|
|
pop rbx
|
|
pop rbp
|
|
RET
|
|
;------------------------------------------------------------------------------
|
|
; UINT64 hypercall_page ( )
|
|
;------------------------------------------------------------------------------
|
|
|
|
hypercall_page:
|
|
vmcall
|
|
RET
|