#------------------------------------------------------------------------------ #* #* Copyright 2006, Intel Corporation #* All rights reserved. This program and the accompanying materials #* are licensed and made available under the terms and conditions of the BSD License #* which accompanies this distribution. The full text of the license may be found at #* http://opensource.org/licenses/bsd-license.php #* #* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, #* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #* #* efi64.asm #* #* Abstract: #* #------------------------------------------------------------------------------ ############################################################################## # Now in 64-bit long mode. ############################################################################## .486: .stack: .code: .org 0x21000 .equ DEFAULT_HANDLER_SIZE, INT1 - INT0 .macro jmpCommonIdtEntry # jmp commonIdtEntry - this must be hand coded to keep the assembler from # using a 8 bit reletive jump when the entries are # within 255 bytes of the common entry. This must # be done to maintain the consistency of the size # of entry points... .byte 0xe9 # jmp 16 bit relative .long commonIdtEntry - . - 4 # offset to jump to .endm Start: movl $0x001fffe8,%esp # make final stack aligned # set OSFXSR and OSXMMEXCPT because some code will use XMM register .byte 0xf .byte 0x20 .byte 0xe0 # mov rax, cr4 btsl $9,%eax btsl $0xa,%eax .byte 0xf .byte 0x22 .byte 0xe0 # mov cr4, rax call ClearScreen # Populate IDT with meaningful offsets for exception handlers... sidt Idtr movl Halt, %eax movl %eax,%ebx # use bx to copy 15..0 to descriptors shrl $16,%eax # use ax to copy 31..16 to descriptors # 63..32 of descriptors is 0 movl $0x78,%ecx # 78h IDT entries to initialize with unique entry points (exceptions) movl (Idtr + 2), %esi movl (%esi),%edi LOOP_1: # loop through all IDT entries exception handlers and initialize to default handler movw %bx, (%edi) # write bits 15..0 of offset movw $0x38, 2(%edi) # SYS_CODE_SEL64 from GDT movw $(0x0e00 | 0x8000), 4(%edi) # type = 386 interrupt gate, present movw %ax, 6(%edi) # write bits 31..16 of offset movl $0, 8(%edi) # write bits 31..16 of offset addl $16, %edi # move up to next descriptor addw DEFAULT_HANDLER_SIZE, %bx # move to next entry point loopl LOOP_1 # loop back through again until all descriptors are initialized ## at this point edi contains the offset of the descriptor for INT 20 ## and bx contains the low 16 bits of the offset of the default handler ## so initialize all the rest of the descriptors with these two values... # mov ecx, 101 ; there are 100 descriptors left (INT 20 (14h) - INT 119 (77h) #@@: ; loop through all IDT entries exception handlers and initialize to default handler # mov word ptr [edi], bx ; write bits 15..0 of offset # mov word ptr [edi+2], 38h ; SYS_CODE64_SEL from GDT # mov word ptr [edi+4], 0e00h OR 8000h ; type = 386 interrupt gate, present # mov word ptr [edi+6], ax ; write bits 31..16 of offset # mov dword ptr [edi+8], 0 ; write bits 63..32 of offset # add edi, 16 ; move up to next descriptor # loop @b ; loop back through again until all descriptors are initialized ## DUMP location of IDT and several of the descriptors # mov ecx, 8 # mov eax, [offset Idtr + 2] # mov eax, [eax] # mov edi, 0b8000h # call PrintQword # mov esi, eax # mov edi, 0b80a0h # jmp OuterLoop ## ## just for fun, let's do a software interrupt to see if we correctly land in the exception handler... # mov eax, 011111111h # mov ebx, 022222222h # mov ecx, 033333333h # mov edx, 044444444h # mov ebp, 055555555h # mov esi, 066666666h # mov edi, 077777777h # push 011111111h # push 022222222h # push 033333333h # int 119 movl $0x22000,%esi # esi = 22000 movl 0x14(%esi),%eax # eax = [22014] addl %eax,%esi # esi = 22000 + [22014] = Base of EFILDR.C movl 0x3c(%esi),%ebp # ebp = [22000 + [22014] + 3c] = NT Image Header for EFILDR.C addl %esi,%ebp movl 0x30(%ebp),%edi # edi = [[22000 + [22014] + 3c] + 2c] = ImageBase (63..32 is zero, ignore) movl 0x28(%ebp),%eax # eax = [[22000 + [22014] + 3c] + 24] = EntryPoint addl %edi,%eax # eax = ImageBase + EntryPoint movl %ebx, EfiLdrOffset movl %eax, (%ebx) # Modify far jump instruction for correct entry point movw 6(%ebp), %bx # bx = Number of sections xorl %eax,%eax movw 0x14(%ebp), %ax # ax = Optional Header Size addl %eax,%ebp addl $0x18,%ebp # ebp = Start of 1st Section SectionLoop: pushl %esi # Save Base of EFILDR.C pushl %edi # Save ImageBase addl 0x14(%ebp),%esi # esi = Base of EFILDR.C + PointerToRawData addl 0x0c(%ebp),%edi # edi = ImageBase + VirtualAddress movl 0x10(%ebp),%ecx # ecs = SizeOfRawData cld shrl $2,%ecx rep movsl popl %edi # Restore ImageBase popl %esi # Restore Base of EFILDR.C addw $0x28,%bp # ebp = ebp + 028h = Pointer to next section record .byte 0x66 .byte 0xff .byte 0xcb # dec bx cmpw $0,%bx jne SectionLoop movl (Idtr), %eax # get size of IDT movzx (%edx), %eax .byte 0xff .byte 0xc0 # inc eax addl 2(%edx), %eax # add to base of IDT to get location of memory map... xorl %ecx,%ecx movl %eax,%ecx # put argument to RCX .byte 0x48 .byte 0xc7 .byte 0xc0 EfiLdrOffset: .long 0x00401000 # Offset of EFILDR # mov rax, 401000h .byte 0x50 # push rax # ret .byte 0xc3 # db "**** DEFAULT IDT ENTRY ***",0 .p2align 1 Halt: INT0: pushl $0x0 # push error code place holder on the stack pushl $0x0 jmpCommonIdtEntry # db 0e9h ; jmp 16 bit reletive # dd commonIdtEntry - $ - 4 ; offset to jump to INT1: pushl $0x0 # push error code place holder on the stack pushl $0x1 jmpCommonIdtEntry INT2: pushl $0x0 # push error code place holder on the stack pushl $0x2 jmpCommonIdtEntry INT3: pushl $0x0 # push error code place holder on the stack pushl $0x3 jmpCommonIdtEntry INT4: pushl $0x0 # push error code place holder on the stack pushl $0x4 jmpCommonIdtEntry INT5: pushl $0x0 # push error code place holder on the stack pushl $0x5 jmpCommonIdtEntry INT6: pushl $0x0 # push error code place holder on the stack pushl $0x6 jmpCommonIdtEntry INT7: pushl $0x0 # push error code place holder on the stack pushl $0x7 jmpCommonIdtEntry INT8: # Double fault causes an error code to be pushed so no phony push necessary nop nop pushl $0x8 jmpCommonIdtEntry INT9: pushl $0x0 # push error code place holder on the stack pushl $0x9 jmpCommonIdtEntry INT10: # Invalid TSS causes an error code to be pushed so no phony push necessary nop nop pushl $10 jmpCommonIdtEntry INT11: # Segment Not Present causes an error code to be pushed so no phony push necessary nop nop pushl $11 jmpCommonIdtEntry INT12: # Stack fault causes an error code to be pushed so no phony push necessary nop nop pushl $12 jmpCommonIdtEntry INT13: # GP fault causes an error code to be pushed so no phony push necessary nop nop pushl $13 jmpCommonIdtEntry INT14: # Page fault causes an error code to be pushed so no phony push necessary nop nop pushl $14 jmpCommonIdtEntry INT15: pushl $0x0 # push error code place holder on the stack pushl $15 jmpCommonIdtEntry INT16: pushl $0x0 # push error code place holder on the stack pushl $16 jmpCommonIdtEntry INT17: # Alignment check causes an error code to be pushed so no phony push necessary nop nop pushl $17 jmpCommonIdtEntry INT18: pushl $0x0 # push error code place holder on the stack pushl $18 jmpCommonIdtEntry INT19: pushl $0x0 # push error code place holder on the stack pushl $19 jmpCommonIdtEntry INTUnknown: .rept (0x78 - 20) pushl $0x0 # push error code place holder on the stack # push xxh ; push vector number .byte 0x6a .byte ( . - INTUnknown - 3 ) / 9 + 20 # vector number jmpCommonIdtEntry .endr commonIdtEntry: pushl %eax pushl %ecx pushl %edx pushl %ebx pushl %esp pushl %ebp pushl %esi pushl %edi .byte 0x41 .byte 0x50 # push r8 .byte 0x41 .byte 0x51 # push r9 .byte 0x41 .byte 0x52 # push r10 .byte 0x41 .byte 0x53 # push r11 .byte 0x41 .byte 0x54 # push r12 .byte 0x41 .byte 0x55 # push r13 .byte 0x41 .byte 0x56 # push r14 .byte 0x41 .byte 0x57 # push r15 .byte 0x48 movl %esp,%ebp # mov rbp, rsp ## ## At this point the stack looks like this: ## ## Calling SS ## Calling RSP ## rflags ## Calling CS ## Calling RIP ## Error code or 0 ## Int num or 0ffh for unknown int num ## rax ## rcx ## rdx ## rbx ## rsp ## rbp ## rsi ## rdi ## r8 ## r9 ## r10 ## r11 ## r12 ## r13 ## r14 ## r15 <------- RSP, RBP ## call ClearScreen mov String1, %esi call PrintString .byte 0x48 movl 16*8(%ebp),%eax ## move Int number into RAX .byte 0x48 cmpl $18,%eax ja PrintDefaultString PrintExceptionString: shll $3,%eax ## multiply by 8 to get offset from StringTable to actual string address addl StringTable, %eax movl (%eax),%esi jmp PrintTheString PrintDefaultString: movl IntUnknownString, %esi # patch Int number movl %eax,%edx call A2C movb %al,1(%esi) movl %edx,%eax shrl $4,%eax call A2C movb %al,(%esi) PrintTheString: call PrintString movl String2, %esi call PrintString .byte 0x48 movl 19*8(%ebp),%eax # CS call PrintQword movb $':', %al movb %al, (%edi) addl $2,%edi .byte 0x48 movl 18*8(%ebp),%eax # RIP call PrintQword movl String3, %esi call PrintString movl $0xb8140,%edi movl StringRax, %esi call PrintString .byte 0x48 movl 15*8(%ebp),%eax call PrintQword movl StringRcx, %esi call PrintString .byte 0x48 movl 14*8(%ebp),%eax call PrintQword movl StringRdx, %esi call PrintString .byte 0x48 movl 13*8(%ebp),%eax call PrintQword movl $0xb81e0,%edi movl StringRbx, %esi call PrintString .byte 0x48 movl 12*8(%ebp),%eax call PrintQword movl StringRsp, %esi call PrintString .byte 0x48 movl 21*8(%ebp),%eax call PrintQword movl StringRbp, %esi call PrintString .byte 0x48 movl 10*8(%ebp),%eax call PrintQword movl $0xb8280,%edi movl StringRsi, %esi call PrintString .byte 0x48 movl 9*8(%ebp),%eax call PrintQword movl StringRdi, %esi call PrintString .byte 0x48 movl 8*8(%ebp),%eax call PrintQword movl StringEcode, %esi call PrintString .byte 0x48 movl 17*8(%ebp),%eax call PrintQword movl $0xb8320,%edi movl StringR8, %esi call PrintString .byte 0x48 movl 7*8(%ebp),%eax call PrintQword movl StringR9, %esi call PrintString .byte 0x48 movl 6*8(%ebp),%eax call PrintQword movl StringR10, %esi call PrintString .byte 0x48 movl 5*8(%ebp),%eax call PrintQword movl $0xb83c0,%edi movl StringR11, %esi call PrintString .byte 0x48 movl 4*8(%ebp),%eax call PrintQword movl StringR12, %esi call PrintString .byte 0x48 movl 3*8(%ebp),%eax call PrintQword movl StringR13, %esi call PrintString .byte 0x48 movl 2*8(%ebp),%eax call PrintQword movl $0xb8460,%edi movl StringR14, %esi call PrintString .byte 0x48 movl 1*8(%ebp),%eax call PrintQword movl StringR15, %esi call PrintString .byte 0x48 movl 0*8(%ebp),%eax call PrintQword movl StringSs, %esi call PrintString .byte 0x48 movl 22*8(%ebp),%eax call PrintQword movl $0xb8500,%edi movl StringRflags, %esi call PrintString .byte 0x48 movl 20*8(%ebp),%eax call PrintQword movl $0xb8640,%edi movl %ebp,%esi addl $23*8,%esi movl $4,%ecx OuterLoop: pushl %ecx movl $4,%ecx .byte 0x48 movl %edi,%edx InnerLoop: .byte 0x48 movl (%esi),%eax call PrintQword addl $8,%esi mov $0x00, %al movb %al,(%edi) addl $2,%edi loop InnerLoop popl %ecx addl $0xa0,%edx movl %edx,%edi loop OuterLoop movl $0xb8960,%edi .byte 0x48 movl 18*8(%ebp),%eax # RIP subl $8*8,%eax .byte 0x48 movl %eax,%esi # esi = rip - 8 QWORD linear (total 16 QWORD) movl $4,%ecx OuterLoop1: pushl %ecx movl $4,%ecx movl %edi,%edx InnerLoop1: .byte 0x48 movl (%esi),%eax call PrintQword addl $8,%esi movb $0x00, %al movb %al,(%edi) addl $2,%edi loop InnerLoop1 popl %ecx addl $0xa0,%edx movl %edx,%edi loop OuterLoop1 #wbinvd LN_C1: jmp LN_C1 # # return # movl %ebp,%esp # mov rsp, rbp .byte 0x41 .byte 0x5f # pop r15 .byte 0x41 .byte 0x5e # pop r14 .byte 0x41 .byte 0x5d # pop r13 .byte 0x41 .byte 0x5c # pop r12 .byte 0x41 .byte 0x5b # pop r11 .byte 0x41 .byte 0x5a # pop r10 .byte 0x41 .byte 0x59 # pop r9 .byte 0x41 .byte 0x58 # pop r8 popl %edi popl %esi popl %ebp popl %eax # esp popl %ebx popl %edx popl %ecx popl %eax .byte 0x48 .byte 0x83 .byte 0xc4 .byte 0x10 # add esp, 16 ; error code and INT number .byte 0x48 .byte 0xcf # iretq PrintString: pushl %eax LN_C2: movb (%esi), %al cmpb $0,%al je LN_C3 movb %al, (%edi) .byte 0xff .byte 0xc6 # inc esi addl $2,%edi jmp LN_C2 LN_C3: popl %eax ret ## RAX contains qword to print ## RDI contains memory location (screen location) to print it to PrintQword: pushl %ecx pushl %ebx pushl %eax .byte 0x48 .byte 0xc7 .byte 0xc1 .long 16 # mov rcx, 16 looptop: .byte 0x48 roll $4,%eax movb %al,%bl andb $0xf,%bl addb $'0', %bl cmpb $'9', %bl jle @f addb $7,%bl @@: movb %bl, (%edi) addl $2,%edi loop looptop #wbinvd popl %eax popl %ebx popl %ecx ret ClearScreen: pushl %eax pushl %ecx movb $0x00, %al movb $0xc,%ah movl $0xb8000,%edi movl $80*24,%ecx LN_C4: movw %ax, (%edi) addl $2,%edi loop LN_C4 movl $0xb8000,%edi popl %ecx popl %eax ret A2C: andb $0xf,%al addb $'0', %al cmpb $'9', %al jle @f addb $7,%al LN_C5: ret String1: .asciz "*** INT " Int0String: .asciz "00h Divide by 0 -" Int1String: .asciz "01h Debug exception -" Int2String: .asciz "02h NMI -" Int3String: .asciz "03h Breakpoint -" Int4String: .asciz "04h Overflow -" Int5String: .asciz "05h Bound -" Int6String: .asciz "06h Invalid opcode -" Int7String: .asciz "07h Device not available -" Int8String: .asciz "08h Double fault -" Int9String: .asciz "09h Coprocessor seg overrun (reserved) -" Int10String: .asciz "0Ah Invalid TSS -" Int11String: .asciz "0Bh Segment not present -" Int12String: .asciz "0Ch Stack fault -" Int13String: .asciz "0Dh General protection fault -" Int14String: .asciz "0Eh Page fault -" Int15String: .asciz "0Fh (Intel reserved) -" Int16String: .asciz "10h Floating point error -" Int17String: .asciz "11h Alignment check -" Int18String: .asciz "12h Machine check -" Int19String: .asciz "13h SIMD Floating-Point Exception -" IntUnknownString: .asciz "??h Unknown interrupt -" StringTable: .long Int0String, Int1String, Int2String, Int3String, \ Int4String, Int5String, Int6String, Int7String, \ Int8String, Int9String, Int10String, Int11String, \ Int12String, Int13String, Int14String, Int15String,\ Int16String, Int17String, Int18String, Int19String String2: .asciz " HALT!! *** (" String3: .asciz ")" StringRax: .asciz "RAX=" StringRcx: .asciz " RCX=" StringRdx: .asciz " RDX=" StringRbx: .asciz "RBX=" StringRsp: .asciz " RSP=" StringRbp: .asciz " RBP=" StringRsi: .asciz "RSI=" StringRdi: .asciz " RDI=" StringEcode: .asciz " ECODE=" StringR8: .asciz "R8 =" StringR9: .asciz " R9 =" StringR10: .asciz " R10=" StringR11: .asciz "R11=" StringR12: .asciz " R12=" StringR13: .asciz " R13=" StringR14: .asciz "R14=" StringR15: .asciz " R15=" StringSs: .asciz " SS =" StringRflags: .asciz "RFLAGS=" Idtr: .float 0 .float 0 .org 0x21ffe BlockSignature: .word 0xaa55