Begin NBOOT V2, Cleanup old files

This commit is contained in:
Xircon 2026-05-06 21:20:59 -04:00
parent 843d3b6c0c
commit e1696b82e7
27 changed files with 707 additions and 177 deletions

View File

@ -39,26 +39,28 @@ case $yn in
echo ---------------- echo ----------------
sudo losetup -d /dev/loop900 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 mkdir -p build/mnt
sudo losetup -P /dev/loop900 build/main.img sudo losetup -P /dev/loop900 build/main.img
sudo parted /dev/loop900 mktable msdos sudo mkfs.fat -F12 /dev/loop900
sudo parted /dev/loop900 mkpart primary fat16 2048s 100% sudo mount /dev/loop900 build/mnt
sudo parted /dev/loop900p1 set 1 boot on
sudo mkfs.fat -F16 /dev/loop900p1
sudo mount /dev/loop900p1 build/mnt
sudo mkdir build/mnt/boot sudo mkdir build/mnt/boot
sudo mkdir build/mnt/boot/grub sudo mkdir build/mnt/boot/grub
sudo mkdir build/mnt/misc sudo mkdir build/mnt/misc
sudo mkdir build/mnt/misc/src 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 -r grub/* build/mnt/boot/grub
sudo cp build/nanite.bin build/mnt/boot/nanite sudo cp build/nanite.bin build/mnt/boot/nanite
sudo grub-install \ 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 \ --boot-directory=build/mnt/boot \
--target=i386-pc \ --target=i386-pc \
--bootloader-id=GRUB \ --bootloader-id=GRUB \
--allow-floppy \
--force \
/dev/loop900 -v /dev/loop900 -v
sudo umount build/mnt sudo umount build/mnt
sudo losetup -d /dev/loop900 sudo losetup -d /dev/loop900
@ -86,8 +88,11 @@ case $yn in
-serial chardev:serial1 \ -serial chardev:serial1 \
-audiodev pa,id=speaker \ -audiodev pa,id=speaker \
-machine pcspk-audiodev=speaker \ -machine pcspk-audiodev=speaker \
-hda build/main.img \ -fda build/main.img \
-m size=16M -m size=4M \
-vga std \
-cpu 486-v1 \
-name Nanite
echo -------- echo --------
echo Finshed! echo Finshed!
echo -------- echo --------

13
doc/Bootloader.md Normal file
View File

@ -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.

View File

@ -3,26 +3,15 @@ set default=0
set pager=1 set pager=1
insmod part_msdos insmod part_msdos
set root='hd0,1' set root='fd0'
set gfxmode=800x600 set gfxmode=800x600
insmod all_video
set locale_dir=$prefix/locale set locale_dir=$prefix/locale
set lang=en_CA
insmod gettext
terminal_input console 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" { menuentry "NANITE" {
set root='hd0,1' set root='fd0'
insmod fat insmod fat
multiboot2 /boot/nanite multiboot2 /boot/nanite
echo "Booting NANITE..." echo "Booting NANITE..."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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"
}

View File

@ -20,18 +20,6 @@
align 4 align 4
%endmacro %endmacro
section .boot
extern start
global _start
_start:
push 0
popf
push ebx
push eax
call start
cli
hlt
section .multiboot section .multiboot
header_start: header_start:
dd 0xe85250d6 ; magic number dd 0xe85250d6 ; magic number

View File

@ -157,8 +157,8 @@ char kscan() {
case KEYBOARD_LAYOUT_8: _keyboard_scancode = 0; return '8'; case KEYBOARD_LAYOUT_8: _keyboard_scancode = 0; return '8';
case KEYBOARD_LAYOUT_9: _keyboard_scancode = 0; return '9'; case KEYBOARD_LAYOUT_9: _keyboard_scancode = 0; return '9';
case KEYBOARD_LAYOUT_0: _keyboard_scancode = 0; return '0'; case KEYBOARD_LAYOUT_0: _keyboard_scancode = 0; return '0';
case KEYBOARD_LAYOUT_OEM_MI: _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; 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_BACK: _keyboard_scancode = 0; return '\b';
case KEYBOARD_LAYOUT_TAB: _keyboard_scancode = 0; return '\t'; case KEYBOARD_LAYOUT_TAB: _keyboard_scancode = 0; return '\t';
case KEYBOARD_LAYOUT_Q: _keyboard_scancode = 0; return 'Q'; 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_P: _keyboard_scancode = 0; return 'P';
case KEYBOARD_LAYOUT_OEM_4: _keyboard_scancode = 0; return '['; case KEYBOARD_LAYOUT_OEM_4: _keyboard_scancode = 0; return '[';
case KEYBOARD_LAYOUT_OEM_6: _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_A: _keyboard_scancode = 0; return 'A';
case KEYBOARD_LAYOUT_S: _keyboard_scancode = 0; return 'S'; case KEYBOARD_LAYOUT_S: _keyboard_scancode = 0; return 'S';
case KEYBOARD_LAYOUT_D: _keyboard_scancode = 0; return 'D'; 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_J: _keyboard_scancode = 0; return 'J';
case KEYBOARD_LAYOUT_K: _keyboard_scancode = 0; return 'K'; case KEYBOARD_LAYOUT_K: _keyboard_scancode = 0; return 'K';
case KEYBOARD_LAYOUT_L: _keyboard_scancode = 0; return 'L'; 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_OEM_7: _keyboard_scancode = 0; return '\'';
case KEYBOARD_LAYOUT_RETURN: _keyboard_scancode = 0; return '\n'; case KEYBOARD_LAYOUT_RETURN: _keyboard_scancode = 0; return '\n';
case KEYBOARD_LAYOUT_Z: _keyboard_scancode = 0; return 'Z'; case KEYBOARD_LAYOUT_Z: _keyboard_scancode = 0; return 'Z';

View File

@ -1,11 +1,10 @@
ENTRY(_start) ENTRY(start)
SECTIONS SECTIONS
{ {
.multiboot : { __multiboot_start = .; *(.multiboot)} .multiboot : { __multiboot_start = .; *(.multiboot)}
.notes : { __notes_start = .; *(.notes) } .notes : { __notes_start = .; *(.notes) }
.boot : { __boot_start = .; *(.boot) } .entry : { __entry_start = .; *(.entry) }
.entry : { __entry_start = .; *(.entry) }
.text : { __text_start = .; *(.text) } .text : { __text_start = .; *(.text) }
.data : { __data_start = .; *(.data) } .data : { __data_start = .; *(.data) }
.rodata : { __rodata_start = .; *(.rodata*) } .rodata : { __rodata_start = .; *(.rodata*) }

View File

@ -48,8 +48,6 @@
// Utilities // Utilities
#include <util/param.h>
#include <util/util.h>
#include <util/binary.h> #include <util/binary.h>
// Other // 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 uint16_t DEBUG_COM_PORT = COM1_PORT; // COM Port to Output Debug strings to
/*Main Kernel Function*/ /*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; struct multiboot_tag* tag;
@ -121,7 +119,6 @@ void start(unsigned long magic, unsigned long address) {
// Hardware Detection // 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); 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("%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 // 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] "); printf("Would you like to change the time and date? [y/N] ");
scanf("%s", answer); scanf("%s", answer);
if (!strcmp(answer, "Y") || !strcmp(answer, "y")) { 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); scanf("%s", answer);
printf("\n"); printf("\n");
} }
printf("Starting Shell..."); printf("Starting Shell...");
spinner(20); spinner(20); // yes. i fake the loading, i think its funny cope
printf("Done!\n"); printf("Done!\n");
for(;;) { for(;;) {
char* input;
printf(":>"); printf(":>");
scanf(""); scanf("%s", input);
} }
end: end:

View File

@ -404,7 +404,9 @@ int scanf(const char* fmt, ...) {
switch (character) { switch (character) {
case '\n': printf("\n"); case '\n': printf("\n");
return 0; return 0;
case '\b': printf("\b "); case '\t': printf(" ");
break;
case '\b': printf("\b "); // keep here lmao.
default: if(character != 0) { default: if(character != 0) {
if(_shift == true) { if(_shift == true) {
printf("%c", character); printf("%c", character);
@ -424,10 +426,9 @@ int scanf(const char* fmt, ...) {
case '\n': printf("\n"); case '\n': printf("\n");
*va_arg(args, char*) = *buffer; *va_arg(args, char*) = *buffer;
return 0; return 0;
case '\b': printf("\b"); i--; buffer[i] = '\0';
break;
case '\t': printf(" "); case '\t': printf(" ");
break; break;
case '\b': printf("\b "); buffer[i] = '\0'; i--;
default: if(character != 0) { default: if(character != 0) {
if(_shift == true) { if(_shift == true) {
printf("%c", character); printf("%c", character);

View File

@ -10,11 +10,3 @@ uint8_t Get_Bit(uint8_t bits, uint8_t pos)
{ {
return (bits >> pos) & 0x01; 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;
// }

View File

@ -12,5 +12,3 @@
#define BCD2BIN(bcd) ((((bcd)&15) + ((bcd)>>4)*10)) // Takes value in `bcd` and outputs it as binary #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); uint8_t Get_Bit(uint8_t bits, uint8_t pos);
//int Byte_Parse(int8_t byteFlag, int whichBit);

View File

@ -1,14 +0,0 @@
/*----------------*\
|Nanite OS |
|Copyright (C) 2026|
|Xircon |
\*----------------*/
#include "param.h"
#include <stdio.h>
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;
}

View File

@ -1,8 +0,0 @@
/*----------------*\
|Nanite OS |
|Copyright (C) 2026|
|Xircon |
\*----------------*/
#pragma once
int paramloader(char filename);

View File

@ -1,40 +0,0 @@
/*----------------*\
|Nanite OS |
|Copyright (C) 2026|
|Xircon |
\*----------------*/
#include "util.h"
#include <stdio.h>
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");
// }

View File

@ -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);

View File

@ -6,6 +6,6 @@
#pragma once #pragma once
#define LOGO " _ _____ _ __________________\n / | / / | / | / / _/_ __/ ____/\n / |/ / /| | / |/ // / / / / __/ \n / /| / ___ |/ /| // / / / / /___ \n/_/ |_/_/ |_/_/ |_/___/ /_/ /_____/" // Nanite's Logo as a formatted string #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 #define BOOTLOGO " _ ______ ____ ____ ______\n / | / / __ )/ __ \\/ __ /_ __/\n / |/ / __ / / / / / / // / \n / /| / /_/ / /_/ / /_/ // / \n/_/ |_/_____/\\____/\\____//_/ \n" // Old bootloader logo
// one day i will re-implement NBOOT V 2 // one day i will re-implement NBOOT V 2

View File

@ -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

View File

@ -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:

44
src/nboot/stage2/Makefile Normal file
View File

@ -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

175
src/nboot/stage2/entry.asm Normal file
View File

@ -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

View File

@ -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 = .;
}

10
src/nboot/stage2/main.c Normal file
View File

@ -0,0 +1,10 @@
/*----------------*\
|NBOOT |
|Copyright (C) 2026|
|Xircon |
\*----------------*/
#include <version.h>
void __attribute__((section(".entry"))) start() {
}

View File

@ -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