VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToRM.asm@ 86728

Last change on this file since 86728 was 83013, checked in by vboxsync, 5 years ago

bs3kit: Fixed silly non-max CS16 limit crap causing trouble when returning to real-mode.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 KB
Line 
1; $Id: bs3-mode-SwitchToRM.asm 83013 2020-02-07 02:13:38Z vboxsync $
2;; @file
3; BS3Kit - Bs3SwitchToRM
4;
5
6;
7; Copyright (C) 2007-2020 Oracle Corporation
8;
9; This file is part of VirtualBox Open Source Edition (OSE), as
10; available from http://www.virtualbox.org. This file is free software;
11; you can redistribute it and/or modify it under the terms of the GNU
12; General Public License (GPL) as published by the Free Software
13; Foundation, in version 2 as it comes in the "COPYING" file of the
14; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16;
17; The contents of this file may alternatively be used under the terms
18; of the Common Development and Distribution License Version 1.0
19; (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20; VirtualBox OSE distribution, in which case the provisions of the
21; CDDL are applicable instead of those of the GPL.
22;
23; You may elect to license modified versions of this file under the
24; terms and conditions of either the GPL or the CDDL or both.
25;
26
27%include "bs3kit-template-header.mac"
28
29BS3_EXTERN_SYSTEM16 Bs3Gdt
30%if TMPL_MODE == BS3_MODE_PE16
31BS3_EXTERN_DATA16 g_uBs3CpuDetected
32BS3_EXTERN_CMN Bs3KbdWrite
33BS3_EXTERN_CMN Bs3KbdWait
34%endif
35
36
37;*********************************************************************************************************************************
38;* Global Variables *
39;*********************************************************************************************************************************
40%if TMPL_MODE == BS3_MODE_PE16
41BS3_BEGIN_DATA16
42;; Where to start restoring stack.
43g_ResumeSp: dw 0xfeed
44;; Where to start restoring stack.
45g_ResumeSs: dw 0xface
46%endif
47
48TMPL_BEGIN_TEXT
49
50
51;;
52; Switch to real mode from any other mode.
53;
54; @cproto BS3_DECL(void) Bs3SwitchToRM(void);
55;
56; @uses GPRs and EFLAGS are unchanged (except high 32-bit register (AMD64) parts).
57; CS is loaded with CGROUP16.
58; SS:[RE]SP is converted to real mode address.
59; DS and ES are loaded with BS3DATA16_GROUP.
60; FS and GS are loaded with zero if present.
61;
62; @remarks Obviously returns to 16-bit mode, even if the caller was
63; in 32-bit or 64-bit mode.
64;
65; @remarks Does not require 20h of parameter scratch space in 64-bit mode.
66;
67%if TMPL_BITS == 16
68BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToRM_Safe), function , 0
69%endif
70BS3_PROC_BEGIN_MODE Bs3SwitchToRM, BS3_PBC_NEAR
71%ifdef TMPL_RM
72 push ax
73 mov ax, BS3_SEL_DATA16
74 mov ds, ax
75 mov es, ax
76 pop ax
77 ret
78
79%elif BS3_MODE_IS_V86(TMPL_MODE)
80 ;
81 ; V8086 - Switch to 16-bit ring-0 and call worker for that mode.
82 ;
83 extern BS3_CMN_NM(Bs3SwitchToRing0)
84 call BS3_CMN_NM(Bs3SwitchToRing0)
85 extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToRM)
86 jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToRM)
87
88%else
89 ;
90 ; Protected mode.
91 ; 80286 requirements for PE16 clutters the code a little.
92 ;
93 %if TMPL_MODE == BS3_MODE_PE16
94 cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286
95 ja .do_386_prologue
96 push ax
97 push bx
98 pushf
99 push word 1
100 jmp .done_prologue
101 %endif
102.do_386_prologue:
103 push sAX
104 push sBX
105 sPUSHF
106 %if TMPL_MODE == BS3_MODE_PE16
107 push word 0
108 %elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE)
109 push sDX
110 push sCX
111 %endif
112.done_prologue:
113
114 ;
115 ; Get to 16-bit ring-0 and disable interrupts.
116 ;
117 extern BS3_CMN_NM(Bs3SwitchToRing0)
118 call BS3_CMN_NM(Bs3SwitchToRing0)
119
120 cli
121
122 %if TMPL_MODE == BS3_MODE_PE16
123 ;
124 ; On 80286 we must reset the CPU to get back to real mode.
125 ;
126 CPU 286
127 pop ax
128 push ax
129 test ax, ax
130 jz .is_386_or_better
131
132 ; Save registers and flags, storing SS:SP in at a known global address.
133%ifdef BS3_STRICT
134 mov ax, 0feedh
135 mov bx, 0faceh
136%endif
137 push di
138 push si
139 push bp
140 push bx
141 push dx
142 push cx
143 push ax
144 pushf
145
146 ; Convert ss:sp to real mode address.
147 BS3_EXTERN_CMN Bs3SelProtFar32ToFlat32
148 mov ax, sp
149 push ss
150 push 0
151 push ax
152 call Bs3SelProtFar32ToFlat32
153 add sp, 6
154
155 mov [g_ResumeSp], ax
156 shl dx, 12
157 mov [g_ResumeSs], dx
158
159 ; Setup resume vector.
160 mov bx, BS3_SEL_R0_SS16
161 mov es, bx
162 mov word [es:467h], .resume
163 mov word [es:467h+2], BS3_SEL_TEXT16
164
165 mov al, 0fh | 80h
166 out 70h, al ; set register index
167 in al, 80h
168 mov al, 0ah ; shutdown action command - no EOI, no 287 reset.
169 out 71h, al ; set cmos[f] = al - invoke testResume as early as possible.
170 in al, 71h ; flush
171
172 %if 0 ; for testing in VM
173 CPU 386
174 mov ax, BS3_SEL_R0_DS16
175 mov ds, ax
176 mov es, ax
177 mov fs, ax
178 mov gs, ax
179
180 mov eax, cr0
181 and ax, ~X86_CR0_PE
182 mov cr0, eax
183 jmp BS3_SEL_TEXT16:.resume
184 %endif
185
186 ; Port A reset. (FYI: tripple fault does not do the trick)
187 in al, 92h
188 or al, 1
189 out 92h, al
190 in al, 80h ; flush
191 mov cx, 0ffffh
192.reset_delay:
193 loop .reset_delay
194
195 ; Keyboard controller reset.
196 call Bs3KbdWait
197 push 0 ; zero data (whatever.
198 push 0fh ; KBD_CCMD_RESET
199 call Bs3KbdWrite
200.forever:
201 jmp .forever
202
203 ; This is the resume point. We should be in real mode now, at least in theory.
204.resume:
205 mov ax, BS3_SEL_DATA16
206 mov ds, ax
207 mov es, ax
208 mov ax, [g_ResumeSp]
209 mov ss, [g_ResumeSs]
210 mov sp, ax
211
212 popf
213 pop ax
214 pop cx
215 pop dx
216 pop bx
217 pop bp
218 pop si
219 pop di
220 %ifdef BS3_STRICT
221 cmp ax, 0feedh
222 jne .bad_286_rm_switch
223 cmp bx, 0faceh
224 jne .bad_286_rm_switch
225 %endif
226 jmp .enter_mode
227
228 %ifdef BS3_STRICT
229.bad_286_rm_switch:
230 mov ax, 0e00h + 'Q'
231 mov bx, 0ff00h
232 int 10h
233 jmp .bad_286_rm_switch
234 %endif
235
236 CPU 386
237 %elif TMPL_BITS != 16
238 ;
239 ; Must be in 16-bit segment when calling Bs3SwitchTo16Bit.
240 ;
241 jmp .sixteen_bit_segment wrt FLAT
242BS3_BEGIN_TEXT16
243 BS3_SET_BITS TMPL_BITS
244BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment
245
246 extern BS3_CMN_NM(Bs3SwitchTo16Bit)
247 call BS3_CMN_NM(Bs3SwitchTo16Bit)
248 BS3_SET_BITS 16
249 %endif
250 ;
251 ; Before exiting to real mode we must load sensible selectors into the
252 ; segment registers so the hidden parts (which doesn't get reloaded in
253 ; real mode) are real mode compatible.
254 ;
255 ; ASSUMES BS3_SEL_R0_SS16 and BS3_SEL_R0_CS16 are both maxed out and
256 ; has no funny bits set!
257 ;
258.is_386_or_better:
259;; @todo Testcase: Experiment leaving weird stuff in the hidden segment registers.
260 mov ax, BS3_SEL_R0_DS16
261 mov ds, ax
262 mov es, ax
263 mov fs, ax
264 mov gs, ax
265
266 ;
267 ; Exit to real mode.
268 ;
269 mov eax, cr0
270 and eax, X86_CR0_NO_PE_NO_PG
271 mov cr0, eax
272 jmp CGROUP16:.reload_cs
273.reload_cs:
274
275 ;
276 ; Convert the stack (now 16-bit prot) to real mode.
277 ;
278 mov ax, BS3_SEL_SYSTEM16
279 mov ds, ax
280 mov bx, ss
281 and bx, X86_SEL_MASK ; ASSUMES GDT stack selector
282 mov al, [bx + 4 + Bs3Gdt]
283 mov ah, [bx + 7 + Bs3Gdt]
284 add sp, [bx + 2 + Bs3Gdt] ; ASSUMES not expand down segment.
285 adc ax, 0
286 %ifdef BS3_STRICT
287 test ax, 0fff0h
288 jz .stack_conv_ok
289 int3
290.stack_conv_ok:
291 %endif
292 shl ax, 12
293 mov ss, ax
294 %if TMPL_BITS != 16
295 and esp, 0ffffh
296 %endif
297
298 %if BS3_MODE_IS_64BIT_SYS(TMPL_MODE)
299 ;
300 ; Clear the long mode enable bit.
301 ;
302 mov ecx, MSR_K6_EFER
303 rdmsr
304 and eax, ~MSR_K6_EFER_LME
305 wrmsr
306 %endif
307
308 ;
309 ; Call routine for doing mode specific setups.
310 ;
311.enter_mode:
312 extern NAME(Bs3EnteredMode_rm)
313 call NAME(Bs3EnteredMode_rm)
314
315 %if TMPL_MODE == BS3_MODE_PE16
316 pop ax
317 test ax, ax
318 jz .do_386_epilogue
319 popf
320 pop bx
321 pop ax
322 ret
323 %endif
324.do_386_epilogue:
325 %if BS3_MODE_IS_64BIT_SYS(TMPL_MODE)
326 pop ecx
327TONLY64 pop eax
328 pop edx
329TONLY64 pop eax
330 %endif
331 popfd
332TONLY64 pop eax
333 pop ebx
334TONLY64 pop eax
335 pop eax
336TONLY64 add sp, 4
337 retn (TMPL_BITS - 16) / 8
338
339 %if TMPL_BITS != 16
340TMPL_BEGIN_TEXT
341 %endif
342%endif
343BS3_PROC_END_MODE Bs3SwitchToRM
344
345
346%if TMPL_BITS == 16
347;;
348; Custom far stub.
349BS3_BEGIN_TEXT16_FARSTUBS
350BS3_PROC_BEGIN_MODE Bs3SwitchToRM, BS3_PBC_FAR
351 inc bp
352 push bp
353 mov bp, sp
354
355 ; Call the real thing.
356 call TMPL_NM(Bs3SwitchToRM)
357
358 %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE)
359 ; Jmp to common code for the tedious conversion.
360 BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn
361 jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn
362 %else
363 pop bp
364 dec bp
365 retf
366 %endif
367BS3_PROC_END_MODE Bs3SwitchToRM
368
369%else
370;;
371; Safe far return to non-BS3TEXT16 code.
372BS3_EXTERN_CMN Bs3SelFlatCodeToRealMode
373BS3_BEGIN_TEXT16
374BS3_SET_BITS TMPL_BITS
375BS3_PROC_BEGIN_MODE Bs3SwitchToRM_Safe, BS3_PBC_NEAR
376 %if TMPL_BITS == 64
377 push xAX
378 push xCX
379 sub xSP, 20h
380
381 mov xCX, [xSP + xCB*2 + 20h]
382 call Bs3SelFlatCodeToRealMode ; well behaved assembly function, only clobbers ecx
383 mov [xSP + xCB*2 + 20h + 4], eax
384
385 add xSP, 20h
386 pop xCX
387 pop xAX
388 add xSP, 4
389 %else
390 xchg eax, [xSP]
391 push xAX
392 call Bs3SelFlatCodeToRealMode ; well behaved assembly function, only clobbers eax
393 add xSP, 4
394 xchg [xSP], eax
395 %endif
396 call TMPL_NM(Bs3SwitchToRM)
397 BS3_SET_BITS 16
398 retf
399BS3_PROC_END_MODE Bs3SwitchToRM_Safe
400%endif
401
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette