diff --git a/build.i686 b/build.i686 index 86ad1b0..a5da0ae 100755 --- a/build.i686 +++ b/build.i686 @@ -39,26 +39,28 @@ case $yn in echo ---------------- sudo losetup -d /dev/loop900 - dd if=/dev/zero of=build/main.img bs=512 count=50000 + dd if=/dev/zero of=build/main.img bs=512 count=2880 mkdir -p build/mnt sudo losetup -P /dev/loop900 build/main.img - sudo parted /dev/loop900 mktable msdos - sudo parted /dev/loop900 mkpart primary fat16 2048s 100% - sudo parted /dev/loop900p1 set 1 boot on - sudo mkfs.fat -F16 /dev/loop900p1 - sudo mount /dev/loop900p1 build/mnt + sudo mkfs.fat -F12 /dev/loop900 + sudo mount /dev/loop900 build/mnt sudo mkdir build/mnt/boot sudo mkdir build/mnt/boot/grub sudo mkdir build/mnt/misc sudo mkdir build/mnt/misc/src - sudo cp -r src/* build/mnt/src + sudo cp -r src/* build/mnt/misc/src sudo cp -r grub/* build/mnt/boot/grub sudo cp build/nanite.bin build/mnt/boot/nanite sudo grub-install \ - --install-modules="part_msdos gettext all_video gfxterm png normal echo multiboot2" \ + --install-modules="part_msdos normal echo multiboot2 ls" \ + --locales=en@quot \ + --fonts=none \ + --themes=none \ --boot-directory=build/mnt/boot \ --target=i386-pc \ --bootloader-id=GRUB \ + --allow-floppy \ + --force \ /dev/loop900 -v sudo umount build/mnt sudo losetup -d /dev/loop900 @@ -86,8 +88,11 @@ case $yn in -serial chardev:serial1 \ -audiodev pa,id=speaker \ -machine pcspk-audiodev=speaker \ - -hda build/main.img \ - -m size=16M + -fda build/main.img \ + -m size=4M \ + -vga std \ + -cpu 486-v1 \ + -name Nanite echo -------- echo Finshed! echo -------- diff --git a/doc/Bootloader.md b/doc/Bootloader.md new file mode 100644 index 0000000..169bf6f --- /dev/null +++ b/doc/Bootloader.md @@ -0,0 +1,13 @@ +# Bootloader + +Nanite has support for a couple of loaders, including GRUB2 and anything supporting the multiboot2 standard +Nanite ALSO has its own custom bootloader called NBOOT, while temporarily abandoned between 2025-2026 its being re-written from scratch. + +## GRUB + +Grub's support is... mixed? its fairly buggy as it falls back on BIOS memory detection (since i can't seem to get multiboot2's mem info block to work...) +Its very Useful for testing tho + +## NBOOT + +NBOOT is, experimental and unfinished, looking at it wrong would likely break it. \ No newline at end of file diff --git a/grub/grub.cfg b/grub/grub.cfg index eef97ed..a024385 100644 --- a/grub/grub.cfg +++ b/grub/grub.cfg @@ -3,26 +3,15 @@ set default=0 set pager=1 insmod part_msdos -set root='hd0,1' +set root='fd0' set gfxmode=800x600 -insmod all_video set locale_dir=$prefix/locale -set lang=en_CA -insmod gettext terminal_input console -insmod gfxmenu -# loadfont /boot/grub/themes/nanite/font10.pf2 -# loadfont /boot/grub/themes/nanite/font12.pf2 -# loadfont /boot/grub/themes/nanite/font14.pf2 -# set theme=/boot/grub/themes/nanite/theme.txt -# export theme -insmod png - menuentry "NANITE" { - set root='hd0,1' + set root='fd0' insmod fat multiboot2 /boot/nanite echo "Booting NANITE..." diff --git a/grub/themes/nanite/background.png b/grub/themes/nanite/background.png deleted file mode 100644 index 6d07fa1..0000000 Binary files a/grub/themes/nanite/background.png and /dev/null differ diff --git a/grub/themes/nanite/font10.pf2 b/grub/themes/nanite/font10.pf2 deleted file mode 100644 index 0a5c9f2..0000000 Binary files a/grub/themes/nanite/font10.pf2 and /dev/null differ diff --git a/grub/themes/nanite/font12.pf2 b/grub/themes/nanite/font12.pf2 deleted file mode 100644 index 945679e..0000000 Binary files a/grub/themes/nanite/font12.pf2 and /dev/null differ diff --git a/grub/themes/nanite/font14.pf2 b/grub/themes/nanite/font14.pf2 deleted file mode 100644 index 5cfacc4..0000000 Binary files a/grub/themes/nanite/font14.pf2 and /dev/null differ diff --git a/grub/themes/nanite/theme.txt b/grub/themes/nanite/theme.txt deleted file mode 100644 index 659e9e4..0000000 --- a/grub/themes/nanite/theme.txt +++ /dev/null @@ -1,40 +0,0 @@ -# Nanite GRUB 2 Theme - -message-font: "DEFCON Regular 14" -message-color: "#FFF" -terminal-font: "DEFCON Regular 12" -desktop-image: "background.png" -desktop-image-scale-method: "crop" - - -#boot menu -+ boot_menu { - left = 10% - width = 80% - top = 20% - height = 50% - item_font = "DEFCON Regular 12" - item_color = "#fff" - selected_item_font = "DEFCON Regular 14" - selected_item_color= "#f0f" - icon_height = 25 - icon_width = 25 - item_height = 26 - item_padding = 0 - item_icon_space = 0 - item_spacing = 1 - scrollbar = true - scrollbar_width = 20 -} - -+ label { - top = 100%-25 - left = 0 - width = 100% - height = 20 - text = "@KEYMAP_MIDDLE@" - align = "center" - font = "DEFCON Regular 10" - color = "#FFF" - bg_color = "#000" -} \ No newline at end of file diff --git a/src/kernel/arch/i686/multiboot.asm b/src/kernel/arch/i686/multiboot.asm index ccf9ee3..019a1cd 100644 --- a/src/kernel/arch/i686/multiboot.asm +++ b/src/kernel/arch/i686/multiboot.asm @@ -20,18 +20,6 @@ align 4 %endmacro -section .boot -extern start -global _start -_start: - push 0 - popf - push ebx - push eax - call start - cli - hlt - section .multiboot header_start: dd 0xe85250d6 ; magic number diff --git a/src/kernel/dri/keyboard.c b/src/kernel/dri/keyboard.c index 6d11b9a..b313203 100644 --- a/src/kernel/dri/keyboard.c +++ b/src/kernel/dri/keyboard.c @@ -157,8 +157,8 @@ char kscan() { case KEYBOARD_LAYOUT_8: _keyboard_scancode = 0; return '8'; case KEYBOARD_LAYOUT_9: _keyboard_scancode = 0; return '9'; case KEYBOARD_LAYOUT_0: _keyboard_scancode = 0; return '0'; - case KEYBOARD_LAYOUT_OEM_MI: _keyboard_scancode = 0; return '-'; - case KEYBOARD_LAYOUT_OEM_PL: _keyboard_scancode = 0; return '='; + case KEYBOARD_LAYOUT_OEM_MI: _keyboard_scancode = 0; if(_shift == true) return '_'; else return '-'; + case KEYBOARD_LAYOUT_OEM_PL: _keyboard_scancode = 0; if(_shift == true) return '+'; else return '='; case KEYBOARD_LAYOUT_BACK: _keyboard_scancode = 0; return '\b'; case KEYBOARD_LAYOUT_TAB: _keyboard_scancode = 0; return '\t'; case KEYBOARD_LAYOUT_Q: _keyboard_scancode = 0; return 'Q'; @@ -173,7 +173,7 @@ char kscan() { case KEYBOARD_LAYOUT_P: _keyboard_scancode = 0; return 'P'; case KEYBOARD_LAYOUT_OEM_4: _keyboard_scancode = 0; return '['; case KEYBOARD_LAYOUT_OEM_6: _keyboard_scancode = 0; return ']'; - case KEYBOARD_LAYOUT_OEM_5: _keyboard_scancode = 0; return '\\'; + case KEYBOARD_LAYOUT_OEM_5: _keyboard_scancode = 0; if(_shift == true) return '|'; else return '\\'; case KEYBOARD_LAYOUT_A: _keyboard_scancode = 0; return 'A'; case KEYBOARD_LAYOUT_S: _keyboard_scancode = 0; return 'S'; case KEYBOARD_LAYOUT_D: _keyboard_scancode = 0; return 'D'; @@ -183,7 +183,7 @@ char kscan() { case KEYBOARD_LAYOUT_J: _keyboard_scancode = 0; return 'J'; case KEYBOARD_LAYOUT_K: _keyboard_scancode = 0; return 'K'; case KEYBOARD_LAYOUT_L: _keyboard_scancode = 0; return 'L'; - case KEYBOARD_LAYOUT_OEM_1: _keyboard_scancode = 0; return ';'; + case KEYBOARD_LAYOUT_OEM_1: _keyboard_scancode = 0; if(_shift == true) return ':'; else return ';'; case KEYBOARD_LAYOUT_OEM_7: _keyboard_scancode = 0; return '\''; case KEYBOARD_LAYOUT_RETURN: _keyboard_scancode = 0; return '\n'; case KEYBOARD_LAYOUT_Z: _keyboard_scancode = 0; return 'Z'; diff --git a/src/kernel/linker.ld b/src/kernel/linker.ld index 6022929..d569113 100644 --- a/src/kernel/linker.ld +++ b/src/kernel/linker.ld @@ -1,11 +1,10 @@ -ENTRY(_start) +ENTRY(start) SECTIONS { .multiboot : { __multiboot_start = .; *(.multiboot)} .notes : { __notes_start = .; *(.notes) } - .boot : { __boot_start = .; *(.boot) } - .entry : { __entry_start = .; *(.entry) } + .entry : { __entry_start = .; *(.entry) } .text : { __text_start = .; *(.text) } .data : { __data_start = .; *(.data) } .rodata : { __rodata_start = .; *(.rodata*) } diff --git a/src/kernel/main.c b/src/kernel/main.c index 8bd8213..0b5819d 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -48,8 +48,6 @@ // Utilities -#include -#include #include // Other @@ -67,7 +65,7 @@ extern int uptime; // System uptime measured by precision timer unit. uint16_t DEBUG_COM_PORT = COM1_PORT; // COM Port to Output Debug strings to /*Main Kernel Function*/ -void start(unsigned long magic, unsigned long address) { +void __attribute__((section(".entry"))) start(unsigned long magic, unsigned long address) { struct multiboot_tag* tag; @@ -121,7 +119,6 @@ void start(unsigned long magic, unsigned long address) { // Hardware Detection Serial_Printf(DEBUG_COM_PORT, "MEMORY:> There is %dKB of Memory Available\nThe Kernel is loaded between 0x%x and 0x%x\n", Detect_Memory(), __bss_start, __end); printf("%dKB Of Memory Availible!\n", Detect_Memory()); - // printf("Random Number! %u\n", rand()); // Serial_Printf(DEBUG_COM_PORT, "CPU Vendor: %s\n", CPUID_Get_Vendor()); // CPUID Stuff is pain and suffering, like page faults and suffering @@ -144,16 +141,17 @@ void start(unsigned long magic, unsigned long address) { printf("Would you like to change the time and date? [y/N] "); scanf("%s", answer); if (!strcmp(answer, "Y") || !strcmp(answer, "y")) { - printf("Please insert Date and Time in [SS]:[MM]:[HH] [DD]/[MM]/[YYYY] Format: "); + printf("Please insert Date and Time in [SS]:[MM]:[HH] [DD]/[MM]/[YYYY] Format:\n"); scanf("%s", answer); printf("\n"); } printf("Starting Shell..."); - spinner(20); + spinner(20); // yes. i fake the loading, i think its funny cope printf("Done!\n"); for(;;) { + char* input; printf(":>"); - scanf(""); + scanf("%s", input); } end: diff --git a/src/kernel/stdio.c b/src/kernel/stdio.c index f712238..ac381e0 100644 --- a/src/kernel/stdio.c +++ b/src/kernel/stdio.c @@ -404,7 +404,9 @@ int scanf(const char* fmt, ...) { switch (character) { case '\n': printf("\n"); return 0; - case '\b': printf("\b "); + case '\t': printf(" "); + break; + case '\b': printf("\b "); // keep here lmao. default: if(character != 0) { if(_shift == true) { printf("%c", character); @@ -424,10 +426,9 @@ int scanf(const char* fmt, ...) { case '\n': printf("\n"); *va_arg(args, char*) = *buffer; return 0; - case '\b': printf("\b"); i--; buffer[i] = '\0'; - break; case '\t': printf(" "); break; + case '\b': printf("\b "); buffer[i] = '\0'; i--; default: if(character != 0) { if(_shift == true) { printf("%c", character); diff --git a/src/kernel/util/binary.c b/src/kernel/util/binary.c index 9d352b7..61b84aa 100644 --- a/src/kernel/util/binary.c +++ b/src/kernel/util/binary.c @@ -10,11 +10,3 @@ uint8_t Get_Bit(uint8_t bits, uint8_t pos) { return (bits >> pos) & 0x01; } - -// int Byte_Parse(int8_t byteFlag, int whichBit) -// { -// if (whichBit > 0 && whichBit <= 8) -// return (byteFlag & (1<<(whichBit-1))); -// else -// return 0; -// } \ No newline at end of file diff --git a/src/kernel/util/binary.h b/src/kernel/util/binary.h index 3404755..fe631a8 100644 --- a/src/kernel/util/binary.h +++ b/src/kernel/util/binary.h @@ -12,5 +12,3 @@ #define BCD2BIN(bcd) ((((bcd)&15) + ((bcd)>>4)*10)) // Takes value in `bcd` and outputs it as binary uint8_t Get_Bit(uint8_t bits, uint8_t pos); - -//int Byte_Parse(int8_t byteFlag, int whichBit); \ No newline at end of file diff --git a/src/kernel/util/param.c b/src/kernel/util/param.c deleted file mode 100644 index 9b3addd..0000000 --- a/src/kernel/util/param.c +++ /dev/null @@ -1,14 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2026| -|Xircon | -\*----------------*/ -#include "param.h" - -#include - -int paramloader(char filename) { - printf("Sorry! This is not currently implemented, Need to Make disk calls and kinda uhm... forgot? i didn't before soooooo YEP!"); - printf("And heres yer filename: %s", filename); - return 0; -} \ No newline at end of file diff --git a/src/kernel/util/param.h b/src/kernel/util/param.h deleted file mode 100644 index 556e236..0000000 --- a/src/kernel/util/param.h +++ /dev/null @@ -1,8 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2026| -|Xircon | -\*----------------*/ -#pragma once - -int paramloader(char filename); \ No newline at end of file diff --git a/src/kernel/util/util.c b/src/kernel/util/util.c deleted file mode 100644 index 8958f95..0000000 --- a/src/kernel/util/util.c +++ /dev/null @@ -1,40 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2026| -|Xircon | -\*----------------*/ -#include "util.h" - -#include - -int string_length(char s[]) { - int i = 0; - while (s[i] != '\0') { - ++i; - } - return i; -} - -void append(char s[], char n) { - int len = string_length(s); - s[len] = n; - s[len + 1] = '\0'; -} - -// void Print_Storage_Types(int masterFDDType, int slaveFDDType) -// { -// // Master FDD -// if (masterFDDType == 0) printf("No Master Floppy Drive Detected!\n"); -// if (masterFDDType == 1) printf("Master Floppy Drive Detected!\nType: 360 KB 5.25 Inch Drive\n"); -// if (masterFDDType == 2) printf("Master Floppy Drive Detected!\nType: 1.2 MB 5.25 Inch Drive\n"); -// if (masterFDDType == 3) printf("Master Floppy Drive Detected!\nType: 720 KB 3.5 Inch Drive\n"); -// if (masterFDDType == 4) printf("Master Floppy Drive Detected!\nType: 1.44 MB 3.5 Inch Drive\n"); -// if (masterFDDType == 5) printf("Master Floppy Drive Detected!\nType: 2.88 MB 3.5 Inch Drive\n"); -// // Slave FDD -// if (slaveFDDType == 0) printf("No Slave Floppy Drive Detected!\n"); -// if (slaveFDDType == 1) printf("Slave Floppy Drive Detected!\nType: 360 KB 5.25 Inch Drive\n"); -// if (slaveFDDType == 2) printf("Slave Floppy Drive Detected!\nType: 1.2 MB 5.25 Inch Drive\n"); -// if (slaveFDDType == 3) printf("Slave Floppy Drive Detected!\nType: 720 KB 3.5 Inch Drive\n"); -// if (slaveFDDType == 4) printf("Slave Floppy Drive Detected!\nType: 1.44 MB 3.5 Inch Drive\n"); -// if (slaveFDDType == 5) printf("Slave Floppy Drive Detected!\nType: 2.88 MB 3.5 Inch Drive\n"); -// } \ No newline at end of file diff --git a/src/kernel/util/util.h b/src/kernel/util/util.h deleted file mode 100644 index e1fbf74..0000000 --- a/src/kernel/util/util.h +++ /dev/null @@ -1,12 +0,0 @@ -/*----------------*\ -|Nanite OS | -|Copyright (C) 2026| -|Xircon | -\*----------------*/ -#pragma once - -#define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n))) - -int string_length(char s[]); -void append(char s[], char n); -// void Print_Storage_Types(int masterFDDType, int slaveFDDType); \ No newline at end of file diff --git a/src/kernel/version.h b/src/kernel/version.h index 44ba131..544f8cd 100644 --- a/src/kernel/version.h +++ b/src/kernel/version.h @@ -6,6 +6,6 @@ #pragma once #define LOGO " _ _____ _ __________________\n / | / / | / | / / _/_ __/ ____/\n / |/ / /| | / |/ // / / / / __/ \n / /| / ___ |/ /| // / / / / /___ \n/_/ |_/_/ |_/_/ |_/___/ /_/ /_____/" // Nanite's Logo as a formatted string -#define VERSION "RD-00128" // Current Version of Nanite +#define VERSION "RD-00132" // Current Version of Nanite #define BOOTLOGO " _ ______ ____ ____ ______\n / | / / __ )/ __ \\/ __ /_ __/\n / |/ / __ / / / / / / // / \n / /| / /_/ / /_/ / /_/ // / \n/_/ |_/_____/\\____/\\____//_/ \n" // Old bootloader logo // one day i will re-implement NBOOT V 2 diff --git a/src/nboot/bootsector/Makefile b/src/nboot/bootsector/Makefile new file mode 100644 index 0000000..34d41e7 --- /dev/null +++ b/src/nboot/bootsector/Makefile @@ -0,0 +1,14 @@ +BUILD_DIR?=build/ +TARGET_ASMFLAGS += -f bin + +.PHONY: all clean + +all: bootsector + +bootsector: $(BUILD_DIR)/bootsector.bin + +$(BUILD_DIR)/bootsector.bin: + $(TARGET_ASM) bootsector.asm $(TARGET_ASMFLAGS) -o $(BUILD_DIR)/bootsector.bin + +clean: + rm -f $(BUILD_DIR)/bootsector.bin \ No newline at end of file diff --git a/src/nboot/bootsector/bootsector.asm b/src/nboot/bootsector/bootsector.asm new file mode 100644 index 0000000..02eafa8 --- /dev/null +++ b/src/nboot/bootsector/bootsector.asm @@ -0,0 +1,396 @@ +;/////////////////////; +;NBOOT ; +;COPYRIGHT (C) 2026 ; +;Xircon ; +;/////////////////////; +org 0x7C00 +[bits 16] + + +%define ENDL 0x0D, 0x0A + + +; +; FAT12 header +; +jmp short start +nop + +bdb_oem: db 'MSWIN4.1' ; 8 bytes +bdb_bytes_per_sector: dw 512 +bdb_sectors_per_cluster: db 1 +bdb_reserved_sectors: dw 1 +bdb_fat_count: db 2 +bdb_dir_entries_count: dw 0E0h +bdb_total_sectors: dw 2880 ; 2880 * 512 = 1.44MB +bdb_media_descriptor_type: db 0F0h ; F0 = 3.5" floppy disk +bdb_sectors_per_fat: dw 9 ; 9 sectors/fat +bdb_sectors_per_track: dw 18 +bdb_heads: dw 2 +bdb_hidden_sectors: dd 0 +bdb_large_sector_count: dd 0 + +; extended boot record +ebr_drive_number: db 0 ; 0x00 floppy, 0x80 hdd, useless + db 0 ; reserved +ebr_signature: db 29h +ebr_volume_id: db 12h, 34h, 56h, 78h ; serial number, value doesn't matter +ebr_volume_label: db 'NANITE ' ; 11 bytes, padded with spaces +ebr_system_id: db 'FAT12 ' ; 8 bytes + +; +; Code goes here +; + +start: + ; setup data segments + mov ax, 0 ; can't set ds/es directly + mov ds, ax + mov es, ax + + ; setup stack + mov ss, ax + mov sp, 0x7C00 ; stack grows downwards from where we are loaded in memory + + ; some BIOSes might start us at 07C0:0000 instead of 0000:7C00, make sure we are in the + ; expected location + push es + push word .after + retf + +.after: + + ; read something from floppy disk + ; BIOS should set DL to drive number + mov [ebr_drive_number], dl + + ; show loading message + mov si, msg_loading + call puts + + ; read drive parameters (sectors per track and head count), + ; instead of relying on data on formatted disk + push es + mov ah, 08h + int 13h + jc error + pop es + + and cl, 0x3F ; remove top 2 bits + xor ch, ch + mov [bdb_sectors_per_track], cx ; sector count + + inc dh + mov [bdb_heads], dh ; head count + + ; compute LBA of root directory = reserved + fats * sectors_per_fat + ; note: this section can be hardcoded + mov ax, [bdb_sectors_per_fat] + mov bl, [bdb_fat_count] + xor bh, bh + mul bx ; ax = (fats * sectors_per_fat) + add ax, [bdb_reserved_sectors] ; ax = LBA of root directory + push ax + + ; compute size of root directory = (32 * number_of_entries) / bytes_per_sector + mov ax, [bdb_dir_entries_count] + shl ax, 5 ; ax *= 32 + xor dx, dx ; dx = 0 + div word [bdb_bytes_per_sector] ; number of sectors we need to read + + test dx, dx ; if dx != 0, add 1 + jz .root_dir_after + inc ax ; division remainder != 0, add 1 + ; this means we have a sector only partially filled with entries +.root_dir_after: + + ; read root directory + mov cl, al ; cl = number of sectors to read = size of root directory + pop ax ; ax = LBA of root directory + mov dl, [ebr_drive_number] ; dl = drive number (we saved it previously) + mov bx, buffer ; es:bx = buffer + call disk_read + + ; search for stage2 + xor bx, bx + mov di, buffer + +; .search_boot_dir: +; mov si, boot_dir +; mov cx, 11 ; compare up to 11 characters +; push di +; repe cmpsb +; pop di +; je .found_boot_dir + +; add di, 32 +; inc bx +; cmp bx, [bdb_dir_entries_count] +; jl .search_boot_dir + +; ; kernel not found +; jmp error + +; .found_boot_dir: +; hlt + +.search_stage2: + mov si, file_stage2_bin + mov cx, 11 ; compare up to 11 characters + push di + repe cmpsb + pop di + je .found_stage2 + + add di, 32 + inc bx + cmp bx, [bdb_dir_entries_count] + jl .search_stage2 + + ; kernel not found + jmp error + +.found_stage2: + + ; di should have the address to the entry + mov ax, [di + 26] ; first logical cluster field (offset 26) + mov [stage2_cluster], ax + + ; load FAT from disk into memory + mov ax, [bdb_reserved_sectors] + mov bx, buffer + mov cl, [bdb_sectors_per_fat] + mov dl, [ebr_drive_number] + call disk_read + + ; read kernel and process FAT chain + mov bx, STAGE2_LOAD_SEGMENT + mov es, bx + mov bx, STAGE2_LOAD_OFFSET + +.load_stage2_loop: + + ; Read next cluster + mov ax, [stage2_cluster] + + ; not nice :( hardcoded value + add ax, 31 ; first cluster = (kernel_cluster - 2) * sectors_per_cluster + start_sector + ; start sector = reserved + fats + root directory size = 1 + 18 + 134 = 33 + mov cl, 1 + mov dl, [ebr_drive_number] + call disk_read + + add bx, [bdb_bytes_per_sector] + + ; compute location of next cluster + mov ax, [stage2_cluster] + mov cx, 3 + mul cx + mov cx, 2 + div cx ; ax = index of entry in FAT, dx = cluster mod 2 + + mov si, buffer + add si, ax + mov ax, [ds:si] ; read entry from FAT table at index ax + + or dx, dx + jz .even + +.odd: + shr ax, 4 + jmp .next_cluster_after + +.even: + and ax, 0x0FFF + +.next_cluster_after: + cmp ax, 0x0FF8 ; end of chain + jae .read_finish + + mov [stage2_cluster], ax + jmp .load_stage2_loop + +.read_finish: + + ; jump to our kernel + mov dl, [ebr_drive_number] ; boot device in dl + + mov ax, STAGE2_LOAD_SEGMENT ; set segment registers + mov ds, ax + mov es, ax + + jmp STAGE2_LOAD_SEGMENT:STAGE2_LOAD_OFFSET + + jmp wait_key_and_reboot ; should never happen + + cli ; disable interrupts, this way CPU can't get out of "halt" state + hlt + + +; +; Error handler (i needed more room.) +; + +error: + mov si, msg_error + call puts + jmp wait_key_and_reboot + +wait_key_and_reboot: + mov ah, 0 + int 16h ; wait for keypress + jmp 0FFFFh:0 ; jump to beginning of BIOS, should reboot + +.halt: + cli ; disable interrupts, this way CPU can't get out of "halt" state + hlt + + +; +; Prints a string to the screen +; Params: +; - ds:si points to string +; +puts: + ; save registers we will modify + push si + push ax + push bx + +.loop: + lodsb ; loads next character in al + or al, al ; verify if next character is null? + jz .done + + mov ah, 0x0E ; call bios interrupt + mov bh, 0 ; set page number to 0 + int 0x10 + + jmp .loop + +.done: + pop bx + pop ax + pop si + ret + +; +; Disk routines +; + +; +; Converts an LBA address to a CHS address +; Parameters: +; - ax: LBA address +; Returns: +; - cx [bits 0-5]: sector number +; - cx [bits 6-15]: cylinder +; - dh: head +; + +lba_to_chs: + + push ax + push dx + + xor dx, dx ; dx = 0 + div word [bdb_sectors_per_track] ; ax = LBA / SectorsPerTrack + ; dx = LBA % SectorsPerTrack + + inc dx ; dx = (LBA % SectorsPerTrack + 1) = sector + mov cx, dx ; cx = sector + + xor dx, dx ; dx = 0 + div word [bdb_heads] ; ax = (LBA / SectorsPerTrack) / Heads = cylinder + ; dx = (LBA / SectorsPerTrack) % Heads = head + mov dh, dl ; dh = head + mov ch, al ; ch = cylinder (lower 8 bits) + shl ah, 6 + or cl, ah ; put upper 2 bits of cylinder in CL + + pop ax + mov dl, al ; restore DL + pop ax + ret + + +; +; Reads sectors from a disk +; Parameters: +; - ax: LBA address +; - cl: number of sectors to read (up to 128) +; - dl: drive number +; - es:bx: memory address where to store read data +; +disk_read: + + push ax ; save registers we will modify + push bx + push cx + push dx + push di + + push cx ; temporarily save CL (number of sectors to read) + call lba_to_chs ; compute CHS + pop ax ; AL = number of sectors to read + + mov ah, 02h + mov di, 3 ; retry count + +.retry: + pusha ; save all registers, we don't know what bios modifies + stc ; set carry flag, some BIOS'es don't set it + int 13h ; carry flag cleared = success + jnc .done ; jump if carry not set + + ; read failed + popa + call disk_reset + + dec di + test di, di + jnz .retry + +.fail: + ; all attempts are exhausted + jmp error + +.done: + popa + + pop di + pop dx + pop cx + pop bx + pop ax ; restore registers modified + ret + + +; +; Resets disk controller +; Parameters: +; dl: drive number +; +disk_reset: + pusha + mov ah, 0 + stc + int 13h + jc error + popa + ret + + +msg_loading: db 'Loading NBOOT...', ENDL, 0 +msg_error: db 'ERR!', ENDL, 0 +file_stage2_bin: db 'NBOOT BIN' +boot_dir: db 'BOOT ' +stage2_cluster: dw 0 + +STAGE2_LOAD_SEGMENT equ 0x0 +STAGE2_LOAD_OFFSET equ 0x500 + +times 510-($-$$) db 0 +dw 0AA55h + +buffer: diff --git a/src/nboot/stage2/Makefile b/src/nboot/stage2/Makefile new file mode 100644 index 0000000..4c04c47 --- /dev/null +++ b/src/nboot/stage2/Makefile @@ -0,0 +1,44 @@ +TARGET_ASMFLAGS += -f elf +TARGET_CFLAGS += -ffreestanding -nostdlib -I. +TARGET_LIBS += -lgcc +TARGET_LINKFLAGS += -T linker.ld -nostdlib + +HEADERS_C = $(wildcard *.h) \ + $(wildcard */*.h) \ + $(wildcard */*/*.h) \ + $(wildcard */*/*/*.h) \ + +SOURCES_C = $(wildcard *.c) \ + $(wildcard */*.c) \ + $(wildcard */*/*.c) \ + $(wildcard */*/*/*.c) \ + +OBJECTS_C = $(patsubst %.c, $(BUILD_DIR)/nboot/c/%.obj, $(SOURCES_C)) + +HEADERS_ASM = $(wildcard *.inc) +SOURCES_ASM = $(wildcard *.asm) + +OBJECTS_ASM = $(patsubst %.asm, $(BUILD_DIR)/nboot/asm/%.obj, $(SOURCES_ASM)) + +.PHONY: all nboot clean always + +all: nboot + +nboot: $(BUILD_DIR)/nboot.bin + +$(BUILD_DIR)/nboot.bin: $(OBJECTS_ASM) $(OBJECTS_C) + @$(TARGET_LD) $(TARGET_LINKFLAGS) -Wl,-Map=$(BUILD_DIR)/kernel.map -o $@ $^ $(TARGET_LIBS) + @echo "--> Created: nboot.bin" + +$(BUILD_DIR)/nboot/c/%.obj: %.c $(HEADERS_C) + @mkdir -p $(@D) + @$(TARGET_CC) $(TARGET_CFLAGS) -c -o $@ $< + @echo "--> Compiled: " $< + +$(BUILD_DIR)/nboot/asm/%.obj: %.asm $(HEADERS_ASM) + @mkdir -p $(@D) + @$(TARGET_ASM) $(TARGET_ASMFLAGS) -o $@ $< + @echo "--> Compiled: " $< + +clean: + rm -f $(BUILD_DIR)/nboot.bin \ No newline at end of file diff --git a/src/nboot/stage2/entry.asm b/src/nboot/stage2/entry.asm new file mode 100644 index 0000000..d609419 --- /dev/null +++ b/src/nboot/stage2/entry.asm @@ -0,0 +1,175 @@ +;/////////////////////; +;NBOOT ; +;COPYRIGHT (C) 2026 ; +;Xircon ; +;/////////////////////; +[bits 16] + +section .entry + +extern __bss_start +extern __end + +extern start +global entry + +entry: + cli + + ; save boot drive + mov [g_BootDrive], dl + + ; setup stack + mov ax, ds + mov ss, ax + mov sp, 0xFFF0 + mov bp, sp + + ; switch to PMODE + call EnableA20 + call LoadGDT + + ; set PMODE enable flag in CR0 + mov eax, CR0 + or al, 1 + mov cr0, eax + + ; far jmp into PMODE + jmp dword 08h:.pmode + +.pmode: + ; we are now in protected mode! + [bits 32] + + ; 6 - setup segment registers + mov ax, 0x10 + mov ds, ax + mov ss, ax + mov al, 0 + cld + rep stosb + + ; clear BSS (uninit data) + mov edi, __bss_start + mov ecx, __end + sub ecx, edi + + + xor edx, edx + mov dl, [g_BootDrive] + push edx + call start + + cli + hlt + + + +EnableA20: + [bits 16] + ; disable keyboard + call A20WaitInput + mov al, KbdControllerDisableKeyboard + out KbdControllerCommandPort, al + + ; read control output port + call A20WaitInput + mov al, KbdControllerReadCtrlOutputPort + out KbdControllerCommandPort, al + + call A20WaitOutput + in al, KbdControllerDataPort + push eax + + ; write control output port + call A20WaitInput + mov al, KbdControllerWriteCtrlOutputPort + out KbdControllerCommandPort, al + + call A20WaitInput + pop eax + or al, 2 ; bit 2 = A20 bit + out KbdControllerDataPort, al + + ; enable keyboard + call A20WaitInput + mov al, KbdControllerEnableKeyboard + out KbdControllerCommandPort, al + + call A20WaitInput + ret + + +A20WaitInput: + [bits 16] + ; wait until status bit 2 (input buffer) is 0 + ; by reading from command port, we read status byte + in al, KbdControllerCommandPort + test al, 2 + jnz A20WaitInput + ret + +A20WaitOutput: + [bits 16] + ; wait until status bit 1 (output buffer) is 1 so it can be read + in al, KbdControllerCommandPort + test al, 1 + jz A20WaitOutput + ret + + +LoadGDT: + [bits 16] + lgdt [g_GDTDesc] + ret + + + +KbdControllerDataPort equ 0x60 +KbdControllerCommandPort equ 0x64 +KbdControllerDisableKeyboard equ 0xAD +KbdControllerEnableKeyboard equ 0xAE +KbdControllerReadCtrlOutputPort equ 0xD0 +KbdControllerWriteCtrlOutputPort equ 0xD1 + +ScreenBuffer equ 0xB8000 + +g_GDT: ; NULL descriptor + dq 0 + + ; 32-bit code segment + dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF for full 32-bit range + dw 0 ; base (bits 0-15) = 0x0 + db 0 ; base (bits 16-23) + db 10011010b ; access (present, ring 0, code segment, executable, direction 0, readable) + db 11001111b ; granularity (4k pages, 32-bit pmode) + limit (bits 16-19) + db 0 ; base high + + ; 32-bit data segment + dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF for full 32-bit range + dw 0 ; base (bits 0-15) = 0x0 + db 0 ; base (bits 16-23) + db 10010010b ; access (present, ring 0, data segment, executable, direction 0, writable) + db 11001111b ; granularity (4k pages, 32-bit pmode) + limit (bits 16-19) + db 0 ; base high + + ; 16-bit code segment + dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF + dw 0 ; base (bits 0-15) = 0x0 + db 0 ; base (bits 16-23) + db 10011010b ; access (present, ring 0, code segment, executable, direction 0, readable) + db 00001111b ; granularity (1b pages, 16-bit pmode) + limit (bits 16-19) + db 0 ; base high + + ; 16-bit data segment + dw 0FFFFh ; limit (bits 0-15) = 0xFFFFF + dw 0 ; base (bits 0-15) = 0x0 + db 0 ; base (bits 16-23) + db 10010010b ; access (present, ring 0, data segment, executable, direction 0, writable) + db 00001111b ; granularity (1b pages, 16-bit pmode) + limit (bits 16-19) + db 0 ; base high + +g_GDTDesc: dw g_GDTDesc - g_GDT - 1 ; limit = size of GDT + dd g_GDT ; address of GDT + +g_BootDrive: db 0 diff --git a/src/nboot/stage2/linker.ld b/src/nboot/stage2/linker.ld new file mode 100644 index 0000000..c6ba510 --- /dev/null +++ b/src/nboot/stage2/linker.ld @@ -0,0 +1,12 @@ +ENTRY(start) + +SECTIONS +{ + .entry : { __entry_start = .; *(.entry) } + .text : { __text_start = .; *(.text) } + .data : { __data_start = .; *(.data) } + .rodata : { __rodata_start = .; *(.rodata*) } + .bss : { __bss_start = .; *(.bss) } + + __end = .; +} \ No newline at end of file diff --git a/src/nboot/stage2/main.c b/src/nboot/stage2/main.c new file mode 100644 index 0000000..2f967e9 --- /dev/null +++ b/src/nboot/stage2/main.c @@ -0,0 +1,10 @@ +/*----------------*\ +|NBOOT | +|Copyright (C) 2026| +|Xircon | +\*----------------*/ +#include + +void __attribute__((section(".entry"))) start() { + +} \ No newline at end of file diff --git a/src/nboot/stage2/version.h b/src/nboot/stage2/version.h new file mode 100644 index 0000000..69746cf --- /dev/null +++ b/src/nboot/stage2/version.h @@ -0,0 +1,10 @@ +/*----------------*\ +|NBOOT | +|Copyright (C) 2026| +|Xircon | +\*----------------*/ +#pragma once + +#define VERSION "RD-00002" // Current Version of Nanite +#define LOGO " _ ______ ____ ____ ______\n / | / / __ )/ __ \\/ __ /_ __/\n / |/ / __ / / / / / / // / \n / /| / /_/ / /_/ / /_/ // / \n/_/ |_/_____/\\____/\\____//_/ \n" +// one day i will re-implement NBOOT V 2