wrote a basic bootloader

This commit is contained in:
2025-02-25 01:14:52 +00:00
commit 012b0454ed
36 changed files with 1667 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
section .text.boot
extern stage2_main
extern STAGE2_SIZE
extern STAGE2_SECTORS
section .header
global _header_start
_header_start:
dd STAGE2_SIZE
dw STAGE2_SECTORS
db 0x55, 0xAA
global _start
[BITS 16]
_start:
mov ah, 0x00
mov al, 0x03
int 0x10
mov ah, 0x06
mov al, 0
mov bh, 0x07 ; normal attribute (white on black)
mov cx, 0 ; upper left = (0,0)
mov dx, 0x184F ; lower right = (24,79) - full screen
int 0x10
; print "loaded"
mov ax, 0xb800
mov ds, ax
mov byte [0], 'L'
mov byte [1], 0x07
mov byte [2], 'O'
mov byte [3], 0x07
mov byte [4], 'A'
mov byte [5], 0x07
mov byte [6], 'D'
mov byte [7], 0x07
mov byte [8], 'E'
mov byte [9], 0x07
mov byte [10], 'D'
mov byte [11], 0x07
; Set up stack
mov ax, 0x7000
mov ss, ax
mov sp, 0xFFFF
; Enable A20 line
in al, 0x92
or al, 2
out 0x92, al
; Load GDT and switch to protected mode
cli
lgdt [GDT.pointer]
mov eax, cr0
or eax, 1
mov cr0, eax
hlt
; Jump to 32-bit code
jmp GDT.code32:protected_mode
[BITS 32]
protected_mode:
; Set up segment registers
mov ax, GDT.data32
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Clear BSS section
mov edi, bss_start
mov ecx, bss_end
sub ecx, edi
xor eax, eax
rep stosb
; Call C code
call stage2_main
; Should never return
cli
hlt
section .rodata
GDT:
; Null descriptor
dq 0
.code32: equ $ - GDT
; 32-bit code segment
dw 0xFFFF ; Limit 0:15
dw 0x0000 ; Base 0:15
db 0x00 ; Base 16:23
db 0x9A ; Access byte - Code
db 0xCF ; Flags + Limit 16:19
db 0x00 ; Base 24:31
.data32: equ $ - GDT
; 32-bit data segment
dw 0xFFFF ; Limit 0:15
dw 0x0000 ; Base 0:15
db 0x00 ; Base 16:23
db 0x92 ; Access byte - Data
db 0xCF ; Flags + Limit 16:19
db 0x00 ; Base 24:31
.pointer:
dw $ - GDT - 1 ; Size
dd GDT ; Address
extern bss_start
extern bss_end
+78
View File
@@ -0,0 +1,78 @@
#include "stage2.h"
// Constants for page tables
#define PRESENT (1 << 0)
#define WRITABLE (1 << 1)
#define HUGE_PAGE (1 << 7)
// Page tables (must be aligned)
__attribute__((aligned(4096))) uint64_t pml4[512];
__attribute__((aligned(4096))) uint64_t pdpt[512];
__attribute__((aligned(4096))) uint64_t pd[512];
void enable_long_mode(void) {
// Zero out page tables
for (int i = 0; i < 512; i++) {
pml4[i] = 0;
pdpt[i] = 0;
pd[i] = 0;
}
// Set up identity mapping for first 1GB
pml4[0] = ((uint64_t)pdpt) | PRESENT | WRITABLE;
pdpt[0] = ((uint64_t)pd) | PRESENT | WRITABLE;
// Map 2MB pages for first 1GB
for (int i = 0; i < 512; i++) {
pd[i] = (i * 0x200000) | PRESENT | WRITABLE | HUGE_PAGE;
}
// Load PML4 into CR3
__asm__ volatile (
"mov %0, %%cr3"
:
: "r"(pml4)
: "memory"
);
// Enable PAE
__asm__ volatile (
"mov %%cr4, %%eax\n"
"or $0x20, %%eax\n"
"mov %%eax, %%cr4"
:
:
: "eax"
);
// Enable Long Mode in EFER
__asm__ volatile (
"mov $0xC0000080, %%ecx\n"
"rdmsr\n"
"or $0x100, %%eax\n"
"wrmsr"
:
:
: "eax", "ecx", "edx"
);
// Enable paging
__asm__ volatile (
"mov %%cr0, %%eax\n"
"or $0x80000000, %%eax\n"
"mov %%eax, %%cr0"
:
:
: "eax"
);
}
void stage2_main(void) {
// This is where we'll start in 32-bit mode
enable_long_mode();
// After long mode is enabled, we can load the kernel
// TODO: Add FAT32 code here
while(1) { }
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef STAGE2_H
#define STAGE2_H
// Type definitions
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
// Function declarations
void stage2_main(void);
void enable_long_mode(void);
// Assembly interface functions (defined in boot.s)
void load_gdt(void* gdt_ptr);
void load_idt(void* idt_ptr);
#endif /* STAGE2_H */
+37
View File
@@ -0,0 +1,37 @@
ENTRY(_start)
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0x8000; /* Stage2 loads here */
.header : {
*(.header*)
}
.text : {
*(.text.boot) /* Our assembly boot code first */
*(.text*) /* Then other text sections */
}
.rodata : {
*(.rodata*) /* Read-only data */
}
.data : {
*(.data*) /* Writable data */
}
.bss : {
bss_start = .;
*(.bss*) /* Zero-initialized data */
*(COMMON)
bss_end = .;
}
._end = .; /* Mark end of binary */
/* Calculate total size and sectors at the end */
STAGE2_SIZE = ABSOLUTE(._end - 0x8000);
STAGE2_SECTORS = (STAGE2_SIZE + 511) / 512;
}
+50
View File
@@ -0,0 +1,50 @@
extern STAGE2_SIZE
extern STAGE2_SECTORS
section .header
global _header_start
_header_start:
dd STAGE2_SIZE
dw STAGE2_SECTORS
db 0x55, 0xAA
section .text
global _start
[BITS 16]
_start:
mov ah, 0x00
mov al, 0x03
int 0x10
mov ah, 0x06
mov al, 0
mov bh, 0x07 ; normal attribute (white on black)
mov cx, 0 ; upper left = (0,0)
mov dx, 0x184F ; lower right = (24,79) - full screen
int 0x10
jmp something
times 500 db 0
something:
; print "loaded"
mov ax, 0xb800
mov ds, ax
mov byte [0], 'L'
mov byte [1], 0x07
mov byte [2], 'O'
mov byte [3], 0x07
mov byte [4], 'A'
mov byte [5], 0x07
mov byte [6], 'D'
mov byte [7], 0x07
mov byte [8], 'E'
mov byte [9], 0x07
mov byte [10], 'D'
mov byte [11], 0x07
hlt
hang:
hang