?
This commit is contained in:
parent
cbf6c48b22
commit
5b34321456
45
Makefile
45
Makefile
@ -2,7 +2,7 @@ BUILD=./build
|
||||
|
||||
# Default rule
|
||||
.PHONY: default
|
||||
default: all
|
||||
default: $(BUILD)/disk.img
|
||||
|
||||
# Remove all build files
|
||||
.PHONY: clean
|
||||
@ -10,16 +10,11 @@ clean:
|
||||
rm -drf $(BUILD)
|
||||
cd tetros; cargo clean
|
||||
|
||||
# Make everything
|
||||
# (but don't run qemu)
|
||||
.PHONY: all
|
||||
all: img
|
||||
|
||||
#
|
||||
# MARK: boot
|
||||
# MARK: disk
|
||||
#
|
||||
|
||||
# Compile tetros as library
|
||||
# Compile tetros
|
||||
LIB_SRC = ./tetros/Cargo.toml ./tetros/Cargo.lock $(shell find ./tetros/src -type f)
|
||||
$(BUILD)/tetros.lib: $(LIB_SRC)
|
||||
@mkdir -p $(BUILD)
|
||||
@ -35,7 +30,7 @@ $(BUILD)/tetros.lib: $(LIB_SRC)
|
||||
-- \
|
||||
--emit link="$(CURDIR)/$@"
|
||||
|
||||
# Link tetros
|
||||
# Link tetros using custom linker script
|
||||
BIOS_LD = ./tetros/linkers/x86-unknown-none.ld
|
||||
$(BUILD)/tetros.elf: $(BUILD)/tetros.lib $(BIOS_LD)
|
||||
ld \
|
||||
@ -49,13 +44,13 @@ $(BUILD)/tetros.elf: $(BUILD)/tetros.lib $(BIOS_LD)
|
||||
objcopy --only-keep-debug "$@" "$@.sym"
|
||||
objcopy --strip-debug "$@"
|
||||
|
||||
# Wrap tetros in three-stage BIOS loader
|
||||
# Wrap tetros in BIOS loader
|
||||
# Parameters:
|
||||
# - BIOS_SRC: source directory of bios assembly
|
||||
# - STAGE2_SECTOR: the index of the first sector of the stage 2 binary on the disk
|
||||
BIOS_SRC = ./bios
|
||||
STAGE2_SECTOR = 1
|
||||
$(BUILD)/bios.bin: $(wildcard $(BIOS_SRC)/*.asm) $(BUILD)/tetros.elf
|
||||
$(BUILD)/disk.img: $(wildcard $(BIOS_SRC)/*.asm) $(BUILD)/tetros.elf
|
||||
@mkdir -p "$(BUILD)"
|
||||
nasm \
|
||||
-f bin \
|
||||
@ -66,30 +61,12 @@ $(BUILD)/bios.bin: $(wildcard $(BIOS_SRC)/*.asm) $(BUILD)/tetros.elf
|
||||
-i "$(BIOS_SRC)" \
|
||||
"$(BIOS_SRC)/main.asm"
|
||||
|
||||
# Extract full mbr (first 512 bytes)
|
||||
$(BUILD)/mbr.bin: $(BUILD)/bios.bin
|
||||
@mkdir -p "$(BUILD)"
|
||||
@echo ""
|
||||
dd if="$<" bs=512 count=1 of="$@"
|
||||
|
||||
# Extract stage 2 (rest of file)
|
||||
$(BUILD)/stage2.bin: $(BUILD)/bios.bin
|
||||
@mkdir -p "$(BUILD)"
|
||||
@echo ""
|
||||
dd if="$<" bs=512 skip=1 of="$@"
|
||||
|
||||
#
|
||||
# MARK: bundle
|
||||
# MARK: qemu
|
||||
#
|
||||
# Do not use `-enable-kvm` or `-cpu host`
|
||||
# this confuses gdb.
|
||||
#
|
||||
|
||||
# Make full disk image
|
||||
.PHONY: img
|
||||
img: $(BUILD)/disk.img
|
||||
$(BUILD)/disk.img: $(BUILD)/mbr.bin $(BUILD)/stage2.bin
|
||||
@mkdir -p $(BUILD)
|
||||
@echo ""
|
||||
dd if="$(BUILD)/mbr.bin" of=$@ conv=notrunc bs=512
|
||||
dd if="$(BUILD)/stage2.bin" of=$@ conv=notrunc seek=$(STAGE2_SECTOR) bs=512
|
||||
|
||||
.PHONY: qemu
|
||||
qemu: $(BUILD)/disk.img
|
||||
@ -129,5 +106,3 @@ qemu-gdb: $(BUILD)/disk.img
|
||||
-gdb tcp::26000 \
|
||||
-S
|
||||
|
||||
# Do not use `-enable-kvm` or `-cpu host`,
|
||||
# this confuses gdb.
|
@ -4,27 +4,22 @@ sectalign off
|
||||
; STAGE3, a path to the stage3 binary
|
||||
; STAGE2_SECTOR, the location of stage 2
|
||||
; on the disk, in 512-byte sectors.
|
||||
; On a gpt disk, this is probably 34.
|
||||
|
||||
; Stage 1 is MBR code, and should fit in LBA 0
|
||||
; (512 bytes). Layout is as follows:
|
||||
; (Format is `offset, length: purpose`)
|
||||
; 0, 424: x86 boot code
|
||||
; 440, 4: Unique disk signature
|
||||
; 444, 2: unknown
|
||||
; 446, 16*4: Array of four legacy MBR records
|
||||
; 510, 2: signature 0x55 0xAA
|
||||
; 512 to end of logical block: reserved
|
||||
;
|
||||
; See https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html
|
||||
|
||||
|
||||
; BIOS loads stage 1 at 0x7C00
|
||||
ORG 0x7C00
|
||||
SECTION .text
|
||||
|
||||
; stage 1 is sector 0, loaded into memory at 0x7C00
|
||||
; Stage 1 is MBR code, and should fit in LBA 0
|
||||
; (i.e, in the first 512 bytes).
|
||||
%include "stage1.asm"
|
||||
|
||||
; Stage 1 is at most 440 bytes
|
||||
; This limit is set by the GPT spec.
|
||||
; See https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html
|
||||
;
|
||||
; This `times` will throw an error if the subtraction is negative.
|
||||
times 440-($-$$) db 0
|
||||
db 0xee
|
||||
|
||||
@ -32,30 +27,39 @@ db 0xee
|
||||
times 510-($-$$) db 0
|
||||
|
||||
; MBR signature.
|
||||
; This isn't loaded into memory, it's
|
||||
; only here for debugging.
|
||||
; This tells the BIOS that this disk is bootable.
|
||||
db 0x55
|
||||
db 0xaa
|
||||
|
||||
|
||||
; Include stage 2. This is loaded into memory by stage 1.
|
||||
;
|
||||
; Stage 2 sets up protected mode, sets up the GDT,
|
||||
; and initializes a minimal environment for stage 3.
|
||||
;
|
||||
; On a "real" boot disk, this data will not immediately follow stage 1.
|
||||
; It would be stored in a special disk partition.
|
||||
;
|
||||
; We don't need this kind of complexity here, though, so we store
|
||||
; stage 2 right after stage 1. (This is why STAGE2_SECTOR is 1.)
|
||||
;
|
||||
; This is nice, because the layout of the code on our boot disk
|
||||
; matches the layout of the code in memory. THIS IS NOT USUALLY THE CASE.
|
||||
stage2:
|
||||
%include "stage2.asm"
|
||||
align 512, db 0
|
||||
stage2.end:
|
||||
|
||||
; The maximum size of stage2 is 4 KiB,
|
||||
; This fill will throw an error if the subtraction is negative.
|
||||
times (4*1024)-($-stage2) db 0
|
||||
|
||||
; Pad to 0x9000.
|
||||
; This needs to match the value configured in the stage3 linker script
|
||||
; This needs to match the value configured in the Stage 3 linker script
|
||||
; TODO: why? can we make this smaller?
|
||||
times (0x9000 - 0x7c00)-($-$$) db 0
|
||||
|
||||
|
||||
|
||||
; Include stage 3, the binary compiled from Rust sources.
|
||||
stage3:
|
||||
%defstr STAGE3_STR %[STAGE3]
|
||||
incbin STAGE3_STR
|
||||
align 512, db 0
|
||||
.end:
|
||||
|
||||
; TODO: why? Of the disk, or of memory?
|
||||
; the maximum size of the boot loader portion is 384 KiB
|
||||
times (384*1024)-($-$$) db 0
|
||||
|
@ -1,22 +1,21 @@
|
||||
SECTION .text
|
||||
USE16
|
||||
|
||||
; provide function for printing in x86 real mode
|
||||
|
||||
; print a string and a newline
|
||||
; CLOBBER
|
||||
; ax
|
||||
; Print a string and a newline
|
||||
;
|
||||
; Clobbers ax
|
||||
print_line:
|
||||
mov al, 13
|
||||
call print_char
|
||||
mov al, 10
|
||||
jmp print_char
|
||||
|
||||
; print a string
|
||||
; IN
|
||||
; Print a string
|
||||
;
|
||||
; Input:
|
||||
; si: points at zero-terminated String
|
||||
; CLOBBER
|
||||
; si, ax
|
||||
;
|
||||
; Clobbers si, ax
|
||||
print:
|
||||
pushf
|
||||
cld
|
||||
@ -30,8 +29,9 @@ print:
|
||||
popf
|
||||
ret
|
||||
|
||||
; print a character
|
||||
; IN
|
||||
; Print a character
|
||||
;
|
||||
; Input:
|
||||
; al: character to print
|
||||
print_char:
|
||||
pusha
|
||||
@ -42,10 +42,11 @@ print_char:
|
||||
ret
|
||||
|
||||
; print a number in hex
|
||||
; IN
|
||||
;
|
||||
; Input:
|
||||
; bx: the number
|
||||
; CLOBBER
|
||||
; al, cx
|
||||
;
|
||||
; Clobbers al, cx
|
||||
print_hex:
|
||||
mov cx, 4
|
||||
.lp:
|
||||
|
121
bios/stage1.asm
121
bios/stage1.asm
@ -1,37 +1,39 @@
|
||||
USE16
|
||||
|
||||
stage1: ; dl comes with disk
|
||||
; initialize segment registers
|
||||
xor ax, ax
|
||||
stage1:
|
||||
; Initialize segment registers
|
||||
xor ax, ax ; Set ax to 0
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
|
||||
; initialize stack
|
||||
; Initialize stack pointer
|
||||
; (stack grows up)
|
||||
mov sp, 0x7C00
|
||||
|
||||
; initialize CS
|
||||
; far jump sets both CS and IP to a known-good state,
|
||||
; we don't know where the BIOS put us at startup.
|
||||
; (could be 0x00:0x7C00, could be 0x7C00:0x00.
|
||||
; Not everybody follows spec.)
|
||||
push ax
|
||||
; Initialize CS
|
||||
;
|
||||
; `retf` sets both CS and IP to a known-good state.
|
||||
; This is necessary because we don't know where the BIOS put us at startup.
|
||||
; (could be 0x00:0x7C00, could be 0x7C00:0x00. Not everybody follows spec.)
|
||||
push ax ; `ax` is still 0
|
||||
push word .set_cs
|
||||
retf
|
||||
|
||||
.set_cs:
|
||||
; save disk number
|
||||
; Save disk number.
|
||||
; BIOS sets `dl` to the number of
|
||||
; the disk we're booting from.
|
||||
mov [disk], dl
|
||||
|
||||
; Print "Stage 1"
|
||||
mov si, stage_msg
|
||||
call print
|
||||
mov al, '1'
|
||||
call print_char
|
||||
call print_line
|
||||
|
||||
|
||||
|
||||
; read CHS gemotry
|
||||
; read CHS gemotry, save into [chs]
|
||||
; CL (bits 0-5) = maximum sector number
|
||||
; CL (bits 6-7) = high bits of max cylinder number
|
||||
; CH = low bits of maximum cylinder number
|
||||
@ -51,11 +53,10 @@ stage1: ; dl comes with disk
|
||||
and cl, 0x3f
|
||||
mov [chs.s], cl
|
||||
|
||||
; disk address of stage 2
|
||||
; (start sector)
|
||||
; First sector of stage 2
|
||||
mov eax, STAGE2_SECTOR
|
||||
|
||||
; where to load stage 2
|
||||
; Where to load stage 2
|
||||
mov bx, stage2
|
||||
|
||||
; length of stage2 + stage3
|
||||
@ -63,21 +64,22 @@ stage1: ; dl comes with disk
|
||||
mov cx, (stage3.end - stage2) / 512
|
||||
mov dx, 0
|
||||
|
||||
; Consume eax, bx, cx, dx
|
||||
; and load code from disk.
|
||||
call load
|
||||
|
||||
jmp stage2.entry
|
||||
|
||||
; load some sectors from disk to a buffer in memory
|
||||
; buffer has to be below 1MiB
|
||||
; IN
|
||||
; Load sectors from disk to memory.
|
||||
; Cannot load more than 1MiB.
|
||||
;
|
||||
; Input:
|
||||
; ax: start sector
|
||||
; bx: offset of buffer
|
||||
; cx: number of sectors (512 Bytes each)
|
||||
; dx: segment of buffer
|
||||
; CLOBBER
|
||||
; ax, bx, cx, dx, si
|
||||
; TODO rewrite to (eventually) move larger parts at once
|
||||
; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end)
|
||||
;
|
||||
; Clobbers ax, bx, cx, dx, si
|
||||
load:
|
||||
; replaced 127 with 1.
|
||||
; see https://stackoverflow.com/questions/58564895/problem-with-bios-int-13h-read-sectors-from-drive
|
||||
@ -101,44 +103,32 @@ load:
|
||||
mov [DAPACK.count], cx
|
||||
mov [DAPACK.seg], dx
|
||||
|
||||
; This should be a subroutine,
|
||||
; but we don't call/ret to save a few bytes.
|
||||
; (we only use this once)
|
||||
;
|
||||
;call print_dapack
|
||||
;print_dapack:
|
||||
; Print the data we're reading
|
||||
; TODO: decode
|
||||
mov bx, [DAPACK.addr + 2]
|
||||
call print_hex
|
||||
|
||||
mov bx, [DAPACK.addr]
|
||||
call print_hex
|
||||
|
||||
mov al, '#'
|
||||
call print_char
|
||||
|
||||
mov bx, [DAPACK.count]
|
||||
call print_hex
|
||||
|
||||
mov al, ' '
|
||||
call print_char
|
||||
|
||||
mov bx, [DAPACK.seg]
|
||||
call print_hex
|
||||
|
||||
mov al, ':'
|
||||
call print_char
|
||||
|
||||
mov bx, [DAPACK.buf]
|
||||
call print_hex
|
||||
|
||||
call print_line
|
||||
;ret
|
||||
; End of print_dapack
|
||||
|
||||
|
||||
cmp byte [chs.s], 0
|
||||
jne .chs
|
||||
;INT 0x13 extended read does not work on CDROM!
|
||||
; Read from disk.
|
||||
;
|
||||
; Note:
|
||||
; int 0x13 extended read does not work on CDROM,
|
||||
; but we don't care. We're booting from a floppy.
|
||||
mov dl, [disk]
|
||||
mov si, DAPACK
|
||||
mov ah, 0x42
|
||||
@ -146,51 +136,6 @@ load:
|
||||
jc error ; carry flag set on error
|
||||
ret
|
||||
|
||||
.chs:
|
||||
; calculate CHS
|
||||
xor edx, edx
|
||||
mov eax, [DAPACK.addr]
|
||||
div dword [chs.s] ; divide by sectors
|
||||
mov ecx, edx ; move sector remainder to ecx
|
||||
xor edx, edx
|
||||
div dword [chs.h] ; divide by heads
|
||||
; eax has cylinders, edx has heads, ecx has sectors
|
||||
|
||||
; Sector cannot be greater than 63
|
||||
inc ecx ; Sector is base 1
|
||||
cmp ecx, 63
|
||||
ja error_chs
|
||||
|
||||
; Head cannot be greater than 255
|
||||
cmp edx, 255
|
||||
ja error_chs
|
||||
|
||||
; Cylinder cannot be greater than 1023
|
||||
cmp eax, 1023
|
||||
ja error_chs
|
||||
|
||||
; Move CHS values to parameters
|
||||
mov ch, al
|
||||
shl ah, 6
|
||||
and cl, 0x3f
|
||||
or cl, ah
|
||||
shl dx, 8
|
||||
|
||||
; read from disk using CHS
|
||||
mov al, [DAPACK.count]
|
||||
mov ah, 0x02 ; disk read (CHS)
|
||||
mov bx, [DAPACK.buf]
|
||||
mov dl, [disk]
|
||||
push es ; save ES
|
||||
mov es, [DAPACK.seg]
|
||||
int 0x13
|
||||
pop es ; restore EC
|
||||
jc error ; carry flag set on error
|
||||
ret
|
||||
|
||||
error_chs:
|
||||
mov ah, 0
|
||||
|
||||
error:
|
||||
call print_line
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user