wrote a basic bootloader
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
[build]
|
||||
target = "x86_64-custom.json"
|
||||
|
||||
[unstable]
|
||||
build-std = ["core", "compiler_builtins"]
|
||||
build-std-features = ["compiler-builtins-mem"]
|
||||
|
||||
[target.'cfg(target_os = "none")']
|
||||
runner = "bootimage runner"
|
||||
|
||||
[target.x86_64-custom]
|
||||
rustflags = [
|
||||
"-C", "link-arg=-Tlinker.ld",
|
||||
"-C", "code-model=kernel",
|
||||
"-C", "relocation-model=static"
|
||||
]
|
||||
Binary file not shown.
@@ -0,0 +1,55 @@
|
||||
[BITS 16]
|
||||
[ORG 0x7c00]
|
||||
start:
|
||||
mov ah,0x00 ; set mode
|
||||
mov al,0x03 ; set vga text buffer mode (80x25)
|
||||
int 0x10 ; call bios
|
||||
|
||||
cli
|
||||
|
||||
in al, 0x92
|
||||
or al, 2
|
||||
out 0x92, al
|
||||
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
|
||||
lgdt [GDT_PTR]
|
||||
|
||||
mov eax, 0x11
|
||||
mov cr0, eax
|
||||
jmp GDT_BOOT_CS-GDT:protmode
|
||||
|
||||
[BITS 32]
|
||||
protmode:
|
||||
mov ax, GDT_BOOT_DS-GDT
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
mov esp, 0x90000 ; temporary stack
|
||||
|
||||
mov edi, 0xb8000
|
||||
mov eax, "P R "
|
||||
stosd
|
||||
|
||||
hang:
|
||||
pause
|
||||
jmp hang
|
||||
|
||||
GDT_PTR:
|
||||
dw GDT_END-GDT-1
|
||||
dd GDT
|
||||
|
||||
|
||||
align 16
|
||||
GDT:
|
||||
|
||||
GDT_NULL: dq 0 ; segment zero cannot be used
|
||||
GDT_BOOT_DS: dq 0X00CF92000000FFFF
|
||||
GDT_BOOT_CS: dq 0X00CF9A000000FFFF
|
||||
|
||||
GDT_END:
|
||||
|
||||
times 510-$+start db 0;
|
||||
db 0x55;
|
||||
db 0xaa;
|
||||
@@ -0,0 +1,118 @@
|
||||
[BITS 16]
|
||||
[ORG 0x7C00]
|
||||
|
||||
; Initialize segment registers
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov sp, 0x7C00
|
||||
|
||||
; Reset disk system
|
||||
mov ah, 0
|
||||
int 0x13
|
||||
|
||||
; Load FAT32 BPB
|
||||
mov si, bpb_oem_name
|
||||
mov di, 0x7E00
|
||||
mov cx, bpb_size
|
||||
rep movsb
|
||||
|
||||
; Read FAT32 root directory
|
||||
mov ax, [bpb_reserved_sectors]
|
||||
mov [dapack.lba_start], ax
|
||||
|
||||
mov ah, 0x42
|
||||
mov si, dapack
|
||||
int 0x13
|
||||
jc error
|
||||
|
||||
; Find kernel file
|
||||
mov si, kernel_name
|
||||
mov di, 0x8000
|
||||
mov cx, 11 ; FAT32 8.3 filename length
|
||||
|
||||
find_kernel:
|
||||
push cx
|
||||
push si
|
||||
push di
|
||||
rep cmpsb
|
||||
pop di
|
||||
pop si
|
||||
pop cx
|
||||
je found_kernel
|
||||
|
||||
add di, 32 ; Move to next directory entry
|
||||
cmp di, 0x8200 ; Check if we've reached the end of the sector
|
||||
jl find_kernel
|
||||
|
||||
; Kernel not found
|
||||
mov si, err_no_kernel
|
||||
call print
|
||||
jmp $
|
||||
|
||||
found_kernel:
|
||||
; Get cluster number
|
||||
mov ax, [di + 20] ; High word
|
||||
shl eax, 16
|
||||
mov ax, [di + 26] ; Low word
|
||||
|
||||
; Load kernel
|
||||
mov [cluster], eax
|
||||
call load_cluster
|
||||
|
||||
; Jump to kernel
|
||||
jmp 0x8000
|
||||
|
||||
error:
|
||||
mov si, err_disk
|
||||
call print
|
||||
jmp $
|
||||
|
||||
print:
|
||||
lodsb
|
||||
or al, al
|
||||
jz .done
|
||||
mov ah, 0x0E
|
||||
int 0x10
|
||||
jmp print
|
||||
.done:
|
||||
ret
|
||||
|
||||
load_cluster:
|
||||
; Convert cluster to LBA
|
||||
sub eax, 2
|
||||
mul dword [sectors_per_cluster]
|
||||
add eax, [first_data_sector]
|
||||
|
||||
mov [dapack.lba_start], eax
|
||||
mov ah, 0x42
|
||||
mov si, dapack
|
||||
int 0x13
|
||||
ret
|
||||
|
||||
align 4
|
||||
dapack:
|
||||
db 0x10 ; Size of packet
|
||||
db 0 ; Reserved
|
||||
dw 1 ; Number of sectors
|
||||
dw 0x8000 ; Offset
|
||||
dw 0 ; Segment
|
||||
dq 0 ; LBA
|
||||
|
||||
cluster: dd 0
|
||||
sectors_per_cluster: dd 8
|
||||
first_data_sector: dd 0
|
||||
|
||||
kernel_name: db "KERNEL BIN"
|
||||
err_disk: db "Disk error", 0
|
||||
err_no_kernel: db "No kernel", 0
|
||||
|
||||
bpb_oem_name: times 8 db 0
|
||||
bpb_bytes_per_sector: dw 512
|
||||
bpb_sectors_per_cluster: db 8
|
||||
bpb_reserved_sectors: dw 32
|
||||
bpb_size: equ $ - bpb_oem_name
|
||||
|
||||
times 510-($-$$) db 0
|
||||
dw 0xAA55
|
||||
@@ -0,0 +1,83 @@
|
||||
.section .efi.text, "ax"
|
||||
.global _start
|
||||
.code64 // UEFI is already in 64-bit protected mode
|
||||
|
||||
_start:
|
||||
// Save UEFI parameters
|
||||
mov %rcx, uefi_image_handle
|
||||
mov %rdx, uefi_system_table
|
||||
|
||||
// Get memory map
|
||||
call get_memory_map
|
||||
|
||||
// Exit boot services
|
||||
mov uefi_image_handle, %rcx
|
||||
mov memory_map_key, %rdx
|
||||
call exit_boot_services
|
||||
|
||||
// Disable interrupts
|
||||
cli
|
||||
|
||||
// Load GDT for long mode
|
||||
lgdt gdt64_pointer(%rip)
|
||||
|
||||
// Setup page tables (identity map first 2MB + map kernel to higher half)
|
||||
call setup_page_tables
|
||||
|
||||
// Enable PAE
|
||||
mov %cr4, %rax
|
||||
or $(1 << 5), %rax
|
||||
mov %rax, %cr4
|
||||
|
||||
// Set long mode bit
|
||||
mov $0xC0000080, %ecx
|
||||
rdmsr
|
||||
or $(1 << 8), %eax
|
||||
wrmsr
|
||||
|
||||
// Enable paging
|
||||
mov %cr0, %rax
|
||||
or $0x80000000, %rax
|
||||
mov %rax, %cr0
|
||||
|
||||
// Long jump to higher half kernel
|
||||
lea higher_half(%rip), %rax
|
||||
jmp *%rax
|
||||
|
||||
.align 8
|
||||
higher_half:
|
||||
// Now in long mode at higher half
|
||||
// Setup stack and jump to Rust code
|
||||
mov $kernel_stack_top, %rsp
|
||||
call kmain
|
||||
|
||||
// GDT for long mode
|
||||
.align 16
|
||||
gdt64:
|
||||
.quad 0 // Null descriptor
|
||||
.quad 0x00AF9A000000FFFF // Code segment
|
||||
.quad 0x00CF92000000FFFF // Data segment
|
||||
|
||||
gdt64_pointer:
|
||||
.word gdt64_pointer - gdt64 - 1
|
||||
.quad gdt64
|
||||
|
||||
.section .efi.data, "aw"
|
||||
uefi_image_handle: .quad 0
|
||||
uefi_system_table: .quad 0
|
||||
memory_map_key: .quad 0
|
||||
|
||||
.section .bss
|
||||
.align 4096
|
||||
kernel_stack_bottom:
|
||||
.skip 16384 // 16 KB stack
|
||||
kernel_stack_top:
|
||||
|
||||
// Page tables
|
||||
.align 4096
|
||||
pml4_table:
|
||||
.skip 4096
|
||||
pdpt_table:
|
||||
.skip 4096
|
||||
pd_table:
|
||||
.skip 4096
|
||||
@@ -0,0 +1,94 @@
|
||||
.section .efi.text
|
||||
|
||||
// Function to get UEFI memory map
|
||||
get_memory_map:
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
|
||||
// Local variables for memory map
|
||||
sub $48, %rsp
|
||||
mov $0, -8(%rbp) // memory_map_size
|
||||
mov $0, -16(%rbp) // memory_map_buffer
|
||||
mov $0, -24(%rbp) // map_key
|
||||
mov $0, -32(%rbp) // descriptor_size
|
||||
mov $0, -40(%rbp) // descriptor_version
|
||||
|
||||
// First call to get size
|
||||
lea -8(%rbp), %rcx // memory_map_size
|
||||
mov $0, %rdx // memory_map
|
||||
lea -24(%rbp), %r8 // map_key
|
||||
lea -32(%rbp), %r9 // descriptor_size
|
||||
push $0 // descriptor_version
|
||||
call boot_services_get_memory_map
|
||||
|
||||
// Allocate buffer
|
||||
mov -8(%rbp), %rcx // size
|
||||
add $1000, %rcx // Add some extra space
|
||||
mov $8, %rdx // alignment
|
||||
lea -16(%rbp), %r8 // buffer pointer
|
||||
call boot_services_allocate_pool
|
||||
|
||||
// Get actual map
|
||||
mov -8(%rbp), %rcx
|
||||
mov -16(%rbp), %rdx
|
||||
lea -24(%rbp), %r8
|
||||
lea -32(%rbp), %r9
|
||||
push -40(%rbp)
|
||||
call boot_services_get_memory_map
|
||||
|
||||
// Save map key
|
||||
mov -24(%rbp), %rax
|
||||
mov %rax, memory_map_key
|
||||
|
||||
leave
|
||||
ret
|
||||
|
||||
// Function to exit boot services
|
||||
exit_boot_services:
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
|
||||
// Parameters already in rcx (image_handle) and rdx (map_key)
|
||||
call boot_services_exit
|
||||
|
||||
leave
|
||||
ret
|
||||
|
||||
// Function to set up page tables
|
||||
setup_page_tables:
|
||||
push %rbp
|
||||
mov %rsp, %rbp
|
||||
|
||||
// Clear tables
|
||||
mov $pml4_table, %rdi
|
||||
mov $12288, %ecx // 3 pages (PML4, PDPT, PD)
|
||||
xor %eax, %eax
|
||||
rep stosb
|
||||
|
||||
// Set up identity mapping for first 2MB
|
||||
// PML4[0] -> PDPT
|
||||
mov $pdpt_table, %eax
|
||||
or $3, %eax // Present + Write
|
||||
mov %eax, pml4_table
|
||||
|
||||
// PDPT[0] -> PD
|
||||
mov $pd_table, %eax
|
||||
or $3, %eax
|
||||
mov %eax, pdpt_table
|
||||
|
||||
// PD[0] -> 2MB page
|
||||
mov $0x83, %eax // Present + Write + Huge
|
||||
mov %eax, pd_table
|
||||
|
||||
// Map kernel to higher half
|
||||
// PML4[511] -> PDPT
|
||||
mov $pdpt_table, %eax
|
||||
or $3, %eax
|
||||
mov %eax, pml4_table + 4088
|
||||
|
||||
// Load CR3
|
||||
mov $pml4_table, %rax
|
||||
mov %rax, %cr3
|
||||
|
||||
leave
|
||||
ret
|
||||
@@ -0,0 +1,140 @@
|
||||
/* Tell the linker that we want an x86_64 ELF64 output file */
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
|
||||
/* Entry points */
|
||||
ENTRY(start)
|
||||
|
||||
/* Define the program headers we want in our final kernel executable */
|
||||
PHDRS
|
||||
{
|
||||
boot PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
|
||||
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
|
||||
rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */
|
||||
data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
|
||||
}
|
||||
|
||||
/* The kernel is linked to run at -2GB (KERNEL_BASE) */
|
||||
KERNEL_BASE = 0xFFFFFFFF80000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* For BIOS boot, start at 1MB physical */
|
||||
. = 1M;
|
||||
|
||||
.boot : {
|
||||
/* BIOS boot sections */
|
||||
KEEP(*(.multiboot)) /* Multiboot header */
|
||||
*(.boottext) /* BIOS boot code */
|
||||
*(.boottext.*)
|
||||
|
||||
/* UEFI boot sections */
|
||||
KEEP(*(.pe_header)) /* PE/COFF header for UEFI */
|
||||
*(.efi.header) /* EFI header */
|
||||
. = ALIGN(4K);
|
||||
*(.efi.text) /* UEFI boot code */
|
||||
*(.efi.text.*)
|
||||
*(.efi.data) /* UEFI data */
|
||||
*(.efi.data.*)
|
||||
} :boot
|
||||
|
||||
/* Switch to higher half for kernel proper */
|
||||
. += KERNEL_BASE;
|
||||
|
||||
/* Code section */
|
||||
.text : AT(ADDR(.text) - KERNEL_BASE) {
|
||||
_text_start = .;
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
. = ALIGN(4K);
|
||||
_text_end = .;
|
||||
} :text
|
||||
|
||||
/* Read-only data */
|
||||
.rodata : AT(ADDR(.rodata) - KERNEL_BASE) {
|
||||
_rodata_start = .;
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
. = ALIGN(4K);
|
||||
_rodata_end = .;
|
||||
} :rodata
|
||||
|
||||
/* Read-write data (initialized) */
|
||||
.data : AT(ADDR(.data) - KERNEL_BASE) {
|
||||
_data_start = .;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.got)
|
||||
*(.got.*)
|
||||
. = ALIGN(4K);
|
||||
_data_end = .;
|
||||
} :data
|
||||
|
||||
/* Read-write data (uninitialized) */
|
||||
.bss : AT(ADDR(.bss) - KERNEL_BASE) {
|
||||
_bss_start = .;
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
. = ALIGN(4K);
|
||||
_bss_end = .;
|
||||
} :data
|
||||
|
||||
/* Page-aligned data structures */
|
||||
.padata ALIGN(4K) : AT(ADDR(.padata) - KERNEL_BASE) {
|
||||
*(.padata)
|
||||
} :data
|
||||
|
||||
/* Initial stack space */
|
||||
.stack ALIGN(4K) : AT(ADDR(.stack) - KERNEL_BASE) {
|
||||
*(.stack)
|
||||
} :data
|
||||
|
||||
/* Thread-local storage */
|
||||
.tdata ALIGN(4K) : AT(ADDR(.tdata) - KERNEL_BASE) {
|
||||
_tdata_start = .;
|
||||
*(.tdata)
|
||||
*(.tdata.*)
|
||||
. = ALIGN(4K);
|
||||
_tdata_end = .;
|
||||
} :data
|
||||
|
||||
.tbss ALIGN(4K) : AT(ADDR(.tbss) - KERNEL_BASE) {
|
||||
_tbss_start = .;
|
||||
*(.tbss)
|
||||
*(.tbss.*)
|
||||
. = ALIGN(4K);
|
||||
_tbss_end = .;
|
||||
} :data
|
||||
|
||||
/* Debugging information */
|
||||
.debug_info 0 : { *(.debug_info) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_ranges 0 : { *(.debug_ranges) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
|
||||
/* Discard unused sections */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
*(.note.*)
|
||||
*(.comment)
|
||||
}
|
||||
}
|
||||
|
||||
/* Symbols needed by both BIOS and UEFI boot code */
|
||||
PROVIDE(_kernel_start = ADDR(.boot));
|
||||
PROVIDE(_kernel_end = ADDR(.tbss) + SIZEOF(.tbss));
|
||||
PROVIDE(_kernel_physical_end = ADDR(.tbss) - KERNEL_BASE + SIZEOF(.tbss));
|
||||
PROVIDE(_kernel_virtual_base = KERNEL_BASE);
|
||||
|
||||
/* UEFI-specific symbols */
|
||||
PROVIDE(_efi_start = ADDR(.boot));
|
||||
PROVIDE(_efi_text_start = ADDR(.efi.text));
|
||||
PROVIDE(_efi_text_end = ADDR(.efi.text) + SIZEOF(.efi.text));
|
||||
|
||||
/* BIOS-specific symbols */
|
||||
PROVIDE(_multiboot_start = ADDR(.multiboot));
|
||||
PROVIDE(_boottext_start = ADDR(.boottext));
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Build the bootloader
|
||||
nasm -f bin mbr.asm -o mbr.bin
|
||||
|
||||
# Build the kernel
|
||||
cargo build --release
|
||||
|
||||
# Create disk image
|
||||
./create_image.sh
|
||||
|
||||
# Write MBR
|
||||
dd if=mbr.bin of=disk.img conv=notrunc
|
||||
|
||||
echo "Build complete! You can now boot disk.img"
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Image configuration
|
||||
IMAGE_NAME="disk.img"
|
||||
IMAGE_SIZE_MB=64
|
||||
ESP_SIZE_MB=32 # EFI System Partition size
|
||||
|
||||
# Create a new disk image
|
||||
dd if=/dev/zero of=$IMAGE_NAME bs=1M count=$IMAGE_SIZE_MB
|
||||
|
||||
# Create partition table and ESP partition
|
||||
parted $IMAGE_NAME mklabel gpt
|
||||
parted $IMAGE_NAME mkpart ESP fat32 1MiB ${ESP_SIZE_MB}MiB
|
||||
parted $IMAGE_NAME set 1 esp on
|
||||
|
||||
# Calculate offset for mounting
|
||||
SECTOR_SIZE=512
|
||||
START_SECTOR=$(parted $IMAGE_NAME -ms unit s print | grep "^1:" | cut -d: -f2 | tr -d 's')
|
||||
OFFSET=$((START_SECTOR * SECTOR_SIZE))
|
||||
|
||||
# Create FAT32 filesystem
|
||||
LOOP_DEVICE=$(sudo losetup -f --show -o $OFFSET $IMAGE_NAME)
|
||||
sudo mkfs.fat -F 32 $LOOP_DEVICE
|
||||
|
||||
# Mount the image
|
||||
MOUNT_POINT="/tmp/esp"
|
||||
mkdir -p $MOUNT_POINT
|
||||
sudo mount $LOOP_DEVICE $MOUNT_POINT
|
||||
|
||||
# Create EFI directory structure
|
||||
sudo mkdir -p $MOUNT_POINT/EFI/BOOT
|
||||
|
||||
# Copy kernel to the ESP
|
||||
# For UEFI boot, rename it to BOOTX64.EFI
|
||||
sudo cp target/x86_64-custom/release/kernel $MOUNT_POINT/EFI/BOOT/BOOTX64.EFI
|
||||
|
||||
# For BIOS boot, also copy it to the root
|
||||
sudo cp target/x86_64-custom/release/kernel $MOUNT_POINT/
|
||||
|
||||
# Cleanup
|
||||
sudo umount $MOUNT_POINT
|
||||
sudo losetup -d $LOOP_DEVICE
|
||||
rm -rf $MOUNT_POINT
|
||||
|
||||
echo "Disk image created successfully!"
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
"target-c-int-width": "32",
|
||||
"os": "none",
|
||||
"executables": true,
|
||||
"linker-flavor": "ld.lld",
|
||||
"linker": "rust-lld",
|
||||
"panic-strategy": "abort",
|
||||
"disable-redzone": true,
|
||||
"features": "-mmx,-sse,+soft-float",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [
|
||||
"--gc-sections"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user