An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
101 lines
3.4 KiB
ArmAsm
101 lines
3.4 KiB
ArmAsm
# Stage 1 — the actual MBR boot sector. Hard-limited to 510 bytes (+2-byte
|
|
# 0x55AA signature) by the BIOS, so there's no room here for anything but
|
|
# "load stage 2 off disk and jump to it". All the VBE/A20/protected-mode/
|
|
# splash/kernel-loading work now lives in stage2.S + stage2main.c, which
|
|
# aren't sector-size-constrained.
|
|
#
|
|
# How many sectors of stage2 to pull in. This, the padding the Makefile gives
|
|
# stage2's binary, and the "+(STAGE2_SECTORS+1)" sector math in stage2main.c's
|
|
# readseg() all have to agree on where the kernel starts on disk -- so the
|
|
# Makefile passes -DSTAGE2_SECTORS and is the single authority. The value below
|
|
# is only a fallback for reading this file standalone.
|
|
#
|
|
# It is 48, not the old 24, because stage2 now carries the boot logo
|
|
# (include/logo.h, 8 KiB). The real ceiling is memory rather than this number:
|
|
# stage2 loads at 0x7E00 and the multiboot kernel-search buffer starts at
|
|
# 0x10000, so stage2 cannot exceed 0x8200 bytes = 65 sectors.
|
|
#ifndef STAGE2_SECTORS
|
|
#define STAGE2_SECTORS 48
|
|
#endif
|
|
#define STAGE2_ADDR 0x7E00
|
|
|
|
.code16
|
|
.global start
|
|
start:
|
|
cli
|
|
xorw %ax, %ax
|
|
movw %ax, %ds
|
|
movw %ax, %es
|
|
movw %ax, %ss
|
|
movw $0x7c00, %sp
|
|
|
|
# Read STAGE2_SECTORS sectors, starting at disk sector 1 (LBA), into
|
|
# memory right after this boot sector (0x7E00). Raw IDE PIO (LBA28) —
|
|
# same register convention as stage2main.c's own readsect(), just
|
|
# inlined here since we can't call C code yet. Port numbers 0x1F2-0x1F7
|
|
# are all > 0xFF, so they must go through %dx — `out $imm8,%al` only
|
|
# encodes an 8-bit port and silently truncates anything larger.
|
|
# "You were not booted from a CD." stage2main.c reads this byte to choose
|
|
# between ATA and ATAPI when it loads the kernel, and nothing else clears
|
|
# it -- so a warm reboot from a disc could otherwise leave the flag set and
|
|
# send a perfectly ordinary hard-disk boot looking for an optical drive.
|
|
# Placed one byte past the verbose flag; both sit clear of the 256-byte VBE
|
|
# mode info block that stage2.S is about to write at 0x30000.
|
|
movw $0x3000, %ax
|
|
movw %ax, %es
|
|
movw $0x101, %di
|
|
movb $0, %al
|
|
movb %al, %es:(%di)
|
|
xorw %ax, %ax
|
|
movw %ax, %es
|
|
|
|
movw $STAGE2_ADDR, %di # ES:DI destination, ES=0
|
|
movw $1, %si # first LBA sector to read
|
|
movb $STAGE2_SECTORS, %bl
|
|
|
|
.Lsector:
|
|
.Lwait1:
|
|
movw $0x1F7, %dx
|
|
inb %dx, %al
|
|
andb $0xC0, %al
|
|
cmpb $0x40, %al
|
|
jne .Lwait1
|
|
|
|
movw $0x1F2, %dx
|
|
movb $1, %al
|
|
outb %al, %dx # sector count = 1
|
|
|
|
incw %dx # 0x1F3
|
|
movw %si, %ax
|
|
outb %al, %dx # LBA [7:0]
|
|
|
|
incw %dx # 0x1F4
|
|
xorb %al, %al
|
|
outb %al, %dx # LBA [15:8]
|
|
|
|
incw %dx # 0x1F5
|
|
outb %al, %dx # LBA [23:16]
|
|
|
|
incw %dx # 0x1F6
|
|
movb $0xE0, %al
|
|
outb %al, %dx # drive 0, LBA mode
|
|
|
|
incw %dx # 0x1F7
|
|
movb $0x20, %al
|
|
outb %al, %dx # READ SECTORS command
|
|
|
|
.Lwait2:
|
|
inb %dx, %al # %dx still 0x1F7
|
|
andb $0xC0, %al
|
|
cmpb $0x40, %al
|
|
jne .Lwait2
|
|
|
|
movw $256, %cx # 256 words = 512 bytes
|
|
movw $0x1F0, %dx
|
|
rep insw # reads into ES:DI, DI += 512 automatically
|
|
|
|
incw %si
|
|
decb %bl
|
|
jnz .Lsector
|
|
|
|
ljmp $0, $STAGE2_ADDR
|