major refactoring for upcoming cross platform, also recycle allocator for the physical frames
This commit is contained in:
parent
095c369061
commit
6d8c31b42c
26 changed files with 567 additions and 379 deletions
|
|
@ -9,9 +9,13 @@ crate-type = ["staticlib"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rlibc = "1.0"
|
rlibc = "1.0"
|
||||||
bitflags = "1.0.1"
|
bitflags = "1.0.1"
|
||||||
|
spin = "0.4"
|
||||||
multiboot2 = { path = "multiboot2-elf64" }
|
multiboot2 = { path = "multiboot2-elf64" }
|
||||||
|
slab_allocator = "0.3.1"
|
||||||
x86 = { path = "x86" }
|
x86 = { path = "x86" }
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
features = ["spin_no_std"]
|
features = ["spin_no_std"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,77 +1,42 @@
|
||||||
SHELL := /bin/bash
|
SHELL := /bin/bash
|
||||||
|
|
||||||
ifeq ($(shell whoami), william)
|
ARCH := x86
|
||||||
PORT := 4242
|
OS := bluesnow
|
||||||
PORTG := 4244
|
target ?= $(ARCH)-$(OS)
|
||||||
else
|
|
||||||
PORT := 4342
|
|
||||||
PORTG := 4344
|
|
||||||
endif
|
|
||||||
|
|
||||||
project := bluesnow
|
|
||||||
arch ?= x86
|
|
||||||
NASM := /usr/bin/nasm -f elf -g
|
NASM := /usr/bin/nasm -f elf -g
|
||||||
LD := /usr/bin/ld -m elf_i386 -L ./ -n --gc-sections
|
LD := /usr/bin/ld -m elf_i386 -L ./ -n --gc-sections
|
||||||
# QEMU := qemu-system-x86_64 -device isa-debug-exit,iobase=0xf4,iosize=0x04 -gdb tcp::$(PORTG) -enable-kvm -monitor telnet:127.0.0.1:$(PORT),server,nowait
|
MKDIR := mkdir -p
|
||||||
QEMU := qemu-system-x86_64 -gdb tcp::$(PORTG) -enable-kvm -monitor telnet:127.0.0.1:$(PORT),server,nowait
|
|
||||||
|
|
||||||
kerName := BlueSnow
|
kernel := build/$(OS)
|
||||||
kernel := build/$(kerName)
|
|
||||||
iso := $(kernel).iso
|
iso := $(kernel).iso
|
||||||
DIRISO := build/isofiles
|
DIRISO := build/isofiles
|
||||||
|
|
||||||
target ?= $(arch)-$(project)
|
rust_os := target/$(target)/debug/lib$(OS).a
|
||||||
rust_os := target/$(target)/debug/lib$(project).a
|
|
||||||
|
|
||||||
linker_script := src/arch/$(arch)/linker.ld
|
linker_script := src/arch/$(ARCH)/linker.ld
|
||||||
grub.cfg := src/arch/$(arch)/grub.cfg
|
grub.cfg := src/arch/$(ARCH)/grub.cfg
|
||||||
asm_source := $(wildcard src/arch/$(arch)/*.asm)
|
asm_source := $(wildcard src/arch/$(ARCH)/*.asm)
|
||||||
asm_object := $(patsubst src/arch/$(arch)/%.asm, build/arch/$(arch)/%.o, $(asm_source))
|
asm_object := $(patsubst src/arch/$(ARCH)/%.asm, build/arch/$(ARCH)/%.o, $(asm_source))
|
||||||
|
|
||||||
KERNEL_RUN := $(QEMU) -curses -cdrom $(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\"
|
|
||||||
|
|
||||||
all: $(kernel)
|
all: $(kernel)
|
||||||
|
|
||||||
build/arch/$(arch)/%.o: src/arch/$(arch)/%.asm Makefile
|
build/arch/$(ARCH)/%.o: src/arch/$(ARCH)/%.asm Makefile
|
||||||
@mkdir -p $(shell dirname $@)
|
@$(MKDIR) $(shell dirname $@)
|
||||||
$(NASM) $< -o $@
|
$(NASM) $< -o $@
|
||||||
|
|
||||||
$(kernel): $(rust_os) $(asm_object) $(linker_script) Makefile
|
$(kernel): $(rust_os) $(asm_object) $(linker_script) Makefile
|
||||||
$(LD) -o $@ -T $(linker_script) $(asm_object) $(rust_os)
|
$(LD) -o $@ -T $(linker_script) $(asm_object) $(rust_os)
|
||||||
|
|
||||||
$(iso): $(kernel) $(grub.cfg) Makefile
|
$(iso): $(kernel) $(grub.cfg) Makefile
|
||||||
@mkdir -p $(DIRISO)/boot/grub
|
@$(MKDIR) $(DIRISO)/boot/grub
|
||||||
@cp $(grub.cfg) $(DIRISO)/boot/grub
|
@cp $(grub.cfg) $(DIRISO)/boot/grub
|
||||||
@cp $(kernel) $(DIRISO)/boot/$(kerName)
|
@cp $(kernel) $(DIRISO)/boot/$(OS)
|
||||||
@grub-mkrescue -o $@ $(DIRISO) 2>/dev/null
|
@grub-mkrescue -o $@ $(DIRISO) 2>/dev/null
|
||||||
|
|
||||||
# $(kernel).img: $(kernel)
|
|
||||||
# @cp .clean.img $@
|
|
||||||
# @sudo mount -oloop=/dev/loop0,offset=32256 $@ /mnt
|
|
||||||
# @sudo cp $(kernel) /mnt/boot/.
|
|
||||||
# @sudo umount /mnt
|
|
||||||
|
|
||||||
run: $(iso) Makefile
|
|
||||||
@tmux info >&- || { echo -e "\033[38;5;16m ~~ NOT IN A VALID 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; $(KERNEL_RUN)'
|
|
||||||
|
|
||||||
# Run without try to do a compile
|
|
||||||
R:
|
|
||||||
@tmux info >&- || { echo -e "\033[38;5;16m ~~ NOT IN A VALID 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; $(KERNEL_RUN)'
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@xargo clean
|
@xargo clean
|
||||||
@rm -r build
|
@rm -rf build
|
||||||
|
|
||||||
$(rust_os): $(target).json Makefile
|
$(rust_os): $(target).json Makefile
|
||||||
@RUST_TARGET_PATH="$(shell pwd)" xargo build --target $(target)
|
@RUST_TARGET_PATH="$(shell pwd)" xargo build --target $(target)
|
||||||
|
|
@ -79,4 +44,7 @@ $(rust_os): $(target).json Makefile
|
||||||
kernel: $(rust_os)
|
kernel: $(rust_os)
|
||||||
iso: $(iso)
|
iso: $(iso)
|
||||||
|
|
||||||
.PHONY: R run clean kernel iso $(rust_os)
|
.PHONY: clean kernel iso $(rust_os)
|
||||||
|
|
||||||
|
# Emulation recipes
|
||||||
|
include mk/qemu.mk
|
||||||
|
|
|
||||||
25
kernel-rs/mk/qemu.mk
Normal file
25
kernel-rs/mk/qemu.mk
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
ifeq ($(shell whoami), william)
|
||||||
|
PORT := 4242
|
||||||
|
PORTG := 4244
|
||||||
|
else
|
||||||
|
PORT := 4342
|
||||||
|
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
|
||||||
|
|
||||||
|
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\"
|
||||||
|
|
||||||
|
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) $(iso)'
|
||||||
|
|
||||||
27
kernel-rs/src/allocator/mod.rs
Normal file
27
kernel-rs/src/allocator/mod.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
pub use self::slab::Allocator;
|
||||||
|
mod slab;
|
||||||
|
|
||||||
|
use x86::*;
|
||||||
|
use x86::structures::paging::*;
|
||||||
|
use arch::x86::paging::*;
|
||||||
|
|
||||||
|
fn map_heap(active_table: &mut ActivePageTable, offset: usize, size: usize)
|
||||||
|
{
|
||||||
|
let heap_start_page = Page::containing_address(VirtAddr::new(offset as u32));
|
||||||
|
let heap_end_page = Page::containing_address(VirtAddr::new(
|
||||||
|
offset as u32 + size as u32 - 1));
|
||||||
|
|
||||||
|
for page in heap_start_page..heap_end_page + 1 {
|
||||||
|
active_table.map(page, PageTableFlags::WRITABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// should be called only once
|
||||||
|
pub unsafe fn init(active_table: &mut ActivePageTable) {
|
||||||
|
let offset = ::HEAP_START;
|
||||||
|
let size = ::HEAP_SIZE;
|
||||||
|
|
||||||
|
map_heap(active_table, offset, size);
|
||||||
|
|
||||||
|
Allocator::init(offset, size);
|
||||||
|
}
|
||||||
43
kernel-rs/src/allocator/slab.rs
Normal file
43
kernel-rs/src/allocator/slab.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use alloc::heap::{Alloc, AllocErr, Layout};
|
||||||
|
use spin::Mutex;
|
||||||
|
use slab_allocator::Heap;
|
||||||
|
|
||||||
|
static HEAP: Mutex<Option<Heap>> = Mutex::new(None);
|
||||||
|
|
||||||
|
pub struct Allocator;
|
||||||
|
|
||||||
|
impl Allocator {
|
||||||
|
pub unsafe fn init(offset: usize, size: usize) {
|
||||||
|
*HEAP.lock() = Some(Heap::new(offset, size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> Alloc for &'a Allocator {
|
||||||
|
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
|
||||||
|
if let Some(ref mut heap) = *HEAP.lock() {
|
||||||
|
heap.allocate(layout)
|
||||||
|
} else {
|
||||||
|
panic!("__rust_allocate: heap not initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
|
||||||
|
if let Some(ref mut heap) = *HEAP.lock() {
|
||||||
|
heap.deallocate(ptr, layout)
|
||||||
|
} else {
|
||||||
|
panic!("__rust_deallocate: heap not initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oom(&mut self, error: AllocErr) -> ! {
|
||||||
|
panic!("Out of memory: {:?}", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usable_size(&self, layout: &Layout) -> (usize, usize) {
|
||||||
|
if let Some(ref mut heap) = *HEAP.lock() {
|
||||||
|
heap.usable_size(layout)
|
||||||
|
} else {
|
||||||
|
panic!("__rust_usable_size: heap not initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
kernel-rs/src/arch/mod.rs
Normal file
1
kernel-rs/src/arch/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod x86;
|
||||||
|
|
@ -2,6 +2,6 @@ set timeout=0
|
||||||
set default=0
|
set default=0
|
||||||
|
|
||||||
menuentry "Blue Snow" {
|
menuentry "Blue Snow" {
|
||||||
multiboot2 /boot/BlueSnow
|
multiboot2 /boot/bluesnow
|
||||||
boot
|
boot
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
kernel-rs/src/arch/x86/interrupt/exception.rs
Normal file
34
kernel-rs/src/arch/x86/interrupt/exception.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
// https://wiki.osdev.org/Exceptions
|
||||||
|
|
||||||
|
use x86::structures::idt::*;
|
||||||
|
|
||||||
|
interrupt!(divide_by_zero, {});
|
||||||
|
interrupt!(debug, {});
|
||||||
|
interrupt!(non_maskable, {});
|
||||||
|
interrupt!(breakpoint, {});
|
||||||
|
interrupt!(overflow, {});
|
||||||
|
interrupt!(bound_range, {});
|
||||||
|
interrupt!(invalid_opcode, {});
|
||||||
|
interrupt!(device_not_available, {});
|
||||||
|
interrupt_err!(double_fault, {});
|
||||||
|
interrupt!(coprocessor_segment_overrun, {});
|
||||||
|
interrupt_err!(invalid_tss, {});
|
||||||
|
interrupt_err!(segment_not_present, {});
|
||||||
|
interrupt_err!(stack_segment, {});
|
||||||
|
interrupt_err!(general_protection, {});
|
||||||
|
|
||||||
|
pub extern "x86-interrupt" fn page_fault(
|
||||||
|
stack_frame: &mut ExceptionStackFrame, code: PageFaultErrorCode)
|
||||||
|
{
|
||||||
|
println!("Exception: page_fault");
|
||||||
|
println!("Error code: {:#b}", code);
|
||||||
|
println!("{:#?}", stack_frame);
|
||||||
|
flush!();
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt!(x87_fpu, {});
|
||||||
|
interrupt_err!(alignment_check, {});
|
||||||
|
interrupt!(machine_check, {});
|
||||||
|
interrupt!(simd, {});
|
||||||
|
interrupt!(virtualization, {});
|
||||||
|
interrupt_err!(security, {});
|
||||||
6
kernel-rs/src/arch/x86/interrupt/irq.rs
Normal file
6
kernel-rs/src/arch/x86/interrupt/irq.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
use x86::structures::idt::*;
|
||||||
|
|
||||||
|
interrupt!(keyboard, {
|
||||||
|
println!("key pressed!");
|
||||||
|
flush!();
|
||||||
|
});
|
||||||
46
kernel-rs/src/arch/x86/interrupt/mod.rs
Normal file
46
kernel-rs/src/arch/x86/interrupt/mod.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use x86::structures::idt::*;
|
||||||
|
|
||||||
|
#[macro_use] pub mod exception;
|
||||||
|
#[macro_use] pub mod irq;
|
||||||
|
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref IDT: Idt = {
|
||||||
|
let mut idt = Idt::new();
|
||||||
|
|
||||||
|
// set up CPU exceptions
|
||||||
|
idt.breakpoint.set_handler_fn(exception::breakpoint);
|
||||||
|
idt.debug.set_handler_fn(exception::debug);
|
||||||
|
idt.non_maskable_interrupt.set_handler_fn(exception::non_maskable);
|
||||||
|
idt.breakpoint.set_handler_fn(exception::breakpoint);
|
||||||
|
idt.overflow.set_handler_fn(exception::overflow);
|
||||||
|
idt.bound_range_exceeded.set_handler_fn(exception::bound_range);
|
||||||
|
idt.invalid_opcode.set_handler_fn(exception::invalid_opcode);
|
||||||
|
idt.device_not_available.set_handler_fn(exception::device_not_available);
|
||||||
|
idt.double_fault.set_handler_fn(exception::double_fault);
|
||||||
|
idt.segment_not_present.set_handler_fn(exception::segment_not_present);
|
||||||
|
idt.stack_segment_fault.set_handler_fn(exception::stack_segment);
|
||||||
|
idt.general_protection_fault.set_handler_fn(exception::general_protection);
|
||||||
|
idt.page_fault.set_handler_fn(exception::page_fault);
|
||||||
|
idt.x87_floating_point.set_handler_fn(exception::x87_fpu);
|
||||||
|
idt.alignment_check.set_handler_fn(exception::alignment_check);
|
||||||
|
idt.machine_check.set_handler_fn(exception::machine_check);
|
||||||
|
idt.simd_floating_point.set_handler_fn(exception::simd);
|
||||||
|
idt.virtualization.set_handler_fn(exception::virtualization);
|
||||||
|
|
||||||
|
// set up IRQs
|
||||||
|
idt.interrupts[0].set_handler_fn(irq::keyboard);
|
||||||
|
idt.interrupts[1].set_handler_fn(irq::keyboard);
|
||||||
|
idt.interrupts[2].set_handler_fn(irq::keyboard);
|
||||||
|
idt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn init(memory_controller: &mut ::memory::MemoryController) {
|
||||||
|
pub fn init() {
|
||||||
|
// let double_fault_stack = memory_controller.alloc_stack(1)
|
||||||
|
// .expect("could not allocate double fault stack");
|
||||||
|
// println!("DF stack: {:#?}", double_fault_stack);
|
||||||
|
// flush!();
|
||||||
|
IDT.load();
|
||||||
|
}
|
||||||
36
kernel-rs/src/arch/x86/macros.rs
Normal file
36
kernel-rs/src/arch/x86/macros.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt {
|
||||||
|
($name:ident, $func:block) => {
|
||||||
|
pub extern "x86-interrupt" fn $name(stack_frame: &mut ExceptionStackFrame)
|
||||||
|
{
|
||||||
|
println!("Exception: {}", stringify!($name));
|
||||||
|
println!("{:#?}", stack_frame);
|
||||||
|
flush!();
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn inner(stack: &mut ExceptionStackFrame) {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
inner(stack_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! interrupt_err {
|
||||||
|
($name:ident, $func:block) => {
|
||||||
|
pub extern "x86-interrupt" fn $name(
|
||||||
|
stack_frame: &mut ExceptionStackFrame, _error_code: u32)
|
||||||
|
{
|
||||||
|
println!("Exception: {}", stringify!($name));
|
||||||
|
println!("{:#?}", stack_frame);
|
||||||
|
flush!();
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn inner(stack: &mut ExceptionStackFrame) {
|
||||||
|
$func
|
||||||
|
}
|
||||||
|
inner(stack_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
kernel-rs/src/arch/x86/mod.rs
Normal file
42
kernel-rs/src/arch/x86/mod.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
extern crate x86;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
|
pub mod paging;
|
||||||
|
pub mod interrupt;
|
||||||
|
|
||||||
|
use multiboot2;
|
||||||
|
use acpi;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern fn x86_rust_start(multiboot_info_addr: usize) {
|
||||||
|
// parse multiboot2 info
|
||||||
|
let boot_info = multiboot2::load(multiboot_info_addr);
|
||||||
|
|
||||||
|
// ACPI must be intialized BEFORE paging is active
|
||||||
|
if let Some(rsdp) = boot_info.rsdp_v2_tag() {
|
||||||
|
acpi::load(rsdp).expect("ACPI failed");
|
||||||
|
} else if let Some(rsdp) = boot_info.rsdp_tag() {
|
||||||
|
acpi::load(rsdp).expect("ACPI failed");
|
||||||
|
} else {
|
||||||
|
acpi::init().expect("ACPI failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up physical allocator
|
||||||
|
::memory::init(&boot_info);
|
||||||
|
|
||||||
|
// set up virtual mapping
|
||||||
|
let mut active_table = self::paging::init(&boot_info);
|
||||||
|
|
||||||
|
// set up heap
|
||||||
|
::allocator::init(&mut active_table);
|
||||||
|
|
||||||
|
// after core has loaded
|
||||||
|
::memory::init_noncore();
|
||||||
|
|
||||||
|
// set up interrupts
|
||||||
|
self::interrupt::init();
|
||||||
|
|
||||||
|
// primary CPU entry point
|
||||||
|
::kmain();
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
use memory::{PAGE_SIZE, FrameAllocator};
|
|
||||||
use core::ptr::Unique;
|
use core::ptr::Unique;
|
||||||
use x86::structures::paging::*;
|
use x86::structures::paging::*;
|
||||||
use x86::instructions::tlb;
|
use x86::instructions::tlb;
|
||||||
use x86::usize_conversions::usize_from;
|
use x86::usize_conversions::usize_from;
|
||||||
use x86::*;
|
use x86::*;
|
||||||
use super::paging::table::RecTable;
|
use super::table::RecTable;
|
||||||
|
|
||||||
// virtual address of recursively mapped P2
|
// virtual address of recursively mapped P2
|
||||||
// for protected mode non PAE
|
// for protected mode non PAE
|
||||||
|
|
@ -59,33 +58,28 @@ impl Mapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// map a virtual page to a physical frame in the page tables
|
/// map a virtual page to a physical frame in the page tables
|
||||||
pub fn map_to<A>(&mut self, page: Page, frame: PhysFrame, flags: PageTableFlags,
|
pub fn map_to(&mut self, page: Page, frame: PhysFrame, flags: PageTableFlags)
|
||||||
allocator: &mut A)
|
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
{
|
||||||
let p2 = self.p2_mut();
|
let p2 = self.p2_mut();
|
||||||
let p1 = p2.next_table_create(usize_from(u32::from(page.p2_index())), allocator);
|
let p1 = p2.next_table_create(usize_from(u32::from(page.p2_index())));
|
||||||
assert!(p1[page.p1_index()].is_unused());
|
assert!(p1[page.p1_index()].is_unused());
|
||||||
p1[page.p1_index()].set(frame, flags | PageTableFlags::PRESENT);
|
p1[page.p1_index()].set(frame, flags | PageTableFlags::PRESENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map<A>(&mut self, page: Page, flags: PageTableFlags, allocator: &mut A)
|
pub fn map(&mut self, page: Page, flags: PageTableFlags)
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
{
|
||||||
let frame = allocator.allocate_frame().expect("out of memory");
|
let frame = ::memory::allocate_frames(1).expect("out of frames");
|
||||||
self.map_to(page, frame, flags, allocator)
|
self.map_to(page, frame, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identity_map<A>(&mut self, frame: PhysFrame, flags: PageTableFlags, allocator: &mut A)
|
pub fn identity_map(&mut self, frame: PhysFrame, flags: PageTableFlags)
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
{
|
||||||
let virt_addr = VirtAddr::new(frame.start_address().as_u32());
|
let virt_addr = VirtAddr::new(frame.start_address().as_u32());
|
||||||
let page = Page::containing_address(virt_addr);
|
let page = Page::containing_address(virt_addr);
|
||||||
self.map_to(page, frame, flags, allocator);
|
self.map_to(page, frame, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap<A>(&mut self, page: Page, allocator: &mut A)
|
pub fn unmap(&mut self, page: Page)
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
{
|
||||||
assert!(self.translate(page.start_address()).is_some());
|
assert!(self.translate(page.start_address()).is_some());
|
||||||
|
|
||||||
|
|
@ -96,6 +90,6 @@ impl Mapper {
|
||||||
p1[page.p1_index()].set_unused();
|
p1[page.p1_index()].set_unused();
|
||||||
tlb::flush(page.start_address());
|
tlb::flush(page.start_address());
|
||||||
// TODO
|
// TODO
|
||||||
// allocator.deallocate_frame(frame);
|
::memory::deallocate_frames(frame, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ mod table;
|
||||||
mod temporary_page;
|
mod temporary_page;
|
||||||
mod mapper;
|
mod mapper;
|
||||||
|
|
||||||
use memory::*;
|
// use memory::*;
|
||||||
use self::mapper::Mapper;
|
use self::mapper::Mapper;
|
||||||
use self::temporary_page::TemporaryPage;
|
use self::temporary_page::TemporaryPage;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
@ -12,6 +12,19 @@ use multiboot2::BootInformation;
|
||||||
use x86::*;
|
use x86::*;
|
||||||
use x86::registers::control::Cr3;
|
use x86::registers::control::Cr3;
|
||||||
use x86::instructions::tlb;
|
use x86::instructions::tlb;
|
||||||
|
use x86::structures::paging::*;
|
||||||
|
use multiboot2;
|
||||||
|
|
||||||
|
/// should be called only once
|
||||||
|
pub fn init(boot_info: &multiboot2::BootInformation) -> ActivePageTable {
|
||||||
|
use x86::registers::control::*;
|
||||||
|
Cr4::add(Cr4Flags::PSE);
|
||||||
|
Cr0::add(Cr0Flags::PAGING | Cr0Flags::WRITE_PROTECT);
|
||||||
|
|
||||||
|
let active_table = remap_the_kernel(boot_info);
|
||||||
|
|
||||||
|
active_table
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ActivePageTable {
|
pub struct ActivePageTable {
|
||||||
mapper: Mapper,
|
mapper: Mapper,
|
||||||
|
|
@ -92,27 +105,26 @@ impl InactivePageTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
|
pub fn remap_the_kernel(boot_info: &BootInformation) -> ActivePageTable
|
||||||
-> ActivePageTable
|
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
{
|
||||||
let mut temporary_page = TemporaryPage::new(Page{number: 0xcafe}, allocator);
|
let mut temporary_page = TemporaryPage::new(Page{number: 0xcafe});
|
||||||
let mut active_table = unsafe { ActivePageTable::new() };
|
let mut active_table = unsafe { ActivePageTable::new() };
|
||||||
let mut new_table = {
|
let mut new_table = {
|
||||||
let frame = allocator.allocate_frame().expect("no more frames");
|
let frame = ::memory::allocate_frames(1).expect("no more frames");
|
||||||
InactivePageTable::new(frame, &mut active_table, &mut temporary_page)
|
InactivePageTable::new(frame, &mut active_table, &mut temporary_page)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
active_table.with(&mut new_table, &mut temporary_page, |mapper| {
|
active_table.with(&mut new_table, &mut temporary_page, |mapper| {
|
||||||
|
|
||||||
// identity map the VGA text buffer
|
// id map vga buffer
|
||||||
let vga_buffer_frame = PhysFrame::containing_address(PhysAddr::new(0xb8000));
|
let vga_buffer_frame = PhysFrame::containing_address(PhysAddr::new(0xb8000));
|
||||||
mapper.identity_map(vga_buffer_frame, PageTableFlags::WRITABLE, allocator);
|
mapper.identity_map(vga_buffer_frame, PageTableFlags::WRITABLE);
|
||||||
|
|
||||||
let elf_sections_tag = boot_info.elf_sections_tag()
|
let elf_sections_tag = boot_info.elf_sections_tag()
|
||||||
.expect("Memory map tag required");
|
.expect("Memory map tag required");
|
||||||
|
|
||||||
|
// id map kernel sections
|
||||||
for section in elf_sections_tag.sections() {
|
for section in elf_sections_tag.sections() {
|
||||||
if !section.is_allocated() {
|
if !section.is_allocated() {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -126,16 +138,17 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
|
||||||
let end_frame = PhysFrame::containing_address(
|
let end_frame = PhysFrame::containing_address(
|
||||||
PhysAddr::new(section.end_address() as u32 - 1));
|
PhysAddr::new(section.end_address() as u32 - 1));
|
||||||
for frame in start_frame..end_frame + 1 {
|
for frame in start_frame..end_frame + 1 {
|
||||||
mapper.identity_map(frame, flags, allocator);
|
mapper.identity_map(frame, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// id map multiboot
|
||||||
let multiboot_start = PhysFrame::containing_address(
|
let multiboot_start = PhysFrame::containing_address(
|
||||||
PhysAddr::new(boot_info.start_address() as u32));
|
PhysAddr::new(boot_info.start_address() as u32));
|
||||||
let multiboot_end = PhysFrame::containing_address(
|
let multiboot_end = PhysFrame::containing_address(
|
||||||
PhysAddr::new(boot_info.end_address() as u32 - 1));
|
PhysAddr::new(boot_info.end_address() as u32 - 1));
|
||||||
for frame in multiboot_start..multiboot_end + 1 {
|
for frame in multiboot_start..multiboot_end + 1 {
|
||||||
mapper.identity_map(frame, PageTableFlags::PRESENT, allocator);
|
mapper.identity_map(frame, PageTableFlags::PRESENT);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -144,7 +157,7 @@ pub fn remap_the_kernel<A>(allocator: &mut A, boot_info: &BootInformation)
|
||||||
let old_p2_page = Page::containing_address(
|
let old_p2_page = Page::containing_address(
|
||||||
VirtAddr::new(old_table.p2_frame.start_address().as_u32()));
|
VirtAddr::new(old_table.p2_frame.start_address().as_u32()));
|
||||||
|
|
||||||
active_table.unmap(old_p2_page, allocator);
|
active_table.unmap(old_p2_page);
|
||||||
|
|
||||||
active_table
|
active_table
|
||||||
}
|
}
|
||||||
|
|
@ -163,10 +176,6 @@ fn elf_to_pagetable_flags(elf_flags: &multiboot2::ElfSectionFlags)
|
||||||
if elf_flags.contains(ElfSectionFlags::WRITABLE) {
|
if elf_flags.contains(ElfSectionFlags::WRITABLE) {
|
||||||
flags = flags | PageTableFlags::WRITABLE;
|
flags = flags | PageTableFlags::WRITABLE;
|
||||||
}
|
}
|
||||||
// LONG MODE STUFF
|
|
||||||
// if !elf_flags.contains(ELF_SECTION_EXECUTABLE) {
|
|
||||||
// flags = flags | PageTableFlags::NO_EXECUTE;
|
|
||||||
// }
|
|
||||||
|
|
||||||
flags
|
flags
|
||||||
}
|
}
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
use memory::*;
|
|
||||||
use x86::structures::paging::*;
|
use x86::structures::paging::*;
|
||||||
// use x86::ux::*;
|
|
||||||
|
|
||||||
pub trait RecTable
|
pub trait RecTable
|
||||||
{
|
{
|
||||||
fn next_table_address(&self, index: usize) -> Option<u32>;
|
fn next_table_address(&self, index: usize) -> Option<u32>;
|
||||||
fn next_table(&self, index: usize) -> Option<&PageTable>;
|
fn next_table(&self, index: usize) -> Option<&PageTable>;
|
||||||
fn next_table_mut(&mut self, index: usize) -> Option<&mut PageTable>;
|
fn next_table_mut(&mut self, index: usize) -> Option<&mut PageTable>;
|
||||||
fn next_table_create<A: FrameAllocator>(&mut self,
|
fn next_table_create(&mut self,
|
||||||
index: usize,
|
index: usize)
|
||||||
allocator: &mut A)
|
|
||||||
-> &mut PageTable;
|
-> &mut PageTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,15 +32,14 @@ impl RecTable for PageTable
|
||||||
.map(|address| unsafe { &mut *(address as *mut _) })
|
.map(|address| unsafe { &mut *(address as *mut _) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_table_create<A>(&mut self,
|
fn next_table_create(&mut self,
|
||||||
index: usize,
|
index: usize) -> &mut PageTable
|
||||||
allocator: &mut A) -> &mut PageTable
|
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
{
|
||||||
if self.next_table(index).is_none() {
|
if self.next_table(index).is_none() {
|
||||||
assert!(!self[index].flags().contains(PageTableFlags::HUGE_PAGE),
|
assert!(!self[index].flags().contains(PageTableFlags::HUGE_PAGE),
|
||||||
"mapping code does not support huge pages");
|
"mapping code does not support huge pages");
|
||||||
let frame = allocator.allocate_frame().expect("no frames available");
|
let frame = ::memory::allocate_frames(1)
|
||||||
|
.expect("out of memory");
|
||||||
self[index].set(frame, PageTableFlags::PRESENT | PageTableFlags::WRITABLE);
|
self[index].set(frame, PageTableFlags::PRESENT | PageTableFlags::WRITABLE);
|
||||||
self.next_table_mut(index).expect("next_table_mut gave None").zero()
|
self.next_table_mut(index).expect("next_table_mut gave None").zero()
|
||||||
}
|
}
|
||||||
|
|
@ -1,21 +1,15 @@
|
||||||
use super::ActivePageTable;
|
use super::ActivePageTable;
|
||||||
use memory::{FrameAllocator};
|
|
||||||
use x86::*;
|
use x86::*;
|
||||||
use x86::structures::paging::*;
|
use x86::structures::paging::*;
|
||||||
|
|
||||||
pub struct TemporaryPage {
|
pub struct TemporaryPage {
|
||||||
pub page: Page,
|
pub page: Page,
|
||||||
allocator: TinyAllocator,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TemporaryPage {
|
impl TemporaryPage {
|
||||||
pub fn new<A>(page: Page, allocator: &mut A) -> TemporaryPage
|
pub fn new(page: Page) -> TemporaryPage
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
{
|
||||||
TemporaryPage {
|
TemporaryPage { page: page }
|
||||||
page: page,
|
|
||||||
allocator: TinyAllocator::new(allocator),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps the temporary page to the given frame in the active table.
|
/// Maps the temporary page to the given frame in the active table.
|
||||||
|
|
@ -25,7 +19,7 @@ impl TemporaryPage {
|
||||||
{
|
{
|
||||||
assert!(active_table.translate_page(self.page).is_none(),
|
assert!(active_table.translate_page(self.page).is_none(),
|
||||||
"temporary page is already mapped");
|
"temporary page is already mapped");
|
||||||
active_table.map_to(self.page, frame, PageTableFlags::WRITABLE, &mut self.allocator);
|
active_table.map_to(self.page, frame, PageTableFlags::WRITABLE);
|
||||||
// this kind of check should be done in a test routine
|
// this kind of check should be done in a test routine
|
||||||
assert!(active_table.translate_page(self.page).is_some(),
|
assert!(active_table.translate_page(self.page).is_some(),
|
||||||
"temporary page was not mapped");
|
"temporary page was not mapped");
|
||||||
|
|
@ -34,7 +28,7 @@ impl TemporaryPage {
|
||||||
|
|
||||||
/// Unmaps the temporary page in the active table.
|
/// Unmaps the temporary page in the active table.
|
||||||
pub fn unmap(&mut self, active_table: &mut ActivePageTable) {
|
pub fn unmap(&mut self, active_table: &mut ActivePageTable) {
|
||||||
active_table.unmap(self.page, &mut self.allocator)
|
active_table.unmap(self.page)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps the temporary page to the given page table frame in the active
|
/// Maps the temporary page to the given page table frame in the active
|
||||||
|
|
@ -46,36 +40,3 @@ impl TemporaryPage {
|
||||||
unsafe { &mut *(self.map(frame, active_table).as_u32() as *mut PageTable) }
|
unsafe { &mut *(self.map(frame, active_table).as_u32() as *mut PageTable) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TinyAllocator([Option<PhysFrame>; 1]);
|
|
||||||
|
|
||||||
impl TinyAllocator {
|
|
||||||
fn new<A>(allocator: &mut A) -> TinyAllocator
|
|
||||||
where A: FrameAllocator
|
|
||||||
{
|
|
||||||
let mut f = || allocator.allocate_frame();
|
|
||||||
let frames = [f()];
|
|
||||||
TinyAllocator(frames)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FrameAllocator for TinyAllocator {
|
|
||||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
|
||||||
for frame_option in &mut self.0 {
|
|
||||||
if frame_option.is_some() {
|
|
||||||
return frame_option.take();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deallocate_frame(&mut self, frame: PhysFrame) {
|
|
||||||
for frame_option in &mut self.0 {
|
|
||||||
if frame_option.is_none() {
|
|
||||||
*frame_option = Some(frame);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic!("Tiny allocator can only hold 1 frame.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
global x86_start
|
global x86_start
|
||||||
extern kmain
|
extern x86_rust_start
|
||||||
|
|
||||||
section .text
|
section .text
|
||||||
bits 32
|
bits 32
|
||||||
|
|
@ -11,7 +11,7 @@ x86_start:
|
||||||
mov fs, ax
|
mov fs, ax
|
||||||
mov gs, ax
|
mov gs, ax
|
||||||
|
|
||||||
call kmain
|
call x86_rust_start
|
||||||
|
|
||||||
cli ; clear interrupt
|
cli ; clear interrupt
|
||||||
HALT:
|
HALT:
|
||||||
|
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
use x86::structures::idt::*;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref IDT: Idt = {
|
|
||||||
let mut idt = Idt::new();
|
|
||||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
|
||||||
idt.double_fault.set_handler_fn(double_fault_handler);
|
|
||||||
// int #1 is keyboard
|
|
||||||
idt.interrupts[1].set_handler_fn(::keyboard::kbd_callback);
|
|
||||||
idt
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(memory_controller: &mut ::memory::MemoryController) {
|
|
||||||
let double_fault_stack = memory_controller.alloc_stack(1)
|
|
||||||
.expect("could not allocate double fault stack");
|
|
||||||
// println!("DF stack: {:#?}", double_fault_stack);
|
|
||||||
// flush!();
|
|
||||||
IDT.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "x86-interrupt" fn double_fault_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame, _error_code: u32)
|
|
||||||
{
|
|
||||||
println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
|
||||||
flush!();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "x86-interrupt" fn breakpoint_handler(
|
|
||||||
stack_frame: &mut ExceptionStackFrame)
|
|
||||||
{
|
|
||||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
|
||||||
flush!();
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
extern crate core;
|
extern crate core;
|
||||||
use x86::structures::idt::*;
|
|
||||||
|
|
||||||
use cpuio;
|
use cpuio;
|
||||||
use vga;
|
use vga;
|
||||||
|
|
@ -77,8 +76,7 @@ fn check_key_state(key: u8) -> (bool, usize) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "x86-interrupt" fn kbd_callback(
|
pub fn kbd_callback() {
|
||||||
stack_frame: &mut ExceptionStackFrame) {
|
|
||||||
println!("kbd callback called");
|
println!("kbd callback called");
|
||||||
flush!();
|
flush!();
|
||||||
static mut SHIFT: bool = false;
|
static mut SHIFT: bool = false;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//! project hosted on [github](https://github.com/jzck/kernel)
|
//! project hosted on [github](https://github.com/jzck/kernel)
|
||||||
|
//! exclusively x86
|
||||||
|
//!
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
|
|
@ -13,12 +14,16 @@
|
||||||
#![feature(abi_x86_interrupt)]
|
#![feature(abi_x86_interrupt)]
|
||||||
|
|
||||||
extern crate rlibc;
|
extern crate rlibc;
|
||||||
extern crate multiboot2;
|
|
||||||
#[macro_use] extern crate lazy_static;
|
|
||||||
#[macro_use] extern crate alloc;
|
#[macro_use] extern crate alloc;
|
||||||
|
#[macro_use] extern crate lazy_static;
|
||||||
|
extern crate spin;
|
||||||
|
extern crate multiboot2;
|
||||||
|
extern crate slab_allocator;
|
||||||
|
|
||||||
|
// used by arch/x86, need conditional compilation here
|
||||||
extern crate x86;
|
extern crate x86;
|
||||||
|
|
||||||
/// 80x25 screen and simplistic terminal driver
|
/// 80x25 terminal driver
|
||||||
#[macro_use] pub mod vga;
|
#[macro_use] pub mod vga;
|
||||||
/// PS/2 detection and processing
|
/// PS/2 detection and processing
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
|
|
@ -26,40 +31,21 @@ pub mod keyboard;
|
||||||
pub mod console;
|
pub mod console;
|
||||||
/// rust wrappers around cpu I/O instructions.
|
/// rust wrappers around cpu I/O instructions.
|
||||||
pub mod cpuio;
|
pub mod cpuio;
|
||||||
/// ACPI self-content module
|
/// ACPI self contained module
|
||||||
pub mod acpi;
|
pub mod acpi;
|
||||||
/// physical frame allocator + paging module + heap allocator
|
/// Heap allocators
|
||||||
|
pub mod allocator;
|
||||||
|
/// Memory management
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
/// x86 interruptions
|
/// arch specific entry points
|
||||||
pub mod interrupts;
|
pub mod arch;
|
||||||
|
|
||||||
fn init_kernel(multiboot_info_addr: usize) -> Result <(), &'static str> {
|
/// kernel entry point. arch module is responsible for calling this
|
||||||
|
pub fn kmain() -> ! {
|
||||||
|
|
||||||
let boot_info = unsafe { multiboot2::load(multiboot_info_addr)};
|
// vga is specific to chipset not cpu
|
||||||
|
|
||||||
// ACPI must be intialized BEFORE paging (memory::init()) is active
|
|
||||||
if let Some(rsdp) = boot_info.rsdp_v2_tag() {
|
|
||||||
acpi::load(rsdp)?;
|
|
||||||
} else if let Some(rsdp) = boot_info.rsdp_tag() {
|
|
||||||
acpi::load(rsdp)?;
|
|
||||||
} else {
|
|
||||||
acpi::init()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut memory_controller = memory::init(&boot_info);
|
|
||||||
interrupts::init(&mut memory_controller);
|
|
||||||
vga::init();
|
vga::init();
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern fn kmain(multiboot_info_addr: usize) -> ! {
|
|
||||||
if let Err(msg) = init_kernel(multiboot_info_addr) {
|
|
||||||
println!("Kernel initialization has failed: {}", msg);
|
|
||||||
cpuio::halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
// x86::instructions::interrupts::int3();
|
// x86::instructions::interrupts::int3();
|
||||||
|
|
||||||
// fn stack_overflow() { stack_overflow(); }
|
// fn stack_overflow() { stack_overflow(); }
|
||||||
|
|
@ -69,13 +55,13 @@ pub extern fn kmain(multiboot_info_addr: usize) -> ! {
|
||||||
// *(0xdead as *mut u32) = 42;
|
// *(0xdead as *mut u32) = 42;
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
println!("at main now!");
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "eh_personality"] #[no_mangle]
|
#[lang = "eh_personality"] #[no_mangle]
|
||||||
pub extern fn eh_personality() {
|
pub extern fn eh_personality() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[lang = "panic_fmt"] #[no_mangle]
|
#[lang = "panic_fmt"] #[no_mangle]
|
||||||
pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32)
|
pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32)
|
||||||
|
|
@ -87,11 +73,8 @@ pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str, line: u32
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
use memory::BumpAllocator;
|
|
||||||
|
|
||||||
pub const HEAP_START: usize = (1 << 22); //first entry of p2
|
pub const HEAP_START: usize = (1 << 22); //first entry of p2
|
||||||
pub const HEAP_SIZE: usize = 100 * 1024; //100 KiB
|
pub const HEAP_SIZE: usize = 10 * 4096 * 8; //~ 100 KiB
|
||||||
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static HEAP_ALLOCATOR: BumpAllocator = BumpAllocator::new(HEAP_START,
|
static HEAP_ALLOCATOR: allocator::Allocator = allocator::Allocator;
|
||||||
HEAP_START + HEAP_SIZE);
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use memory::*;
|
|
||||||
use multiboot2::{MemoryAreaIter, MemoryArea};
|
use multiboot2::{MemoryAreaIter, MemoryArea};
|
||||||
use x86::*;
|
use x86::*;
|
||||||
|
use x86::structures::paging::PhysFrame;
|
||||||
|
use super::FrameAllocator;
|
||||||
|
|
||||||
pub struct AreaFrameAllocator {
|
pub struct BumpFrameAllocator {
|
||||||
next_free_frame: PhysFrame,
|
next_free_frame: PhysFrame,
|
||||||
current_area: Option<&'static MemoryArea>,
|
current_area: Option<&'static MemoryArea>,
|
||||||
areas: MemoryAreaIter,
|
areas: MemoryAreaIter,
|
||||||
|
|
@ -12,11 +13,11 @@ pub struct AreaFrameAllocator {
|
||||||
multiboot_end: PhysFrame,
|
multiboot_end: PhysFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AreaFrameAllocator {
|
impl BumpFrameAllocator {
|
||||||
pub fn new(kernel_start: usize, kernel_end: usize,
|
pub fn new(kernel_start: usize, kernel_end: usize,
|
||||||
multiboot_start: usize, multiboot_end: usize,
|
multiboot_start: usize, multiboot_end: usize,
|
||||||
memory_areas: MemoryAreaIter) -> AreaFrameAllocator {
|
memory_areas: MemoryAreaIter) -> BumpFrameAllocator {
|
||||||
let mut allocator = AreaFrameAllocator {
|
let mut allocator = BumpFrameAllocator {
|
||||||
next_free_frame: PhysFrame { number: 0 },
|
next_free_frame: PhysFrame { number: 0 },
|
||||||
current_area: None,
|
current_area: None,
|
||||||
areas: memory_areas,
|
areas: memory_areas,
|
||||||
|
|
@ -49,37 +50,42 @@ impl AreaFrameAllocator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrameAllocator for AreaFrameAllocator {
|
impl FrameAllocator for BumpFrameAllocator {
|
||||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
fn allocate_frames(&mut self, count: usize) -> Option<PhysFrame> {
|
||||||
|
if count == 0 { return None };
|
||||||
if let Some(area) = self.current_area {
|
if let Some(area) = self.current_area {
|
||||||
let frame = PhysFrame { number: self.next_free_frame.number };
|
let start_frame = PhysFrame { number: self.next_free_frame.number };
|
||||||
|
let end_frame = PhysFrame { number: self.next_free_frame.number + count as u32 - 1 };
|
||||||
|
|
||||||
let current_area_last_frame = PhysFrame::containing_address(
|
let current_area_last_frame = PhysFrame::containing_address(
|
||||||
PhysAddr::new(area.end_address() as u32));
|
PhysAddr::new(area.end_address() as u32));
|
||||||
if frame > current_area_last_frame {
|
if end_frame > current_area_last_frame {
|
||||||
// all frames are taken in this area
|
// all frames are taken in this area
|
||||||
self.choose_next_area();
|
self.choose_next_area();
|
||||||
} else if frame >= self.kernel_start && frame <= self.kernel_end {
|
} else if (start_frame >= self.kernel_start && start_frame <= self.kernel_end) || (end_frame >= self.kernel_start && end_frame <= self.kernel_end) {
|
||||||
// frame used by kernel
|
// frame used by kernel
|
||||||
self.next_free_frame = PhysFrame {
|
self.next_free_frame = PhysFrame {
|
||||||
number: self.kernel_end.number + 1,
|
number: self.kernel_end.number + 1,
|
||||||
}
|
};
|
||||||
} else if frame >= self.multiboot_start && frame <= self.multiboot_end {
|
} else if (start_frame >= self.multiboot_start && start_frame <= self.multiboot_end) || (end_frame >= self.multiboot_start && end_frame <= self.multiboot_end) {
|
||||||
// frame used by multiboot
|
// frame used by multiboot
|
||||||
self.next_free_frame = PhysFrame {
|
self.next_free_frame = PhysFrame {
|
||||||
number: self.multiboot_end.number + 1,
|
number: self.multiboot_end.number + 1,
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
self.next_free_frame.number += 1;
|
self.next_free_frame.number += count as u32;
|
||||||
return Some(frame);
|
return Some(start_frame);
|
||||||
}
|
}
|
||||||
// try again with next_free_frame
|
// try again with next_free_frame
|
||||||
self.allocate_frame()
|
self.allocate_frames(count)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deallocate_frame(&mut self, frame: PhysFrame) {
|
fn deallocate_frames(&mut self, frame: PhysFrame, count: usize) {
|
||||||
unimplemented!();
|
// bump doesnt deallocate, must be used inside of a recycler
|
||||||
|
println!("lost frames {:#x} ({})", frame.start_address().as_u32(), count);
|
||||||
|
// unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
use alloc::heap::{Alloc, AllocErr, Layout};
|
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BumpAllocator {
|
|
||||||
heap_start: usize,
|
|
||||||
heap_end: usize,
|
|
||||||
next: AtomicUsize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BumpAllocator {
|
|
||||||
pub const fn new(heap_start: usize, heap_end: usize) -> Self {
|
|
||||||
Self { heap_start, heap_end, next: AtomicUsize::new(heap_start) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<'a> Alloc for &'a BumpAllocator {
|
|
||||||
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
|
|
||||||
loop {
|
|
||||||
// load current state of the `next` field
|
|
||||||
let current_next = self.next.load(Ordering::Relaxed);
|
|
||||||
let alloc_start = align_up(current_next, layout.align());
|
|
||||||
let alloc_end = alloc_start.saturating_add(layout.size());
|
|
||||||
|
|
||||||
if alloc_end <= self.heap_end {
|
|
||||||
// update the `next` pointer if it still has the value `current_next`
|
|
||||||
let next_now = self.next.compare_and_swap(current_next, alloc_end,
|
|
||||||
Ordering::Relaxed);
|
|
||||||
if next_now == current_next {
|
|
||||||
return Ok(alloc_start as *mut u8);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(AllocErr::Exhausted{ request: layout })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn dealloc(&mut self, pt: *mut u8, layout: Layout) {
|
|
||||||
// TODO
|
|
||||||
// do nothing, leak memory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Align downwards. Returns the greatest x with alignment `align`
|
|
||||||
/// so that x <= addr. The alignment must be a power of 2.
|
|
||||||
pub fn align_down(addr: usize, align: usize) -> usize {
|
|
||||||
if align.is_power_of_two() {
|
|
||||||
addr & !(align - 1)
|
|
||||||
} else if align == 0 {
|
|
||||||
addr
|
|
||||||
} else {
|
|
||||||
panic!("`align` must be a power of 2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Align upwards. Returns the smallest x with alignment `align`
|
|
||||||
/// so that x >= addr. The alignment must be a power of 2.
|
|
||||||
pub fn align_up(addr: usize, align: usize) -> usize {
|
|
||||||
align_down(addr + align - 1, align)
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +1,26 @@
|
||||||
mod area_allocator;
|
mod bump;
|
||||||
mod heap_allocator;
|
mod recycle;
|
||||||
mod stack_allocator;
|
|
||||||
mod paging;
|
|
||||||
|
|
||||||
pub use self::area_allocator::*;
|
|
||||||
pub use self::heap_allocator::*;
|
|
||||||
pub use self::stack_allocator::*;
|
|
||||||
pub use self::paging::remap_the_kernel;
|
|
||||||
use multiboot2;
|
use multiboot2;
|
||||||
use x86::*;
|
|
||||||
use x86::structures::paging::*;
|
use x86::structures::paging::*;
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use self::bump::BumpFrameAllocator;
|
||||||
|
use self::recycle::RecycleAllocator;
|
||||||
|
|
||||||
pub trait FrameAllocator {
|
pub trait FrameAllocator {
|
||||||
fn allocate_frame(&mut self) -> Option<PhysFrame>;
|
fn allocate_frames(&mut self, size: usize) -> Option<PhysFrame>;
|
||||||
fn deallocate_frame(&mut self, frame: PhysFrame);
|
fn deallocate_frames(&mut self, frame: PhysFrame, size: usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MemoryController {
|
pub struct MemoryControler {
|
||||||
active_table: paging::ActivePageTable,
|
frame_allocator: RecycleAllocator<BumpFrameAllocator>,
|
||||||
frame_allocator: AreaFrameAllocator,
|
// stack_allocator: StackAllocator,
|
||||||
stack_allocator: StackAllocator,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryController {
|
static MEMORY_CONTROLER: Mutex<Option<MemoryControler>> = Mutex::new(None);
|
||||||
pub fn alloc_stack(&mut self, size_in_pages: usize) -> Option<Stack> {
|
|
||||||
let &mut MemoryController { ref mut active_table,
|
|
||||||
ref mut frame_allocator,
|
|
||||||
ref mut stack_allocator } = self;
|
|
||||||
|
|
||||||
stack_allocator.alloc_stack(active_table, frame_allocator,
|
|
||||||
size_in_pages)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// memory initialisation should only be called once
|
|
||||||
pub fn init(boot_info: &multiboot2::BootInformation) -> MemoryController {
|
|
||||||
use x86::registers::control::{Cr0, Cr4, Cr0Flags, Cr4Flags};
|
|
||||||
Cr4::add(Cr4Flags::PSE);
|
|
||||||
Cr0::add(Cr0Flags::PAGING | Cr0Flags::WRITE_PROTECT);
|
|
||||||
|
|
||||||
|
pub fn init(boot_info: &multiboot2::BootInformation) {
|
||||||
let elf_sections_tag = boot_info.elf_sections_tag().unwrap();
|
let elf_sections_tag = boot_info.elf_sections_tag().unwrap();
|
||||||
let memory_map_tag = boot_info.memory_map_tag().unwrap();
|
let memory_map_tag = boot_info.memory_map_tag().unwrap();
|
||||||
|
|
||||||
|
|
@ -52,34 +34,48 @@ pub fn init(boot_info: &multiboot2::BootInformation) -> MemoryController {
|
||||||
.map(|s| s.start_address() + s.size())
|
.map(|s| s.start_address() + s.size())
|
||||||
.max().unwrap();
|
.max().unwrap();
|
||||||
|
|
||||||
let mut frame_allocator = self::AreaFrameAllocator::new(
|
let bump_allocator = BumpFrameAllocator::new(
|
||||||
kernel_start as usize, kernel_end as usize,
|
kernel_start as usize, kernel_end as usize,
|
||||||
boot_info.start_address(), boot_info.end_address(),
|
boot_info.start_address(), boot_info.end_address(),
|
||||||
memory_map_tag.memory_areas());
|
memory_map_tag.memory_areas());
|
||||||
|
|
||||||
let mut active_table = paging::remap_the_kernel(&mut frame_allocator,
|
let frame_allocator = RecycleAllocator::new(bump_allocator);
|
||||||
boot_info);
|
|
||||||
use {HEAP_START, HEAP_SIZE};
|
|
||||||
|
|
||||||
let heap_start_page = Page::containing_address(
|
// let stack_allocator = {
|
||||||
VirtAddr::new(HEAP_START as u32));
|
// let stack_alloc_start = heap_end_page + 1;
|
||||||
let heap_end_page = Page::containing_address(
|
// let stack_alloc_end = stack_alloc_start + 100;
|
||||||
VirtAddr::new(HEAP_START as u32 + HEAP_SIZE as u32 - 1));
|
// let stack_alloc_range = stack_alloc_start..stack_alloc_end + 1;
|
||||||
|
// StackAllocator::new(stack_alloc_range)
|
||||||
|
// };
|
||||||
|
|
||||||
for page in heap_start_page..heap_end_page {
|
*MEMORY_CONTROLER.lock() = Some(MemoryControler {
|
||||||
active_table.map(page, PageTableFlags::WRITABLE, &mut frame_allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
MemoryController {
|
|
||||||
active_table,
|
|
||||||
frame_allocator,
|
frame_allocator,
|
||||||
stack_allocator,
|
// stack_allocator,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_frames(count: usize) -> Option<PhysFrame> {
|
||||||
|
if let Some(ref mut controler) = *MEMORY_CONTROLER.lock() {
|
||||||
|
controler.frame_allocator.allocate_frames(count)
|
||||||
|
} else {
|
||||||
|
panic!("frame allocator not initialized!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deallocate_frames(frame: PhysFrame, count: usize) {
|
||||||
|
if let Some(ref mut controler) = *MEMORY_CONTROLER.lock() {
|
||||||
|
controler.frame_allocator.deallocate_frames(frame, count)
|
||||||
|
} else {
|
||||||
|
panic!("frame allocator not initialized!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Init memory module after core
|
||||||
|
/// Must be called once, and only once,
|
||||||
|
pub unsafe fn init_noncore() {
|
||||||
|
if let Some(ref mut controler) = *MEMORY_CONTROLER.lock() {
|
||||||
|
controler.frame_allocator.set_core(true);
|
||||||
|
} else {
|
||||||
|
panic!("frame allocator not initialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
105
kernel-rs/src/memory/recycle.rs
Normal file
105
kernel-rs/src/memory/recycle.rs
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
//! Recycle allocator
|
||||||
|
//! Uses freed frames if possible, then uses inner allocator
|
||||||
|
|
||||||
|
use alloc::Vec;
|
||||||
|
use x86::*;
|
||||||
|
use x86::structures::paging::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct RecycleAllocator<T: FrameAllocator> {
|
||||||
|
inner: T,
|
||||||
|
core: bool,
|
||||||
|
free: Vec<(usize, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FrameAllocator> RecycleAllocator<T> {
|
||||||
|
pub fn new(inner: T) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: inner,
|
||||||
|
core: true,
|
||||||
|
free: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_core(&mut self, core: bool) {
|
||||||
|
self.core = core;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merge(&mut self, address: usize, count: usize) -> bool {
|
||||||
|
for i in 0 .. self.free.len() {
|
||||||
|
let changed = {
|
||||||
|
let free = &mut self.free[i];
|
||||||
|
if address + count * 4096 == free.0 {
|
||||||
|
free.0 = address;
|
||||||
|
free.1 += count;
|
||||||
|
true
|
||||||
|
} else if free.0 + free.1 * 4096 == address {
|
||||||
|
free.1 += count;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
//TODO: Use do not use recursion
|
||||||
|
let (address, count) = self.free[i];
|
||||||
|
if self.merge(address, count) {
|
||||||
|
self.free.remove(i);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: FrameAllocator> FrameAllocator for RecycleAllocator<T> {
|
||||||
|
fn allocate_frames(&mut self, count: usize) -> Option<PhysFrame> {
|
||||||
|
let mut small_i = None;
|
||||||
|
{
|
||||||
|
let mut small = (0, 0);
|
||||||
|
for i in 0..self.free.len() {
|
||||||
|
let free = self.free[i];
|
||||||
|
// Later entries can be removed faster
|
||||||
|
if free.1 >= count {
|
||||||
|
if free.1 <= small.1 || small_i.is_none() {
|
||||||
|
small_i = Some(i);
|
||||||
|
small = free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(i) = small_i {
|
||||||
|
let (address, remove) = {
|
||||||
|
let free = &mut self.free[i];
|
||||||
|
free.1 -= count;
|
||||||
|
(free.0 + free.1 * 4096, free.1 == 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
if remove {
|
||||||
|
self.free.remove(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//println!("Restoring frame {:?}, {}", frame, count);
|
||||||
|
Some(PhysFrame::containing_address(PhysAddr::new(address as u32)))
|
||||||
|
} else {
|
||||||
|
//println!("No saved frames {}", count);
|
||||||
|
self.inner.allocate_frames(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deallocate_frames(&mut self, frame: PhysFrame, count: usize) {
|
||||||
|
// we cant use vec! before the heap has been initialized
|
||||||
|
if self.core {
|
||||||
|
self.inner.deallocate_frames(frame, count);
|
||||||
|
} else {
|
||||||
|
let address = frame.start_address().as_u32() as usize;
|
||||||
|
if ! self.merge(address, count) {
|
||||||
|
self.free.push((address, count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -123,6 +123,7 @@ impl Writer {
|
||||||
self.buffer[i] = b' ';
|
self.buffer[i] = b' ';
|
||||||
self.buffer[i + 1] = 0;
|
self.buffer[i + 1] = 0;
|
||||||
self.flush();
|
self.flush();
|
||||||
|
// flush!();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_byte(&mut self, byte: u8) {
|
pub fn write_byte(&mut self, byte: u8) {
|
||||||
|
|
@ -179,7 +180,6 @@ impl Writer {
|
||||||
|
|
||||||
for col in 0..BUFFER_COLS/2 {
|
for col in 0..BUFFER_COLS/2 {
|
||||||
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col * 2)] = b' ';
|
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col * 2)] = b' ';
|
||||||
self.buffer[((BUFFER_ROWS - 1) * BUFFER_COLS) + (col * 2) + 1] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS;
|
self.buffer_pos = (BUFFER_ROWS - 1) * BUFFER_COLS;
|
||||||
|
|
@ -214,5 +214,7 @@ pub fn init() {
|
||||||
format_args!("{: ^80}", r#" | : ;| : .' "#),
|
format_args!("{: ^80}", r#" | : ;| : .' "#),
|
||||||
format_args!("{: ^80}", r#" ' ,/ ; | .' "#),
|
format_args!("{: ^80}", r#" ' ,/ ; | .' "#),
|
||||||
format_args!("{: ^80}", r#" '--' `---' "#));
|
format_args!("{: ^80}", r#" '--' `---' "#));
|
||||||
|
set_color!();
|
||||||
unsafe { VGA.prompt(); }
|
unsafe { VGA.prompt(); }
|
||||||
|
unsafe { VGA.flush(); }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit da544c834b3f3d8b53f456c48b3aafa58d09198a
|
Subproject commit 3cef2945c884857a6ef44c942a3d949790792db7
|
||||||
Loading…
Reference in a new issue