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