; $Id$
;; @file
; bootsector #2 kernel for big instruction testcases.
; VBoxManage setextradata bs-vbinstst-64-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1
;
;
; Copyright (C) 2007-2014 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.
;
;
; This is always the first include file.
;
%include "bootsector2-first.mac"
;
; Include and execute the init code.
;
%define BS2_INIT_RM
%define BS2_WITH_TRAPS
%define BS2_WITHOUT_RAW_MODE ; causes troubles with PIC/floppy.
%define BS2_INC_RM
%define BS2_INC_PE16
%define BS2_INC_PE32
%define BS2_INC_PP16
%define BS2_INC_PP32
%define BS2_INC_PAE16
%define BS2_INC_PAE32
%define BS2_INC_LM16
%define BS2_INC_LM32
%define BS2_INC_LM64
%include "bootsector2-common-init-code.mac"
%include "bootsector2-api.mac"
%include "iprt/formats/pe.mac"
%include "iprt/formats/mz.mac"
BEGINCODE
BEGINPROC main
;
; Set up the runtime environment.
;
call Bs2EnableA20_r86
; 16-bit real mode.
%undef BS2_API_TEMPLATE_ACTION
%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _r86)], dword NAME(a_Name %+ _r86)
BS2_API_TEMPLATE
; 16-bit protected mode.
%undef BS2_API_TEMPLATE_ACTION
%define BS2_API_TEMPLATE_ACTION(a_Name) mov word [NAME(g_pfn %+ a_Name %+ _p16)], word NAME(a_Name %+ _p16)
BS2_API_TEMPLATE
mov eax, BS2_SEL_CS16
%undef BS2_API_TEMPLATE_ACTION
%define BS2_API_TEMPLATE_ACTION(a_Name) mov [NAME(g_pfn %+ a_Name %+ _p16) + 2], ax
BS2_API_TEMPLATE
; 32-bit
%undef BS2_API_TEMPLATE_ACTION
%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _p32)], dword NAME(a_Name %+ _p32)
BS2_API_TEMPLATE
; 64-bit
%undef BS2_API_TEMPLATE_ACTION
%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _p64)], dword NAME(a_Name %+ _p64)
BS2_API_TEMPLATE
xor eax, eax
%undef BS2_API_TEMPLATE_ACTION
%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _p64) + 4], eax
BS2_API_TEMPLATE
; The magic markers and version number.
mov dword [g_u32Bs2ApiMagic], BS2_API_MAGIC
mov dword [g_u32Bs2ApiEndMagic], BS2_API_MAGIC
mov dword [g_u32Bs2ApiVersion], BS2_API_VERSION
;
; Load the extended image into high memory.
;
mov dl, [g_bBootDrv]
call NAME(bs2LoadBigImage)
;
; Hand control over to the extended image.
;
%ifdef BS2_BIG_IMAGE_LM64
call Bs2EnterMode_rm_lm64
BITS 64
mov eax, BS2_BIG_LOAD_ADDR
call rax
call Bs2ExitMode_lm64
BITS 16
%elifdef BS2_BIG_IMAGE_PP32
call Bs2EnterMode_rm_pp32
BITS 32
mov eax, BS2_BIG_LOAD_ADDR
call eax
call Bs2ExitMode_pp32
BITS 16
%elifdef BS2_BIG_IMAGE_PAE32
call Bs2EnterMode_rm_pae32
BITS 32
mov eax, BS2_BIG_LOAD_ADDR
call eax
call Bs2ExitMode_pae32
BITS 16
%else
;
; Probe the image, looking for an executable format we can deal with.
; Not doing a lot of checking here, but who cares right now...
;
call Bs2EnterMode_rm_pp32
BITS 32
mov eax, BS2_BIG_LOAD_ADDR
cmp word [eax], IMAGE_DOS_SIGNATURE
jne .not_dos
add eax, [eax + IMAGE_DOS_HEADER.e_lfanew]
.not_dos:
cmp dword [eax], IMAGE_NT_SIGNATURE
je .is_pe
mov eax, BS2_BIG_LOAD_ADDR
jmp .start_32
.is_pe:
lea edx, [eax + IMAGE_NT_HEADERS32.FileHeader]
cmp word [edx + IMAGE_FILE_HEADER.Machine], IMAGE_FILE_MACHINE_I386
je .is_pe32
cmp word [edx + IMAGE_FILE_HEADER.Machine], IMAGE_FILE_MACHINE_AMD64
je .is_pe64
jmp .panic_32
.is_pe32:
add edx, IMAGE_FILE_HEADER_size
mov eax, [edx + IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint]
add eax, BS2_BIG_LOAD_ADDR
jmp .start_32
.is_pe64:
add edx, IMAGE_FILE_HEADER_size
mov eax, [edx + IMAGE_OPTIONAL_HEADER64.AddressOfEntryPoint]
add eax, BS2_BIG_LOAD_ADDR
jmp .start_64
; Start executing at eax in 32-bit mode (current).
.start_32:
call eax
.panic_32:
call Bs2ExitMode_pp32
BITS 16
jmp .panic
; Start executing at eax in 64-bit mode.
BITS 32
.start_64:
call Bs2ExitMode_pp32
BITS 16
call Bs2EnterMode_rm_lm64
BITS 64
mov eax, eax
call rax
call Bs2ExitMode_lm64
BITS 16
jmp .panic
.panic:
%endif
call Bs2Panic
ENDPROC main
;;
; Loads the big image off the floppy.
;
; This uses the the_end label to figure out the starting offset.
; The length is assumed to be the whole floppy.
;
; Clobbers nothing, except for 68KB of memory beyond the_end.
;
; @param dl The boot drive number (from BIOS).
;
BITS 16
BEGINPROC bs2LoadBigImage
push ebp
movzx ebp, sp
%define bSavedDiskNo byte [bp - 02h]
push dx
%define bMaxSector byte [bp - 04h]
push 0
%define bMaxHead byte [bp - 06h]
push 0
%define bMaxCylinder byte [bp - 08h]
push 0
%define pbHighDst dword [bp - 0ch]
push dword BS2_BIG_LOAD_ADDR
%define SegTemp word [bp - 0eh]
push 0
%define fStatus byte [bp - 10h]
push 0
push es
push ds
push eax
push edx
push ecx
push ebx
push edi
push esi
push ebp
; Display message.
push cs
push .s_szLoadingBigImage
call PrintF_r86
add sp, 4
;
; Try figure the geometry. This defines how much we'll read.
;
mov ah, 08h
xor di, di ; (es:di = 0000:0000 works around some buggy bioses, says wikipedia.)
mov es, di
int 13h
jc .param_error
mov bMaxSector, cl ; Do the cl[7:6]+ch stuff so we can address 255 sectors on the fake 63MB floppy.
mov bMaxHead, dh
mov bMaxCylinder, ch ; See above.
mov dl, bSavedDiskNo
%if 0
movzx ax, bMaxCylinder
push ax
movzx cx, bMaxHead
push cx
movzx ax, bMaxSector
push ax
push ds
push .s_szDbgParam
call PrintF_r86
jmp .dprintf_param_done
.s_szDbgParam:
db 13, 10, 'Floppy params max: sectors=%RX16 heads=%RX16 cylinders=%RX16', 13, 10, 0
.dprintf_param_done:
%endif
;
; Skip the kernel image (this could be done more efficiently, but this
; also does the trick).
;
lea eax, [dword the_end]
sub eax, start
shr eax, 9 ; sectors to skip
mov cx, 0001h ; sector (1-based), cylinder (0-based).
xor dh, dh ; head (0-based).
.skip_one_more:
inc cl
cmp cl, bMaxSector
jbe .decrement_sector_count
mov cl, 1
inc dh
cmp dh, bMaxHead ; ASSUMES bMaxHead < 255.
jbe .decrement_sector_count
mov dh, 0
inc ch
.decrement_sector_count:
dec ax
jnz .skip_one_more
;
; Load loop. We load and copy 64 KB at the time into the high location.
; Fixed registers (above): dl=drive, cl[7:6]:ch=cylinder, dh=head, cl[5:0]=sector.
;
lea eax, [dword the_end + 0ffffh]
and eax, 0ffff0000h
shr eax, 4
mov SegTemp, ax ; the 64KB segment we use for temporary storage.
.the_load_loop:
mov al, '.'
call PrintChr_r86
; Fill the segment with int3s (in case we don't read a full 64KB).
mov eax, 0cccccccch
mov di, SegTemp
mov es, di
xor edi, edi
push ecx
cld
mov cx, 4000h
rep stosd
pop ecx
;
; Load a bunch of sectors into the temp segment.
;
xor ebx, ebx
.the_sector_load_loop:
; Figure how many sectors we can read without switching track or side.
movzx ax, bMaxSector
sub al, cl
inc al ; al = sectors left to read in the current track on the current side.
mov di, bx
shr di, 9 ; bx/512 = current sector offset.
neg di
add di, 10000h / 512 ; di = sectors left to read in the 64KB buffer.
cmp ax, di ; ax = min(ax, di)
jbe .use_ax_sector_count1
mov ax, di
.use_ax_sector_count1:
cmp ax, 64 ; ax = min(ax,64) - Our BIOS limitation is 72, play safe.
jbe .use_ax_sector_count2
mov ax, 64
.use_ax_sector_count2:
mov di, ax ; save the number of sectors we read
; Do the reading.
%if 0
push bx
push ax
push dx
push cx
push cs
push .s_szDbgRead
call PrintF_r86
jmp .after_read_dprintf
.s_szDbgRead: db 'Reading CX=%RX16 DX=%RX16 AX=%RX16 BX=%RX16', 13, 10, 0
.after_read_dprintf:
%endif
push bx
mov ah, 02h ; ah=read function
int 13h
pop bx
jc .read_error
; advance to the next sector/head/cylinder and address (lazy impl).
.advance_another_sector:
cmp cl, bMaxSector
je .next_head
inc cl
jmp .adv_addr
.next_head:
mov cl, 1
cmp dh, bMaxHead
je .next_cylinder
inc dh
jmp .adv_addr
.next_cylinder:
mov dh, 0
cmp ch, bMaxCylinder ; No the cl[7:6]+ch stuff so we can address 255 sectors on the fake 63MB floppy.
jb .update_ch
mov fStatus, 1
jmp .move_block
.update_ch:
inc ch
.adv_addr:
add bx, 512
dec di
jnz .advance_another_sector
test bx, bx
jnz .the_sector_load_loop
.move_block:
;
; Copy the memory into high mem.
;
%if 0
mov edi, pbHighDst
push edi
push cs
push .s_szDbgMove
call PrintF_r86
jmp .after_move_dprintf
.s_szDbgMove: db 'Moving memory to EDI=%RX32', 13, 10, 0
.after_move_dprintf:
%endif
push ecx
push edx
push ds
push es
call Bs2EnterMode_rm_pp32
BITS 32
; Copy
mov edi, pbHighDst
movzx esi, SegTemp
shl esi, 4
mov ecx, 10000h / 4
cld
rep movsd
; Verify
mov edi, pbHighDst
movzx esi, SegTemp
shl esi, 4
mov ecx, 10000h / 4
cld
repe cmpsd
je .mem_verified_ok
mov fStatus, 2
.mem_verified_ok:
mov pbHighDst, edi
call Bs2ExitMode_pp32
BITS 16
pop es
pop ds
pop edx
pop ecx
; Continue reading and copying?
cmp fStatus, 0
je .the_load_loop
; Do we quit the loop on a failure?
cmp fStatus, 2
je .verify_failed_msg
;
; Done, so end the current message line.
;
mov al, 13
call PrintChr_r86
mov al, 10
call PrintChr_r86
pop esi
pop edi
pop ebx
pop ecx
pop edx
pop eax
pop ds
pop es
mov sp, bp
pop ebp
ret
;
; Something went wrong, display a message.
;
.verify_failed_msg:
mov edi, pbHighDst
push edi
push cs
push .s_szVerifyFailed
jmp .print_message_and_panic
.param_error:
push ax
push cs
push .s_szParamError
jmp .print_message_and_panic
.read_error:
push ax
push cs
push .s_szReadError
jmp .print_message_and_panic
.print_message_and_panic:
call PrintF_r86
call Bs2Panic
jmp .print_message_and_panic
.s_szReadError:
db 13, 10, 'Error reading: %RX8', 13, 10, 0
.s_szParamError:
db 13, 10, 'Error getting params: %RX8', 13, 10, 0
.s_szVerifyFailed:
db 13, 10, 'Failed to move block high... (%RX32) Got enough memory configured?', 13, 10, 0
.s_szLoadingBigImage:
db 'Loading 2nd image.', 0
ENDPROC bs2LoadBigImage
;
; End sections and image.
;
%include "bootsector2-common-end.mac"