#***************************************************************************** #* #* Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
#* 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: #* #* Thunk.S #* #* Abstract: #* #* Real mode thunk #* #***************************************************************************** #include .data .globl ASM_PFX(mCode16Size) .data mCode16Size: .long _Code16End - _Code16Addr NullSegSel: .quad 0 _16CsSegSel: .word -1 .word 0 .byte 0 .byte 0x9b .byte 0x8f #16-bit segment .byte 0 _16DsSegSel: .word -1 .word 0 .byte 0 .byte 0x93 .byte 0x8f #16-bit segment .byte 0 _16Gdtr: .word _16Gdtr - NullSegSel - 1 .long NullSegSel .code: #IA32_REGS STRUC 4t #_EDI DD ? #_ESI DD ? #_EBP DD ? #_ESP DD ? #_EBX DD ? #_EDX DD ? #_ECX DD ? #_EAX DD ? #_DS DW ? #_ES DW ? #_FS DW ? #_GS DW ? #_RFLAGS DQ ? #_EIP DD ? #_CS DW ? #_SS DW ? #IA32_REGS ENDS #_STK16 STRUC 1t #RetEip DD ? #RetCs DW ? #ThunkFlags DW ? #SavedGdtr FWORD ? #Resvd1 DW ? #SavedCr0 DD ? #SavedCr4 DD ? #_STK16 ENDS ASM_PFX(Thunk16): push %rbp push %rbx push %rsi push %rdi push %r12 push %r13 push %r14 push %r15 pushq %fs pushq %gs movl %ds,%r12d movl %es,%r13d movl %ss,%r14d mov %rsp,%r15 mov %rcx,%rsi movzwq 0x36(%rsi),%r10 #movzx r10, (IA32_REGS ptr [rsi])._SS xor %rdi,%rdi mov 0xc(%rsi),%edi #mov edi, (IA32_REGS ptr [rsi])._ESP add $0xffffffffffffffb0,%rdi #add rdi, - sizeof (IA32_REGS) - sizeof (_STK16) push %rdi imul $0x10,%r10,%rax add %rax,%rdi pushq $0xe #push sizeof (IA32_REGS) / 4 pop %rcx rep movsl %ds:(%rsi),%es:(%rdi) #; copy eflags to stack frame mov -16(%rsi), %rax mov %rax, -80(%rsi) pop %rbx #rbx <- 16-bit stack offset lea Label,%eax #42 <_Thunk16+0x42> stos %eax,%es:(%rdi) movl %cs,%eax #return segment stos %ax,%es:(%rdi) mov %edx,%eax #THUNK Flags stos %ax,%es:(%rdi) sgdt 0x58(%rsp) #save GDTR mov 0x58(%rsp),%rax stos %rax,%es:(%rdi) mov %cr0,%rax #save CR0 mov %eax,%esi #esi <- CR0 to set stos %eax,%es:(%rdi) mov %cr4,%rax #save CR4 stos %eax,%es:(%rdi) sidt 0x58(%rsp) #save IDTR and $0x7ffffffe,%esi #clear PE & PG bits mov %r10,%rdi #rdi <- 16-bit stack segment shl $0x10,%r8 push %r8 #far jmp address lea Label_16Bit,%eax push %rax movw $0x8,0x4(%rsp) lgdt _16Gdtr #bugbug: may not match. lret Label_16Bit: .byte 0x66 movl $0xc0000080,%ecx mov %rsi,%cr0 #disable PE & PG rdmsr and $0xfe,%ah wrmsr #clear LME bit mov %cr4,%rax and $0xcf,%al #clear PAE & PSE mov %rax,%cr4 lret Label: xor %rax,%rax movl %ss,%eax shl $0x4,%eax add %esp,%eax mov %r15,%rsp lidt 0x58(%rsp) movl %r12d,%ds movl %r13d,%es movl %r14d,%ss popq %gs popq %fs pop %r15 pop %r14 pop %r13 pop %r12 pop %rdi pop %rsi pop %rbx pop %rbp retq .p2align 4 _Code16Addr: ASM_PFX(RealMode): movl %edi,%ss mov %bx,%sp #set up 16-bit stack .byte 0x2e .byte 0x0f .byte 0x01 .byte 0x1e .word _16Idtr - _Code16Addr #lidt _16Idtr .byte 0x66 .byte 0x61 #popad .byte 0x1f #pop ds .byte 0x07 #pop es popq %fs popq %gs sub 64, %esp .byte 0x66, 0x9d #popfd add $0x4,%esp #skip high part of RFLAGS .byte 0x67 #; test (_STK16 ptr [esp + STACK_PARAM_SIZE + sizeof(IA32_REGS)]).ThunkFlags, 1 .byte 0xf7 .byte 0x44 .byte 0x24 .byte 0x4e .byte 0x01 .byte 0x00 jz 1f pushfq #pushf, actually, when it's INT# 1: .byte 0x0e #push cs .byte 0x68 #push /iw .word FarCallRet - _Code16Addr jz 2f .byte 0x66 ljmp *70(%esp) 2: .byte 0x66 ljmp *68(%esp) FarCallRet: add 64, %esp .byte 0x66 push $0x00 #push a dword of zero .byte 0x66 pushf #pushfd, actually pushq %gs pushq %fs .byte 0x06 #push %es .byte 0x1e #push %ds .byte 0x66 .byte 0x60 cli .byte 0x66 #sizeof (IA32_REGS) = 13 * 4 = 52 lgdt 64(%esp) #lgdt (_STK16 ptr [esp + sizeof (IA32_REGS)]).SavedGdtr .byte 0x66 mov 76(%esp), %eax mov %rax, %cr4 .byte 0x66 mov $0xc0000080, %ecx rdmsr orb $1, %ah wrmsr .byte 0x66 mov 72(%esp), %eax mov %rax, %cr0 #restore CR0 .byte 0x66 ljmpl *52(%esp) _16Idtr: .word 0x3ff #FWORD (1 SHL 10) - 1 .byte 0x00