summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16BitV86.asm
blob: 636e6184c30b059009598ad2d0c0cb5490fe9256 (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
; $Id: bs3-cmn-SwitchTo16BitV86.asm $
;; @file
; BS3Kit - Bs3SwitchTo16BitV86
;

;
; Copyright (C) 2007-2023 Oracle and/or its affiliates.
;
; This file is part of VirtualBox base platform packages, as
; available from https://www.virtualbox.org.
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation, in version 3 of the
; License.
;
; This program is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
; General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, see <https://www.gnu.org/licenses>.
;
; The contents of this file may alternatively be used under the terms
; of the Common Development and Distribution License Version 1.0
; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
; in the VirtualBox distribution, in which case the provisions of the
; CDDL are applicable instead of those of the GPL.
;
; You may elect to license modified versions of this file under the
; terms and conditions of either the GPL or the CDDL or both.
;
; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
;

%include "bs3kit-template-header.mac"

%if TMPL_BITS != 64

BS3_EXTERN_DATA16   g_bBs3CurrentMode
BS3_EXTERN_CMN      Bs3SwitchToRing0
BS3_EXTERN_CMN      Bs3SelProtFar32ToFlat32
TMPL_BEGIN_TEXT


;;
; @cproto   BS3_DECL(void) Bs3SwitchTo16BitV86(void);
; @uses No general registers modified. Regment registers loaded with specific
;       values and the stack register converted to real mode (not ebp).
;
BS3_PROC_BEGIN_CMN Bs3SwitchTo16BitV86, BS3_PBC_NEAR
        ; Construct basic v8086 return frame.
BONLY16 movzx   esp, sp
        push    dword 0                                 ; +0x20: GS
        push    dword 0                                 ; +0x1c: FS
        push    dword BS3_SEL_DATA16                    ; +0x18: ES
        push    dword BS3_SEL_DATA16                    ; +0x14: DS
        push    dword 0                                 ; +0x10: SS - later
        push    dword 0                                 ; +0x0c: return ESP, later.
        pushfd
        or      dword [esp], X86_EFL_VM | X86_EFL_IOPL  ; +0x08: Set IOPL=3 and the VM flag (EFLAGS).
        push    dword BS3_SEL_TEXT16                    ; +0x04
        push    word 0
        push    word [esp + 24h - 2]                    ; +0x00
        ; Save registers and stuff.
        push    eax
        push    edx
        push    ecx
        push    ebx
 %if TMPL_BITS == 16
        push    ds

        ; Check g_bBs3CurrentMode whether we're in v8086 mode or not.
        mov     ax, seg g_bBs3CurrentMode
        mov     ds, ax
        mov     al, [BS3_DATA16_WRT(g_bBs3CurrentMode)]
        test    al, BS3_MODE_CODE_V86
        jz      .not_v8086

        pop     ds
        pop     ebx
        pop     ecx
        pop     edx
        pop     eax
        add     xSP, 0x24
        ret

.not_v8086:
        pop     ax                      ; Drop the push ds so the stacks are identical. Keep DS = BS3KIT_GRPNM_DATA16 though.
 %endif

        ; Ensure that we're in ring-0.
        mov     ax, ss
        test    ax, 3
        jz      .is_ring0
        call    Bs3SwitchToRing0
 %if TMPL_BITS == 16
        mov     ax, seg g_bBs3CurrentMode
        mov     ds, ax                  ; parnoia
 %endif
.is_ring0:

        ; Update globals.
        and     byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], ~BS3_MODE_CODE_MASK
        or      byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86

        ; Thunk return SS:ESP to real-mode address via 32-bit flat.
        lea     eax, [esp + 4*4 + 24h + xCB]
        push    ss
        push    eax
        BS3_CALL Bs3SelProtFar32ToFlat32, 2
        add     esp, sCB + xCB
        mov     [esp + 4*4 + 0ch], ax   ; high word is already zero
 %if TMPL_BITS == 16
        mov     [esp + 4*4 + 10h], dx
 %else
        shr     eax, 16
        mov     [esp + 4*4 + 10h], ax
 %endif

        ; Return to v8086 mode.
        pop     ebx
        pop     ecx
        pop     edx
        pop     eax
        iretd
BS3_PROC_END_CMN   Bs3SwitchTo16BitV86

;; @todo far 16-bit variant.

%endif ; ! 64-bit