summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac')
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac385
1 files changed, 385 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac
new file mode 100644
index 00000000..2b67f908
--- /dev/null
+++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac
@@ -0,0 +1,385 @@
+; $Id: bootsector2-cpu-a20-1-template.mac $
+;; @file
+; bootsector2 A20 - multi mode template.
+;
+
+;
+; 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 "bootsector2-template-header.mac"
+
+
+;;
+; Inner loop dealing with one 64KB segment.
+;
+BEGINPROC TMPL_NM(TestA20_EnabledInner)
+.inner_loop:
+ mov ah, [es:xDI]
+ mov al, [ds:xSI]
+ cmp al, ah
+ jne .inner_next
+
+ not al
+ mov [es:xDI], al
+ cmp al, [ds:xSI]
+ mov [es:xDI], ah
+ je .failed
+
+.inner_next:
+ inc xDI
+ inc xSI
+ dec ecx
+ jnz .inner_loop
+
+ clc
+ ret
+
+.failed:
+ push sBX
+ push sAX
+ push sSI
+ push sDI
+%ifdef TMPL_16BIT
+ push cs
+%endif
+ push .s_szModifiyError
+ call TMPL_NM_CMN(TestFailedF)
+ add xSP, sCB * 5
+ stc
+ ret
+.s_szModifiyError:
+ db TMPL_MODE_STR, '- Same memory; EDI=%RX32 ESI=%RX32 EAX=%RX32 EBX=%RX32', 13, 10, 0
+ENDPROC TMPL_NM(TestA20_EnabledInner)
+
+
+;;
+; Inner loop dealing with one 64KB segment.
+;
+BEGINPROC TMPL_NM(TestA20_DisabledInner)
+.inner_loop:
+ mov ah, [es:xDI]
+ mov al, [ds:xSI]
+ cmp al, ah
+ jne .failed1
+
+ not al
+ mov [es:xDI], al
+ cmp al, [ds:xSI]
+ mov [es:xDI], ah
+ jne .failed2
+
+ inc xDI
+ inc xSI
+ dec ecx
+ jnz .inner_loop
+
+ clc
+ ret
+
+.failed1:
+ push sCX
+ push sBX
+ push sAX
+ push sSI
+ push sDI
+%ifdef TMPL_16BIT
+ push cs
+%endif
+ push .s_szNotEqual
+ call TMPL_NM_CMN(TestFailedF)
+ add xSP, sCB * 6
+ stc
+ ret
+.s_szNotEqual:
+ db TMPL_MODE_STR, ' - Not equal; EDI=%RX32 ESI=%RX32 EAX=%RX32 EBX=%RX32 ECX=%RX32', 13, 10, 0
+
+.failed2:
+ push sCX
+ push sBX
+ push sAX
+ push sSI
+ push sDI
+%ifdef TMPL_16BIT
+ push cs
+%endif
+ push .s_szModifiyError
+ call TMPL_NM_CMN(TestFailedF)
+ add xSP, sCB * 6
+ stc
+ ret
+
+.s_szModifiyError:
+ db TMPL_MODE_STR, ' - Modify error; EDI=%RX32 ESI=%RX32 EAX=%RX32 EBX=%RX32 ECX=%RX32', 13, 10, 0
+ENDPROC TMPL_NM(TestA20_DisabledInner)
+
+
+;;
+; Scans memory calling sDX for each segment.
+;
+BEGINPROC TMPL_NM(TestA20_ScanMemory)
+ push sAX
+ push sBX
+ push sCX
+ push sDX
+ push sSI
+ push sDI
+ pushf
+ cli
+%ifdef TMPL_16BIT
+ push es
+ push ds
+%endif
+
+ ;
+ ; The outer loop walks a segment (64 KB) at a time.
+ ;
+ mov ebx, _1M
+.outer_loop:
+
+ ; Set up the registers.
+%ifdef TMPL_CMN_R86
+ mov ax, 0ffffh
+ mov edi, 00010h
+ mov es, ax
+ mov ax, 00000h
+ mov esi, 00000h
+ mov ds, ax
+ mov ecx, 01000h ; at 101000 there was a VMMDevTesting MMIO page.
+%elifdef TMPL_16BIT
+ ;; @todo need a selector we can modify.
+ jmp .done
+
+%else
+ mov edi, ebx
+ mov esi, ebx
+ and esi, ~_1M
+ mov ecx, _64K
+%endif
+%ifndef TMPL_CMN_R86
+ ; Should we skip this segment or only check parts of it?
+ cmp esi, edi ; affected by A20?
+ je .outer_next
+
+%if BS2_PXX_LAST != 09ffffh
+ %error BS2_PXX_LAST does not have the expected value.
+%endif
+ cmp ebx, BS2_PXX_BASE + _1M ; don't mess with page tables, stacks, MMIO or ROMs.
+ jb .not_low_rom_mmio_region
+ cmp ebx, _1M + _1M
+ jb .outer_next
+.not_low_rom_mmio_region:
+
+ cmp ebx, BS2_ADDR + _1M
+ ja .not_bs2
+ mov ecx, BS2_ADDR ; don't overwrite our own code.
+.not_bs2:
+ cmp ebx, _1M
+ jne .not_VMMDevTestingMMIO
+ mov ecx, 1000h ; don't bother with the MMIO
+.not_VMMDevTestingMMIO:
+%endif ; TMPL_CMN_R86
+
+ ; Invoke the callback.
+ call xDX
+ jc .failure
+
+%ifndef TMPL_CMN_R86
+.outer_next:
+ add ebx, _64K
+ cmp ebx, 32*_1M
+ jbe .outer_loop
+%endif
+
+.done:
+%ifdef TMPL_16BIT
+ pop ds
+ pop es
+%endif
+ popf
+ pop sDI
+ pop sSI
+ pop sDX
+ pop sCX
+ pop sBX
+ pop sAX
+ ret
+
+.failure:
+%if 1
+ cmp ebx, _1M
+ je .contine_at_next_MB
+ cmp ebx, _2M
+ je .contine_at_next_MB
+ cmp ebx, _1M + _2M
+ je .contine_at_next_MB
+ cmp ebx, _4M
+ je .contine_at_next_MB
+%endif
+ jmp .done
+
+.contine_at_next_MB:
+ add ebx, _1M
+ jmp .outer_loop
+ENDPROC TMPL_NM(TestA20_ScanMemory)
+
+
+BEGINPROC TMPL_NM(TestA20_Enabled)
+ push sDX
+ mov xDX, TMPL_NM(TestA20_EnabledInner)
+ call TMPL_NM(TestA20_ScanMemory)
+ pop sDX
+ ret
+ENDPROC TMPL_NM(TestA20_Enabled)
+
+
+;;
+; Checks that the first 64KB at 1MB wraps is the same physical memory as at
+; address 0.
+;
+BEGINPROC TMPL_NM(TestA20_Disabled)
+ push sDX
+ mov xDX, TMPL_NM(TestA20_DisabledInner)
+ call TMPL_NM(TestA20_ScanMemory)
+ pop sDX
+ ret
+ENDPROC TMPL_NM(TestA20_Disabled)
+
+
+BEGINPROC TMPL_NM(TestA20_FlushAll)
+ push sAX
+ wbinvd
+ mov sAX, cr3
+ mov cr3, sAX
+ wbinvd
+ pop sAX
+ ret
+ENDPROC TMPL_NM(TestA20_FlushAll)
+
+
+
+;;
+; Do the A20 tests for this mode.
+;
+; @uses nothing
+;
+BEGINCODELOW
+BITS 16
+BEGINPROC TMPL_NM(TestA20_rm)
+ push eax
+
+ mov ax, .s_szTestName
+ call TestSub_r86
+
+ call TMPL_NM(Bs2IsModeSupported_rm)
+ jz .skip_not_supported
+
+ ;
+ ; Do tests with A20 enabled.
+ ;
+ call Bs2EnableA20_r86
+ call TMPL_NM(Bs2EnterMode_rm)
+BITS TMPL_BITS
+ call TMPL_NM(TestA20_FlushAll)
+ call TMPL_NM(TestA20_Enabled)
+ call TMPL_NM(Bs2ExitMode)
+BITS 16
+ call TestSubErrorCount_r86
+ cmp ax, 0
+ jne .done
+
+ ;
+ ; Do tests with A20 disabled.
+ ;
+ call Bs2DisableA20_r86
+ call TMPL_NM(Bs2EnterMode_rm)
+BITS TMPL_BITS
+ call TMPL_NM(TestA20_FlushAll)
+ call TMPL_NM(TestA20_Disabled)
+ call TMPL_NM(Bs2ExitMode)
+BITS 16
+ call TestSubErrorCount_r86
+ cmp ax, 0
+ jne .done
+
+%ifndef TMPL_CMN_V86
+ ;
+ ; Change A20 state without leaving and entering the CPU mode.
+ ;
+ call Bs2EnableA20_r86
+ call TMPL_NM(Bs2EnterMode_rm)
+BITS TMPL_BITS
+ call TMPL_NM(TestA20_Enabled)
+
+ call TMPL_NM_CMN(Bs2DisableA20)
+ call TMPL_NM(TestA20_FlushAll)
+ call TMPL_NM(TestA20_Disabled)
+
+ call TMPL_NM_CMN(Bs2EnableA20)
+ call TMPL_NM(TestA20_FlushAll)
+ call TMPL_NM(TestA20_Enabled)
+
+ call TMPL_NM_CMN(Bs2DisableA20)
+ call TMPL_NM(TestA20_FlushAll)
+ call TMPL_NM(TestA20_Disabled)
+
+ call TMPL_NM_CMN(Bs2EnableA20)
+ call TMPL_NM(TestA20_FlushAll)
+ call TMPL_NM(TestA20_Enabled)
+
+ call TMPL_NM(Bs2ExitMode)
+BITS 16
+%endif ; !TMPL_CMN_V86
+
+.done:
+ call Bs2DisableA20_r86
+.done1:
+ call TestSubDone_r86
+
+ pop eax
+ ret
+
+.skip_not_supported:
+ mov eax, .s_szSkipNotSupported
+ call TestSkipped_r86
+ jmp .done1
+
+.s_szTestName:
+ db TMPL_MODE_STR, 0
+.s_szSkipNotSupported:
+ db TMPL_MODE_STR, ' is not supported by the CPU', 10, 13, 0
+ENDPROC TMPL_NM(TestA20_rm)
+TMPL_BEGINCODE
+BITS TMPL_BITS
+
+
+%include "bootsector2-template-footer.mac"
+