glip/boot.s
2021-08-13 17:18:25 +01:00

271 lines
4.3 KiB
ArmAsm

[bits 16]
[org 0x7C00]
[cpu 386]
; Memory map:
; 0x500-0x700: filesystem header
; 0x700-0x900: sector table buffer
; 0x900-0xB00: file sector buffer
; 0x7000-0x7C00: stack
; 0x7C00-0x7E00: this code
; 0x10000-0x20000: loaded program
start:
; Setup segment registers and the stack.
cli
xor ax,ax
mov ds,ax
mov ss,ax
mov sp,0x7C00 ; Put stack below the code.
sti
cld
jmp 0x0000:.set_cs
.set_cs:
; Save the BIOS drive number.
mov [drive_number],dl
; Print a loading message.
mov si,loading_message
call print_string
; Get drive parameters.
mov ah,0x08
mov dl,[drive_number]
xor di,di
int 0x13
mov si,error_read
jc error
and cx,31
mov [max_sectors],cx
inc dh
shr dx,8
mov [max_heads],dx
; Load the filesystem header.
xor ax,ax
mov es,ax
mov di,1
mov bx,0x500
call load_sector
; Check for correct signature and version.
mov si,error_disk
mov ax,[0x500]
cmp ax,0x706C
jne error
mov ax,[0x502]
cmp ax,1
jne error
; Load the root directory.
mov ax,[0x51C]
mov [file_remaining_size],ax
mov ax,[0x520]
mov [current_sector],ax
mov di,ax
xor ax,ax
mov es,ax
mov bx,0x900
call load_sector
; Scan the root directory.
xor bx,bx
.scan_root_directory:
cmp bx,0x200
jne .loaded_sector
call next_file_sector
xor bx,bx
.loaded_sector:
; Compare file name.
xor ax,ax
mov es,ax
mov cx,7
mov si,program_name
mov di,0x900
add di,bx
rep cmpsb
jne .next_entry
; Save the startup program's first sector, size and checksum.
mov al,[0x917 + bx]
mov [checksum],al
mov ax,[0x910 + bx]
mov [file_remaining_size],ax
mov di,[0x914 + bx]
mov [current_sector],di
jmp .load_startup_program
; Go to the next entry.
.next_entry:
add bx,0x20
sub word [file_remaining_size],0x20
cmp word [file_remaining_size],0
jne .scan_root_directory
mov si,error_disk
jmp error
; Load the startup program.
.load_startup_program:
xor bx,bx
mov es,bx
mov bx,0x900
call load_sector
; Copy the sector to the destination.
.copy_sector:
mov bx,0x1000
mov es,bx
mov di,[file_destination]
mov si,0x900
mov cx,0x200
rep movsb
; Calculate checksum.
mov bl,[checksum]
mov si,0x900
mov cx,0x200
.checksum_loop:
lodsb
xor bl,al
loop .checksum_loop
mov [checksum],bl
; Load the next sector of the startup program.
add word [file_destination],0x200
mov ax,[file_remaining_size]
cmp ax,0x200
jbe .launch
sub word [file_remaining_size],0x200
call next_file_sector
jmp .copy_sector
; Launch the startup program.
.launch:
mov si,error_disk
cmp byte [checksum],0
jne error
mov dl,[drive_number]
jmp 0x1000:0x0000
next_file_sector:
; Do we need to switch the sector table buffer?
mov ax,[current_sector]
shr ax,8 ; 256 sector table entries per sector
cmp al,[current_sector_table]
je .skip_switch
mov [current_sector_table],al
; Load the new sector table buffer.
add ax,2
mov di,ax
xor bx,bx
mov es,bx
mov bx,0x700
call load_sector
.skip_switch:
; Get the next sector.
mov bx,[current_sector]
and bx,0xFF
shl bx,1
mov di,[0x700 + bx]
mov [current_sector],di
; Load the next sector.
xor bx,bx
mov es,bx
mov bx,0x900
jmp load_sector
; di - LBA.
; es:bx - buffer
load_sector:
mov byte [read_attempts],5
.try_again:
mov si,error_read
mov al,[read_attempts]
or al,al
jz error
dec byte [read_attempts]
; Calculate cylinder and head.
mov ax,di
xor dx,dx
div word [max_sectors]
xor dx,dx
div word [max_heads]
push dx ; remainder - head
mov ch,al ; quotient - cylinder
shl ah,6
mov cl,ah
; Calculate sector.
mov ax,di
xor dx,dx
div word [max_sectors]
inc dx
or cl,dl
; Load the sector.
pop dx
mov dh,dl
mov dl,[drive_number]
mov ax,0x0201
int 0x13
jc .try_again
ret
; ds:si - zero-terminated string.
error:
call print_string
jmp $
; ds:si - zero-terminated string.
print_string:
lodsb
or al,al
jz .done
mov ah,0xE
int 0x10
jmp print_string
.done: ret
file_destination:
dw 0
current_sector_table:
db 0xFF
error_read:
db "Cannot read boot disk.",0
error_disk:
db "Corrupt boot disk.",0
program_name:
db "system",0 ; don't forget to change name length in comparison!
loading_message:
db 'Loading... ',0
times (0x1FE - $ + $$) nop
dw 0xAA55
; Uninitialised variables outside the boot image.
drive_number:
db 0
read_attempts:
db 0
max_sectors:
dw 0
max_heads:
dw 0
current_sector:
dw 0
file_remaining_size:
dw 0
checksum:
db 0