Made it possible to load 8 sectors into ram

This commit is contained in:
Eric-Paul Ickhorn 2023-05-02 08:48:47 +02:00
parent 49230d4c72
commit f5fe3a2172
6 changed files with 219 additions and 381 deletions

View File

@ -8,4 +8,5 @@ cd stage_2
./build.sh
cd ../
cat stage_1/stage_1.bin > nightloader.bin
# cat stage_2/stage_2.bin >> nightloader.bin

2
run.sh Normal file → Executable file
View File

@ -1,3 +1,3 @@
#!/bin/env bash
qemu-system-x86_64 nightloader.bin

4
stage_1/fat32.asm Normal file
View File

@ -0,0 +1,4 @@
; TODO: Read FAT32 filesystem and load raw binary frompath nightloader/stage_2.bin

124
stage_1/partition_table.asm Normal file
View File

@ -0,0 +1,124 @@
times 442 - ($-$$) db 0
db "####"
times 446 - ($-$$) db 0
mbr_table:
.part_1:
db 0x80 ; bootable flag
db 0, 2, 0 ; CHS - start-address (ordering: cylinder, sector, header)
db 0x9d
db 0, 16, 0 ; CHS - end-address (ordering: cylinder, sector, header)
dd 2
dd 16
.part_2:
db 0x00 ; bootable flag
db 0, 0, 0 ; CHS - start-address (ordering: cylinder, sector, header)
db 0x0
db 0, 0, 0 ; CHS - end-address (ordering: cylinder, sector, header)
dd 0
dd 0
.part_3:
db 0x00 ; bootable flag
db 0, 0, 0 ; CHS - start-address (ordering: cylinder, sector, header)
db 0x00
db 0, 0, 0 ; CHS - end-address (ordering: cylinder, sector, header)
dd 0
dd 0
.part_4:
db 0x00 ; bootable flag
db 0, 0, 0 ; CHS - start-address (ordering: cylinder, sector, header)
db 0x00
db 0, 0, 0 ; CHS - end-address (ordering: cylinder, sector, header)
dd 0
dd 0
.signature:
db 0x55, 0xaa
second_stage:
;mov si, finish_text
;mov dl, 36
;mov dh, 12
;mov cx, 8
; set the video mode correctly
xor ah, ah ; bios-function (set video mode)
mov al, 3 ; video mode with 80x25 characters
int 0x10
.happiness:
mov ah, 0x02 ; action: move cursor
mov bh, 0 ; page
mov dh, 1 ; row
mov dl, 1 ; column
int 0x10
mov ah, 0x0a ; action: write character
mov al, '$' ; character
mov bh, 0 ; page
mov cx, 13 ; count
int 10h
jmp .happiness
.prolog:
push di
push cx
push bx
push ax
xor di, di ; character index
.printing_loop:
.set_cursor_position:
.write_character:
push cx ; save len_buffer
; get the current character
mov bx, si
add bx, di
mov al, [bx]
; al now contains the current character
; set the other needed interrupt values
mov ah, 0x0a ; wanted function (write character at cursor position)
mov bh, 0 ; page number
mov cx, 1 ; repetitions of character
int 0x10 ; call bios basic draw functions
pop cx ; restore len_buffer
inc dl ; go to next column
; go to a new line if needed
cmp dl, 80
jb .no_new_line_needed
xor dl, dl
inc dh ; increase column
.no_new_line_needed:
inc di ; go to next character
; go further if the string-printing hasn't been finished
cmp di, cx
jb .printing_loop
.epilog:
jmp .epilog
finish_text:
db "-FINISH-"

View File

@ -1,210 +1,123 @@
section .text
org 0x7c00
start:
STAGE_1_CODE_MEMORY_ADDRESS equ 0x7c00
STAGE_1_STACK_MEMORY_ADDRESS equ 0x07e0
NIGHTLOADER_PARTITION_TYPE equ 0x9d
ORIGINAL_PARTITION_TABLE_OFFSET equ 446
ORIGINAL_NUM_PARTITIONS_IN_TABLE equ 4
ORIGINAL_PARTITION_ENTRY_SIZE equ 16
BOOTABLE_BYTE_OFFSET equ 0
CHS_START_SECTOR_ADDRESS_OFFSET equ 1
PARTITION_TYPE_OFFSET equ 4
CHS_END_SECTOR_ADDRESS equ 5
FIRST_LBA_SECTOR_ADDR_OFFSET equ 8
LAST_LBA_SECTOR_ADDR_OFFSET equ 12
org STAGE_1_CODE_MEMORY_ADDRESS
bits 16
stage_0:
mov ax, 0
mov ds, ax
mov es, ax
mov gs, ax
mov fs, ax
mov ax, 0x7e00
mov ss, ax
mov sp, 256
mov bx, STAGE_1_STACK_MEMORY_ADDRESS
mov ss, bx
mov bx, 0x0800
mov bp, 256
mov sp, 256
mov si, dx ; save the origin disk number
mov bx, 0x0000
mov ds, bx
mov es, bx
mov ax, 0x7c00
add ax, 446
; ax now points to the start of the partition table
mov di, dx
; set the video mode correctly
xor ah, ah ; bios-function (set video mode)
mov al, 3 ; video mode with 80x25 characters
int 0x10
xor di, di
call initialize_video_mode
.search_partition:
mov bx, ax ; get the offset of the current entry
add bx, 4 ; go to the offset of the partition type
mov cl, [bx]
cmp cl, 0x9d
je .load_partition
mov si, STAGE_1_CODE_MEMORY_ADDRESS
add si, ORIGINAL_PARTITION_TABLE_OFFSET
mov cx, 0 ; offset of the current entry from the partition table start
inc di
; leave and print debug message if the last partition entry
; did not provide the wanted bootloader - partition
cmp di, 4
je .no_boot_partition
add ax, 16
jmp .search_partition
.search_loop:
mov bx, si
add bx, cx
add bx, PARTITION_TYPE_OFFSET
mov al, [bx]
cmp al, NIGHTLOADER_PARTITION_TYPE
je .load_partition;
; go to the next entry
add cx, ORIGINAL_PARTITION_ENTRY_SIZE
; check if there are more entries
cmp dx, ORIGINAL_NUM_PARTITIONS_IN_TABLE * ORIGINAL_PARTITION_ENTRY_SIZE
jb .search_loop
jmp .no_boot_partition
.load_partition:
; ax is the start of the bootloader's partition entry in the mbr
; read the chs-entry and push it onto the stack
mov si, cx ; address of the partition table entry of the nightloader-partition
; head
xor dx, dx
mov bx, ax
add bx, 1
mov dl, [bx]
push dx
; TODO: Make this more flexible; that's urgent.
mov ah, 0x02 ; action (read from disk)
mov al, 8 ; num_sectors
mov ch, 0 ; cylinder
mov cl, 2 ; sector (starts at 1, max.: 63)
mov dx, di ; storage device id
mov dh, 0 ; head
mov bx, 0x0800
mov es, bx ; read destination segment
mov bx, 0x0000 ; read destination address
int 0x13
; cylinder
xor dx, dx
mov bx, ax
add bx, 3
mov dh, [bx]
mov bx, ax
add bx, 2
mov dl, [bx]
shr dx, 6
push dx
; sector
xor dx, dx
mov bx, ax
add bx, 2
mov dl, [bx]
and dl, 0b00111111
push dx
; push the partition's length
mov bx, ax
add bx, 12
mov dx, [bx]
push dx ; lower part
mov bx, ax
add bx, 14
mov dx, [bx]
push dx ; higher part
; load it all and read from disk
mov bx, sp
add bx, 4
mov al, [bx] ; sector-count
add bx, 2
mov cl, [bx] ; start-sector
add bx, 2
mov ch, [bx] ; start-cylinder
mov dx, si ; drive
mov bx, 0x0800
mov es, bx ; output segment
mov bx, sp
add bx, 8
mov dh, [bx] ; start-head
call .write_hex
mov cl, 2
mov ah, 0x02
mov al, 1
mov bx, 0x0000 ; output address in es - segment
int 13h
mov cx, 8
mov si, 0x8000
mov cx, 8
mov dh, 12
mov dl, 32
mov dl, 36
call print_string
jmp .keepalive
; jmp .wait
jmp 0x0800:0x0000
.no_boot_partition:
mov cx, LEN_TEXT_NO_BOOT_PARTITION
mov si, error_texts.no_boot_partition
mov si, errors.no_boot_partition
mov cx, 30
mov dl, 25
mov dh, 12
mov dl, 32
call print_string
.keepalive:
jmp .keepalive
.write_hex:
push bx
push cx
mov bx, error_texts.hextab
and cx, 0x0f
add bx, cx
mov cl, [bx]
mov bx, error_texts.hexbuf
inc bx
mov [bx], cl
mov bx, error_texts.hextab
and cx, 0xf0
shr cx, 4
add bx, cx
mov cl, [bx]
mov bx, error_texts.hexbuf
mov [bx], cl
mov cx, 2
mov si, error_texts.hexbuf
mov dh, 12
mov dl, 32
call print_string
pop cx
pop bx
ret
.wait:
cli
hlt
; %include "exfat.asm"
%include "gdt.asm"
%include "utility.asm"
LEN_TEXT_NO_BOOT_PARTITION equ 17
MESSAGE_LENGTH_NO_BOOT_PARTITION equ 30
error_texts:
errors:
.no_boot_partition:
;db "NO_BOOT_PARTITION"
.hextab:
db "NO NIGHTLOADER-PARTITION FOUND"
.hex:
db "0123456789abcdef"
.hexbuf:
resb 4
times 446 - ($-$$) db 0
db 0x80
db 0, 2, 0
db 0x9d
db 0, 3, 0
dd 1
dd 1
times 510 - ($-$$) db 0
db 0x55
db 0xAA
db "################"
%include "utility.asm"
%include "fat32.asm"
%include "partition_table.asm"

View File

@ -1,22 +1,4 @@
section .text
initialize_video_mode:
.prolog:
push ax
; set the video mode correctly
xor ah, ah ; bios-function (set video mode)
mov al, 3 ; video mode with 80x25 characters
int 0x10
.epilog:
pop ax
ret
; cx: len_buffer
; si: buffer
; dl: start_x NOTE: Will contain the end of the text on-screen
@ -82,189 +64,3 @@ print_string:
pop di
ret
; ds: source
; es: destination
; dx: len_to_copy
mem_copy:
push ax
push bx
push cx
push dx
xor cx, cx
mov di, dx
; ax: first region's value
; bx: address at index
; cx: byte_index
; dx: second region's value
.loop:
; retrieve the source byte at the current index
mov bx, cx
mov dx, [bx]
; swap the two segments
; here, ax and bx are used differently.
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
mov [bx], cx
; swap the two segments back
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
inc cx
; if the end has NOT been reached
cmp cx, di
jb .loop ; => continue
ret
; ds: region_1
; es: region_2
; dx: len_regions
; ax: result
mem_equals:
push bx
push cx
push dx
push di
xor cx, cx
mov di, dx
; ax: first region's value
; bx: address at index
; cx: byte_index
; dx: second region's value
.loop:
mov bx, cx
mov dx, [bx]
; swap the two segments
; here, ax and bx are used differently.
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
mov bx, cx
mov ax, [bx]
cmp ax, dx
; swap the two segments back
mov ax, es
mov bx, ds
mov ds, ax
mov es, bx
; jump accordingly to the comparison above
jne .not_equal
inc cx
cmp cx, di ; if the loop needs to continue
jb .loop ; (if the end is NOT reached yet)
; it goes here if the two regions are completely equal
pop di
pop dx
pop cx
pop bx
mov ax, 1
ret
.not_equal:
pop di
pop dx
pop cx
pop bx
mov ax, 0
ret
; ax: start_sector (upper)
; bl: start_sector (lower)
; cx: wanted_sector_count
; dh: drive
; si: buffer_address (upper)
; di: buffer_address (lower)
load_sectors:
; INNER WORKING:
;
; This function first checks if it needs to load sectors going over
; a cylinder boundary and loads to that cylinder boundary first continuing
; in 63-sector - parts after that until the last, < 63-sectors part is read.
;
; This is done because some systems don't like reading over the boundaries
; between the cylinders.
;
; The actual part loading the data is in .read_from_disk, it's no different
; from the first read to the other reads. It just gets different arguments
; from 1).load_first_sectors, and 2) .load_further_sectors
;
.prolog:
push ax
push bx
push cx
push dx
push si
xor si, si ; current sector index
.load_first_sectors:
; ah: EMPTY
; al: num_sectors_to_read
; bx: EMPTY
; ch: cylinder
; cl: sector
; dh: head
; dl: drive
.read_from_disk:
; set es:bx to the address in bytes to which the output should be written.
mov bx, si
shr bx, 9
mov ah, 0x02
int 0x13
.load_further_sectors:
.epilog: