summaryrefslogtreecommitdiff
path: root/Core/MdePkg/Library/BaseLib/Ia32/Thunk16.S
diff options
context:
space:
mode:
Diffstat (limited to 'Core/MdePkg/Library/BaseLib/Ia32/Thunk16.S')
-rw-r--r--Core/MdePkg/Library/BaseLib/Ia32/Thunk16.S222
1 files changed, 222 insertions, 0 deletions
diff --git a/Core/MdePkg/Library/BaseLib/Ia32/Thunk16.S b/Core/MdePkg/Library/BaseLib/Ia32/Thunk16.S
new file mode 100644
index 0000000000..185655eecb
--- /dev/null
+++ b/Core/MdePkg/Library/BaseLib/Ia32/Thunk16.S
@@ -0,0 +1,222 @@
+#------------------------------------------------------------------------------
+#
+# 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)