CloverBootloader/CloverEFI/BootSector/efi32.nasm
2019-09-03 12:58:42 +03:00

409 lines
8.2 KiB
NASM

DEFAULT_HANDLER_SIZE: equ 9 ; size of exception/interrupt stub
SYS_CODE_SEL: equ 0x20 ; 32-bit code selector in GDT
PE_OFFSET_IN_MZ_STUB: equ 0x3c ; place in MsDos stub for offset to PE Header
VGA_FB: equ 0x000b8000 ; VGA framebuffer for 80x25 mono mode
VGA_LINE: equ 80 * 2 ; # bytes in one line
BASE_ADDR_32: equ 0x00021000
STACK_TOP: equ 0x001ffff0
SIZE: equ 0x1000
struc EFILDR_IMAGE
.CheckSum: resd 1
.Offset: resd 1
.Length: resd 1
.FileName: resb 52
endstruc
struc EFILDR_HEADER
.Signature: resd 1
.HeaderCheckSum: resd 1
.FileLength: resd 1
.NumberOfImages: resd 1
endstruc
struc PE_HEADER
resb 6
.NumberOfSections: resw 1
resb 12
.SizeOfOptionalHeader: resw 1
resb 2
.Magic: resb 16
.AddressOfEntryPoint: resd 1
resb 8
.ImageBase32: resd 1
endstruc
struc PE_SECTION_HEADER
resb 12
.VirtualAddress: resd 1
.SizeOfRawData: resd 1
.PointerToRawData: resd 1
resb 16
endstruc
%macro StubWithNoCode 1
push 0 ; push error code place holder on the stack
push %1
jmp strict dword commonIdtEntry
%endmacro
%macro StubWithACode 1
times 2 nop
push %1
jmp strict dword commonIdtEntry
%endmacro
%macro PrintReg 2
mov esi, %1
call PrintString
mov eax, [ebp + %2]
call PrintDword
%endmacro
bits 32
org BASE_ADDR_32
global _start
_start:
mov ax, bx
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
mov esp, STACK_TOP
;
; Populate IDT with meaningful offsets for exception handlers...
;
sidt [Idtr]
mov eax, StubTable
mov ebx, eax ; use bx to copy 15..0 to descriptors
shr eax, 16 ; use ax to copy 31..16 to descriptors
mov ecx, 0x78 ; 78h IDT entries to initialize with unique entry points
mov edi, [Idtr + 2]
.StubLoop: ; loop through all IDT entries exception handlers and initialize to default handler
mov [edi], bx ; write bits 15..0 of offset
mov word [edi + 2], SYS_CODE_SEL ; SYS_CODE_SEL from GDT
mov word [edi + 4], 0x8e00 ; type = 386 interrupt gate, present
mov [edi + 6], ax ; write bits 31..16 of offset
add edi, 8 ; move up to next descriptor
add ebx, DEFAULT_HANDLER_SIZE ; move to next entry point
loop .StubLoop ; loop back through again until all descriptors are initialized
;
; Load EFILDR
;
mov esi, BlockSignature + 2
add esi, [esi + EFILDR_HEADER_size + EFILDR_IMAGE.Offset] ; esi = Base of EFILDR.C
mov ebp, [esi + PE_OFFSET_IN_MZ_STUB]
add ebp, esi ; ebp = PE Image Header for EFILDR.C
mov edi, [ebp + PE_HEADER.ImageBase32] ; edi = ImageBase
mov eax, [ebp + PE_HEADER.AddressOfEntryPoint] ; eax = EntryPoint
add eax, edi ; eax = ImageBase + EntryPoint
mov [.EfiLdrOffset], eax ; Modify jump instruction for correct entry point
movzx ebx, word [ebp + PE_HEADER.NumberOfSections] ; bx = Number of sections
movzx eax, word [ebp + PE_HEADER.SizeOfOptionalHeader]; ax = Optional Header Size
add ebp, eax
add ebp, PE_HEADER.Magic ; ebp = Start of 1st Section
.SectionLoop:
push esi ; Save Base of EFILDR.C
push edi ; Save ImageBase
add esi, [ebp + PE_SECTION_HEADER.PointerToRawData] ; esi = Base of EFILDR.C + PointerToRawData
add edi, [ebp + PE_SECTION_HEADER.VirtualAddress] ; edi = ImageBase + VirtualAddress
mov ecx, [ebp + PE_SECTION_HEADER.SizeOfRawData] ; ecx = SizeOfRawData
cld
shr ecx, 2
rep movsd
pop edi ; Restore ImageBase
pop esi ; Restore Base of EFILDR.C
add ebp, PE_SECTION_HEADER_size ; ebp = Pointer to next section record
dec ebx
jnz .SectionLoop
movzx eax, word [Idtr] ; get size of IDT
inc eax
add eax, [Idtr + 2] ; add to base of IDT to get location of memory map...
push eax ; push memory map location on stack for call to EFILDR...
push eax ; push return address (useless, just for stack balance)
.EfiLdrOffset: equ $ + 1
mov eax, 0x00401000
jmp eax ; jump to entry point
StubTable:
%assign i 0
%rep 8
StubWithNoCode i
%assign i i+1
%endrep
StubWithACode 8 ; Double Fault
StubWithNoCode 9
StubWithACode 10 ; Invalid TSS
StubWithACode 11 ; Segment Not Present
StubWithACode 12 ; Stack Fault
StubWithACode 13 ; GP Fault
StubWithACode 14 ; Page Fault
StubWithNoCode 15
StubWithNoCode 16
StubWithACode 17 ; Alignment Check
%assign i 18
%rep 102
StubWithNoCode i
%assign i i+1
%endrep
commonIdtEntry:
pushad
mov ebp, esp
;
; At this point the stack looks like this:
;
; eflags
; Calling CS
; Calling EIP
; Error code or 0
; Int num or 0ffh for unknown int num
; eax
; ecx
; edx
; ebx
; esp
; ebp
; esi
; edi <------- ESP, EBP
;
; call ClearScreen
mov edi, VGA_FB
mov esi, String1
call PrintString
mov eax, [ebp + 8 * 4] ; move Int number into EAX
cmp eax, 19
ja .PrintDefaultString
mov esi, [eax * 4 + StringTable] ; get offset from StringTable to actual string address
jmp .PrintTheString
.PrintDefaultString:
mov esi, IntUnknownString
; patch Int number
mov edx, eax
call A2C
mov [esi + 1], al
mov eax, edx
shr eax, 4
call A2C
mov [esi], al
.PrintTheString:
call PrintString
PrintReg String2, 11 * 4 ; CS
mov byte [edi], ':'
add edi, 2
mov eax, [ebp + 10 * 4] ; EIP
call PrintDword
mov esi, String3
call PrintString
mov edi, VGA_FB + 2 * VGA_LINE
PrintReg StringEax, 7 * 4
PrintReg StringEbx, 4 * 4
PrintReg StringEcx, 6 * 4
PrintReg StringEdx, 5 * 4
PrintReg StringEcode, 9 * 4
mov edi, VGA_FB + 3 * VGA_LINE
PrintReg StringEsp, 3 * 4
PrintReg StringEbp, 2 * 4
PrintReg StringEsi, 4
PrintReg StringEdi, 0
PrintReg StringEflags, 12 * 4
mov edi, VGA_FB + 5 * VGA_LINE
mov esi, ebp
add esi, 13 * 4 ; stack beyond eflags
mov ecx, 8
.OuterLoop:
push ecx
mov ecx, 8
mov edx, edi
.InnerLoop:
mov eax, [esi]
call PrintDword
add esi, 4
mov byte [edi], ' '
add edi, 2
loop .InnerLoop
pop ecx
add edx, VGA_LINE
mov edi, edx
loop .OuterLoop
mov edi, VGA_FB + 15 * VGA_LINE
mov esi, [ebp + 10 * 4] ; EIP
sub esi, 32 * 4 ; code preceding EIP
mov ecx, 8
.OuterLoop1:
push ecx
mov ecx, 8
mov edx, edi
.InnerLoop1:
mov eax, [esi]
call PrintDword
add esi, 4
mov byte [edi], ' '
add edi, 2
loop .InnerLoop1
pop ecx
add edx, VGA_LINE
mov edi, edx
loop .OuterLoop1
.Halt:
hlt
jmp .Halt
;
; Return
;
mov esp, ebp
popad
add esp, 8 ; error code and INT number
iretd
PrintString:
push eax
.loop:
mov al, [esi]
test al, al
jz .done
mov [edi], al
inc esi
add edi, 2
jmp .loop
.done:
pop eax
ret
; EAX contains dword to print
; EDI contains memory location (screen location) to print it to
PrintDword:
push ecx
push ebx
push eax
mov ecx, 8
.looptop:
rol eax, 4
mov bl, al
and bl, 15
add bl, '0'
cmp bl, '9'
jbe .is_digit
add bl, 7
.is_digit:
mov [edi], bl
add edi, 2
loop .looptop
pop eax
pop ebx
pop ecx
ret
ClearScreen:
push eax
push ecx
mov ax, 0x0c20
mov edi, VGA_FB
mov ecx, 80 * 25
rep stosw
mov edi, VGA_FB
pop ecx
pop eax
ret
A2C:
and al, 15
add al, '0'
cmp al, '9'
jbe .is_digit
add al, 7
.is_digit:
ret
String1: db '*** INT ', 0
Int0String: db '00h Divide by 0 -', 0
Int1String: db '01h Debug exception -', 0
Int2String: db '02h NMI -', 0
Int3String: db '03h Breakpoint -', 0
Int4String: db '04h Overflow -', 0
Int5String: db '05h Bound -', 0
Int6String: db '06h Invalid opcode -', 0
Int7String: db '07h Device not available -', 0
Int8String: db '08h Double fault -', 0
Int9String: db '09h Coprocessor seg overrun (reserved) -', 0
Int10String: db '0Ah Invalid TSS -', 0
Int11String: db '0Bh Segment not present -', 0
Int12String: db '0Ch Stack fault -', 0
Int13String: db '0Dh General protection fault -', 0
Int14String: db '0Eh Page fault -', 0
Int15String: db '0Fh (Intel reserved) -', 0
Int16String: db '10h Floating point error -', 0
Int17String: db '11h Alignment check -', 0
Int18String: db '12h Machine check -', 0
Int19String: db '13h SIMD Floating-Point Exception -', 0
IntUnknownString: db '??h Unknown interrupt -', 0
align 4, db 0
StringTable:
%assign i 0
%rep 20
dd Int%[i]String
%assign i i+1
%endrep
String2: db ' HALT!! *** (', 0
String3: db ')', 0
StringEax: db 'EAX=', 0
StringEbx: db ' EBX=', 0
StringEcx: db ' ECX=', 0
StringEdx: db ' EDX=', 0
StringEcode: db ' ECODE=', 0
StringEsp: db 'ESP=', 0
StringEbp: db ' EBP=', 0
StringEsi: db ' ESI=', 0
StringEdi: db ' EDI=', 0
StringEflags: db ' EFLAGS=', 0
align 2, db 0
Idtr:
times SIZE - 2 - $ + $$ db 0
BlockSignature:
dw 0xaa55