#------------------------------------------------------------------------------ # # Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> # 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. # # Module Name: # # Thunk16.S # # Abstract: # # Real mode thunk # #------------------------------------------------------------------------------ #include <Library/BaseLib.h> ASM_GLOBAL ASM_PFX(m16Start), ASM_PFX(m16Size), ASM_PFX(mThunk16Attr), ASM_PFX(m16Gdt), ASM_PFX(m16GdtrBase), ASM_PFX(mTransition) ASM_GLOBAL ASM_PFX(InternalAsmThunk16) # define the structure of IA32_REGS .set _EDI, 0 #size 4 .set _ESI, 4 #size 4 .set _EBP, 8 #size 4 .set _ESP, 12 #size 4 .set _EBX, 16 #size 4 .set _EDX, 20 #size 4 .set _ECX, 24 #size 4 .set _EAX, 28 #size 4 .set _DS, 32 #size 2 .set _ES, 34 #size 2 .set _FS, 36 #size 2 .set _GS, 38 #size 2 .set _EFLAGS, 40 #size 4 .set _EIP, 44 #size 4 .set _CS, 48 #size 2 .set _SS, 50 #size 2 .set IA32_REGS_SIZE, 52 .text .code16 ASM_PFX(m16Start): SavedGdt: .space 6 ASM_PFX(BackFromUserCode): push %ss push %cs calll L_Base1 # push eip L_Base1: pushfl cli # disable interrupts push %gs push %fs push %es push %ds pushal .byte 0x66, 0xba # mov edx, imm32 ASM_PFX(ThunkAttr): .space 4 testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15, %dl jz 1f movw $0x2401, %ax int $0x15 cli # disable interrupts jnc 2f 1: testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL, %dl jz 2f inb $0x92, %al orb $2, %al outb %al, $0x92 # deactivate A20M# 2: xorl %eax, %eax movw %ss, %ax leal IA32_REGS_SIZE(%esp), %ebp mov %ebp, (_ESP - IA32_REGS_SIZE)(%bp) mov (_EIP - IA32_REGS_SIZE)(%bp), %bx shll $4, %eax addl %eax, %ebp .byte 0x66, 0xb8 # mov eax, imm32 SavedCr4: .space 4 movl %eax, %cr4 lgdtl %cs:(SavedGdt - L_Base1)(%bx) .byte 0x66, 0xb8 # mov eax, imm32 SavedCr0: .space 4 movl %eax, %cr0 .byte 0xb8 # mov ax, imm16 SavedSs: .space 2 movl %eax, %ss .byte 0x66, 0xbc # mov esp, imm32 SavedEsp: .space 4 lretl # return to protected mode _EntryPoint: .long ASM_PFX(ToUserCode) - ASM_PFX(m16Start) .word 0x8 _16Idtr: .word 0x3ff .long 0 _16Gdtr: .word GdtEnd - _NullSegDesc - 1 _16GdtrBase: .long _NullSegDesc ASM_PFX(ToUserCode): movw %ss, %dx movw %cx, %ss # set new segment selectors movw %cx, %ds movw %cx, %es movw %cx, %fs movw %cx, %gs movl %eax, %cr0 # real mode starts at next instruction # which (per SDM) *must* be a far JMP. ljmpw $0,$0 # will be filled in by InternalAsmThunk16 L_Base: # to point here. movl %ebp, %cr4 movw %si, %ss # set up 16-bit stack segment xchgl %ebx, %esp # set up 16-bit stack pointer movw IA32_REGS_SIZE(%esp), %bp # get BackToUserCode address from stack mov %dx, %cs:(SavedSs - ASM_PFX(BackFromUserCode))(%bp) mov %ebx, %cs:(SavedEsp - ASM_PFX(BackFromUserCode))(%bp) lidtl %cs:(_16Idtr - ASM_PFX(BackFromUserCode))(%bp) popal pop %ds pop %es pop %fs pop %gs popfl lretl # transfer control to user code _NullSegDesc: .quad 0 _16CsDesc: .word -1 .word 0 .byte 0 .byte 0x9b .byte 0x8f # 16-bit segment, 4GB limit .byte 0 _16DsDesc: .word -1 .word 0 .byte 0 .byte 0x93 .byte 0x8f # 16-bit segment, 4GB limit .byte 0 GdtEnd: .code32 # # @param RegSet The pointer to a IA32_DWORD_REGS structure # @param Transition The pointer to the transition code # @return The address of the 16-bit stack after returning from user code # ASM_PFX(InternalAsmThunk16): push %ebp push %ebx push %esi push %edi push %ds push %es push %fs push %gs movl 36(%esp), %esi # esi <- RegSet movzwl _SS(%esi), %edx mov _ESP(%esi), %edi add $(-(IA32_REGS_SIZE + 4)), %edi movl %edi, %ebx # ebx <- stack offset imul $0x10, %edx, %eax push $(IA32_REGS_SIZE / 4) addl %eax, %edi # edi <- linear address of 16-bit stack pop %ecx rep movsl # copy RegSet movl 40(%esp), %eax # eax <- address of transition code movl %edx, %esi # esi <- 16-bit stack segment lea (SavedCr0 - ASM_PFX(m16Start))(%eax), %edx movl %eax, %ecx andl $0xf, %ecx shll $12, %eax lea (ASM_PFX(BackFromUserCode) - ASM_PFX(m16Start))(%ecx), %ecx movw %cx, %ax stosl # [edi] <- return address of user code addl $(L_Base - ASM_PFX(BackFromUserCode)), %eax movl %eax, (L_Base - SavedCr0 - 4)(%edx) sgdtl (SavedGdt - SavedCr0)(%edx) sidtl 0x24(%esp) movl %cr0, %eax movl %eax, (%edx) # save CR0 in SavedCr0 andl $0x7ffffffe, %eax # clear PE, PG bits movl %cr4, %ebp mov %ebp, (SavedCr4 - SavedCr0)(%edx) andl $0xffffffcf, %ebp # clear PAE, PSE bits pushl $0x10 pop %ecx # ecx <- selector for data segments lgdtl (_16Gdtr - SavedCr0)(%edx) pushfl lcall *(_EntryPoint - SavedCr0)(%edx) popfl lidtl 0x24(%esp) lea -IA32_REGS_SIZE(%ebp), %eax pop %gs pop %fs pop %es pop %ds pop %edi pop %esi pop %ebx pop %ebp ret .const: ASM_PFX(m16Size): .word ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start) ASM_PFX(mThunk16Attr): .word ASM_PFX(ThunkAttr) - ASM_PFX(m16Start) ASM_PFX(m16Gdt): .word _NullSegDesc - ASM_PFX(m16Start) ASM_PFX(m16GdtrBase): .word _16GdtrBase - ASM_PFX(m16Start) ASM_PFX(mTransition): .word _EntryPoint - ASM_PFX(m16Start)