271 lines
4.3 KiB
ArmAsm
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
|