diff --git a/build.sh b/build.sh index 4bdb45a..c57ada6 100755 --- a/build.sh +++ b/build.sh @@ -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 diff --git a/run.sh b/run.sh old mode 100644 new mode 100755 index efe51ec..1ebbecf --- a/run.sh +++ b/run.sh @@ -1,3 +1,3 @@ #!/bin/env bash - +qemu-system-x86_64 nightloader.bin diff --git a/stage_1/fat32.asm b/stage_1/fat32.asm new file mode 100644 index 0000000..80f5455 --- /dev/null +++ b/stage_1/fat32.asm @@ -0,0 +1,4 @@ +; TODO: Read FAT32 filesystem and load raw binary frompath nightloader/stage_2.bin + + + diff --git a/stage_1/partition_table.asm b/stage_1/partition_table.asm new file mode 100644 index 0000000..55815dd --- /dev/null +++ b/stage_1/partition_table.asm @@ -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-" diff --git a/stage_1/start.asm b/stage_1/start.asm index 4b988f6..2c02bf5 100644 --- a/stage_1/start.asm +++ b/stage_1/start.asm @@ -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" diff --git a/stage_1/utility.asm b/stage_1/utility.asm index 3d91f6c..be8a760 100644 --- a/stage_1/utility.asm +++ b/stage_1/utility.asm @@ -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: - - - - -