123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- /*++
- Copyright (c) 2012 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- realmexe.S
- Abstract:
- This module implements the real and protected mode code necessary to call
- BIOS services.
- Author:
- Evan Green 18-Jul-2012
- Environment:
- Boot
- --*/
- ##
- ## ------------------------------------------------------------------ Includes
- ##
- #include <minoca/kernel/x86.inc>
- ##
- ## --------------------------------------------------------------- Definitions
- ##
- ##
- ## BIOS_CALL_CONTEXT structure definition.
- ##
- .equ CODEPAGE, 0x00
- .equ DATAPAGE, 0x04
- .equ STACKPAGE, 0x08
- .equ EAX, 0x0C
- .equ EBX, 0x10
- .equ ECX, 0x14
- .equ EDX, 0x18
- .equ ESI, 0x1C
- .equ EDI, 0x20
- .equ ESP, 0x24
- .equ EBP, 0x28
- .equ EIP, 0x2C
- .equ EFLAGS, 0x30
- .equ CS, 0x34
- .equ DS, 0x38
- .equ ES, 0x3C
- .equ FS, 0x40
- .equ GS, 0x44
- .equ SS, 0x48
- ##
- ## ----------------------------------------------------------------------- Code
- ##
- ##
- ## .text specifies that this code belongs in the executable section.
- ##
- ## .code32 specifies that this is 32-bit protected mode code.
- ##
- .text
- .code32
- ##
- ## .globl allows this label to be visible to the linker.
- ##
- .globl EfiBiosCallTemplate
- .globl EfiBiosCallTemplateLongJump
- .globl EfiBiosCallTemplateLongJump2
- .globl EfiBiosCallTemplateLongJump3
- .globl EfiBiosCallTemplateIntInstruction
- .globl EfiBiosCallTemplateEnd
- .globl EfipExecuteBiosCall
- ##
- ## This code represents the real-mode code run to call BIOS code. It is 16-bit
- ## real-mode code. SI contains a pointer to the context structure.
- ##
- FUNCTION(EfiBiosCallTemplate)
- ##
- ## Save the GDT, IDT, and CR0.
- ##
- subl $0x8, %esp
- sgdt (%esp)
- subl $0x8, %esp
- sidt (%esp)
- movl %cr0, %ecx
- push %ecx
- andl $0xFFFFFFFE, %ecx
- pushl %esi
- ##
- ## Push the registers from the context onto the stack.
- ##
- movl EFLAGS(%esi), %eax
- pushl %eax
- movl EAX(%esi), %eax
- pushl %eax
- movl ECX(%esi), %eax
- pushl %eax
- movl EDX(%esi), %eax
- pushl %eax
- movl EBX(%esi), %eax
- pushl %eax
- movl EDI(%esi), %eax
- pushl %eax
- movl ESI(%esi), %eax
- pushl %eax
- movl DS(%esi), %eax
- pushl %eax
- movl ES(%esi), %eax
- pushl %eax
- movl FS(%esi), %eax
- pushl %eax
- movl GS(%esi), %eax
- pushl %eax
- ##
- ## Load 16-bit protected mode GDT and IDT registers.
- ##
- lgdt Efi16BitGdt
- lidt Efi16BitIdt
- ##
- ## Jump to consummate the transition to 16-bit protected mode.
- ##
- EfiBiosCallTemplateLongJump:
- ljmp $KERNEL_CS, $0x3456
- ##
- ## This is now 16-bit protected mode code (a weird combination). Remove the
- ## protected mode bit to get to real mode.
- ##
- .code16
- movl %ecx, %cr0
- ##
- ## Perform a long jump to get back to 16 bit real mode. This assumes that
- ## the code is located below 64k. The actual constants will be patched up,
- ## this constant is a dummy.
- ##
- EfiBiosCallTemplateLongJump2:
- ljmp $0x12, $0x3456
- ##
- ## Reset the stack segment, and pop the registers into place.
- ##
- xorw %ax, %ax
- movw %ax, %ss
- popl %eax
- movw %ax, %gs
- popl %eax
- movw %ax, %fs
- popl %eax
- movw %ax, %es
- popl %eax
- movw %ax, %ds
- popl %esi
- popl %edi
- popl %ebx
- popl %edx
- popl %ecx
- popl %eax
- popfl
- ##
- ## Blast off. This 0x1B is a dummy value, the setup code will have
- ## modified that to be the correct vector.
- ##
- EfiBiosCallTemplateIntInstruction:
- int $0x1B
- ##
- ## Push the registers onto the stack. This is still 16 bit code.
- ##
- pushfl
- cli
- pushl %esi
- pushl %edi
- pushl %ebx
- pushl %edx
- pushl %ecx
- pushl %eax
- xorl %eax, %eax
- movw %gs, %ax
- pushl %eax
- movw %fs, %ax
- pushl %eax
- movw %es, %ax
- pushl %eax
- movw %ds, %ax
- pushl %eax
- ##
- ## Restore back to 32-bit protected mode by loading up the GDT and IDT,
- ## then applying the original CR0.
- ##
- xorw %ax, %ax
- movw %ax, %ds
- leal 0x34(%esp), %eax
- lidt (%eax)
- addl $0x8, %eax
- lgdt (%eax)
- movl 0x30(%esp), %eax
- ##
- ## Restore protected mode, and perform a long jump to make it apply.
- ##
- movl %eax, %cr0
- EfiBiosCallTemplateLongJump3:
- ljmp $KERNEL_CS, $0x3456
- .code32
- ##
- ## Restore the protected mode segment registers.
- ##
- movw $KERNEL_DS, %dx
- movw %dx, %ds
- movw %dx, %es
- movw %dx, %fs
- movw %dx, %gs
- movw %dx, %ss
- ##
- ## Safely back in 32-bit land, get the address of the context structure,
- ## and save the registers saved onto the stack into the context structure.
- ##
- movl 0x2C(%esp), %esi
- popl %eax
- movl %eax, DS(%esi)
- popl %eax
- movl %eax, ES(%esi)
- popl %eax
- movl %eax, FS(%esi)
- popl %eax
- movl %eax, GS(%esi)
- popl %eax
- movl %eax, EAX(%esi)
- popl %eax
- movl %eax, ECX(%esi)
- popl %eax
- movl %eax, EDX(%esi)
- popl %eax
- movl %eax, EBX(%esi)
- popl %eax
- movl %eax, EDI(%esi)
- popl %eax
- movl %eax, ESI(%esi)
- popl %eax
- movl %eax, EFLAGS(%esi)
- addl $0x18, %esp
- movl $EfipExecuteBiosCallRestore, %eax
- jmp *%eax
- ##
- ## That was the end of the code. Now define a 16-bit protected mode GDT.
- ## The GDT must be aligned to 8 bytes.
- ##
- .align 8
- Efi16BitGdt:
- .word (3 * 8) - 1 # GDT table limit
- .long Efi16BitGdtTable # GDT table location
- Efi16BitGdtTable:
- .long 0x0 # The first GDT entry is called the
- .long 0x0 # null descriptor, it is essentially
- # unused by the processor.
- ##
- ## Define the code segment descriptor.
- ##
- .word 0xFFFF # Limit 15:0
- .word 0x0 # Base 15:0
- .byte 0x0 # Base 23:16
- .byte 0x9A # Access: Present, Ring 0, Code Segment
- .byte 0x8F # Granularity: 1Kb, 16-bit mode
- .byte 0x00 # Base 31:24
- ##
- ## Define the dat segment descriptor.
- ##
- .word 0xFFFF # Limit 15:0
- .word 0x0 # Base 15:0
- .byte 0x0 # Base 23:16
- .byte 0x92 # Access: Present, Ring 0, Data Segment
- .byte 0x8F # Granularity: 1kB, 16-bit mode
- .byte 0x00 # Base 31:24
- ##
- ## Also define a 16-bit protected mode IDT.
- ##
- Efi16BitIdt:
- .word 0x3FF # IDT Table Limit
- .long 0x0 # IDT Table base
- ##
- ## This label marks the end of the template code. It is useful for determining
- ## the size of the template code.
- ##
- EfiBiosCallTemplateEnd:
- nop
- END_FUNCTION(EfiBiosCallTemplate)
- ##
- ## This function is 32-bit protected mode code.
- ##
- .code32
- ##
- ## VOID
- ## EfipExecuteBiosCall (
- ## PBIOS_CALL_CONTEXT Context
- ## )
- ##
- /*++
- Routine Description:
- This routine executes 16-bit real mode code by switching the processor back
- to real mode.
- Arguments:
- Context - Supplies a pointer to the context structure that will be
- executed. On return, this will contain the executed context.
- Return Value:
- None.
- --*/
- FUNCTION(EfipExecuteBiosCall)
- push %ebp
- movl %esp, %ebp
- ##
- ## Save the non-volatile registers and flags.
- ##
- push %ebx
- push %esi
- push %edi
- push %ebp
- pushfl
- cli
- ##
- ## Load the context parameter into ESI, get EIP, and jump to it.
- ##
- movl 8(%ebp), %esi
- movl CS(%esi), %eax
- shll $4, %eax
- movl EIP(%esi), %edx
- add %edx, %eax
- jmp *%eax
- ##
- ## This code is jumped to by the end of the BIOS call template.
- ##
- EfipExecuteBiosCallRestore:
- ##
- ## Restore the non-volatile registers and flags.
- ##
- popfl
- popl %ebp
- popl %edi
- popl %esi
- popl %ebx
- leave
- ret
- END_FUNCTION(EfipExecuteBiosCall)
|