Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ pub mod sys;

pub mod usr;

use sys::mem::MemoryMap;
use sys::mem::MemoryRegion;
use sys::mem::MemoryRegionType;

use bootloader::BootInfo;

const KERNEL_SIZE: usize = 4 << 20; // 4 MB

pub fn init(boot_info: &'static BootInfo) {
pub fn init(memory_map: &MemoryMap, offset: u64) {
sys::vga::init();
sys::gdt::init();
sys::idt::init();
Expand All @@ -32,7 +36,7 @@ pub fn init(boot_info: &'static BootInfo) {
let v = option_env!("MOROS_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"));
log!("SYS MOROS v{}", v);

sys::mem::init(boot_info);
sys::mem::init(memory_map, offset);
sys::cpu::init();
sys::acpi::init(); // Require MEM
sys::rng::init();
Expand All @@ -46,6 +50,21 @@ pub fn init(boot_info: &'static BootInfo) {
log!("RTC {}", sys::clk::date());
}

pub fn extract_memory_map(boot_info: &'static BootInfo) -> MemoryMap {
use bootloader::bootinfo::MemoryRegionType as Mem;
let mut memory_map = MemoryMap::new();
for region in boot_info.memory_map.iter() {
let addr = region.range.start_addr();
let size = region.range.end_addr() - addr;
let kind = match region.region_type {
Mem::Usable => MemoryRegionType::Usable,
_ => MemoryRegionType::Reserved,
};
memory_map.add(MemoryRegion::new(addr, size, kind));
}
memory_map
}

#[allow(dead_code)]
#[cfg_attr(not(feature = "userspace"), alloc_error_handler)]
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
Expand Down Expand Up @@ -116,7 +135,9 @@ entry_point!(test_kernel_main);

#[cfg(test)]
fn test_kernel_main(boot_info: &'static BootInfo) -> ! {
init(boot_info);
let memory_map = extract_memory_map(boot_info);
let offset = boot_info.physical_memory_offset;
init(&memory_map, offset);
test_main();
hlt_loop();
}
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use moros::{
entry_point!(main);

fn main(boot_info: &'static BootInfo) -> ! {
moros::init(boot_info);
let memory_map = moros::extract_memory_map(boot_info);
let offset = boot_info.physical_memory_offset;
moros::init(&memory_map, offset);
print!("\x1b[?25h"); // Enable cursor
loop {
if let Some(cmd) = option_env!("MOROS_CMD") {
Expand Down
21 changes: 10 additions & 11 deletions src/sys/mem/bitmap.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bootloader::bootinfo::{MemoryMap, MemoryRegionType};
use super::{MemoryMap, MemoryRegionType, MAX_REGIONS};

use core::{cmp, slice};
use spin::{Once, Mutex};
use bit_field::BitField;
Expand Down Expand Up @@ -57,14 +58,12 @@ fn frame_at(addr: u64) -> PhysFrame<Size4KiB> {

static FRAME_ALLOCATOR: Once<Mutex<BitmapFrameAllocator>> = Once::new();

pub fn init_frame_allocator(memory_map: &'static MemoryMap) {
pub fn init_frame_allocator(memory_map: &MemoryMap) {
FRAME_ALLOCATOR.call_once(|| {
Mutex::new(BitmapFrameAllocator::init(memory_map))
});
}

const MAX_REGIONS: usize = 32;

pub struct BitmapFrameAllocator {
bitmap: &'static mut [u64],
next_free_index: usize,
Expand All @@ -74,12 +73,12 @@ pub struct BitmapFrameAllocator {
}

impl BitmapFrameAllocator {
pub fn init(memory_map: &'static MemoryMap) -> Self {
pub fn init(memory_map: &MemoryMap) -> Self {
let mut bitmap_addr = None;

let frames_count: usize = memory_map.iter().map(|region| {
if region.region_type == MemoryRegionType::Usable {
let size = region.range.end_addr() - region.range.start_addr();
if region.kind == MemoryRegionType::Usable {
let size = region.size;
debug_assert_eq!(size % 4096, 0);
(size / 4096) as usize
} else {
Expand All @@ -97,13 +96,13 @@ impl BitmapFrameAllocator {
};

for region in memory_map.iter() {
if region.region_type != MemoryRegionType::Usable {
if region.kind != MemoryRegionType::Usable {
continue;
}

let region_start = region.range.start_addr();
let region_end = region.range.end_addr();
let region_size = (region_end - region_start) as usize;
let region_start = region.addr;
let region_end = region.addr + region.size;
let region_size = region.size as usize;

// Try to place the bitmap in the region
if bitmap_addr.is_none() && region_size >= bitmap_size {
Expand Down
77 changes: 64 additions & 13 deletions src/sys/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub use phys::{phys_addr, PhysBuf};

use crate::sys;

use bootloader::bootinfo::{BootInfo, MemoryMap};
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::Once;
use x86_64::structures::paging::{
Expand All @@ -21,21 +20,74 @@ use x86_64::{PhysAddr, VirtAddr};
static mut MAPPER: Once<OffsetPageTable<'static>> = Once::new();

static PHYS_MEM_OFFSET: Once<u64> = Once::new();
static MEMORY_MAP: Once<&MemoryMap> = Once::new();
static MEMORY_SIZE: AtomicUsize = AtomicUsize::new(0);

pub fn init(boot_info: &'static BootInfo) {
const MAX_REGIONS: usize = 32;

#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum MemoryRegionType {
Usable,
Reserved,
AcpiUsable,
AcpiReserved,
Defective,
Custom(u32),
}

#[derive(Copy, Clone, Debug)]
pub struct MemoryRegion {
addr: u64,
size: u64,
kind: MemoryRegionType,
}

impl MemoryRegion {
pub fn new(addr: u64, size: u64, kind: MemoryRegionType) -> Self {
Self { addr, size, kind }
}
}

#[derive(Copy, Clone, Debug)]
pub struct MemoryMap {
regions: [MemoryRegion; MAX_REGIONS],
len: usize,
}

impl MemoryMap {
pub fn new() -> Self {
let empty = MemoryRegion::new(0, 0, MemoryRegionType::Reserved);
Self {
regions: [empty; MAX_REGIONS],
len: 0,
}
}

pub fn add(&mut self, region: MemoryRegion) {
self.regions[self.len] = region;
self.len += 1;
}

pub fn as_slice(&self) -> &[MemoryRegion] {
&self.regions[..self.len]
}

pub fn iter(&self) -> core::slice::Iter<'_, MemoryRegion> {
self.as_slice().iter()
}
}

pub fn init(memory_map: &MemoryMap, offset: u64) {
// Keep the timer interrupt to have accurate boot time measurement but mask
// the keyboard interrupt that would create a panic if a key is pressed
// during memory allocation otherwise.
sys::idt::set_irq_mask(1);

let mut memory_size = 0;
let mut last_end_addr = 0;
for region in boot_info.memory_map.iter() {
let start_addr = region.range.start_addr();
let end_addr = region.range.end_addr();
let size = end_addr - start_addr;
for region in memory_map.iter() {
let start_addr = region.addr;
let end_addr = region.addr + region.size;
let hole = start_addr - last_end_addr;
if hole > 0 {
log!(
Expand All @@ -48,9 +100,9 @@ pub fn init(boot_info: &'static BootInfo) {
}
log!(
"MEM [{:#016X}-{:#016X}] {:?}", // "({} KB)"
start_addr, end_addr - 1, region.region_type //, size >> 10
start_addr, end_addr - 1, region.kind //, size >> 10
);
memory_size += size as usize;
memory_size += region.size as usize;
last_end_addr = end_addr;
}

Expand All @@ -66,13 +118,12 @@ pub fn init(boot_info: &'static BootInfo) {
unsafe {
MAPPER.call_once(|| OffsetPageTable::new(
paging::active_page_table(),
VirtAddr::new(boot_info.physical_memory_offset),
VirtAddr::new(offset),
))
};

PHYS_MEM_OFFSET.call_once(|| boot_info.physical_memory_offset);
MEMORY_MAP.call_once(|| &boot_info.memory_map);
bitmap::init_frame_allocator(&boot_info.memory_map);
PHYS_MEM_OFFSET.call_once(|| offset);
bitmap::init_frame_allocator(memory_map);
heap::init_heap().expect("heap initialization failed");

sys::idt::clear_irq_mask(1);
Expand Down