diff --git a/kernel-rs/.gdbinit b/kernel-rs/.gdbinit new file mode 100644 index 00000000..12181178 --- /dev/null +++ b/kernel-rs/.gdbinit @@ -0,0 +1,2 @@ +set arch i386:x86-64 +symbol-file build/bluesnow-x86.bin diff --git a/kernel-rs/Cargo.toml b/kernel-rs/Cargo.toml index b44f28a4..45bb02ea 100644 --- a/kernel-rs/Cargo.toml +++ b/kernel-rs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bluesnow" version = "0.1.0" -authors = ["Jack Halford ", "William Escande "] +authors = ["Jack Halford ", "William Escande "] [lib] crate-type = ["staticlib"] diff --git a/kernel-rs/Makefile b/kernel-rs/Makefile index 5f339951..67f3aee6 100644 --- a/kernel-rs/Makefile +++ b/kernel-rs/Makefile @@ -4,6 +4,11 @@ ARCH := x86 OS := bluesnow TARGET ?= $(ARCH)-$(OS) +all: + @printf "make kernel\t# build kernel binary\n" + @printf "make iso\t# build iso cdrom with grub\n" + @printf "make qemu\t# run qemu+gdb in tmux window\n" + ## COMPILE ASM (nasm) asm_source := $(wildcard src/arch/$(ARCH)/*.asm) asm_object := $(patsubst src/arch/$(ARCH)/%.asm, build/arch/$(ARCH)/%.o, $(asm_source)) @@ -15,18 +20,18 @@ build/arch/$(ARCH)/%.o: src/arch/$(ARCH)/%.asm Makefile ## COMPILE RUST (xargo) rust_os := target/$(TARGET)/debug/lib$(OS).a $(rust_os): $(TARGET).json Makefile - @TERM=xterm RUST_TARGET_PATH="$(shell pwd)" xargo build --target $(TARGET) + TERM=xterm RUST_TARGET_PATH="$(shell pwd)" xargo build --target $(TARGET) ## LINKAGE -kernel := build/$(OS) +kernel := build/$(OS)-$(ARCH).bin linker_script := src/arch/$(ARCH)/linker.ld LD := /usr/bin/ld -m elf_i386 -L ./ -n --gc-sections $(kernel): $(rust_os) $(asm_object) $(linker_script) Makefile $(LD) -o $@ -T $(linker_script) $(asm_object) $(rust_os) clean: - @xargo clean - @rm -rf build + xargo clean + rm -rf build .PHONY: clean kernel iso $(rust_os) @@ -37,3 +42,4 @@ include mk/qemu.mk include mk/grub.mk iso: $(grub-iso) +kernel: $(kernel) diff --git a/kernel-rs/mk/grub.mk b/kernel-rs/mk/grub.mk index cb44a41e..80d40dfa 100644 --- a/kernel-rs/mk/grub.mk +++ b/kernel-rs/mk/grub.mk @@ -1,4 +1,4 @@ -grub-iso := $(kernel).iso +grub-iso := $(kernel:.bin=.iso) grub-cfg := src/arch/$(ARCH)/grub.cfg isodir := build/isofiles diff --git a/kernel-rs/mk/qemu.mk b/kernel-rs/mk/qemu.mk index 366a12f5..4ff0c2c3 100644 --- a/kernel-rs/mk/qemu.mk +++ b/kernel-rs/mk/qemu.mk @@ -1,4 +1,4 @@ -ifeq ($(shell whoami), william) +ifeq ($(shell whoami), jack) PORT := 4242 PORTG := 4244 else @@ -6,20 +6,22 @@ else PORTG := 4344 endif -QEMU := qemu-system-x86_64 -QEMUFLAGS := -gdb tcp::$(PORTG) -enable-kvm -monitor telnet:127.0.0.1:$(PORT),server,nowait -curses -cdrom build/bluesnow.iso +QEMU := qemu-system-x86_64\ + -gdb tcp::$(PORTG)\ + -S\ + -enable-kvm\ + -monitor telnet:127.0.0.1:$(PORT),server,nowait\ + -curses\ + -cdrom build/bluesnow-x86.iso MONITOR := sleep 0.5;\ telnet 127.0.0.1 $(PORT);\ kill \`ps -x | grep \"[g]db -q\" | cut -d \ -f 1 \`;\ kill \`ps -x | grep \"[g]db -q\" | cut -d \ -f 2 \` GDB := gdb -q\ - -ex \"set arch i386:x86-64\"\ - -ex \"file $(kernel)\"\ - -ex \"target remote :$(PORTG)\"\ - -ex \"continue\" + -ex \"target remote :$(PORTG)\" qemu: @tmux info >&- || { echo -e "\033[38;5;16mPlease run inside a tmux session\033[0m" ; exit 1; } - @tmux new-window 'tmux split-window -h "$(MONITOR)"; tmux split-window -fv "$(GDB)"; tmux select-pane -t 1; tmux resize-pane -x 80 -y 25; $(QEMU) $(QEMUFLAGS)' + @tmux new-window 'tmux split-window -h "$(MONITOR)"; tmux split-window -fv "$(GDB)"; tmux select-pane -t 1; tmux resize-pane -x 80 -y 25; $(QEMU)' diff --git a/kernel-rs/src/allocator/mod.rs b/kernel-rs/src/allocator/mod.rs index 5837c638..1aa4c172 100644 --- a/kernel-rs/src/allocator/mod.rs +++ b/kernel-rs/src/allocator/mod.rs @@ -5,12 +5,9 @@ use x86::*; use x86::structures::paging::*; use arch::x86::paging::*; -fn map_heap(active_table: &mut ActivePageTable, offset: u32, size: u32) { - let heap_start_page = Page::containing_address(VirtAddr::new(offset)); - let heap_end_page = Page::containing_address(VirtAddr::new(offset + size - 1)); - - for page in heap_start_page..heap_end_page + 1 { - //we really should only map 1 huge page instead of 1024 small pages +fn map_heap(active_table: &mut ActivePageTable) { + //zone for heap is predefines in `consts.rs` + for page in ::KERNEL_HEAP_RANGE { active_table.map(page, PageTableFlags::WRITABLE); } } @@ -20,7 +17,8 @@ pub unsafe fn init(active_table: &mut ActivePageTable) { let offset = ::KERNEL_HEAP_OFFSET; let size = ::KERNEL_HEAP_SIZE; - map_heap(active_table, offset, size); + map_heap(active_table); - Allocator::init(offset as usize, size as usize); + //slab allocator + Allocator::init(offset.as_u32() as usize, size as usize); } diff --git a/kernel-rs/src/arch/x86/boot.asm b/kernel-rs/src/arch/x86/boot.asm index 9737350d..3c24d67d 100644 --- a/kernel-rs/src/arch/x86/boot.asm +++ b/kernel-rs/src/arch/x86/boot.asm @@ -42,6 +42,10 @@ set_up_page_tables: or eax, 0b10000011 ; huge + present + writable mov [p2_table + 4], eax + mov eax, 0x800000 ; 8MB -> 12Mb (second page) + or eax, 0b10000011 ; huge + present + writable + mov [p2_table + 8], eax + mov eax, p2_table mov cr3, eax ret diff --git a/kernel-rs/src/arch/x86/consts.rs b/kernel-rs/src/arch/x86/consts.rs index 9d41c545..d1fb4a29 100644 --- a/kernel-rs/src/arch/x86/consts.rs +++ b/kernel-rs/src/arch/x86/consts.rs @@ -1,31 +1,52 @@ -//layout looks like this: +// p2 layout looks like this: // [kernel 0->4MiB] // [kernel 4->8MiB] +// [start of no man's land] +// . +// . +// . +// [end of no man's land] // [user stack] -// [start of userheap] -// . -// . -// . -// [end of userheap] // [kernel heap] // [recursive map] points to first entry // -// which makes userheap = 4GiB - 4*4MiB (~= 4GiB) -macro_rules! p2 { ($i:expr) => {($i & P2_MASK) / P1_SIZE}} -pub const P2_MASK: u32 = 0xFFC0_0000; //top 10 bits -pub const P1_SIZE: u32 = 0x0040_0000; //4MiB (2**22) +// no man's land should be used in the future for mmap() I guess +// the kernel right now takes up 2 pages with debug symbols, +// if it gets to 3 pages everything will crash and i'll have +// to hardcode the third page here and in `boot.asm` also! +// +// TODO +// kernel is mapped identically (start of memory) but in +// the future it should be higher-half mapped so that +// user memory starts at 0 -pub const RECURSIVE_PAGE_OFFSET: u32 = (-(P1_SIZE as isize)) as u32; -///1023 -pub const RECURSIVE_PAGE_P2: u32 = p2!(RECURSIVE_PAGE_OFFSET); +use x86::structures::paging::*; +use x86::*; +use core::ops::Range; -pub const KERNEL_HEAP_OFFSET: u32 = RECURSIVE_PAGE_OFFSET - P1_SIZE; -///1022 -pub const KERNEL_HEAP_P2: u32 = p2!(KERNEL_HEAP_OFFSET); -pub const KERNEL_HEAP_SIZE: u32 = 4 * 1024 * 1024; //4MiB (1 huge page) +// macro_rules! prange { ($i:expr, $s:expr) => {$i..$i+$s+1}} -pub const USER_OFFSET: u32 = 0x00a0_0000; //3rd page (kernel takes 2 first pages) -pub const USER_P2: u32 = p2!(USER_OFFSET); +// all of this is fucking contrived +// the rust compiler should be able to evaluate const expressions +// by using the impl for my structs, what i'm doing here is obvious +// to me but not to the compiler -pub const USER_STACK_OFFSET: u32 = USER_OFFSET + P1_SIZE; -pub const USER_STACK_2: u32 = p2!(USER_STACK_OFFSET); +pub const RECURSIVE_PAGE_OFFSET: VirtAddr = VirtAddr(0xffc0_000); // first 10 bits +pub const RECURSIVE_PAGE: Page = Page::containing_address(RECURSIVE_PAGE_OFFSET); +pub const RECURSIVE_PAGE_SIZE: u32 = 0x0040_0000; // the whole p2 entry + +pub const KERNEL_HEAP_OFFSET: VirtAddr = VirtAddr(RECURSIVE_PAGE_OFFSET.0 - RECURSIVE_PAGE_SIZE); +// should be +// pub const KERNEL_HEAP_OFFSET: VirtAddr = RECURSIVE_PAGE_OFFSET - RECURSIVE_PAGE_SIZE); +pub const KERNEL_HEAP_SIZE: u32 = 0x0040_0000; //4MiB (1 huge page) +pub const KERNEL_HEAP_START: Page = Page::containing_address(KERNEL_HEAP_OFFSET); +pub const KERNEL_HEAP_END: Page = + Page::containing_address(VirtAddr(KERNEL_HEAP_OFFSET.0 + KERNEL_HEAP_SIZE)); +pub const KERNEL_HEAP_RANGE: Range = KERNEL_HEAP_START..KERNEL_HEAP_END; + +pub const USER_STACK_OFFSET: VirtAddr = VirtAddr(KERNEL_HEAP_OFFSET.0 - KERNEL_HEAP_SIZE); +pub const USER_STACK_START: Page = Page::containing_address(USER_STACK_OFFSET); +pub const USER_STACK_SIZE: u32 = 0x0040_0000; //4MiB (1 huge page) +pub const USER_STACK_END: Page = + Page::containing_address(VirtAddr(USER_STACK_OFFSET.0 + USER_STACK_SIZE)); +pub const USER_STACK_RANGE: Range = USER_STACK_START..USER_STACK_END; diff --git a/kernel-rs/src/arch/x86/gdt.rs b/kernel-rs/src/arch/x86/gdt.rs index 3744733f..cdfc540d 100644 --- a/kernel-rs/src/arch/x86/gdt.rs +++ b/kernel-rs/src/arch/x86/gdt.rs @@ -1,33 +1,41 @@ use x86::structures::gdt; use x86::structures::tss; +use x86::structures::gdt::{Descriptor, SegmentSelector}; use x86::instructions::segmentation::*; use x86::instructions::tables::load_tss; +use x86::PrivilegeLevel::{Ring0, Ring3}; use x86::*; -use spin::Once; pub static mut GDT: gdt::Gdt = gdt::Gdt::new(); pub static mut TSS: tss::TaskStateSegment = tss::TaskStateSegment::new(); pub static GDT_KERNEL_CODE: u16 = 1; -pub static GDT_KERNEL_DATA: u16 = 1; -pub static GDT_USER_CODE: u16 = 2; -pub static GDT_USER_DATA: u16 = 3; +pub static GDT_KERNEL_DATA: u16 = 2; +pub static GDT_USER_CODE: u16 = 3; +pub static GDT_USER_DATA: u16 = 4; +// tss takes 2 spots; +pub static GDT_TSS: u16 = 5; pub unsafe fn init() { TSS.ss0 = gdt::SegmentSelector::new(GDT_KERNEL_CODE, PrivilegeLevel::Ring0).0; - asm!("mov %ebp, $0" : "=r" (TSS.esp0)); + asm!("mov %esp, $0" : "=r" (TSS.esp0)); - // the following order is important + // the following *order* is important let kcode_selector = GDT.add_entry(gdt::Descriptor::kernel_code_segment()); let kdata_selector = GDT.add_entry(gdt::Descriptor::kernel_data_segment()); - let tss_selector = GDT.add_entry(gdt::Descriptor::tss_segment(&TSS)); - //I read that the tss should be twice as long - //fuck knows why... - //also this doesnt work if the tss is after 3rd spot - //once again: fuck knows why... - GDT.add_entry(gdt::Descriptor(0)); let ucode_selector = GDT.add_entry(gdt::Descriptor::user_code_segment()); let udata_selector = GDT.add_entry(gdt::Descriptor::user_data_segment()); + //I read that the tss should be twice as long + //fuck knows why... + let tss_selector = GDT.add_entry(gdt::Descriptor::tss_segment(&TSS)); + GDT.add_entry(gdt::Descriptor(0)); + + // println!( + // "tr({:#x}):\n {:#?}", + // tss_selector.0, + // gdt::Descriptor(GDT.table[tss_selector.index() as usize]) + // ); + // flush!(); GDT.load(); set_cs(kcode_selector); @@ -35,4 +43,5 @@ pub unsafe fn init() { load_es(kdata_selector); load_ss(kdata_selector); load_tss(tss_selector); + // unreachable!(); } diff --git a/kernel-rs/src/arch/x86/linker.ld b/kernel-rs/src/arch/x86/linker.ld index 2dc25860..df7fd06a 100644 --- a/kernel-rs/src/arch/x86/linker.ld +++ b/kernel-rs/src/arch/x86/linker.ld @@ -66,4 +66,16 @@ SECTIONS { *(.bss .bss.*) . = ALIGN(4K); } + + .stab : + { + *(.stab) + . = ALIGN(4K); + } + + .stabstr : + { + *(.stabstr) + . = ALIGN(4K); + } } diff --git a/kernel-rs/src/arch/x86/mod.rs b/kernel-rs/src/arch/x86/mod.rs index 89080806..4355d810 100644 --- a/kernel-rs/src/arch/x86/mod.rs +++ b/kernel-rs/src/arch/x86/mod.rs @@ -53,35 +53,39 @@ pub unsafe extern "C" fn x86_rust_start(multiboot_info_addr: usize) { } pub unsafe fn usermode(ip: u32, sp: u32, arg: u32) -> ! { - asm!("push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - " + use x86::structures::gdt::{Descriptor, SegmentSelector}; + use x86::instructions::segmentation::*; + use x86::PrivilegeLevel::{Ring0, Ring3}; + + x86::instructions::interrupts::disable(); + + // println!("sp: {:#x}", sp); + // println!("ip: {:#x}", ip); + + let udata_selector = SegmentSelector::new(gdt::GDT_USER_DATA, Ring0); + let ucode_selector = SegmentSelector::new(gdt::GDT_USER_CODE, Ring3); + load_ds(udata_selector); + load_es(udata_selector); + load_fs(udata_selector); + load_gs(udata_selector); + + asm!(" + push $0; \ + push $1; \ + push $2; \ + push $3; \ + push $4" : //no output - : "{r10}"(gdt::GDT_USER_DATA << 3 | 3), - "{r11}"(sp), - "{r12}"(1 << 9) // interrupt enable flag - "{r13}"(gdt::GDT_USER_CODE << 3 | 3), - "{r14}"(ip), - "{r15}"(arg) + : "r"(udata_selector), + "r"(sp), + "r"(1 << 9) // interrupt enable flag + "r"(ucode_selector), + "r"(ip) : //no clobbers : "intel", "volatile" ); - asm!("mov ds, r14d - mov es, r14d - mov fs, r15d - mov gs, r14d - fninit - iret" - : //no output (never returns) - : "{r14}"(gdt::GDT_USER_DATA << 3 | 3), - "{r15}"(gdt::GDT_USER_CODE << 3 | 3) - : //no clobbers (never returns) - : "intel", "volatile" - ); + asm!("iret"); + unreachable!(); } diff --git a/kernel-rs/src/arch/x86/paging/mapper.rs b/kernel-rs/src/arch/x86/paging/mapper.rs index c3d8115d..cf8ce6b5 100644 --- a/kernel-rs/src/arch/x86/paging/mapper.rs +++ b/kernel-rs/src/arch/x86/paging/mapper.rs @@ -84,7 +84,6 @@ impl Mapper { let frame = p1[page.p1_index()].pointed_frame().unwrap(); p1[page.p1_index()].set_unused(); tlb::flush(page.start_address()); - // TODO ::memory::deallocate_frames(frame, 1); } } diff --git a/kernel-rs/src/console.rs b/kernel-rs/src/console.rs index e3b45690..5cbf1196 100644 --- a/kernel-rs/src/console.rs +++ b/kernel-rs/src/console.rs @@ -188,17 +188,19 @@ pub fn regs() -> Result<(), &'static str> { use x86::registers::control::*; use x86::instructions::tables::tr; use x86::instructions::segmentation::*; + use x86::registers::flags::*; use x86::structures::gdt; - println!("cr0 = {:?}", Cr0::read()); - println!("cr3 = {:?}", Cr3::read()); - println!("cr4 = {:?}", Cr4::read()); - println!("tr = {:?}", tr()); - println!("ss = {:?}", ss()); - println!("cs = {:?}", cs()); - println!("ds = {:?}", ds()); - println!("es = {:?}", es()); - println!("fs = {:?}", fs()); - println!("gs = {:?}", gs()); + println!("cr0 = {:?}", Cr0::read()); + println!("cr3 = {:?}", Cr3::read()); + println!("cr4 = {:?}", Cr4::read()); + println!("flags= {:?}", flags()); + println!("tr = {:?}", tr()); + println!("ss = {:?}", ss()); + println!("cs = {:?}", cs()); + println!("ds = {:?}", ds()); + println!("es = {:?}", es()); + println!("fs = {:?}", fs()); + println!("gs = {:?}", gs()); unsafe { println!( "tss = {:#?}", diff --git a/kernel-rs/src/lib.rs b/kernel-rs/src/lib.rs index 6c65b86f..afe88457 100644 --- a/kernel-rs/src/lib.rs +++ b/kernel-rs/src/lib.rs @@ -3,6 +3,7 @@ // nightly stuff we need #![no_std] #![feature(lang_items)] +#![feature(naked_functions)] #![feature(const_fn)] #![feature(ptr_internals)] #![feature(asm)] @@ -67,6 +68,26 @@ pub fn kmain() -> ! { // x86::instructions::interrupts::int3(); + // println!("flags: {:?}", x86::registers::flags::flags()); + // flush!(); + + let sp = (::USER_STACK_OFFSET + ::USER_STACK_SIZE).as_u32(); + // let sp: u32; + // unsafe { + // asm!("mov %ebp, $0" : "=r" (sp)); + // } + let ip = self::init as *const () as u32; + + unsafe { + arch::x86::usermode(ip, sp, 0); + } + unreachable!() + // loop {} +} + +pub fn init() { + println!("inside init function!!!!!"); + flush!(); loop {} } diff --git a/kernel-rs/src/memory/mod.rs b/kernel-rs/src/memory/mod.rs index 3fba610d..d747acd5 100644 --- a/kernel-rs/src/memory/mod.rs +++ b/kernel-rs/src/memory/mod.rs @@ -6,7 +6,6 @@ use multiboot2; use x86::structures::paging::*; use arch::x86::paging::ActivePageTable; use x86::*; -// use spin::Mutex; use self::bump::BumpFrameAllocator; use self::recycle::RecycleAllocator; @@ -19,7 +18,7 @@ pub trait FrameAllocator { pub struct MemoryControler { frame_allocator: RecycleAllocator, - stack_allocator: StackAllocator, + // stack_allocator: StackAllocator, } static mut MEMORY_CONTROLER: Option = None; @@ -51,21 +50,12 @@ pub fn init(boot_info: &multiboot2::BootInformation) { ); let frame_allocator = RecycleAllocator::new(bump_allocator); - - let heap_end_page = - Page::containing_address(VirtAddr::new(::KERNEL_HEAP_OFFSET + ::KERNEL_HEAP_SIZE - 1)); - - let stack_allocator = { - let stack_alloc_start = heap_end_page + 1; - let stack_alloc_end = stack_alloc_start + 100; - let stack_alloc_range = stack_alloc_start..stack_alloc_end + 1; - StackAllocator::new(stack_alloc_range) - }; + // let stack_allocator = StackAllocator::new(::USER_STACK_RANGE); unsafe { MEMORY_CONTROLER = Some(MemoryControler { frame_allocator, - stack_allocator, + // stack_allocator, }); } } @@ -90,17 +80,17 @@ pub fn deallocate_frames(frame: PhysFrame, count: usize) { } } -pub fn allocate_stack(mut active_table: &mut ActivePageTable) -> Option { - unsafe { - if let Some(ref mut controler) = MEMORY_CONTROLER { - controler - .stack_allocator - .allocate_stack(&mut active_table, 4) - } else { - panic!("frame allocator not initialized!"); - } - } -} +// pub fn allocate_stack(mut active_table: &mut ActivePageTable) -> Option { +// unsafe { +// if let Some(ref mut controler) = MEMORY_CONTROLER { +// controler +// .stack_allocator +// .allocate_stack(&mut active_table, 4) +// } else { +// panic!("frame allocator not initialized!"); +// } +// } +// } /// Init memory module after core /// Must be called once, and only once, diff --git a/kernel-rs/x86 b/kernel-rs/x86 index 73a83239..3a6ff64c 160000 --- a/kernel-rs/x86 +++ b/kernel-rs/x86 @@ -1 +1 @@ -Subproject commit 73a83239073de4acb5b18bacad049553a086ce3f +Subproject commit 3a6ff64c5fb9a4bdeb8b6b4c83328278c551dbad