diff options
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm')
-rw-r--r-- | src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm new file mode 100644 index 00000000..fd208ca6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm @@ -0,0 +1,396 @@ +; $Id: bs3-bootsector.asm $ +;; @file +; Generic bootsector for BS3. +; +; This sets up stack at %fff0 and loads the next sectors from the floppy at +; %10000 (1000:0000 in real mode), then starts executing at cs:ip=1000:0000. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE 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. +; + + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" + + +%ifdef __YASM__ +[map all] +%endif + +; +; Start with a jump just to follow the convention. +; Also declare all segments/sections to establish them and their order. +; + ORG 07c00h + +BITS 16 +CPU 8086 +start: + jmp short bs3InitCode + db 0ah ; Should be nop, but this looks better. +g_OemId: ; 003h + db 'BS3Kit', 0ah, 0ah + +; +; DOS 4.0 Extended Bios Parameter Block: +; +g_cBytesPerSector: ; 00bh + dw 512 +g_cSectorsPerCluster: ; 00dh + db 1 +g_cReservedSectors: ; 00eh + dw 1 +g_cFATs: ; 010h + db 0 +g_cRootDirEntries: ; 011h + dw 0 +g_cTotalSectors: ; 013h + dw 0 +g_bMediaDescriptor: ; 015h + db 0 +g_cSectorsPerFAT: ; 016h + dw 0 +g_cPhysSectorsPerTrack: ; 018h + dw 18 +g_cHeads: ; 01ah + dw 2 +g_cHiddentSectors: ; 01ch + dd 1 +g_cLargeTotalSectors: ; 020h - We (ab)use this to indicate the number of sectors to load. + dd 0 +g_bBootDrv: ; 024h + db 80h +g_bFlagsEtc: ; 025h + db 0 +g_bExtendedSignature: ; 026h + db 0x29 +g_dwSerialNumber: ; 027h + dd 0x0a458634 +g_abLabel: ; 02bh + db 'VirtualBox', 0ah +g_abFSType: ; 036h + db 'RawCode', 0ah +g_BpbEnd: ; 03ch + + +; +; Where to real init code starts. +; +bs3InitCode: + cli + + ; save the registers. + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.rax], ax + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.rsp], sp + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.ss], ss + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.ds], ds + + ; set up the segment reisters and stack. + mov ax, 0 + mov ds, ax + mov ss, ax + mov sp, BS3_ADDR_STACK + + ; Save more registers, without needing cs prefix. + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rcx], cx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdi], di + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.es], es + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbp], bp + + ; Load es and setup bp frame. + mov es, ax + mov bp, sp + mov [bp], ax ; clear the first 8 bytes (terminates the ebp chain) + mov [bp + 02h], ax + mov [bp + 04h], ax + mov [bp + 06h], ax + + ; Save flags now that we know that there's a valid stack. + pushf + + ; + ; Clear the register area. + ; + mov di, BS3_ADDR_REG_SAVE + mov cx, BS3REGCTX_size/2 + cld + rep stosw + + ; + ; Do basic CPU detection. + ; + + ; 1. bit 15-bit was fixed to 1 in pre-286 CPUs, and fixed to 0 in 286+. + mov ax, [bp - 2] + test ah, 080h ; always set on pre 286, clear on 286 and later + jnz .pre_80286 + + ; 2. On a 286 you cannot popf IOPL and NT from real mode. +.detect_286_or_386plus: +CPU 286 + mov ah, (X86_EFL_IOPL | X86_EFL_NT) >> 8 + push ax + popf + pushf + cmp ah, [bp - 3] + pop ax + je .is_386plus +.is_80286: +CPU 286 + smsw [BS3_ADDR_REG_SAVE + BS3REGCTX.cr0] +.pre_80286: +CPU 8086 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbx], bx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdx], dx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rsi], si + jmp .do_load + + ; Save 386 registers. We can now skip the CS prefix as DS is flat. +CPU 386 +.is_386plus: + shr eax, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rax+2], ax + mov eax, esp + shr eax, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rsp+2], ax + mov eax, ebp + shr eax, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbp+2], ax + shr edi, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdi+2], di + shr ecx, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rcx+2], cx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.fs], fs + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.gs], gs + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbx], ebx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdx], edx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rsi], esi + mov eax, cr2 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr2], eax + mov eax, cr3 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr3], eax + mov byte [BS3_ADDR_REG_SAVE + BS3REGCTX.bMode], BS3_MODE_RM + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.cs], cs + xor eax, eax + mov ax, start + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.rip], eax + + ; Pentium/486+: CR4 requires VME/CPUID, so we need to detect that before accessing it. + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.cr4], eax + popf ; (restores IOPL+NT) + pushfd + pop eax + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rflags], eax + xor eax, X86_EFL_ID + push eax + popfd + pushfd + pop ebx + cmp ebx, eax + jne .no_cr4 + mov eax, cr4 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr4], eax +.no_cr4: + ; Make sure caching is enabled and alignment is off. + mov eax, cr0 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr0], eax + and eax, ~(X86_CR0_NW | X86_CR0_CD | X86_CR0_AM) + mov cr0, eax + + ; Load all the code. +.do_load + mov [g_bBootDrv], dl + call NAME(bs3InitLoadImage) +%if 0 + mov al, '=' + call NAME(bs3PrintChrInAl) +%endif + + ; + ; Call the user 'main' procedure (shouldn't return). + ; + cld + call BS3_SEL_TEXT16:0000h + + ; Panic/hang. +Bs3Panic: + cli + jmp Bs3Panic + + +;; For debug and error handling. +; @uses ax +bs3PrintHexInAl: +CPU 286 + push ax + shr al, 4 + call bs3PrintHexDigitInAl + pop ax +bs3PrintHexDigitInAl: + and al, 0fh + cmp al, 10 + jb .decimal + add al, 'a' - '0' - 10 +.decimal: + add al, '0' +bs3PrintChrInAl: + push bx + mov ah, 0eh + mov bx, 0ff00h + int 10h + pop bx + ret + + +;; +; Loads the image off the floppy. +; +; This uses g_cLargeTotalSectors to figure out how much to load. +; +; Clobbers everything except ebp and esp. Panics on failure. +; +; @param dl The boot drive number (from BIOS). +; @uses ax, cx, bx, esi, di +; +BEGINPROC bs3InitLoadImage + push bp + mov bp, sp + push es +%define bSavedDiskNo byte [bp - 04h] + push dx +%define bMaxSector byte [bp - 06h] + xor ax, ax + push ax +%define bMaxHead byte [bp - 08h] + push ax +%define bMaxCylinder byte [bp - 0ah] + push ax + + ; + ; Try figure the geometry. + ; + mov ah, 08h + int 13h + jc .failure + mov bMaxSector, cl + mov bMaxHead, dh + mov bMaxCylinder, ch + mov dl, bSavedDiskNo + + ; + ; Reload all the sectors one at a time (avoids problems). + ; + mov si, [g_cLargeTotalSectors] ; 16-bit sector count ==> max 512 * 65 535 = 33 553 920 bytes. + dec si + mov di, BS3_ADDR_LOAD / 16 ; The current load segment. + mov cx, 0002h ; ch/cylinder=0 (0-based); cl/sector=2 (1-based) + xor dh, dh ; dh/head=0 +.the_load_loop: +%if 0 + mov al, 'c' + call bs3PrintChrInAl + mov al, ch + call bs3PrintHexInAl + mov al, 's' + call bs3PrintChrInAl + mov al, cl + call bs3PrintHexInAl + mov al, 'h' + call bs3PrintChrInAl + mov al, dh + call bs3PrintHexInAl + mov al, ';' + call bs3PrintChrInAl +%endif + xor bx, bx + mov es, di ; es:bx -> buffer + mov ax, 0201h ; al=1 sector; ah=read function + int 13h + jc .failure + + ; advance to the next sector/head/cylinder. + inc cl + cmp cl, bMaxSector + jbe .adv_addr + + mov cl, 1 + inc dh + cmp dh, bMaxHead + jbe .adv_addr + + mov dh, 0 + inc ch + +.adv_addr: + add di, 512 / 16 + dec si + jnz .the_load_loop +%if 0 + mov al, 'D' + call bs3PrintChrInAl +%endif + + add sp, 3*2 + pop dx + pop es + pop bp + ret + + ; + ; Something went wrong, display a message. + ; +.failure: + push ax + + ; print message + mov si, .s_szErrMsg +.failure_next_char: + lodsb + call bs3PrintChrInAl + cmp si, .s_szErrMsgEnd + jb .failure_next_char + + ; panic + pop ax +%if 1 + mov al, ah + push bs3PrintHexInAl +%endif + call Bs3Panic +.s_szErrMsg: + db 13, 10, 'rd err! ' +.s_szErrMsgEnd: +;ENDPROC bs3InitLoadImage - don't want the padding. + + +; +; Pad the remainder of the sector with int3's and end it with the DOS signature. +; +bs3Padding: + times ( 510 - ( (bs3Padding - start) % 512 ) ) db 0cch + db 055h, 0aah + |