#------------------------------------------------------------------------------\r
#\r
-# Copyright (c) 2006, Intel Corporation\r
-# All rights reserved. This program and the accompanying materials\r
+# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
# are licensed and made available under the terms and conditions of the BSD License\r
# which accompanies this distribution. The full text of the license may be found at\r
-# http://opensource.org/licenses/bsd-license.php\r
+# http://opensource.org/licenses/bsd-license.php.\r
#\r
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
#\r
# Module Name:\r
#\r
-# Thunk.asm\r
+# Thunk16.S\r
#\r
# Abstract:\r
#\r
#\r
#------------------------------------------------------------------------------\r
\r
-.global _m16Start, _m16Size, _mThunk16Attr, _m16GdtBase, _m16Gdt, _m16GdtrBase, _mTransition\r
- ##########\r
- # FIXME! #\r
- ##########\r
-# The following data are INVALID!!\r
-# They just follow GAS syntax.\r
-_m16Start: .byte 0x00\r
-_m16Size: .word 0x00\r
-_mThunk16Attr: .word 0x00\r
-_m16Gdt: .word 0x00\r
-_m16GdtrBase: .word 0x00\r
-_mTransition: .word 0x00\r
-\r
-.global _InternalAsmThunk16\r
-_InternalAsmThunk16:\r
-\r
- ##########\r
- # FIXME! #\r
- ##########\r
- # This function won't work for now.\r
- # it will directly enter dead loop.\r
- jmp .\r
-
\ No newline at end of file
+#include <Library/BaseLib.h>\r
+\r
+ASM_GLOBAL ASM_PFX(m16Start), ASM_PFX(m16Size), ASM_PFX(mThunk16Attr), ASM_PFX(m16Gdt), ASM_PFX(m16GdtrBase), ASM_PFX(mTransition)\r
+ASM_GLOBAL ASM_PFX(InternalAsmThunk16)\r
+\r
+# define the structure of IA32_REGS\r
+.set _EDI, 0 #size 4\r
+.set _ESI, 4 #size 4\r
+.set _EBP, 8 #size 4\r
+.set _ESP, 12 #size 4\r
+.set _EBX, 16 #size 4\r
+.set _EDX, 20 #size 4\r
+.set _ECX, 24 #size 4\r
+.set _EAX, 28 #size 4\r
+.set _DS, 32 #size 2\r
+.set _ES, 34 #size 2\r
+.set _FS, 36 #size 2\r
+.set _GS, 38 #size 2\r
+.set _EFLAGS, 40 #size 4\r
+.set _EIP, 44 #size 4\r
+.set _CS, 48 #size 2\r
+.set _SS, 50 #size 2\r
+.set IA32_REGS_SIZE, 52\r
+\r
+ .text\r
+ .code16\r
+\r
+ASM_PFX(m16Start):\r
+\r
+SavedGdt: .space 6\r
+\r
+ASM_PFX(BackFromUserCode):\r
+ push %ss\r
+ push %cs\r
+\r
+ calll L_Base1 # push eip\r
+L_Base1:\r
+ pushfl\r
+ cli # disable interrupts\r
+ push %gs\r
+ push %fs\r
+ push %es\r
+ push %ds\r
+ pushal\r
+ .byte 0x66, 0xba # mov edx, imm32\r
+ASM_PFX(ThunkAttr): .space 4\r
+ testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15, %dl\r
+ jz 1f\r
+ movw $0x2401, %ax\r
+ int $0x15\r
+ cli # disable interrupts\r
+ jnc 2f\r
+1:\r
+ testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL, %dl\r
+ jz 2f\r
+ inb $0x92, %al\r
+ orb $2, %al\r
+ outb %al, $0x92 # deactivate A20M#\r
+2:\r
+ xorl %eax, %eax\r
+ movw %ss, %ax\r
+ leal IA32_REGS_SIZE(%esp), %ebp\r
+ mov %ebp, (_ESP - IA32_REGS_SIZE)(%bp)\r
+ mov (_EIP - IA32_REGS_SIZE)(%bp), %bx\r
+ shll $4, %eax\r
+ addl %eax, %ebp\r
+ .byte 0x66, 0xb8 # mov eax, imm32\r
+SavedCr4: .space 4\r
+ movl %eax, %cr4\r
+ lgdtl %cs:(SavedGdt - L_Base1)(%bx)\r
+ .byte 0x66, 0xb8 # mov eax, imm32\r
+SavedCr0: .space 4\r
+ movl %eax, %cr0\r
+ .byte 0xb8 # mov ax, imm16\r
+SavedSs: .space 2\r
+ movl %eax, %ss\r
+ .byte 0x66, 0xbc # mov esp, imm32\r
+SavedEsp: .space 4\r
+ lretl # return to protected mode\r
+\r
+_EntryPoint: .long ASM_PFX(ToUserCode) - ASM_PFX(m16Start)\r
+ .word 0x8\r
+_16Idtr: .word 0x3ff\r
+ .long 0\r
+_16Gdtr: .word GdtEnd - _NullSegDesc - 1\r
+_16GdtrBase: .long _NullSegDesc\r
+\r
+ASM_PFX(ToUserCode):\r
+ movw %ss, %dx\r
+ movw %cx, %ss # set new segment selectors\r
+ movw %cx, %ds\r
+ movw %cx, %es\r
+ movw %cx, %fs\r
+ movw %cx, %gs\r
+ movl %eax, %cr0 # real mode starts at next instruction\r
+ # which (per SDM) *must* be a far JMP.\r
+ ljmpw $0,$0 # will be filled in by InternalAsmThunk16\r
+L_Base: # to point here.\r
+ movl %ebp, %cr4\r
+ movw %si, %ss # set up 16-bit stack segment\r
+ xchgl %ebx, %esp # set up 16-bit stack pointer\r
+\r
+ movw IA32_REGS_SIZE(%esp), %bp # get BackToUserCode address from stack\r
+ mov %dx, %cs:(SavedSs - ASM_PFX(BackFromUserCode))(%bp)\r
+ mov %ebx, %cs:(SavedEsp - ASM_PFX(BackFromUserCode))(%bp)\r
+ lidtl %cs:(_16Idtr - ASM_PFX(BackFromUserCode))(%bp)\r
+ popal\r
+ pop %ds\r
+ pop %es\r
+ pop %fs\r
+ pop %gs\r
+ popfl\r
+ lretl # transfer control to user code\r
+\r
+_NullSegDesc: .quad 0\r
+_16CsDesc:\r
+ .word -1\r
+ .word 0\r
+ .byte 0\r
+ .byte 0x9b\r
+ .byte 0x8f # 16-bit segment, 4GB limit\r
+ .byte 0\r
+_16DsDesc:\r
+ .word -1\r
+ .word 0\r
+ .byte 0\r
+ .byte 0x93\r
+ .byte 0x8f # 16-bit segment, 4GB limit\r
+ .byte 0\r
+GdtEnd:\r
+\r
+ .code32\r
+#\r
+# @param RegSet The pointer to a IA32_DWORD_REGS structure\r
+# @param Transition The pointer to the transition code\r
+# @return The address of the 16-bit stack after returning from user code\r
+#\r
+ASM_PFX(InternalAsmThunk16):\r
+ push %ebp\r
+ push %ebx\r
+ push %esi\r
+ push %edi\r
+ push %ds\r
+ push %es\r
+ push %fs\r
+ push %gs\r
+ movl 36(%esp), %esi # esi <- RegSet\r
+ movzwl _SS(%esi), %edx\r
+ mov _ESP(%esi), %edi\r
+ add $(-(IA32_REGS_SIZE + 4)), %edi\r
+ movl %edi, %ebx # ebx <- stack offset\r
+ imul $0x10, %edx, %eax\r
+ push $(IA32_REGS_SIZE / 4)\r
+ addl %eax, %edi # edi <- linear address of 16-bit stack\r
+ pop %ecx\r
+ rep\r
+ movsl # copy RegSet\r
+ movl 40(%esp), %eax # eax <- address of transition code\r
+ movl %edx, %esi # esi <- 16-bit stack segment\r
+ lea (SavedCr0 - ASM_PFX(m16Start))(%eax), %edx\r
+ movl %eax, %ecx\r
+ andl $0xf, %ecx\r
+ shll $12, %eax\r
+ lea (ASM_PFX(BackFromUserCode) - ASM_PFX(m16Start))(%ecx), %ecx\r
+ movw %cx, %ax\r
+ stosl # [edi] <- return address of user code\r
+ addl $(L_Base - ASM_PFX(BackFromUserCode)), %eax\r
+ movl %eax, (L_Base - SavedCr0 - 4)(%edx)\r
+ sgdtl (SavedGdt - SavedCr0)(%edx)\r
+ sidtl 0x24(%esp)\r
+ movl %cr0, %eax\r
+ movl %eax, (%edx) # save CR0 in SavedCr0\r
+ andl $0x7ffffffe, %eax # clear PE, PG bits\r
+ movl %cr4, %ebp\r
+ mov %ebp, (SavedCr4 - SavedCr0)(%edx)\r
+ andl $0xffffffcf, %ebp # clear PAE, PSE bits\r
+ pushl $0x10\r
+ pop %ecx # ecx <- selector for data segments\r
+ lgdtl (_16Gdtr - SavedCr0)(%edx)\r
+ pushfl\r
+ lcall *(_EntryPoint - SavedCr0)(%edx)\r
+ popfl\r
+ lidtl 0x24(%esp)\r
+ lea -IA32_REGS_SIZE(%ebp), %eax\r
+ pop %gs\r
+ pop %fs\r
+ pop %es\r
+ pop %ds\r
+ pop %edi\r
+ pop %esi\r
+ pop %ebx\r
+ pop %ebp\r
+ ret\r
+\r
+ .const:\r
+\r
+ASM_PFX(m16Size): .word ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)\r
+ASM_PFX(mThunk16Attr): .word ASM_PFX(ThunkAttr) - ASM_PFX(m16Start)\r
+ASM_PFX(m16Gdt): .word _NullSegDesc - ASM_PFX(m16Start)\r
+ASM_PFX(m16GdtrBase): .word _16GdtrBase - ASM_PFX(m16Start)\r
+ASM_PFX(mTransition): .word _EntryPoint - ASM_PFX(m16Start)\r