wrote a basic bootloader
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
ENTRY(_start)
|
||||
OUTPUT_FORMAT(binary)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x7C00; /* Where BIOS loads us */
|
||||
.text : {
|
||||
*(.text)
|
||||
. = 446; /* Pad to 510 bytes */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
section .text
|
||||
global _start
|
||||
|
||||
[BITS 16]
|
||||
_start:
|
||||
; Set video mode (clear screen)
|
||||
mov ah, 0x00
|
||||
mov al, 0x03
|
||||
int 0x10
|
||||
|
||||
; Print loading message
|
||||
mov ax, 0xb800
|
||||
mov ds, ax
|
||||
|
||||
mov dword [ 0], "L O "
|
||||
mov dword [ 4], "A D "
|
||||
mov dword [ 8], "I N "
|
||||
mov dword [ 12], "G . "
|
||||
mov dword [ 16], ". . "
|
||||
|
||||
; setup a stack
|
||||
cli
|
||||
mov ax, 0x9000
|
||||
mov ss, ax
|
||||
mov sp, 0x0000
|
||||
mov bp, sp
|
||||
|
||||
mov bx, 0x0800 ; this is the first memory location we're interested in.
|
||||
mov es, bx
|
||||
xor bx, bx
|
||||
|
||||
mov cl, 0x02 ; this is the first sector we're interested in.
|
||||
|
||||
call load_sector
|
||||
|
||||
mov ax, [es:6] ; load last two bytes (0x1FE = 510)
|
||||
cmp ax, 0xAA55 ; check if it matches boot signature
|
||||
jne error ; if not equal, not a valid boot sector
|
||||
|
||||
; jmp success
|
||||
|
||||
mov ax, [es:4] ; load sector count
|
||||
|
||||
next_sector:
|
||||
dec ax ; decrement sectors left to write
|
||||
inc cl
|
||||
|
||||
cmp ax, 0
|
||||
je success
|
||||
|
||||
add bx, 0x200 ; Add 512 to offset
|
||||
|
||||
call load_sector
|
||||
jmp next_sector
|
||||
|
||||
load_sector:
|
||||
pusha
|
||||
|
||||
; setup registers for disk read
|
||||
mov ah, 0x02 ; read sectors function
|
||||
mov dl, 0x80 ; first hard disk
|
||||
mov ch, 0x00 ; cylinder 0
|
||||
mov dh, 0x00 ; head 0
|
||||
mov al, 1 ; read 1 sector
|
||||
|
||||
; do the read
|
||||
int 0x13
|
||||
jc error ; if carry set, read failed
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
hang:
|
||||
jmp hang
|
||||
|
||||
error:
|
||||
; error getting the magic number
|
||||
mov ah, 0x00
|
||||
mov al, 0x03
|
||||
int 0x10
|
||||
|
||||
mov ax, 0xb800
|
||||
mov ds, ax
|
||||
|
||||
mov dword [ 0], "E R "
|
||||
mov dword [ 4], "R O "
|
||||
mov dword [ 8], "R . "
|
||||
|
||||
jmp hang
|
||||
|
||||
success:
|
||||
jmp 0x0800:0x0016 ; jump to start of stage 2
|
||||
@@ -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
|
||||
@@ -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) { }
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user