memtest86plus/boot/mbr.S

180 lines
3.5 KiB
ArmAsm

// SPDX-License-Identifier: GPL-2.0
//
// mbr.S supports booting directly from the BIOS when a memtest binary image is
// stored on a hard disk or USB stick. When booted by the BIOS, it is loaded
// at address 0x7c00. It then loads the setup code immediately after itself
// (address 0x7e00) and the main program code at segment MAIN_SEG, using BIOS
// interrupts to read the data from disk. It locates the start of the memtest
// image containing the setup and main program code from the LBA stored at
// offset 0x1b0. The LBA value is assumed to be offset by 4, for compatibility
// with the xorrisofs --grub2-mbr option.
//
// The first 512B of the memtest binary image is not used, so either of the
// memtest.bin or memtest.efi images may be used.
//
// Copyright (C) 2020 Martin Whitaker.
#define __ASSEMBLY__
#include "boot.h"
.section ".mbr", "ax", @progbits
.code16
# The BIOS boot entry point. This will be located at 0x7c00.
.globl boot
boot:
# Initialise the segment registers and the stack.
ljmp $BOOT_SEG, $init
init:
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw $BOOT_STACK_TOP, %ax
movw %ax, %sp
# Check we have a valid drive number. If not, assume we are
# booting from the first hard drive.
testb $0x80, %dl
jz 0f
testb $0x70, %dl
jz 1f
0: movb $0x80, %dl
1:
# Load the setup code.
movw $SETUP_SECS, dap_length
movw $SETUP_SEG, dap_segment
movl image_base, %eax
subl $3, %eax
movl %eax, dap_lba_start
movw $dap, %si
movb $0x42, %ah
int $0x13
jc load_error
# Print a message.
pushw %dx
movb $0x03, %ah # read cursor pos
xorb %bh, %bh
int $0x10
leaw boot_msg, %bp
movw $(boot_msg_end - boot_msg), %cx
movw $0x0007, %bx # page 0, attribute 7 (normal)
movw $0x1301, %ax # write string, move cursor
int $0x10
popw %dx
# Load the main test program.
movw $MAIN_SEG, dap_segment
addl $SETUP_SECS, dap_lba_start
movw $_sys_size, %cx # length in 16B chunks
addw $31, %cx # convert to sectors (rounding up)
shrw $5, %cx
0: movw $64, %bx # load either 64 sectors or remaining
cmpw %bx, %cx # length if less than 64 sectors
ja 1f
movw %cx, %bx
1: movw %bx, dap_length
movw $dap, %si
movb $0x42, %ah
int $0x13
jc load_error
addw $0x800, dap_segment
addl $0x40, dap_lba_start
subw %bx, %cx
jg 0b
# Turn off the floppy drive motor.
movw $0x3f2, %dx
xorb %al, %al
outb %al, %dx
# Turn off the text display cursor.
movb $0x01, %ah
movb $0x00, %bh
movw $0x2000, %cx
int $0x10
# Fix up the Linux boot header to indicate we've loaded into low memory.
movl $LOW_LOAD_ADDR, 0x214
# After that (everything loaded), we jump to the setup code loaded
# directly after the boot block.
ljmp $SETUP_SEG, $0
load_error:
movb %ah, %al
call hex_to_ascii
movb %al, error_msg+1
movb %ah, %al
shrb $4, %al
call hex_to_ascii
movb %al, error_msg+0
movb $0x03, %ah # read cursor pos
xorb %bh, %bh
int $0x10
leaw error_msg, %bp
movw $(error_msg_end - error_msg), %cx
movw $0x0007, %bx # page 0, attribute 7 (normal)
movw $0x1301, %ax # write string, move cursor
int $0x10
0: hlt
jmp 0b
hex_to_ascii:
andb $0xf, %al
addb $'0', %al
cmpb $'9', %al
jle 1f
addb $('A' - '0' - 10), %al
1: ret
# Local variables.
dap:
.byte 0x10
.byte 0
dap_length:
.word 0
dap_offset:
.word 0
dap_segment:
.word 0
dap_lba_start:
.quad 0
boot_msg:
.ascii "Loading Memtest86+\r\n"
boot_msg_end:
error_msg:
.ascii " Disk read failed\r\n"
error_msg_end:
.org 0x1b0
image_base:
.quad 5 # default to sector 1, offset by 4
.org 0x1fe
boot_flag:
.word 0xAA55