1#------------------------------------------------------------------------------ 2# 3# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> 4# This program and the accompanying materials 5# are licensed and made available under the terms and conditions of the BSD License 6# which accompanies this distribution. The full text of the license may be found at 7# http://opensource.org/licenses/bsd-license.php. 8# 9# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11# 12# Module Name: 13# 14# Thunk16.S 15# 16# Abstract: 17# 18# Real mode thunk 19# 20#------------------------------------------------------------------------------ 21 22#include <Library/BaseLib.h> 23 24ASM_GLOBAL ASM_PFX(m16Start), ASM_PFX(m16Size), ASM_PFX(mThunk16Attr), ASM_PFX(m16Gdt), ASM_PFX(m16GdtrBase), ASM_PFX(mTransition) 25ASM_GLOBAL ASM_PFX(InternalAsmThunk16) 26 27# define the structure of IA32_REGS 28.set _EDI, 0 #size 4 29.set _ESI, 4 #size 4 30.set _EBP, 8 #size 4 31.set _ESP, 12 #size 4 32.set _EBX, 16 #size 4 33.set _EDX, 20 #size 4 34.set _ECX, 24 #size 4 35.set _EAX, 28 #size 4 36.set _DS, 32 #size 2 37.set _ES, 34 #size 2 38.set _FS, 36 #size 2 39.set _GS, 38 #size 2 40.set _EFLAGS, 40 #size 4 41.set _EIP, 44 #size 4 42.set _CS, 48 #size 2 43.set _SS, 50 #size 2 44.set IA32_REGS_SIZE, 52 45 46 .text 47 .code16 48 49ASM_PFX(m16Start): 50 51SavedGdt: .space 6 52 53ASM_PFX(BackFromUserCode): 54 push %ss 55 push %cs 56 57 calll L_Base1 # push eip 58L_Base1: 59 pushfl 60 cli # disable interrupts 61 push %gs 62 push %fs 63 push %es 64 push %ds 65 pushal 66 .byte 0x66, 0xba # mov edx, imm32 67ASM_PFX(ThunkAttr): .space 4 68 testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15, %dl 69 jz 1f 70 movw $0x2401, %ax 71 int $0x15 72 cli # disable interrupts 73 jnc 2f 741: 75 testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL, %dl 76 jz 2f 77 inb $0x92, %al 78 orb $2, %al 79 outb %al, $0x92 # deactivate A20M# 802: 81 xorl %eax, %eax 82 movw %ss, %ax 83 leal IA32_REGS_SIZE(%esp), %ebp 84 mov %ebp, (_ESP - IA32_REGS_SIZE)(%bp) 85 mov (_EIP - IA32_REGS_SIZE)(%bp), %bx 86 shll $4, %eax 87 addl %eax, %ebp 88 .byte 0x66, 0xb8 # mov eax, imm32 89SavedCr4: .space 4 90 movl %eax, %cr4 91 lgdtl %cs:(SavedGdt - L_Base1)(%bx) 92 .byte 0x66, 0xb8 # mov eax, imm32 93SavedCr0: .space 4 94 movl %eax, %cr0 95 .byte 0xb8 # mov ax, imm16 96SavedSs: .space 2 97 movl %eax, %ss 98 .byte 0x66, 0xbc # mov esp, imm32 99SavedEsp: .space 4 100 lretl # return to protected mode 101 102_EntryPoint: .long ASM_PFX(ToUserCode) - ASM_PFX(m16Start) 103 .word 0x8 104_16Idtr: .word 0x3ff 105 .long 0 106_16Gdtr: .word GdtEnd - _NullSegDesc - 1 107_16GdtrBase: .long _NullSegDesc 108 109ASM_PFX(ToUserCode): 110 movw %ss, %dx 111 movw %cx, %ss # set new segment selectors 112 movw %cx, %ds 113 movw %cx, %es 114 movw %cx, %fs 115 movw %cx, %gs 116 movl %eax, %cr0 # real mode starts at next instruction 117 # which (per SDM) *must* be a far JMP. 118 ljmpw $0,$0 # will be filled in by InternalAsmThunk16 119L_Base: # to point here. 120 movl %ebp, %cr4 121 movw %si, %ss # set up 16-bit stack segment 122 xchgl %ebx, %esp # set up 16-bit stack pointer 123 124 movw IA32_REGS_SIZE(%esp), %bp # get BackToUserCode address from stack 125 mov %dx, %cs:(SavedSs - ASM_PFX(BackFromUserCode))(%bp) 126 mov %ebx, %cs:(SavedEsp - ASM_PFX(BackFromUserCode))(%bp) 127 lidtl %cs:(_16Idtr - ASM_PFX(BackFromUserCode))(%bp) 128 popal 129 pop %ds 130 pop %es 131 pop %fs 132 pop %gs 133 popfl 134 lretl # transfer control to user code 135 136_NullSegDesc: .quad 0 137_16CsDesc: 138 .word -1 139 .word 0 140 .byte 0 141 .byte 0x9b 142 .byte 0x8f # 16-bit segment, 4GB limit 143 .byte 0 144_16DsDesc: 145 .word -1 146 .word 0 147 .byte 0 148 .byte 0x93 149 .byte 0x8f # 16-bit segment, 4GB limit 150 .byte 0 151GdtEnd: 152 153 .code32 154# 155# @param RegSet The pointer to a IA32_DWORD_REGS structure 156# @param Transition The pointer to the transition code 157# @return The address of the 16-bit stack after returning from user code 158# 159ASM_PFX(InternalAsmThunk16): 160 push %ebp 161 push %ebx 162 push %esi 163 push %edi 164 push %ds 165 push %es 166 push %fs 167 push %gs 168 movl 36(%esp), %esi # esi <- RegSet 169 movzwl _SS(%esi), %edx 170 mov _ESP(%esi), %edi 171 add $(-(IA32_REGS_SIZE + 4)), %edi 172 movl %edi, %ebx # ebx <- stack offset 173 imul $0x10, %edx, %eax 174 push $(IA32_REGS_SIZE / 4) 175 addl %eax, %edi # edi <- linear address of 16-bit stack 176 pop %ecx 177 rep 178 movsl # copy RegSet 179 movl 40(%esp), %eax # eax <- address of transition code 180 movl %edx, %esi # esi <- 16-bit stack segment 181 lea (SavedCr0 - ASM_PFX(m16Start))(%eax), %edx 182 movl %eax, %ecx 183 andl $0xf, %ecx 184 shll $12, %eax 185 lea (ASM_PFX(BackFromUserCode) - ASM_PFX(m16Start))(%ecx), %ecx 186 movw %cx, %ax 187 stosl # [edi] <- return address of user code 188 addl $(L_Base - ASM_PFX(BackFromUserCode)), %eax 189 movl %eax, (L_Base - SavedCr0 - 4)(%edx) 190 sgdtl (SavedGdt - SavedCr0)(%edx) 191 sidtl 0x24(%esp) 192 movl %cr0, %eax 193 movl %eax, (%edx) # save CR0 in SavedCr0 194 andl $0x7ffffffe, %eax # clear PE, PG bits 195 movl %cr4, %ebp 196 mov %ebp, (SavedCr4 - SavedCr0)(%edx) 197 andl $0xffffffcf, %ebp # clear PAE, PSE bits 198 pushl $0x10 199 pop %ecx # ecx <- selector for data segments 200 lgdtl (_16Gdtr - SavedCr0)(%edx) 201 pushfl 202 lcall *(_EntryPoint - SavedCr0)(%edx) 203 popfl 204 lidtl 0x24(%esp) 205 lea -IA32_REGS_SIZE(%ebp), %eax 206 pop %gs 207 pop %fs 208 pop %es 209 pop %ds 210 pop %edi 211 pop %esi 212 pop %ebx 213 pop %ebp 214 ret 215 216 .const: 217 218ASM_PFX(m16Size): .word ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start) 219ASM_PFX(mThunk16Attr): .word ASM_PFX(ThunkAttr) - ASM_PFX(m16Start) 220ASM_PFX(m16Gdt): .word _NullSegDesc - ASM_PFX(m16Start) 221ASM_PFX(m16GdtrBase): .word _16GdtrBase - ASM_PFX(m16Start) 222ASM_PFX(mTransition): .word _EntryPoint - ASM_PFX(m16Start) 223