mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-10 14:23:31 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
409 lines
8.2 KiB
NASM
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
|