some stuff

This commit is contained in:
Jack Halford 2018-05-17 13:17:39 +02:00
parent 0aae87eda3
commit e2cf54877e
16 changed files with 186 additions and 116 deletions

2
kernel-rs/.gdbinit Normal file
View file

@ -0,0 +1,2 @@
set arch i386:x86-64
symbol-file build/bluesnow-x86.bin

View file

@ -1,7 +1,7 @@
[package]
name = "bluesnow"
version = "0.1.0"
authors = ["Jack Halford <j@crans.org>", "William Escande <wescande@student.42.fr>"]
authors = ["Jack Halford <jack@crans.org>", "William Escande <wescande@student.42.fr>"]
[lib]
crate-type = ["staticlib"]

View file

@ -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)

View file

@ -1,4 +1,4 @@
grub-iso := $(kernel).iso
grub-iso := $(kernel:.bin=.iso)
grub-cfg := src/arch/$(ARCH)/grub.cfg
isodir := build/isofiles

View file

@ -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)'

View file

@ -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);
}

View file

@ -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

View file

@ -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<Page> = 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<Page> = USER_STACK_START..USER_STACK_END;

View file

@ -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!();
}

View file

@ -66,4 +66,16 @@ SECTIONS {
*(.bss .bss.*)
. = ALIGN(4K);
}
.stab :
{
*(.stab)
. = ALIGN(4K);
}
.stabstr :
{
*(.stabstr)
. = ALIGN(4K);
}
}

View file

@ -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!();
}

View file

@ -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);
}
}

View file

@ -188,10 +188,12 @@ 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!("flags= {:?}", flags());
println!("tr = {:?}", tr());
println!("ss = {:?}", ss());
println!("cs = {:?}", cs());

View file

@ -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 {}
}

View file

@ -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<BumpFrameAllocator>,
stack_allocator: StackAllocator,
// stack_allocator: StackAllocator,
}
static mut MEMORY_CONTROLER: Option<MemoryControler> = 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<Stack> {
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<Stack> {
// 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,

@ -1 +1 @@
Subproject commit 73a83239073de4acb5b18bacad049553a086ce3f
Subproject commit 3a6ff64c5fb9a4bdeb8b6b4c83328278c551dbad