diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 0000000000..20ee1ec977 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,9 @@ +[build] +rustflags = [ + # Kernel should preserve floating-point registers + "-Csoft-float", +] + +[unstable] +build-std = ["core", "alloc", "compiler_builtins"] +build-std-features = ["panic-unwind"] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..c3dca1b96f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/build +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..aaa8a0ade9 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "redox_bootloader" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..e3181840a9 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "redox_bootloader" +version = "0.1.0" +edition = "2018" + +[lib] +name = "bootloader" +path = "src/lib.rs" +crate-type = ["staticlib"] + +[dependencies] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..7425691aea --- /dev/null +++ b/Makefile @@ -0,0 +1,51 @@ +ARCH=x86 +TARGET=$(ARCH)-unknown-none + +export LD=ld -m elf_i386 +export OBJCOPY=objcopy +export PARTED=parted +export QEMU=qemu-system-i386 +export RUST_TARGET_PATH=$(CURDIR)/targets + +all: build/bootloader.bin + +clean: + rm -rf build + +build/libbootloader.a: Cargo.lock Cargo.toml src/** + mkdir -p build + cargo rustc --lib --target $(TARGET) --release -- -C soft-float -C debuginfo=2 --emit link=$@ + +build/bootloader.elf: linkers/$(ARCH).ld build/libbootloader.a + mkdir -p build + $(LD) --gc-sections -z max-page-size=0x1000 -T $< -o $@ build/libbootloader.a && \ + $(OBJCOPY) --only-keep-debug $@ $@.sym && \ + $(OBJCOPY) --strip-debug $@ + +build/bootloader.bin: build/bootloader.elf $(ARCH)/** + mkdir -p build + nasm -f bin -o $@ -l $@.lst -D ARCH_$(ARCH) -D KERNEL=$< -i$(ARCH) $(ARCH)/disk.asm + +build/harddrive.bin: build/bootloader.bin + mkdir -p build + rm -f $@.partial + fallocate -l 256MiB $@.partial + $(PARTED) -s -a minimal $@.partial mklabel msdos + $(PARTED) -s -a minimal $@.partial mkpart primary 1MiB 100% + dd if=$< of=$@.partial bs=1 count=446 conv=notrunc + dd if=$< of=$@.partial bs=512 skip=1 seek=1 conv=notrunc + mv $@.partial $@ + +qemu: build/harddrive.bin + $(QEMU) \ + -d cpu_reset \ + -d guest_errors \ + -smp 4 -m 2048 \ + -chardev stdio,id=debug,signal=off,mux=on \ + -serial chardev:debug \ + -mon chardev=debug \ + -machine q35 \ + -net none \ + -enable-kvm \ + -cpu host \ + -drive file=$<,format=raw diff --git a/linkers/x86.ld b/linkers/x86.ld new file mode 100644 index 0000000000..abaf92bd00 --- /dev/null +++ b/linkers/x86.ld @@ -0,0 +1,56 @@ +ENTRY(kstart) +OUTPUT_FORMAT(elf32-i386) + +SECTIONS { + . = 0x100000; + + . += SIZEOF_HEADERS; + . = ALIGN(4096); + + .text : { + __text_start = .; + *(.text*) + . = ALIGN(4096); + __text_end = .; + } + + .rodata : { + __rodata_start = .; + *(.rodata*) + . = ALIGN(4096); + __rodata_end = .; + } + + .data : { + __data_start = .; + *(.data*) + . = ALIGN(4096); + __data_end = .; + __bss_start = .; + *(.bss*) + . = ALIGN(4096); + __bss_end = .; + } + + .tdata : { + __tdata_start = .; + *(.tdata*) + . = ALIGN(4096); + __tdata_end = .; + __tbss_start = .; + *(.tbss*) + . += 8; + . = ALIGN(4096); + __tbss_end = .; + } + + __end = .; + + /DISCARD/ : { + *(.comment*) + *(.eh_frame*) + *(.gcc_except_table*) + *(.note*) + *(.rel.eh_frame*) + } +} diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000000..2b782427dd --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly-2021-06-15 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000000..001513e716 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,10 @@ +#![no_std] +#![feature(lang_items)] +#![feature(llvm_asm)] + +mod panic; + +#[no_mangle] +pub unsafe extern "C" fn kstart() -> ! { + loop {} +} diff --git a/src/panic.rs b/src/panic.rs new file mode 100644 index 0000000000..d2c3259b48 --- /dev/null +++ b/src/panic.rs @@ -0,0 +1,38 @@ +//! Intrinsics for panic handling + +use core::alloc::Layout; +use core::panic::PanicInfo; + +#[lang = "eh_personality"] +#[no_mangle] +pub extern "C" fn rust_eh_personality() {} + +/// Required to handle panics +#[panic_handler] +#[no_mangle] +pub extern "C" fn rust_begin_unwind(info: &PanicInfo) -> ! { + //println!("BOOTLOADER PANIC: {}", info); + loop { + unsafe { + llvm_asm!("hlt" : : : : "intel", "volatile"); + } + } +} + +#[lang = "oom"] +#[no_mangle] +#[allow(improper_ctypes_definitions)] // Layout is not repr(C) +pub extern fn rust_oom(_layout: Layout) -> ! { + panic!("kernel memory allocation failed"); +} + +#[allow(non_snake_case)] +#[no_mangle] +/// Required to handle panics +pub extern "C" fn _Unwind_Resume() -> ! { + loop { + unsafe { + llvm_asm!("hlt" : : : : "intel", "volatile"); + } + } +} diff --git a/targets/x86-unknown-none.json b/targets/x86-unknown-none.json new file mode 100644 index 0000000000..433a8bef16 --- /dev/null +++ b/targets/x86-unknown-none.json @@ -0,0 +1,29 @@ +{ + "llvm-target": "i686-unknown-none", + "target-endian": "little", + "target-pointer-width": "32", + "target-c-int-width": "32", + "data-layout": "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128", + "arch": "x86", + "os": "none", + "env": "", + "vendor": "unknown", + "linker-flavor": "gcc", + "target-family": "redox", + "pre-link-args": { + "gcc": ["-m32", "-nostdlib", "-static"] + }, + "features": "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float", + "dynamic-linking": false, + "executables": false, + "relocation-model": "pic", + "code-model": "kernel", + "disable-redzone": true, + "eliminate-frame-pointer": false, + "exe-suffix": "", + "has-rpath": false, + "no-compiler-rt": true, + "no-default-libraries": true, + "position-independent-executables": false, + "has-elf-tls": true +} diff --git a/x86_64/bootsector.asm b/x86/bootsector.asm similarity index 100% rename from x86_64/bootsector.asm rename to x86/bootsector.asm diff --git a/x86_64/config.asm b/x86/config.asm similarity index 100% rename from x86_64/config.asm rename to x86/config.asm diff --git a/x86_64/cpuid.asm b/x86/cpuid.asm similarity index 100% rename from x86_64/cpuid.asm rename to x86/cpuid.asm diff --git a/x86_64/cpuid.inc b/x86/cpuid.inc similarity index 100% rename from x86_64/cpuid.inc rename to x86/cpuid.inc diff --git a/x86_64/descriptor_flags.inc b/x86/descriptor_flags.inc similarity index 100% rename from x86_64/descriptor_flags.inc rename to x86/descriptor_flags.inc diff --git a/x86_64/disk.asm b/x86/disk.asm similarity index 91% rename from x86_64/disk.asm rename to x86/disk.asm index 1ef4cc36c9..d4e602d2f6 100644 --- a/x86_64/disk.asm +++ b/x86/disk.asm @@ -3,8 +3,8 @@ sectalign off %include "bootsector.asm" startup_start: -%ifdef ARCH_i386 - %include "startup-i386.asm" +%ifdef ARCH_x86 + %include "startup-x86.asm" %endif %ifdef ARCH_x86_64 diff --git a/x86_64/gdt_entry.inc b/x86/gdt_entry.inc similarity index 100% rename from x86_64/gdt_entry.inc rename to x86/gdt_entry.inc diff --git a/x86_64/initialize.asm b/x86/initialize.asm similarity index 100% rename from x86_64/initialize.asm rename to x86/initialize.asm diff --git a/x86_64/memory_map.asm b/x86/memory_map.asm similarity index 100% rename from x86_64/memory_map.asm rename to x86/memory_map.asm diff --git a/x86_64/partitions.asm b/x86/partitions.asm similarity index 100% rename from x86_64/partitions.asm rename to x86/partitions.asm diff --git a/x86_64/print.asm b/x86/print.asm similarity index 100% rename from x86_64/print.asm rename to x86/print.asm diff --git a/x86_64/redoxfs.asm b/x86/redoxfs.asm similarity index 100% rename from x86_64/redoxfs.asm rename to x86/redoxfs.asm diff --git a/x86_64/startup-common.asm b/x86/startup-common.asm similarity index 100% rename from x86_64/startup-common.asm rename to x86/startup-common.asm diff --git a/x86/startup-x86.asm b/x86/startup-x86.asm new file mode 100644 index 0000000000..ac8f0c77b9 --- /dev/null +++ b/x86/startup-x86.asm @@ -0,0 +1,63 @@ +%include "startup-common.asm" + +startup_arch: + ; load protected mode GDT and IDT + cli + lgdt [gdtr] + ; set protected mode bit of cr0 + mov eax, cr0 + or eax, 1 + mov cr0, eax + + ; far jump to load CS with 32 bit segment + jmp gdt.kernel_code:protected_mode + +USE32 +protected_mode: + ; load all the other segments with 32 bit data segments + mov eax, gdt.kernel_data + mov ds, eax + mov es, eax + mov fs, eax + mov gs, eax + mov ss, eax + + mov esp, 0x800000 - 128 + + ; entry point + mov eax, [args.kernel_base] + call [eax + 0x18] +.halt: + cli + hlt + jmp .halt + +gdtr: + dw gdt.end + 1 ; size + dd gdt ; offset + +gdt: +.null equ $ - gdt + dq 0 + +.kernel_code equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code | attrib.readable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.kernel_data equ $ - gdt + istruc GDTEntry + at GDTEntry.limitl, dw 0xFFFF + at GDTEntry.basel, dw 0 + at GDTEntry.basem, db 0 + at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable + at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size + at GDTEntry.baseh, db 0 + iend + +.end equ $ - gdt diff --git a/x86_64/startup-x86_64.asm b/x86/startup-x86_64.asm similarity index 100% rename from x86_64/startup-x86_64.asm rename to x86/startup-x86_64.asm diff --git a/x86_64/unreal.asm b/x86/unreal.asm similarity index 100% rename from x86_64/unreal.asm rename to x86/unreal.asm diff --git a/x86_64/vesa.asm b/x86/vesa.asm similarity index 100% rename from x86_64/vesa.asm rename to x86/vesa.asm diff --git a/x86_64/vesa.inc b/x86/vesa.inc similarity index 100% rename from x86_64/vesa.inc rename to x86/vesa.inc diff --git a/x86_64/startup-i386.asm b/x86_64/startup-i386.asm deleted file mode 100644 index c38a09e7d8..0000000000 --- a/x86_64/startup-i386.asm +++ /dev/null @@ -1,148 +0,0 @@ -%include "startup-common.asm" - -startup_arch: - ; load protected mode GDT and IDT - cli - lgdt [gdtr] - lidt [idtr] - ; set protected mode bit of cr0 - mov eax, cr0 - or eax, 1 - mov cr0, eax - - ; far jump to load CS with 32 bit segment - jmp gdt.kernel_code:protected_mode - -USE32 -protected_mode: - ; load all the other segments with 32 bit data segments - mov eax, gdt.kernel_data - mov ds, eax - mov es, eax - mov fs, eax - mov gs, eax - mov ss, eax - - mov esp, 0x800000 - 128 - - mov eax, gdt.tss - ltr ax - - ;rust init - mov eax, [kernel_base + 0x18] - mov [interrupts.handler], eax - mov eax, gdtr - mov ebx, idtr - mov ecx, tss - int 255 -.lp: - sti - hlt - jmp .lp - -gdtr: - dw gdt.end + 1 ; size - dd gdt ; offset - -gdt: -.null equ $ - gdt - dq 0 - -.kernel_code equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.user | attrib.code | attrib.readable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.kernel_data equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.user_code equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.code | attrib.readable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.user_data equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.user_tls equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw 0xFFFF - at GDTEntry.basel, dw 0 - at GDTEntry.basem, db 0 - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.user | attrib.writable - at GDTEntry.flags__limith, db 0xFF | flags.granularity | flags.default_operand_size - at GDTEntry.baseh, db 0 - iend - -.tss equ $ - gdt - istruc GDTEntry - at GDTEntry.limitl, dw (tss.end - tss) & 0xFFFF - at GDTEntry.basel, dw (tss-$$+0x7C00) & 0xFFFF - at GDTEntry.basem, db ((tss-$$+0x7C00) >> 16) & 0xFF - at GDTEntry.attribute, db attrib.present | attrib.ring3 | attrib.tssAvailabe32 - at GDTEntry.flags__limith, db ((tss.end - tss) >> 16) & 0xF - at GDTEntry.baseh, db ((tss-$$+0x7C00) >> 24) & 0xFF - iend -.end equ $ - gdt - -struc TSS - .prev_tss resd 1 ;The previous TSS - if we used hardware task switching this would form a linked list. - .esp0 resd 1 ;The stack pointer to load when we change to kernel mode. - .ss0 resd 1 ;The stack segment to load when we change to kernel mode. - .esp1 resd 1 ;everything below here is unused now.. - .ss1 resd 1 - .esp2 resd 1 - .ss2 resd 1 - .cr3 resd 1 - .eip resd 1 - .eflags resd 1 - .eax resd 1 - .ecx resd 1 - .edx resd 1 - .ebx resd 1 - .esp resd 1 - .ebp resd 1 - .esi resd 1 - .edi resd 1 - .es resd 1 - .cs resd 1 - .ss resd 1 - .ds resd 1 - .fs resd 1 - .gs resd 1 - .ldt resd 1 - .trap resw 1 - .iomap_base resw 1 -endstruc - -tss: - istruc TSS - at TSS.esp0, dd 0x800000 - 128 - at TSS.ss0, dd gdt.kernel_data - at TSS.iomap_base, dw 0xFFFF - iend -.end: