summaryrefslogtreecommitdiff
path: root/MdePkg/Library/BaseLib/ia32/Thunk16.asm
blob: 2d62d72aef5bc3b728a7124653e3da9f335a2d6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
;------------------------------------------------------------------------------
;
; Copyright (c) 2006, 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
;
;------------------------------------------------------------------------------

    .686p
    .model  flat,C

    .data

NullSegSel      DQ      0
_16BitCsSel     LABEL   QWORD
                DW      -1
                DW      0
                DB      0
                DB      9bh
                DB      8fh             ; 16-bit segment
                DB      0
_16BitDsSel     LABEL   QWORD
                DW      -1
                DW      0
                DB      0
                DB      93h
                DB      8fh             ; 16-bit segment
                DB      0
GdtEnd          LABEL   QWORD

    .const

_16Gdtr         LABEL   FWORD
                DW      offset GdtEnd - offset NullSegSel - 1
                DD      offset NullSegSel

_16Idtr         FWORD   (1 SHL 10) - 1

    .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      ?
_EFLAGS     DD      ?
_EIP        DD      ?
_CS         DW      ?
_SS         DW      ?
IA32_REGS   ENDS

InternalAsmThunk16  PROC    USES    ebp ebx esi edi ds  es  fs  gs
    mov     esi, [esp + 36]             ; esi <- RegSet
    push    sizeof (IA32_REGS)
    pop     ecx
    movzx   edx, (IA32_REGS ptr [esi])._SS
    mov     edi, (IA32_REGS ptr [esi])._ESP
    sub     edi, ecx                    ; reserve space on realmode stack
    push    edi                         ; save stack offset
    imul    eax, edx, 16                ; eax <- edx * 16
    add     edi, eax                    ; edi <- linear address of 16-bit stack
    rep     movsb                       ; copy RegSet
    mov     esi, edx                    ; esi <- 16-bit stack segment
    pop     ebx                         ; ebx <- 16-bit stack offset
    mov     edi, [esp + 40]             ; edi <- realmode patch
    push    cs                          ; save CS segment selector
    push    offset @BackToThunk         ; offset to back from real mode
    mov     eax, offset @16Return
    stosd
    xor     eax, eax
    stosw                               ; set CS base to 0
    mov     eax, esp
    stosd
    mov     eax, ss
    stosd
    mov     eax, cr0
    mov     ecx, eax                    ; ecx <- CR0
    and     ecx, 7ffffffeh              ; clear PE, PG bits
    stosd
    mov     eax, cr4
    mov     ebp, eax
    and     ebp, 300h                   ; clear all but PCE and OSFXSR bits
    stosd
    sidt    fword ptr [esp + 44]        ; use parameter space to save IDTR
    sgdt    fword ptr [edi]
    lidt    _16Idtr
    push    10h
    pop     eax
    push    8
    push    offset @16Start
    lgdt    _16Gdtr
    retf
@16Start:                               ; 16-bit starts here
    mov     ss, eax                     ; set SS to be a 16-bit segment
    mov     cr0, ecx
    mov     cr4, ebp
    mov     ss, esi                     ; set up 16-bit stack
    mov     sp, bx                      ; mov esp, ebx actually
    popaw                               ; popad actually
    pop     ds
    pop     es
    pop     fs
    pop     gs
    add     sp, 4                       ; skip _EFLAGS
    DB      66h
    retf                                ; transfer control to 16-bit code
@16Return:
    pushf                               ; pushfd actually
    push    gs
    push    fs
    push    es
    push    ds
    pushaw                              ; pushad actually
    DB      67h, 66h
    lds     esi, fword ptr (IA32_REGS ptr [esp])._EIP
    DB      67h, 66h
    mov     eax, [esi + 12]
    mov     cr4, eax                    ; restore CR4
    DB      67h, 66h
    lgdt    fword ptr [esi + 16]
    DB      67h, 66h
    mov     eax, [esi + 8]
    mov     cr0, eax                    ; restore CR0
    xor     ax, ax                      ; xor eax, eax actually
    mov     eax, ss
    DB      67h
    mov     dword ptr (IA32_REGS ptr [esp])._SS, eax
    shl     ax, 4                       ; shl eax, 4 actually
    add     ax, sp                      ; add eax, esp actually
    add     sp, sizeof (IA32_REGS)      ; add esp, sizeof (IA32_REGS)
    DB      67h, 66h
    mov     dword ptr (IA32_REGS ptr [esp - sizeof (IA32_REGS)])._ESP, esp
    DB      67h, 66h
    lss     esp, fword ptr [esi]        ; restore protected mode stack
    DB      66h
    retf                                ; go back to protected mode
@BackToThunk:
    lidt    fword ptr [esp + 36]        ; restore protected mode IDTR
    ret
InternalAsmThunk16  ENDP

    END