allocation :D
This commit is contained in:
parent
a9d86656ef
commit
ee4dd3e2f2
|
@ -41,6 +41,14 @@ dependencies = [
|
||||||
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked_list_allocator"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nodrop"
|
name = "nodrop"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
|
@ -101,6 +109,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bootloader 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bootloader 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"linked_list_allocator 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -117,6 +126,7 @@ dependencies = [
|
||||||
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
"checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427"
|
||||||
"checksum cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
|
"checksum cpuio 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22b8e308ccfc5acf3b82f79c0eac444cf6114cb2ac67a230ca6c177210068daa"
|
||||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
"checksum linked_list_allocator 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "47314ec1d29aa869ee7cb5a5be57be9b1055c56567d59c3fb6689926743e0bea"
|
||||||
"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
||||||
"checksum pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fff50ab09ba31bcebc0669f4e64c0952fae1acdca9e6e0587e68e4e8443808ac"
|
"checksum pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fff50ab09ba31bcebc0669f4e64c0952fae1acdca9e6e0587e68e4e8443808ac"
|
||||||
"checksum pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc64b2fd10828da8521b6cdabe0679385d7d2a3a6d4c336b819d1fa31ba35c72"
|
"checksum pic8259_simple 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc64b2fd10828da8521b6cdabe0679385d7d2a3a6d4c336b819d1fa31ba35c72"
|
||||||
|
|
|
@ -7,13 +7,14 @@ edition = "2018"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bootloader = "0.8.0"
|
bootloader = { version = "0.8.0", features = ["map_physical_memory"]}
|
||||||
volatile = "0.2.6"
|
volatile = "0.2.6"
|
||||||
spin = "0.5.2"
|
spin = "0.5.2"
|
||||||
x86_64 = "0.7.5"
|
x86_64 = "0.7.5"
|
||||||
uart_16550 = "0.2.0"
|
uart_16550 = "0.2.0"
|
||||||
pic8259_simple = "0.1.1"
|
pic8259_simple = "0.1.1"
|
||||||
pc-keyboard = "0.3.1"
|
pc-keyboard = "0.3.1"
|
||||||
|
linked_list_allocator = "0.6.4"
|
||||||
|
|
||||||
[dependencies.lazy_static]
|
[dependencies.lazy_static]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
use alloc::alloc::{GlobalAlloc, Layout};
|
||||||
|
use bootloader::BootInfo;
|
||||||
|
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
|
||||||
|
use core::ptr::null_mut;
|
||||||
|
use x86_64::{
|
||||||
|
structures::paging::{
|
||||||
|
mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
||||||
|
},
|
||||||
|
VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Dummy;
|
||||||
|
|
||||||
|
unsafe impl GlobalAlloc for Dummy {
|
||||||
|
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
|
||||||
|
null_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {
|
||||||
|
panic!("dealloc should be never called")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const HEAP_START: usize = 0x_4444_4444_0000;
|
||||||
|
pub const HEAP_SIZE: usize = 100 * 1024; // 100 KiB
|
||||||
|
|
||||||
|
pub fn init_heap(
|
||||||
|
mapper: &mut impl Mapper<Size4KiB>,
|
||||||
|
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||||
|
) -> Result<(), MapToError> {
|
||||||
|
let page_range = {
|
||||||
|
let heap_start = VirtAddr::new(HEAP_START as u64);
|
||||||
|
let heap_end = heap_start + HEAP_SIZE - 1u64;
|
||||||
|
let heap_start_page = Page::containing_address(heap_start);
|
||||||
|
let heap_end_page = Page::containing_address(heap_end);
|
||||||
|
Page::range_inclusive(heap_start_page, heap_end_page)
|
||||||
|
};
|
||||||
|
|
||||||
|
for page in page_range {
|
||||||
|
let frame = frame_allocator
|
||||||
|
.allocate_frame()
|
||||||
|
.ok_or(MapToError::FrameAllocationFailed)?;
|
||||||
|
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE;
|
||||||
|
unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() };
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
super::ALLOCATOR.lock().init(HEAP_START, HEAP_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(boot_info: &'static BootInfo) {
|
||||||
|
use crate::memory::{self, BootInfoFrameAllocator};
|
||||||
|
|
||||||
|
let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset);
|
||||||
|
let mut mapper = unsafe { memory::init(phys_mem_offset) };
|
||||||
|
let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) };
|
||||||
|
|
||||||
|
init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
|
||||||
|
}
|
14
src/gdt.rs
14
src/gdt.rs
|
@ -1,7 +1,7 @@
|
||||||
use x86_64::VirtAddr;
|
|
||||||
use x86_64::structures::tss::TaskStateSegment;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use x86_64::structures::gdt::{GlobalDescriptorTable, Descriptor, SegmentSelector};
|
use x86_64::structures::gdt::{Descriptor, GlobalDescriptorTable, SegmentSelector};
|
||||||
|
use x86_64::structures::tss::TaskStateSegment;
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
|
||||||
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
|
pub const DOUBLE_FAULT_IST_INDEX: u16 = 0;
|
||||||
|
|
||||||
|
@ -36,7 +36,13 @@ lazy_static! {
|
||||||
let mut gdt = GlobalDescriptorTable::new();
|
let mut gdt = GlobalDescriptorTable::new();
|
||||||
let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
|
let code_selector = gdt.add_entry(Descriptor::kernel_code_segment());
|
||||||
let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
|
let tss_selector = gdt.add_entry(Descriptor::tss_segment(&TSS));
|
||||||
(gdt, Selectors { code_selector, tss_selector })
|
(
|
||||||
|
gdt,
|
||||||
|
Selectors {
|
||||||
|
code_selector,
|
||||||
|
tss_selector,
|
||||||
|
},
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
use crate::{gdt, hlt_loop, print, println};
|
||||||
use crate::{gdt, print, println};
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref IDT: InterruptDescriptorTable = {
|
static ref IDT: InterruptDescriptorTable = {
|
||||||
let mut idt = InterruptDescriptorTable::new();
|
let mut idt = InterruptDescriptorTable::new();
|
||||||
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
idt.breakpoint.set_handler_fn(breakpoint_handler);
|
||||||
|
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||||
unsafe {
|
unsafe {
|
||||||
idt.double_fault.set_handler_fn(double_fault_handler)
|
idt.double_fault
|
||||||
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
.set_handler_fn(double_fault_handler)
|
||||||
|
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
|
||||||
}
|
}
|
||||||
idt[InterruptIndex::Timer.as_usize()]
|
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
|
||||||
.set_handler_fn(timer_interrupt_handler);
|
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
|
||||||
idt[InterruptIndex::Keyboard.as_usize()]
|
|
||||||
.set_handler_fn(keyboard_interrupt_handler);
|
|
||||||
idt
|
idt
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,15 +22,14 @@ pub fn init_idt() {
|
||||||
IDT.load();
|
IDT.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn breakpoint_handler(
|
extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) {
|
||||||
stack_frame: &mut InterruptStackFrame)
|
|
||||||
{
|
|
||||||
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn double_fault_handler(
|
extern "x86-interrupt" fn double_fault_handler(
|
||||||
stack_frame: &mut InterruptStackFrame, _error_code: u64)
|
stack_frame: &mut InterruptStackFrame,
|
||||||
{
|
_error_code: u64,
|
||||||
|
) {
|
||||||
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +70,7 @@ impl InterruptIndex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer_interrupt_handler(
|
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
|
||||||
_stack_frame: &mut InterruptStackFrame)
|
|
||||||
{
|
|
||||||
//print!(".");
|
//print!(".");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -82,12 +79,10 @@ extern "x86-interrupt" fn timer_interrupt_handler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: &mut InterruptStackFrame) {
|
||||||
_stack_frame: &mut InterruptStackFrame)
|
use pc_keyboard::{layouts, DecodedKey, Keyboard, ScancodeSet1};
|
||||||
{
|
|
||||||
use x86_64::instructions::port::Port;
|
|
||||||
use pc_keyboard::{Keyboard, ScancodeSet1, DecodedKey, layouts};
|
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||||
|
@ -112,3 +107,18 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(
|
||||||
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
|
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use x86_64::structures::idt::PageFaultErrorCode;
|
||||||
|
|
||||||
|
extern "x86-interrupt" fn page_fault_handler(
|
||||||
|
stack_frame: &mut InterruptStackFrame,
|
||||||
|
error_code: PageFaultErrorCode,
|
||||||
|
) {
|
||||||
|
use x86_64::registers::control::Cr2;
|
||||||
|
|
||||||
|
println!("EXCEPTION: PAGE FAULT");
|
||||||
|
println!("Accessed Address: {:?}", Cr2::read());
|
||||||
|
println!("Error Code: {:?}", error_code);
|
||||||
|
println!("{:#?}", stack_frame);
|
||||||
|
hlt_loop();
|
||||||
|
}
|
||||||
|
|
34
src/lib.rs
34
src/lib.rs
|
@ -1,22 +1,39 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(test, no_main)]
|
#![cfg_attr(test, no_main)]
|
||||||
#![feature(abi_x86_interrupt)]
|
#![feature(abi_x86_interrupt)]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(custom_test_frameworks)]
|
#![feature(custom_test_frameworks)]
|
||||||
#![test_runner(crate::test_runner)]
|
#![test_runner(crate::test_runner)]
|
||||||
#![reexport_test_harness_main = "test_main"]
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
pub mod allocator;
|
||||||
pub mod gdt;
|
pub mod gdt;
|
||||||
pub mod serial;
|
|
||||||
pub mod interrupts;
|
pub mod interrupts;
|
||||||
|
pub mod memory;
|
||||||
|
pub mod serial;
|
||||||
pub mod vga_buffer;
|
pub mod vga_buffer;
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use linked_list_allocator::LockedHeap;
|
||||||
|
|
||||||
pub fn init() {
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||||
|
|
||||||
|
#[alloc_error_handler]
|
||||||
|
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
||||||
|
panic!("allocation error: {:?}", layout)
|
||||||
|
}
|
||||||
|
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
use bootloader::BootInfo;
|
||||||
|
|
||||||
|
pub fn init(boot_info: &'static BootInfo) {
|
||||||
gdt::init();
|
gdt::init();
|
||||||
interrupts::init_idt();
|
interrupts::init_idt();
|
||||||
unsafe { interrupts::PICS.lock().initialize() };
|
unsafe { interrupts::PICS.lock().initialize() };
|
||||||
x86_64::instructions::interrupts::enable();
|
x86_64::instructions::interrupts::enable();
|
||||||
|
allocator::init(&boot_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hlt_loop() -> ! {
|
pub fn hlt_loop() -> ! {
|
||||||
|
@ -40,11 +57,16 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! {
|
||||||
hlt_loop();
|
hlt_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use bootloader::entry_point;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
entry_point!(test_kernel_main);
|
||||||
|
|
||||||
/// Entry point for `cargo xtest`
|
/// Entry point for `cargo xtest`
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[no_mangle]
|
fn test_kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||||
pub extern "C" fn _start() -> ! {
|
init(boot_info);
|
||||||
init();
|
|
||||||
test_main();
|
test_main();
|
||||||
hlt_loop();
|
hlt_loop();
|
||||||
}
|
}
|
||||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -4,14 +4,27 @@
|
||||||
#![test_runner(xe_os::test_runner)]
|
#![test_runner(xe_os::test_runner)]
|
||||||
#![reexport_test_harness_main = "test_main"]
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use bootloader::{entry_point, BootInfo};
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
use xe_os::println;
|
use xe_os::println;
|
||||||
|
|
||||||
#[no_mangle]
|
entry_point!(kernel_main);
|
||||||
pub extern "C" fn _start() -> ! {
|
|
||||||
xe_os::init();
|
fn kernel_main(boot_info: &'static BootInfo) -> ! {
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
use xe_os::allocator;
|
||||||
|
use xe_os::memory::{self, BootInfoFrameAllocator};
|
||||||
|
|
||||||
|
xe_os::init(&boot_info);
|
||||||
println!("Hello World{}", "!");
|
println!("Hello World{}", "!");
|
||||||
|
|
||||||
|
// allocate a number on the heap
|
||||||
|
let heap_value = Box::new(41);
|
||||||
|
println!("heap_value at {:p}", heap_value);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
test_main();
|
test_main();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
|
||||||
|
use x86_64::{
|
||||||
|
structures::paging::{
|
||||||
|
FrameAllocator, Mapper, OffsetPageTable, Page, PageTable, PhysFrame, Size4KiB,
|
||||||
|
},
|
||||||
|
PhysAddr, VirtAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Initialize a new OffsetPageTable.
|
||||||
|
///
|
||||||
|
/// This function is unsafe because the caller must guarantee that the
|
||||||
|
/// complete physical memory is mapped to virtual memory at the passed
|
||||||
|
/// `physical_memory_offset`. Also, this function must be only called once
|
||||||
|
/// to avoid aliasing `&mut` references (which is undefined behavior).
|
||||||
|
pub unsafe fn init(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
|
||||||
|
let level_4_table = active_level_4_table(physical_memory_offset);
|
||||||
|
OffsetPageTable::new(level_4_table, physical_memory_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a mutable reference to the active level 4 table.
|
||||||
|
///
|
||||||
|
/// This function is unsafe because the caller must guarantee that the
|
||||||
|
/// complete physical memory is mapped to virtual memory at the passed
|
||||||
|
/// `physical_memory_offset`. Also, this function must be only called once
|
||||||
|
/// to avoid aliasing `&mut` references (which is undefined behavior).
|
||||||
|
unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
|
||||||
|
use x86_64::registers::control::Cr3;
|
||||||
|
|
||||||
|
let (level_4_table_frame, _) = Cr3::read();
|
||||||
|
|
||||||
|
let phys = level_4_table_frame.start_address();
|
||||||
|
let virt = physical_memory_offset + phys.as_u64();
|
||||||
|
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
|
||||||
|
|
||||||
|
&mut *page_table_ptr // unsafe
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an example mapping for the given page to frame `0xb8000`.
|
||||||
|
pub fn create_example_mapping(
|
||||||
|
page: Page,
|
||||||
|
mapper: &mut OffsetPageTable,
|
||||||
|
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||||
|
) {
|
||||||
|
use x86_64::structures::paging::PageTableFlags as Flags;
|
||||||
|
|
||||||
|
let frame = PhysFrame::containing_address(PhysAddr::new(0xb8000));
|
||||||
|
let flags = Flags::PRESENT | Flags::WRITABLE;
|
||||||
|
|
||||||
|
let map_to_result = unsafe { mapper.map_to(page, frame, flags, frame_allocator) };
|
||||||
|
map_to_result.expect("map_to failed").flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A FrameAllocator that always returns `None`.
|
||||||
|
pub struct EmptyFrameAllocator;
|
||||||
|
|
||||||
|
unsafe impl FrameAllocator<Size4KiB> for EmptyFrameAllocator {
|
||||||
|
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A FrameAllocator that returns usable frames from the bootloader's memory map.
|
||||||
|
pub struct BootInfoFrameAllocator {
|
||||||
|
memory_map: &'static MemoryMap,
|
||||||
|
next: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BootInfoFrameAllocator {
|
||||||
|
/// Create a FrameAllocator from the passed memory map.
|
||||||
|
///
|
||||||
|
/// This function is unsafe because the caller must guarantee that the passed
|
||||||
|
/// memory map is valid. The main requirement is that all frames that are marked
|
||||||
|
/// as `USABLE` in it are really unused.
|
||||||
|
pub unsafe fn init(memory_map: &'static MemoryMap) -> Self {
|
||||||
|
BootInfoFrameAllocator {
|
||||||
|
memory_map,
|
||||||
|
next: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over the usable frames specified in the memory map.
|
||||||
|
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> {
|
||||||
|
// get usable regions from memory map
|
||||||
|
let regions = self.memory_map.iter();
|
||||||
|
let usable_regions = regions.filter(|r| r.region_type == MemoryRegionType::Usable);
|
||||||
|
// map each region to its address range
|
||||||
|
let addr_ranges = usable_regions.map(|r| r.range.start_addr()..r.range.end_addr());
|
||||||
|
// transform to an iterator of frame start addresses
|
||||||
|
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
||||||
|
// create `PhysFrame` types from the start addresses
|
||||||
|
frame_addresses.map(|addr| PhysFrame::containing_address(PhysAddr::new(addr)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
|
||||||
|
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||||
|
let frame = self.usable_frames().nth(self.next);
|
||||||
|
self.next += 1;
|
||||||
|
frame
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
use uart_16550::SerialPort;
|
|
||||||
use spin::Mutex;
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use spin::Mutex;
|
||||||
|
use uart_16550::SerialPort;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref SERIAL1: Mutex<SerialPort> = {
|
pub static ref SERIAL1: Mutex<SerialPort> = {
|
||||||
|
@ -16,7 +16,10 @@ pub fn _print(args: ::core::fmt::Arguments) {
|
||||||
use x86_64::instructions::interrupts;
|
use x86_64::instructions::interrupts;
|
||||||
|
|
||||||
interrupts::without_interrupts(|| {
|
interrupts::without_interrupts(|| {
|
||||||
SERIAL1.lock().write_fmt(args).expect("Printing to serial failed");
|
SERIAL1
|
||||||
|
.lock()
|
||||||
|
.write_fmt(args)
|
||||||
|
.expect("Printing to serial failed");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
#![reexport_test_harness_main = "test_main"]
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
use bootloader::{entry_point, BootInfo};
|
||||||
use xe_os::{println, serial_print, serial_println};
|
use xe_os::{println, serial_print, serial_println};
|
||||||
|
|
||||||
#[no_mangle] // don't mangle the name of this function
|
entry_point!(kmain);
|
||||||
pub extern "C" fn _start() -> ! {
|
|
||||||
|
fn kmain(_: &'static BootInfo) -> ! {
|
||||||
test_main();
|
test_main();
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![feature(custom_test_frameworks)]
|
||||||
|
#![test_runner(xe_os::test_runner)]
|
||||||
|
#![reexport_test_harness_main = "test_main"]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use bootloader::{entry_point, BootInfo};
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
entry_point!(main);
|
||||||
|
|
||||||
|
fn main(boot_info: &'static BootInfo) -> ! {
|
||||||
|
use xe_os::allocator;
|
||||||
|
use xe_os::memory::{self, BootInfoFrameAllocator};
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
|
||||||
|
xe_os::init(boot_info);
|
||||||
|
|
||||||
|
test_main();
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
xe_os::test_panic_handler(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
use xe_os::{serial_print, serial_println};
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn simple_allocation() {
|
||||||
|
serial_print!("simple_allocation... ");
|
||||||
|
let heap_value = Box::new(41);
|
||||||
|
assert_eq!(*heap_value, 41);
|
||||||
|
serial_println!("[ok]");
|
||||||
|
}
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn large_vec() {
|
||||||
|
serial_print!("large_vec... ");
|
||||||
|
let n = 1000;
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
for i in 0..n {
|
||||||
|
vec.push(i);
|
||||||
|
}
|
||||||
|
assert_eq!(vec.iter().sum::<u64>(), (n - 1) * n / 2);
|
||||||
|
serial_println!("[ok]");
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ pub extern "C" fn _start() -> ! {
|
||||||
should_fail();
|
should_fail();
|
||||||
serial_println!("[test did not panic]");
|
serial_println!("[test did not panic]");
|
||||||
exit_qemu(QemuExitCode::Failed);
|
exit_qemu(QemuExitCode::Failed);
|
||||||
loop{}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_fail() {
|
fn should_fail() {
|
||||||
|
|
|
@ -43,8 +43,8 @@ lazy_static! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
use xe_os::{exit_qemu, QemuExitCode, serial_println};
|
|
||||||
use x86_64::structures::idt::InterruptStackFrame;
|
use x86_64::structures::idt::InterruptStackFrame;
|
||||||
|
use xe_os::{exit_qemu, serial_println, QemuExitCode};
|
||||||
|
|
||||||
extern "x86-interrupt" fn test_double_fault_handler(
|
extern "x86-interrupt" fn test_double_fault_handler(
|
||||||
_stack_frame: &mut InterruptStackFrame,
|
_stack_frame: &mut InterruptStackFrame,
|
||||||
|
|
Loading…
Reference in New Issue