Home | History | Annotate | Download | only in Ia32
      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 
     24 ASM_GLOBAL ASM_PFX(m16Start), ASM_PFX(m16Size), ASM_PFX(mThunk16Attr), ASM_PFX(m16Gdt), ASM_PFX(m16GdtrBase), ASM_PFX(mTransition)
     25 ASM_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 
     49 ASM_PFX(m16Start):
     50 
     51 SavedGdt:     .space  6
     52 
     53 ASM_PFX(BackFromUserCode):
     54     push    %ss
     55     push    %cs
     56 
     57     calll   L_Base1                     # push eip
     58 L_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
     67 ASM_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
     74 1:
     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#
     80 2:
     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
     89 SavedCr4:   .space  4
     90     movl    %eax, %cr4
     91     lgdtl   %cs:(SavedGdt - L_Base1)(%bx)
     92     .byte   0x66, 0xb8                  # mov eax, imm32
     93 SavedCr0:   .space  4
     94     movl    %eax, %cr0
     95     .byte   0xb8                        # mov ax, imm16
     96 SavedSs:    .space  2
     97     movl    %eax, %ss
     98     .byte   0x66, 0xbc                  # mov esp, imm32
     99 SavedEsp:   .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 
    109 ASM_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
    119 L_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
    151 GdtEnd:
    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 #
    159 ASM_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 
    218 ASM_PFX(m16Size):        .word      ASM_PFX(InternalAsmThunk16)  - ASM_PFX(m16Start)
    219 ASM_PFX(mThunk16Attr):   .word      ASM_PFX(ThunkAttr)          - ASM_PFX(m16Start)
    220 ASM_PFX(m16Gdt):         .word      _NullSegDesc        - ASM_PFX(m16Start)
    221 ASM_PFX(m16GdtrBase):    .word      _16GdtrBase         - ASM_PFX(m16Start)
    222 ASM_PFX(mTransition):    .word      _EntryPoint         - ASM_PFX(m16Start)
    223