371 lines
8.1 KiB
NASM
371 lines
8.1 KiB
NASM
;; @file
|
|
;
|
|
; Assembly code that supports x64 for Thunk64To32Lib
|
|
;******************************************************************************
|
|
;* Copyright (c) 2015 - 2018, Insyde Software Corporation. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
|
|
|
|
SECTION .text
|
|
DEFAULT REL
|
|
|
|
;
|
|
; Data Types
|
|
;
|
|
%define UINT64 RESQ
|
|
%define UINT32 RESD
|
|
%define UINT16 RESW
|
|
%define UINT8 RESB
|
|
%define CHAR8 RESB
|
|
|
|
;
|
|
; Define what a processor GDT looks like
|
|
; Keep in sync with Thunk.c
|
|
;
|
|
struc GDT_ENTRY
|
|
.LimitLow: UINT16 1
|
|
.BaseLow: UINT16 1
|
|
.BaseMid: UINT8 1
|
|
.Attribute: UINT8 1
|
|
.LimitHi: UINT8 1
|
|
.BaseHi: UINT8 1
|
|
endstruc
|
|
|
|
;
|
|
; Define what a processor descriptor looks like
|
|
; Keep in sync with Thunk.c definition
|
|
;
|
|
struc DESCRIPTOR64
|
|
.Limit: UINT16 1
|
|
.Base: UINT64 1
|
|
endstruc
|
|
|
|
struc DESCRIPTOR32
|
|
.Limit: UINT16 1
|
|
.Base: UINT32 1
|
|
endstruc
|
|
|
|
;
|
|
; LOW_MEMORY_THUNK - Keep in sync with Thunc.c definition
|
|
;
|
|
struc MEMORY_THUNK
|
|
.x64GdtDesc: ISTRUC DESCRIPTOR64
|
|
AT DESCRIPTOR64.Limit, UINT16 1
|
|
AT DESCRIPTOR64.Base, UINT64 1
|
|
IEND
|
|
.x64IdtDesc: ISTRUC DESCRIPTOR64
|
|
AT DESCRIPTOR64.Limit, UINT16 1
|
|
AT DESCRIPTOR64.Base, UINT64 1
|
|
IEND
|
|
.x64Ss: UINT64 1
|
|
.x64Esp: UINT64 1
|
|
.ia32Stack: UINT64 1
|
|
.ia32IdtDesc: ISTRUC DESCRIPTOR32
|
|
AT DESCRIPTOR32.Limit, UINT16 1
|
|
AT DESCRIPTOR32.Base, UINT32 1
|
|
IEND
|
|
.ia32GdtDesc: ISTRUC DESCRIPTOR32
|
|
AT DESCRIPTOR32.Limit, UINT16 1
|
|
AT DESCRIPTOR32.Base, UINT32 1
|
|
IEND
|
|
.CodeSeg32offset: UINT16 1
|
|
endstruc
|
|
|
|
; RCX - MEMORY_THUNK *IntThunk
|
|
; RDX - UINT32 CodePoint
|
|
; R8 - UINT32 PeiServicesPoint
|
|
global ASM_PFX(InternalThunk64To32)
|
|
ASM_PFX(InternalThunk64To32):
|
|
|
|
pushf ; Save flags (note that this is before the cli)
|
|
cli
|
|
|
|
push rsp
|
|
push rdi
|
|
push rsi
|
|
push rbp
|
|
push rax
|
|
push rbx
|
|
push rcx
|
|
push rdx
|
|
push r8
|
|
push r9
|
|
push r10
|
|
push r11
|
|
push r12
|
|
push r13
|
|
push r14
|
|
push r15
|
|
|
|
;
|
|
; Save PeiServicesPoint in r9
|
|
;
|
|
mov r9, r8
|
|
;
|
|
; Save IntThunk and CodePoint
|
|
;
|
|
mov r8, rcx
|
|
mov rdi, rdx
|
|
|
|
mov ax, [r8 + MEMORY_THUNK.CodeSeg32offset]
|
|
mov word[CodeSeg32offset], ax
|
|
|
|
sgdt [r8 + MEMORY_THUNK.x64GdtDesc]
|
|
sidt [r8 + MEMORY_THUNK.x64IdtDesc]
|
|
|
|
xor rax, rax ; zero RAX
|
|
mov ax, ss ; read in the stack segment
|
|
mov [r8 + MEMORY_THUNK.x64Ss], rax ; save in data structure
|
|
|
|
;
|
|
; Save flat x64 stack location (RSP).
|
|
;
|
|
mov [r8 + MEMORY_THUNK.x64Esp], rsp
|
|
|
|
;
|
|
; patch in the current IntThunkAddr2.
|
|
;
|
|
mov rax, r8
|
|
mov qword [IntThunkAddr2], rax ; 8 bytes at IntThunkAddr2 = current address of IntThunk.
|
|
|
|
;
|
|
; Poke the TrampoleanCr3 value into the code.
|
|
;
|
|
mov rax, cr3
|
|
mov dword[TrampoleanCr3], eax
|
|
|
|
;
|
|
; patch in the current ds, fs, gs and cs, so we can use it to return to x64 mode.
|
|
;
|
|
xor rax, rax
|
|
mov ax, ds
|
|
mov qword [PatchX64Ds1], rax
|
|
|
|
mov ax, fs
|
|
mov qword [PatchX64Fs1], rax
|
|
|
|
mov ax, gs
|
|
mov qword [PatchX64Gs1], rax
|
|
|
|
mov ax, cs
|
|
mov word [PatchLongModeCS], ax
|
|
|
|
;
|
|
; patch the address of OffsetInLongMode.
|
|
;
|
|
mov rax, InLongMode
|
|
mov dword[OffsetInLongMode], eax
|
|
|
|
;
|
|
; patch the address of CompatibilityModeVector.
|
|
;
|
|
mov rax, CompatibilityMode
|
|
mov dword[CompatibilityModeVector], eax
|
|
|
|
mov rsi, r8
|
|
|
|
;
|
|
; PeiServicesPoint store in rdx
|
|
;
|
|
mov rdx, r9
|
|
|
|
;
|
|
; jmp to x64 Compatibility Mode.
|
|
;
|
|
mov rax, CompatibilityModeVector
|
|
|
|
; jmp FWORD PTR[rax]
|
|
DB 0xFF
|
|
DB 0x28
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; now in 64-bit compatibility mode ;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
CompatibilityMode:
|
|
|
|
;
|
|
; disable paging
|
|
;
|
|
mov rax, cr0
|
|
btr eax, 31 ; set PG=0
|
|
mov cr0, rax
|
|
|
|
;
|
|
; set EFER.LME = 0 to leave long mode
|
|
;
|
|
push rdx
|
|
mov ecx, 0xc0000080 ; EFER MSR number.
|
|
rdmsr ; Read EFER.
|
|
btr eax, 8 ; Set LME=0.
|
|
wrmsr ; Write EFER.
|
|
pop rdx
|
|
jmp Legacy32bitProtectedMode
|
|
Legacy32bitProtectedMode:
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
; now in 32-bit legacy mode ;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;
|
|
; This is the Trapolean Page Tables that are guarenteed
|
|
; under 4GB.
|
|
;
|
|
xor eax, eax
|
|
DB 0xb8 ; mov eax, imm32
|
|
global mIA32Cr3
|
|
mIA32Cr3: DD 0
|
|
|
|
mov cr3, rax
|
|
|
|
;
|
|
; Get the IA32 mode stack
|
|
;
|
|
lea rcx, [abs 0 + MEMORY_THUNK.ia32Stack]
|
|
add rcx, rsi
|
|
|
|
DB 0x8b ; mov ebx, DWORD PTR [ecx]
|
|
DB 0x19
|
|
|
|
mov esp,ebx ;set stack
|
|
|
|
;
|
|
; Enable paging to activate IA32 mode (set CR0.PG=1)
|
|
;
|
|
mov rax, cr0 ; Read CR0.
|
|
bts eax, 31 ; Set PG=1.
|
|
mov cr0, rax ; Write CR0.
|
|
|
|
;
|
|
; Prepare parameter : PeiServicesPoint
|
|
;
|
|
DB 0x52 ; 'push edx' opcode
|
|
call rdi
|
|
DB 0x5A ; 'pop edx' opcode
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;
|
|
; Go Long Mode HERE!!!!!
|
|
;
|
|
|
|
;
|
|
; disable paging
|
|
;
|
|
mov rax, cr0
|
|
btr eax, 31 ; set PG=0
|
|
mov cr0, rax
|
|
|
|
;
|
|
; Switch back to the original page tables
|
|
;
|
|
;;; mov eax, imm32
|
|
DB 0xB8 ; 'mov eax,imm32' opcode
|
|
TrampoleanCr3:
|
|
DD 00000000 ; imm32
|
|
mov cr3, rax
|
|
;
|
|
; Enable the 64-bit page-translation-table entries by
|
|
; setting CR4.PAE=1 (this is _required_ before activating
|
|
; long mode). Paging is not enabled until after long mode
|
|
; is enabled.
|
|
;
|
|
mov rax, cr4
|
|
bts eax, 5
|
|
mov cr4, rax
|
|
|
|
;
|
|
; Enable long mode (set EFER.LME=1).
|
|
;
|
|
mov ecx, 0xc0000080 ; EFER MSR number.
|
|
rdmsr ; Read EFER.
|
|
bts eax, 8 ; Set LME=1.
|
|
wrmsr ; Write EFER.
|
|
|
|
;
|
|
; Enable paging to activate long mode (set CR0.PG=1)
|
|
;
|
|
mov rax, cr0 ; Read CR0.
|
|
bts eax, 31 ; Set PG=1.
|
|
mov cr0, rax ; Write CR0.
|
|
|
|
;
|
|
; This is the next instruction after enabling paging. Jump to long mode
|
|
;
|
|
db 0x67
|
|
db 0xea ; Far Jump $+9:Selector to reload CS
|
|
OffsetInLongMode:
|
|
dd 00000009 ; $+9 Offset is ensuing instruction boundary
|
|
PatchLongModeCS:
|
|
dw 0x0 ; Selector is our code selector, 10h
|
|
InLongMode:
|
|
|
|
DB 0x48 ; mov ax, imm16
|
|
DB 0xB8
|
|
PatchX64Ds1:
|
|
DQ 0x0
|
|
mov es, ax
|
|
mov ss, ax
|
|
mov ds, ax
|
|
|
|
; restore fs and gs
|
|
DB 0x48 ; mov rax, imm16
|
|
DB 0xB8
|
|
PatchX64Fs1:
|
|
DQ 0x0
|
|
mov fs, ax
|
|
|
|
DB 0x48 ; mov rax, imm16
|
|
DB 0xB8
|
|
PatchX64Gs1:
|
|
DQ 0x0
|
|
mov gs, ax
|
|
|
|
DB 0x48
|
|
DB 0xBE ; 'mov rsi,imm64' opcode (0xB8 + 6)
|
|
IntThunkAddr2:
|
|
DQ 0x0 ; address of IntThunk (imm64)
|
|
|
|
;
|
|
; Restore 64-bit stack
|
|
;
|
|
mov rcx, [rsi + MEMORY_THUNK.x64Ss]
|
|
mov ss, cx
|
|
|
|
mov rsp, [rsi + MEMORY_THUNK.x64Esp]
|
|
|
|
;
|
|
; Restore C regs
|
|
;
|
|
pop r15
|
|
pop r14
|
|
pop r13
|
|
pop r12
|
|
pop r11
|
|
pop r10
|
|
pop r9
|
|
pop r8
|
|
pop rdx
|
|
pop rcx
|
|
pop rbx
|
|
pop rax
|
|
pop rbp
|
|
pop rsi
|
|
pop rdi
|
|
pop rsp
|
|
popf
|
|
|
|
ret
|
|
|
|
align 16
|
|
CompatibilityModeVector:
|
|
DD 0
|
|
CodeSeg32offset:
|
|
DW 0
|
|
|