; $Id: bootsector2-cpu-a20-1-template.mac 106061 2024-09-16 14:03:52Z vboxsync $ ;; @file ; bootsector2 A20 - multi mode template. ; ; ; Copyright (C) 2007-2024 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 . ; ; 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"