#*****************************************************************************
#*
#*   Copyright (c) 2006 - 2007, 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.asm
#*  
#*   Abstract:
#*  
#*    Real mode thunk
#*  
#*****************************************************************************
#include <EfiBind.h>

    .686p: 

.globl ASM_PFX(mCode16Size)

.data
mCode16Size:    .long   _TEXT16SIZE

.data

NullSegSel:     .quad   0
_16BitCsSel:    
                .word   -1
                .word   0
                .byte   0
                .byte   0x9b
                .byte   0x8f            # 16-bit segment
                .byte   0
_16BitSsSel:
                .word   -1
                .word   0
                .byte   0
                .byte   0x93
                .byte   0x8f           # 16-bit segment
                .byte   0

_16Gdtr:
                .word      _16Gdtr - NullSegSel - 1
                .long      NullSegSel


.text
.align  16


ASM_PFX(Thunk16):
    push   %ebp
    push   %ebx
    push   %esi
    push   %edi
    push   %ds
    push   %es
    push   %fs
    push   %gs
    mov    0x24(%esp),%esi
    movzwl 0x32(%esi),%edx
    mov    0xc(%esi),%edi
    add    $0xffffffb0,%edi
    push   %edi                       #; save stack offset
    imul   $0x10,%edx,%eax            #; eax <- edx*16
    add    %eax,%edi                  #; edi <- linear address of 16-bit stack
    push   $0xd
    pop    %ecx
    rep movsl %ds:(%esi),%es:(%edi)   #; copy context to 16-bit stack
    pop    %ebx                       #; ebx <- 16-bit stack offset
    mov    $L_Label1,%eax
    stos   %eax,%es:(%edi)
    movl   %cs,%eax
    stos   %ax,%es:(%edi)
    mov    0x28(%esp),%eax
    stos   %ax,%es:(%edi)
    mov    %esp,%eax
    stos   %eax,%es:(%edi)
    movl   %ss,%eax
    stos   %ax,%es:(%edi)
    sgdtl  (%edi)
    sidtl  0x24(%esp)
    mov    %cr0,%esi
    mov    %esi,0x6(%edi)             #; save CR0
    and    $0x7ffffffe,%esi           #; esi <- CR0 to set
    mov    %cr4,%eax
    mov    %eax,0xa(%edi)             #; save CR4
    and    $0xcf,%al                  #; clear PAE & PSE
    mov    %edx,%edi                  #; edi <- 16-bit stack segment
    mov    0x2c(%esp),%edx
    shl    $0x10,%edx
    push   %edx
    pop    %edx
    mov    $(_16BitSsSel - NullSegSel),%dx
    lgdtl  _16Gdtr                    #bugbug mismatch.
    .byte  0xea
    .long  L_16Bit                    #bugbug mismatch.
    .word  _16BitCsSel - NullSegSel
L_16Bit:   
    .byte  0x66 
    movw   %dx,%ss
    mov    %esi,%cr0
    mov    %eax,%cr4
    .byte  0x67
    .byte  0xff
    .byte  0x6c
    .byte  0x24
    .byte  0xfc
    
L_Lable1:
    movl   %ss,%eax
    shl    $0x4,%eax
    add    %esp,%eax
    lss    0x3c(%esp),%esp
    lidtl  0x24(%esp)
    pop    %gs
    pop    %fs
    pop    %es
    pop    %ds
    pop    %edi
    pop    %esi
    pop    %ebx
    pop    %ebp
    ret 

.code16
_Code16Addr:
ASM_PFX(RealMode):
    movw    %di, %ss                    # set up stack
    movl    %ebx, %esp
    lidt    %cs:_16Idtr - _Code16Addr  #lidt    fword ptr cs:[_16Idtr - _Code16Addr]
    .byte   0x66
    popaw
    popw    %ds
    popw    %es
    popw    %fs
    popw    %gs
    addw    $4, %sp                     # skip EFlags
    testw   $1, 14(%esp)                  #(_STK16 ptr [esp + 8]).ThunkFlags, 1
    jz      1f
    pushf
1: 
    pushw   %cs
#    push    @FarCallRet - _Code16Addr
    .byte   0x68                        # push /iw
    .word   FarCallRet - _Code16Addr
    jz      2f
    ljmp    *6(%esp)                  #bugbug
2: 
    ljmp    *4(%esp)                  #bugbug
FarCallRet: 
    pushfl
    pushw   %gs
    pushw   %fs
    pushw   %es
    pushw   %ds
    pushal
    cli
    .byte   0x66                        # sizeof (IA32_REGS) = 13 * 4 = 52
    lgdt    66(%esp)                    #lgdt    (_STK16 ptr [esp + sizeof (IA32_REGS)]).SavedGdtr
    mov     76(%esp), %eax
    movl    %eax, %cr4
    mov     72(%esp), %eax
    movl    %eax, %cr0                   # restore CR0
    ljmpl   *52(%esp)                    
#RealMode ENDP

.text
_16Idtr:
    .word 0x3ff                         #_16Idtr     FWORD   (1 SHL 10) - 1
    .byte 0x00

_TEXT16END: 

_TEXT16SIZE = _TEXT16END - _Code16Addr


