Nyanix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

commit 565c8a986eaa5937300a861bc9ddd8c6c1712c16
parent 43158992c0797aada13af8f6b1cf5f3b1af86067
Author: Dani Frisk <dani@silverskin.fi>
Date:   Sun, 19 Aug 2018 20:10:45 +0300

Unreal mode works.

Diffstat:
README.md | 9+++++++++
src/boot_early/2nd_stage.s | 410-------------------------------------------------------------------------------
src/boot_early/a20gate.s | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/boot_early/boot.s | 198+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
src/boot_early/second_stage.s | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/descriptor_tables/gd32table.s | 33---------------------------------
src/drivers/FDC.s | 26--------------------------
src/drivers/cmos.s | 94-------------------------------------------------------------------------------
src/drivers/framebuffer.s | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/drivers/kbd_ctl.s | 40++++++++++++++++++++++++++++++++++++++++
src/main/main_loader.s | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/main_loader/kernel_loader.s | 67-------------------------------------------------------------------
12 files changed, 640 insertions(+), 711 deletions(-)

diff --git a/README.md b/README.md @@ -1,2 +1,11 @@ # Nyanix Simple bootloader project. Aiming for clean code. + +boot.s: + -> swap to unreal mode + -> load rest of the loader + -> jump to 2nd stage + + + + diff --git a/src/boot_early/2nd_stage.s b/src/boot_early/2nd_stage.s @@ -1,410 +0,0 @@ - -; ========================================================================== ; -; /src/2nd_stage.s ; -; Copyright (c) 2018, k4m1 <k4m1@protonmail.com> ; -; All rights reserved. ; -; See /LICENSE for further copyright information. ; -; ; -; Entry of 2nd stage of the bootloader ; -; ========================================================================== ; -global _start -_start: - ; disable interrupts, adjust Stack pointer - cli - xor bp, bp - add sp, 0x200 - - ; Back uping boot device from - ; 1st 512 byte sector. - - mov dl, [BOOT_DEVICE_DB] - mov [BOOT_DEV_DB], dl - - ; Functionality to get amount of RAM in system. - - - - .continue: - ; we'll jump to protected mode now. - ; after that, we should _never_ return to real 16-bit mode. - ; closest to that we'll get is virtual 8086 mode, aka - ; emulated 16-bit mode. - ; If we return, we'll hang. - call switch_to_pm - - .hang: - cli - hlt - jmp .hang - -; ========================================================================== ; -; GDT & few variables ; -; ========================================================================== ; -msg_failed_to_switch_pm db "Failed to swap to protected mode", 0x0A, 0x0D, 0 -newline db 0x0A, 0 -BOOT_DEV_DB db 0 - -; ========================================================================== ; -; Function to print debug messages in 16-bit real mode. ; -; ; -; param message_in (DI), String to print. ; -; ========================================================================== ; -real16_dbg_print: - lodsb - or al, al - jnz .continue - ret - .continue: - mov ah, 0x0E - int 0x10 - jmp real16_dbg_print - -; ========================================================================== ; -; Function to switch to protected mode ; -; ========================================================================== ; -switch_to_pm: - lgdt [GDT_32_PTR] - mov eax, cr0 - or eax, 1 - mov cr0, eax - ; 1 more instruction to execute in - ; 16 bit real mode, then we'll be - ; in 32-bit mode ! - jmp GDT_32_CODE:main_init - -; ============================================================================ ; -; 32-bit protected mode ; -; ============================================================================ ; -[bits 32] -; Function to initialize main -main_init: - mov ax, GDT_32_DATA - mov ds, ax - mov ss, ax - mov es, ax - mov fs, ax - mov gs, ax - - ; Setting up new stack - mov ebp, 0x7e00 - mov esp, ebp - - ; disable interrupts - cli - call main - -; ============================================================================ ; -; Function that's in protected 32-bit mode. ; -; This function server as the 'main' function of tthe bootloader. ; -; ============================================================================ ; -main: - push ebp - mov ebp, esp - - xor eax, eax - xor ebx, ebx - xor ecx, ecx - xor edx, edx - - mov esi, msg_nyanix - call print32dbg - mov esi, msg_mem_avail - call print32dbg - - call cmos_get_ram - - call print32dbg_hex - mov esi, newline - call print32dbg - - call check_a20 - cmp ax, 0 - je .a20_enabled - call enable_a20 - call check_a20 - cmp ax, 0 - je .a20_enabled - - ; Failed to enable a20 ! - mov esi, msg_a20fail - call print32dbg - jmp .hang - -; ============================================================================ ; -; We now have enabled A-20 gate. It's time to read the kernel from the disk. ; -; First we'll swap to unreal v8086 mode, load the kernel with BIOS interrupts, ; -; and then swap back to protected 32 bit mode. ; -; We never return from kernel_loader. If we somehow do due error, we'll jump ; -; to the hang. ; -; ============================================================================ ; -.a20_enabled: - cli - hlt - call kernel_loader - jmp .hang -.hang: - mov esi, msg_booting_failed - call print32dbg -.__hang: - cli - hlt - jmp .__hang - -; ============================================================================ ; -; Messages ; -; ============================================================================ ; -msg_nyanix db "Nyanix 0.1 loading your kernel :) ...", 0x0A, 0x00 -msg_mem_avail db "System RAM amount: ", 0 - -; Fatal errors, start with 'Fatal: ' prefix. -msg_a20fail db "Fatal: Failed to enable A20 line.", 0x0A, 0x00 -msg_booting_failed db "Fatal: Failed to boot the kernel!", 0x0A, 0x00 - -; ============================================================================ ; -; Functionality for enabling a20-gate ; -; ============================================================================ ; -; returns 0 if a20 is enabled, -; returns 1 if a20 is not enabled, -check_a20: - push ebp - mov ebp, esp - ; first gotta check if a20 line is enabled already - pushad - mov esi, 0x012345 - mov edi, 0x112345 - mov [esi], esi - mov [edi], edi - cmpsd - popad - jne .enabled - mov ax, 1 - jmp .ret -.enabled: - xor ax, ax -.ret: - mov esp, ebp - pop ebp - ret - -; ========================================================================== ; -; Function to enable A20 ; -; ========================================================================== ; -enable_a20: - push ebp - mov ebp, esp - ; we'll enable a20-gate via keyboard controller. - call kbd_wait - mov al, __KBD_DISABLE - call kbd_send - - call kbd_wait - mov al, __KBD_READ_IN - call kbd_send - - call kbd_read - push eax - - call kbd_wait - mov al, __KBD_WRITE_OUT - call kbd_send - - call kbd_wait - pop eax - or al, 2 - call kbd_send - call kbd_wait - - mov esp, ebp - ret - -; ============================================================================ ; -; Keyboard Control related functionality. ; -; ============================================================================ ; - -__KBD_DISABLE equ 0xAD -__KBD_ENABLE equ 0xAE -__KBD_READ_IN equ 0xD0 -__KBD_WRITE_OUT equ 0xD1 - -; does not return nor require args -kbd_wait: - push eax - in al, 0x64 - test al, 2 - jnz kbd_wait - pop eax - ret - -; returns one byte at al -kbd_read: - in al, 0x64 - test al, 1 - jz kbd_read - in al, 0x60 - ret - -; parameters for kbd_send: one byte at al -kbd_send: - out 0x64, al - ret - -; ============================================================================ ; -; Functionality for printing to the framebuffer ; -; ; -; Requires a null-terminated string at ESI ; -; ============================================================================ ; -__TTY_COLUMNS db 0 -__TTY_ROWS db 0 -__TTY_COLOR db 0x0F -print32dbg: - push ebp - mov ebp, esp - - push eax - push ebx - push ecx - push edx - - .print_loop: - xor eax, eax - xor ebx, ebx - xor edx, edx - - cmp byte [esi + ecx], 0x00 - je .done - - ; VGA_ADDR = (0xB8000 + (y * 80 + x)) - mov bl, byte [__TTY_COLUMNS] - mov dl, byte [__TTY_ROWS] - - ; setting EBX = VGA-Color - ; and EDX = VGA-address - push ecx - mov ecx, 0xb8000 - imul edx, 80 - add edx, ebx - add ecx, edx - mov edx, ecx - pop ecx - - mov bh, byte [__TTY_COLOR] - - ; printing the character - xor eax, eax - mov al, byte [esi + ecx] - - inc ecx - cmp ecx, 0xffff - jge .prevent_overflow - - cmp al, 0x0A - je .newline - mov ah, bh - mov word [edx], ax - - xor ebx, ebx - mov bl, byte [__TTY_COLUMNS] - add bl, 2 - mov byte [__TTY_COLUMNS], bl - cmp bl, 80 - jl .print_loop - mov bl, byte [__TTY_ROWS] - mov byte [__TTY_COLUMNS], 0 - inc bl - mov byte [__TTY_ROWS], bl - cmp bl, 25 - jl .print_loop - - ; 80x24 lines used? what for, this is a bootloader, - ; not a fairy-tale. No need for roll-over... - .rollover: - mov byte [__TTY_COLUMNS], 0 - mov byte [__TTY_ROWS], 0 - jmp .print_loop - - .newline: - xor ebx, ebx - mov bl, byte [__TTY_ROWS] - cmp bl, 24 - je .rollover - add bl, 2 - mov byte [__TTY_ROWS], bl - mov byte [__TTY_COLUMNS], 0 - jmp .print_loop - - .prevent_overflow: - .done: - mov dl, byte [__TTY_ROWS] - mov bl, byte [__TTY_COLUMNS] - pop edx - pop ecx - pop ebx - pop eax - mov esp, ebp - pop ebp - ret - -; Printing a 32-bit register content -print32dbg_hex: - push ebp - mov ebp, esp - - mov esi, .hex_prefix - call print32dbg - - mov ebx, eax - and eax, 0x0000ffff - and ebx, 0xffff0000 - rol ebx, 16 - and ebx, 0x0000ffff - - call __p16dbghx - mov eax, ebx - call __p16dbghx - - mov esi, newline - call print32dbg - - mov esp, ebp - pop ebp - ret - - .hex_prefix db '0x', 0 - -__p16dbghx: - push ebp - mov ebp, esp - push ebx - - mov di, .outstr16 - mov si, .hexstr - mov cx, 4 - xor bx, bx - .loop: - rol ax, 4 - mov bx, ax - and bx, 0x0f - mov bl, [si + bx] - mov [di], bl - inc di - dec cx - jnz .loop - mov esi, .outstr16 - call print32dbg - - pop ebx - mov esp, ebp - pop ebp - ret - - .hexstr db '0123456789ABCDEF' - .outstr16 db '0000', 0 - -; ========================================================================== ; -; Include of the next part of the bootloader (kernel_load). ; -; ========================================================================== ; -%include "src/descriptor_tables/gd32table.s" -%include "src/drivers/cmos.s" -%include "src/main_loader/kernel_loader.s" - - diff --git a/src/boot_early/a20gate.s b/src/boot_early/a20gate.s @@ -0,0 +1,76 @@ +; ============================================================================= ; +; /boot_early/a20gate.s ; +; Copyright (C) 2018, k4m1 <k4m1@protonmail.com> ; +; See /LICENSE for full license text. ; +; ; +; This file provides functionality for checking the status of a20 gate, and ; +; toggling the a20 gate. ; +; ============================================================================= ; + +[ BITS 16 ] + +%ifndef __a20_gate_h__ +%define __a20_gate_h__ 1 + +check_a20gate: + mov eax, 0x112345 + mov ebx, 0x012345 + + mov byte [eax], 0xFA + mov byte [ebx], 0xFF + + push ecx + push edx + mov ecx, dword [eax] + mov edx, dword [ebx] + cmp ecx, edx + pop edx + pop ecx + + xor eax, eax + jne .a20_isenabled + ret +.a20_isenabled: + inc eax + ret + +; ============================================================================= ; +; This function is used for togglin the a20 gate. ; +; Not returning anythin, nor requiring arguments. ; +; ============================================================================= ; +toggle_a20_status: + push ebp + mov ebp, esp + + cli + call __kbdctl_wait + mov eax, KBD_DISABLE + call __kbdctl_outb + + call __kbdctl_wait + mov eax, KBD_READ + call __kbdctl_outb + + call __kbdctl_wait + call __kbdctl_inb + push eax + + call __kbdctl_wait + mov eax, KBD_WRITE + call __kbdctl_outb + + call __kbdctl_wait + pop eax + or eax, 2 + call __kbdctl_outb + + call __kbdctl_wait + mov eax, KBD_ENABLE + call __kbdctl_outb + + sti + mov esp, ebp + pop ebp + ret + +%endif diff --git a/src/boot_early/boot.s b/src/boot_early/boot.s @@ -1,98 +1,134 @@ -; ============================================================================ ; -; /src/boot.s ; -; Copyright (c) 2018, k4m1 <k4m1@protonmail.com> ; -; All rights reserved. ; -; See /LICENSE for further copyright information. ; -; ; -; The entrypoint for bootloader. ; -; ============================================================================ ; +; =========================================================================== ; +; /src/boot_early/boot.s ; +; Copyright (C) 2018, k4m1 <k4m1@protonmail.com> ; +; All rights reserved. ; +; See /LICENSE for whole license text. ; +; ; +; This code acts as the initial entry point for the bootloader. ; +; First we'll setup unreal mode, then load rest of the loader and jump to ; +; second stage of the bootloader. ; +; =========================================================================== ; -bits 16 -align 4 -org 0x7c00 -section .text +org 0x7c00 +bits 16 +align 4 -; Clear out the Code-Segment, as some BIOSes start the bootloader -; by setting CS=0x7c00 instead of just jmp 0x0000:0x7c00 -jmp 0x0000:_entry +%define SECTOR_COUNT 2 -%define SECTOR_COUNT 5 +; clearing out CS +jmp 0x0000:start -_entry: - cld +BOOT_DEVICE db 0 +BL_SECTORS db 0 + +start: + xor ax, ax + mov ds, ax + mov ss, ax + mov sp, 0x9c00 + + ; swapping to unreal mode cli + push ds + lgdt [dummy_gdt] + mov eax, cr0 + or al, 1 + mov cr0, eax + jmp .pmode +.pmode: + mov bx, 0x08 + mov ds, bx + and al, 0xFE + mov cr0, eax + pop ds + sti + + ; now we're in unreal mode, we have access to 32-bit registers + ; and to BIOS interrupts. + + mov [BOOT_DEVICE], dl + + ; clearing the screen + xor eax, eax + mov al, 0x03 + int 0x10 - ; backup boot device id & clearing registers - mov [BOOT_DEVICE_DB], dl - ; change to textmode (and clear the screen) - xor ah, ah - mov al, 0x03 - int 0x10 - xor ax, ax - xor bx, bx - xor cx, cx - - xor si, si - xor di, di - - xor bp, bp - mov ss, ax - mov es, ax - mov fs, ax - ; stack starts at 0x7c00 - mov sp, 0x7c00 ; ============================================================================ ; -; We'll load 2nd stage of bootloader with BIOS interrupts ; -; (int 13h, ah=2) ; +; Function to load 2nd stage bootloader from disk. ; ; ============================================================================ ; -load_2nd_stage: - sti - mov bx, _start - mov dh, SECTOR_COUNT - mov dl, [BOOT_DEVICE_DB] - mov byte [BL_SECTORS], dh - xor ch, ch - xor dh, dh - mov cl, 0x02 -.read_start: - mov di, 5 -.read: - mov ah, 0x02 - mov al, [BL_SECTORS] - int 0x13 - jc .retry - sub [BL_SECTORS], al - jz .read_done - mov cl, 0x01 - xor dh, 1 - jnz .read_start - inc ch - jmp .read_start -.retry: - xor ah, ah - int 0x13 - dec di - jnz .read - mov si, msg_loader_failed - call real16_dbg_print -.error_hang: +load_second_stage: + mov bx, _start + mov dh, SECTOR_COUNT + mov dl, [BOOT_DEVICE] + mov byte [BL_SECTORS], dh + xor ch, ch + xor dh, dh + mov cl, 0x02 + .read_start: + mov di, 5 + .read: + mov ah, 0x02 + mov al, [BL_SECTORS] + int 0x13 + jc .retry + sub [BL_SECTORS], al + jz .read_done + mov cl, 0x01 + xor dh, 1 + jnz .read_start + inc ch + jmp .read_start + .retry: + ; disk read failed, reseting disk & retrying + xor ah, ah + int 0x13 + dec di + jnz .read + mov si, msg_disk_read_failed + call panic_early + .read_done: + jmp _start + +msg_disk_read_failed db "Failed to read boot disk.", 0x0A, 0x0D, 0 + +hang: cli hlt -.read_done: - jmp _start + jmp hang + +panic_early: + lodsb + or al, al + mov ah, 0x0E + int 0x10 + cmp al, 0 + jne panic_early +.hang: + cli + hlt + jmp .hang + + +dummy_gdt: + dw gdt_end - gdt - 1 + dd gdt +gdt: + dq 0 + dw 0xffff + dw 0 + db 0 + db 10010010b + db 11001111b + db 0 +gdt_end: - msg_loader_failed db "Failed to load bootloader.", 0x0A, 0x0D, 0 - BOOT_DEVICE_DB db 0 - BL_SECTORS db 0 +times 510-($-$$) db 0 +dw 0xAA55 -; Fill rest of the sector with null-bytes until signature. - times 510-($-$$) db 0x00 - db 0x55 - db 0xAA +%include "src/boot_early/second_stage.s" -; Rest of the bootloader code comes here. +times (1024 * SECTOR_COUNT) - ($-$$) db 0 -%include "src/boot_early/2nd_stage.s" diff --git a/src/boot_early/second_stage.s b/src/boot_early/second_stage.s @@ -0,0 +1,94 @@ +; =========================================================================== ; +; src/boot_early/second_stage.s ; +; Copyright (C) 2018, k4m1 <k4m1@protonmail.com> ; +; See /LICENSE for full license text. ; +; ; +; This is the beginning of the second stage of bootloader. ; +; Main purpose of the following code is to enable a20 gate, and then find ; +; kernel from the boot disk. ; +; =========================================================================== ; + +[ BITS 16 ] +_start: + jmp main + +; =========================================================================== ; +; defines, macros, etc ... ; +; =========================================================================== ; +%define kernel_found 1 +%define sector_size 0x1000 + +; drivers. +%include "src/drivers/kbd_ctl.s" +%include "src/drivers/framebuffer.s" + +; a20 gate related operations. +%include "src/boot_early/a20gate.s" + +; The main_loader functionality. +%include "src/boot/main_loader.s" + +; =========================================================================== ; +; Messages ; +; =========================================================================== ; +msg_a20_fail db "Failed to enable A20 gate!", 0x0A, 0 +msg_main_loader_ret db "Unknown fatal error with main loader!", 0x0A, 0 +msg_panic db "[!] Panic: ", 0 + +; =========================================================================== ; +; boot device backup ; +; =========================================================================== ; +boot_device_db db 0 + +; =========================================================================== ; +; Main function of second stage entry. ; +; =========================================================================== ; +main: + xor ebp, ebp + mov esp, 0x9c00 + + mov al, [BOOT_DEVICE] + mov [boot_device_db], al + + call check_a20gate + test eax, eax + jnz .a20_is_enabled + + call toggle_a20_status + call check_a20gate + test eax, eax + jnz .a20_is_enabled + + ; we apparently failed to enable a20 gate. :( + mov esi, msg_a20_fail + call panic + + ; we've enabled a20 gate now, time to start loading + ; kernel from the disk. + .a20_is_enabled: + call main_loader + + ; we returned from main loader? + ; that means we've failed hard, and it's time + ; to panic now! + + mov esi, msg_main_loader_ret + call panic + +; Fancy little panic function. +panic: + push ebp + mov ebp, esp + + push esi + mov esi, msg_panic + call print32dbg + + pop esi + call print32dbg + + .hang: + cli + hlt + jmp .hang + diff --git a/src/descriptor_tables/gd32table.s b/src/descriptor_tables/gd32table.s @@ -1,33 +0,0 @@ - -%ifndef GDT_32_H -%define GDT_32_H 1 - -; Global Descriptor Table & ptrs for that. - -__null: - dq 0 -; code segment (0x9a) -__code: - dw 0xffff - dw 0 - db 0 - db 10011010b - db 11001111b - db 0 -; data segment (0x92) -__data: - dw 0xffff - dw 0 - db 0 - db 10010010b - db 11001111b - db 0 -__end: - -GDT_32_PTR: - dw __end - __null - 1 ; See amd system programmers manual - dd __null -GDT_32_CODE equ __code - __null -GDT_32_DATA equ __data - __null - -%endif diff --git a/src/drivers/FDC.s b/src/drivers/FDC.s @@ -1,26 +0,0 @@ -; ========================================================================== ; -; /src/FDC.s ; -; Copyright (c) 2018, k4m1 <k4m1@protonmail.com> ; -; All rights reserved. ; -; See /LICENSE for further copyright information. ; -; ; -; This code is responsible of controlling the Floppy-disk in protected mode ; -; ========================================================================== ; - -[bits 32] - -%ifndef __FDC_H -%define __FDC_H 1 - -; ========================================================================== ; -; Functionality to find floppy disks. ; -; ========================================================================== ; - - - - - - - -%endif - diff --git a/src/drivers/cmos.s b/src/drivers/cmos.s @@ -1,94 +0,0 @@ -; ========================================================================== ; -; /src/cmos.s ; -; Copyright (C) 2018 k4m1 <k4m1@protonmail.com> ; -; All rights reserved ; -; See /License for further copyright information. ; -; ; -; This code is responsible of communicating with CMOS. ; -; ========================================================================== ; - -%ifndef CMOS_H -%define CMOS_H 1 - -[BITS 32] - -%define CMOS_GPIO_OUT 0x70 -%define CMOS_GPIO_IN 0x71 -%define CMOS_FLOPPY_DATA 0x10 - -%define CMOS_FLOPPY_NO_DRIVE 0 -%define CMOS_FLOPPY_360kb_525_DRIVE 1 -%define CMOS_FLOPPY_1_2mb_525_DRIVE 2 -%define CMOS_FLOPPY_720kb_35_DRIVE 3 -%define CMOS_FLOPPY_1_44mb_35_DRIVE 4 -%define CMOS_FLOPPY_2_88mb_35_DRIVE 5 - -%define CMOS_GETRAM_LOW 0x30 -%define CMOS_GETRAM_HIGH 0x31 - -; ========================================================================== ; -; Functions related to read operations to CMOS ; -; ========================================================================== ; - -; ========================================================================== ; -; This function sets CMOS register to use. ; -; ; -; param register_to_use (stack), register we want to use for Read operations ; -; ========================================================================== ; -cmos_select_register: - push ebp - mov ebp, esp - - xor al, al - in al, CMOS_GPIO_IN - or al, 0x80 - shl al, 7 - mov bl, byte [ebp-4] - or al, bl - out CMOS_GPIO_OUT, al - - mov esp, ebp - pop ebp - ret - -; ========================================================================== ; -; Really slow delay() for CMOS operations. ; -; ========================================================================== ; -cmos_delay: - push ebp - mov ebp, esp - - push ecx - xor ecx, ecx - .loop: - inc ecx - nop - cmp ecx, 0xff - jne .loop - pop ecx - - mov esp, ebp - pop ebp - ret - -; ========================================================================== ; -; This function is used to get the status of floppy drives on system. ; -; ; -; return value is at eax. ; -; ========================================================================== ; -cmos_get_floppy_data: - push ebp - mov ebp, esp - - push CMOS_FLOPPY_DATA - call cmos_select_register - call cmos_delay - in al, CMOS_GPIO_IN - - mov esp, ebp - pop ebp - ret - - -%endif - diff --git a/src/drivers/framebuffer.s b/src/drivers/framebuffer.s @@ -0,0 +1,168 @@ +; =========================================================================== ; +; /src/drivers/framebuffer.s ; +; Copyright (C) 2018, k4m1 <k4m1@protonmail.com> ; +; All rights reserved. ; +; See /LICENSE for whole license text ; +; ; +; This code is responsible of controlling the framebuffer. ; +; In practise, this means write-operations to memory address 0xB8000, which ; +; is directed to screen. ; +; =========================================================================== ; + +%ifndef __FRAMEBUFFER_S__ +%define __FRAMEBUFFER_S__ 1 + +__TTY_COLUMNS db 0 +__TTY_ROWS db 0 +__TTY_COLOR db 0x0F + +newline db 0x0A, 0 + +; String to print at ESI. +print32dbg: + push ebp + mov ebp, esp + + push eax + push ebx + push ecx + push edx + xor ecx, ecx + + .print_loop: + xor eax, eax + xor ebx, ebx + xor edx, edx + + cmp byte [esi + ecx], 0x00 + je .done + + ; VGA_ADDR = (0xB8000 + (y * 80 + x)) + mov bl, byte [__TTY_COLUMNS] + mov dl, byte [__TTY_ROWS] + + ; setting EBX = VGA-Color + ; and EDX = VGA-address + push ecx + mov ecx, 0xb8000 + imul edx, 80 + add edx, ebx + add ecx, edx + mov edx, ecx + pop ecx + + mov bh, byte [__TTY_COLOR] + + ; printing the character + xor eax, eax + mov al, byte [esi + ecx] + + inc ecx + cmp ecx, 0xffff + jge .prevent_overflow + + cmp al, 0x0A + je .newline + mov ah, bh + mov word [edx], ax + + xor ebx, ebx + mov bl, byte [__TTY_COLUMNS] + add bl, 2 + mov byte [__TTY_COLUMNS], bl + cmp bl, 80 + jl .print_loop + mov bl, byte [__TTY_ROWS] + mov byte [__TTY_COLUMNS], 0 + inc bl + mov byte [__TTY_ROWS], bl + cmp bl, 25 + jl .print_loop + + ; 80x24 lines used? what for, this is a bootloader, + ; not a fairy-tale. No need for roll-over... + .rollover: + mov byte [__TTY_COLUMNS], 0 + mov byte [__TTY_ROWS], 0 + jmp .print_loop + + .newline: + xor ebx, ebx + mov bl, byte [__TTY_ROWS] + cmp bl, 24 + je .rollover + add bl, 2 + mov byte [__TTY_ROWS], bl + mov byte [__TTY_COLUMNS], 0 + jmp .print_loop + + .prevent_overflow: + .done: + mov dl, byte [__TTY_ROWS] + mov bl, byte [__TTY_COLUMNS] + pop edx + pop ecx + pop ebx + pop eax + mov esp, ebp + pop ebp + ret + +; Printing a 32-bit register content +print32dbg_hex: + push ebp + mov ebp, esp + + mov esi, .hex_prefix + call print32dbg + + mov ebx, eax + and eax, 0x0000ffff + and ebx, 0xffff0000 + rol ebx, 16 + and ebx, 0x0000ffff + + call __p16dbghx + mov eax, ebx + call __p16dbghx + + mov esi, newline + call print32dbg + + mov esp, ebp + pop ebp + ret + + .hex_prefix db '0x', 0 + +__p16dbghx: + push ebp + mov ebp, esp + push ebx + + mov di, .outstr16 + mov si, .hexstr + mov cx, 4 + xor bx, bx + .loop: + rol ax, 4 + mov bx, ax + and bx, 0x0f + mov bl, [si + bx] + mov [di], bl + inc di + dec cx + jnz .loop + mov esi, .outstr16 + call print32dbg + + pop ebx + mov esp, ebp + pop ebp + ret + + .hexstr db '0123456789ABCDEF' + .outstr16 db '0000', 0 + +%endif + diff --git a/src/drivers/kbd_ctl.s b/src/drivers/kbd_ctl.s @@ -0,0 +1,40 @@ +; ============================================================================= ; +; /drivers/kbd_ctl.s ; +; Copyright (C) 2018, k4m1 <k4m1@protonmail.com> ; +; For full license, see /LICENSE file. ; +; ; +; This file provides functionality needed for interacting with ; +; Keyboard Controller chip (chip 8042). ; +; ============================================================================= ; + +[ BITS 16 ] + +%ifndef __DRIVERS_KBDCTL_H__ +%define __DRIVERS_KBDCTL_H__ 1 + + +%define KBDCTL_PORT 0x64 ; GPIO port for keyboard controller. +%define KBD_DISABLE 0xAD +%define KBD_READ 0xD0 +%define KBD_WRITE 0xD1 +%define KBD_ENABLE 0xAE + +__kbdctl_wait: + in al, KBDCTL_PORT + test al, 2 + jnz __kbdctl_wait + ret + +; Returns one byte at al +__kbdctl_inb: + in al, KBDCTL_PORT + test al, 1 + jz __kbdctl_inb + ret + +; byte to output at al +__kbdctl_outb: + out KBDCTL_PORT, al + ret + +%endif diff --git a/src/main/main_loader.s b/src/main/main_loader.s @@ -0,0 +1,136 @@ +; =========================================================================== ; +; /src/main/main_loader.s ; +; Copyright (C) 2018, k4m1 <k4m1@protonmail.com> ; +; See /LICENSE for whole license text. ; +; ; +; This is the main loader code, with a20 gate enabled, running in unreal mode ; +; and having located to suitable place, it's time to start loading the kernel ; +; from boot disk. ; +; =========================================================================== ; + +[ BITS 16 ] + +%ifndef __LOADER_MAIN_S__ +%define __LOADER_MAIN_S__ 1 + +; Kernel entry signature: +; +; bytes 0 - 7 : "Nyan_hed" +; bytes 8 - 9 : Size of kernel in sectors (how many 1024 bytes chunks) +; may be adding some more stuff + +; =========================================================================== ; +; Variables needed for kernel loading process. ; +; =========================================================================== ; + +kernel_entry_address db 0x10000 +kernel_entry_signature db "Nyan_hed", 0 +kernel_sector_count db 0 +kernel_sectors_loaded db 0 + +main_loader: + push ebp + mov ebp, esp + + ; loading 1 sector from 0x10000 -> + ; to see if we have a valid kernel at disk. + mov eax, kernel_entry_address + mov kernel_sector_count 1 + mov bl, boot_device_db + mov cl, 1 + call load_sectors + + mov eax, 0x10000 + call search_kernel_header + + mov esp, ebp + pop ebp + ret + +; =========================================================================== ; +; Helper functions for kernel loading process. ; +; =========================================================================== ; + +; Function to load N amount of sectors starting from +; address X at device Y +; +; Initial address at EAX +; Boot device at bl +; Sector count at cl +load_sectors: + push ebp + mov ebp, esp + + mov dh, cl ; Sector count + mov byte [.sectors_to_load], cl + mov dl, bl ; boot device + mov byte [.boot_device], bl + + mov ebx, eax ; initial address + mov byte [.sectors_left], cl + xor ch, ch + xor dh, dh + mov cl, 0x02 + xor eax, eax + .read_start: + mov di, 5 + .read: + mov ah, 0x02 + mov al, [.sectors_left] + int 0x13 + jc .retry + sub [.sectors_left], al + jz .read_done + mov cl, 0x01 + xor dh, 1 + jnz .read_start + inc ch, 1 + jmp .read_start + .retry: + ; reset disk + xor ah, ah + int 0x13 + dec di + jnz .read + mov esi, msg_disk_read_failed + call panic + .read_done: + mov esp, ebp + pop ebp + ret + + .sectors_to_load db 0 + .boot_device db 0 + .sectors_left db 0 + + +; Function to find kernel header. +; kernel entrypoint address at EAX +; Returns: +; code entry: EAX +; sector count: EBX +search_kernel_header: + push ebp + mov ebp, esp + + xor ecx, ecx + xor edx, edx + mov esi, kernel_entry_signature + .search_loop: + inc ecx + cmp ecx, 0xff + jge .not_found + mov edx, dword [eax + ecx] + cmp edx, dword [esi] + jne .search_loop + + ; we found the header :) + add ecx, 8 ; stepping over kenrel_entry_signature. + + + mov esp, ebp + pop ebp + ret + +%endif + diff --git a/src/main_loader/kernel_loader.s b/src/main_loader/kernel_loader.s @@ -1,67 +0,0 @@ -; ========================================================================== ; -; /src/kernel_loader.s ; -; Copyright (c) 2018, k4m1 <k4m1@protonmail.com> ; -; All rights reserved. ; -; See /LICENSE for further copyright information. ; -; ; -; This file contains code responsible for rest of the loading process. ; -; At this point, usage of A20 line has been enabled, we've loaded a little ; -; GDT, swapped to 32-bit protected mode, and saved Real mode Data segment & ; -; Boot device to: ; -; BOOT_DEV_DB ; -; REALMODE_DB ; -; ========================================================================== ; - -%ifndef KERNEL_LOADER_S -%define KERNEL_LOADER_S 1 - -%define V8086_MODE_ON 1 -%define V8086_MODE_OFF 0 - -[ BITS 32 ] -; ========================================================================== ; -; The main function of this file. All rest of the functions are called from ; -; this function. ; -; Referring to cs.emu.edu(1), many of bootloaders do achieve ; -; high-memory disk read by constantly swapping between 16 and 32 bit mode. ; -; The constant swaps allows us to use both BIOS interrupts, and 32-bit ; -; addressing. ; -; ========================================================================== ; -kernel_loader: - push ebp - mov ebp, esp - - cli - hlt - - mov esp, ebp - pop ebp - -; ========================================================================== ; -; The memory area reserved for different sort of variables we'll use between ; -; 16 and 32 bit modes. ; -; ========================================================================== ; -KERNEL_LOCATION dw 0 -KERNEL_SIZE dw 0 -KERNEL_ENTRY dw 0 -SECTORS_LOADED db 0 -MULTIBOOT_LOCATION dw 0 -RUNMODE db 0 ; v8086 MODE - -; ========================================================================== ; -; Functions used by kernel_loader for different purposes. ; -; Helper functions for these functions can be found belowe these. ; -; NOTE: Define bitness for every function belove this line! ; -; ========================================================================== ; - - - -; ========================================================================== ; -; Helper functions for kernel loading process. ; -; ========================================================================== ; - - -times SECTOR_COUNT * 1024 - ($-$$) db 0 - -%endif -