Compare commits
5 Commits
2fb1741100
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
| ecdc76b068 | |||
| 8ee4af1a48 | |||
| 03c07cb5c4 | |||
| ef70bcf51e | |||
| e8237f4610 |
@@ -3,12 +3,12 @@
|
|||||||
use core::arch::x86_64::__cpuid;
|
use core::arch::x86_64::__cpuid;
|
||||||
|
|
||||||
use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET;
|
use crate::arch::x86_64::memory::mapping::PHYSICAL_MEMORY_OFFSET;
|
||||||
use crate::{serial_print, serial_println};
|
use crate::{debugln, serial_print, serial_println};
|
||||||
use x86_64::{
|
use x86_64::{
|
||||||
PhysAddr, VirtAddr,
|
PhysAddr, VirtAddr,
|
||||||
structures::paging::{Mapper, Page, PageTableFlags, PhysFrame, Size4KiB},
|
structures::paging::{Mapper, Page, PageTableFlags, PhysFrame, Size4KiB},
|
||||||
};
|
};
|
||||||
|
use x86_64::structures::paging::Translate;
|
||||||
use crate::arch::x86_64::cpu::msr::*;
|
use crate::arch::x86_64::cpu::msr::*;
|
||||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
||||||
|
|
||||||
@@ -28,9 +28,11 @@ const CPUID_FEAT_EDX_APIC: u64 = 1 << 9; // the cpuid instruction will return th
|
|||||||
|
|
||||||
fn set_apic_base_enable(apic: PhysAddr) {
|
fn set_apic_base_enable(apic: PhysAddr) {
|
||||||
let rax = (apic.as_u64() & 0xfffff0000) | IA32_APIC_BASE_MSR_ENABLE;
|
let rax = (apic.as_u64() & 0xfffff0000) | IA32_APIC_BASE_MSR_ENABLE;
|
||||||
|
debugln!("apic {:?}", PhysAddr::new(rax));
|
||||||
cpu_set_msr(IA32_APIC_BASE_MSR, rax);
|
cpu_set_msr(IA32_APIC_BASE_MSR, rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn set_apic_base_disable(apic: PhysAddr) {
|
fn set_apic_base_disable(apic: PhysAddr) {
|
||||||
let rax = (apic.as_u64() & 0xfffff0000) & IA32_APIC_BASE_MSR_DISABLE;
|
let rax = (apic.as_u64() & 0xfffff0000) & IA32_APIC_BASE_MSR_DISABLE;
|
||||||
cpu_set_msr(IA32_APIC_BASE_MSR, rax);
|
cpu_set_msr(IA32_APIC_BASE_MSR, rax);
|
||||||
@@ -39,22 +41,27 @@ fn set_apic_base_disable(apic: PhysAddr) {
|
|||||||
fn get_apic_base() -> PhysAddr {
|
fn get_apic_base() -> PhysAddr {
|
||||||
let mut value: u64 = 0;
|
let mut value: u64 = 0;
|
||||||
cpu_get_msr(IA32_APIC_BASE_MSR, &mut value);
|
cpu_get_msr(IA32_APIC_BASE_MSR, &mut value);
|
||||||
|
|
||||||
|
debugln!("apic base {:#x}", value);
|
||||||
|
|
||||||
PhysAddr::new(value & 0xfffff0000)
|
PhysAddr::new(value & 0xfffff0000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_apic_register(apic_base: &PhysAddr, reg: u8, value: u32) {
|
fn write_apic_register(apic_base: &PhysAddr, reg: u64, value: u32) {
|
||||||
let apic_base = apic_base.as_u64();
|
let apic_base = apic_base.as_u64();
|
||||||
let reg_addr = (apic_base & 0xFFFFF0000) + reg as u64;
|
let reg_addr = (apic_base & 0xFFFFF0000) + reg;
|
||||||
|
|
||||||
let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) };
|
let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) };
|
||||||
|
|
||||||
|
let phys_check = OFFSET_PAGE_TABLE.get().unwrap().lock().translate(virt_addr);
|
||||||
|
debugln!("{:?}", phys_check);
|
||||||
|
|
||||||
unsafe { *(virt_addr.as_u64() as *mut u32) = value };
|
unsafe { *(virt_addr.as_u64() as *mut u32) = value };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_apic_register(apic_base: &PhysAddr, reg: u8) -> u32 {
|
fn read_apic_register(apic_base: &PhysAddr, reg: u64) -> u32 {
|
||||||
let apic_base = apic_base.as_u64();
|
let apic_base = apic_base.as_u64();
|
||||||
let reg_addr = (apic_base & 0xFFFFF0000) + reg as u64;
|
let reg_addr = (apic_base & 0xFFFFF0000) + reg;
|
||||||
|
|
||||||
serial_println!("reading: {:?}", VirtAddr::new(reg_addr));
|
|
||||||
|
|
||||||
let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) };
|
let virt_addr = unsafe { phys_to_virt(PhysAddr::new(reg_addr)) };
|
||||||
unsafe { *(virt_addr.as_u64() as *const u32) }
|
unsafe { *(virt_addr.as_u64() as *const u32) }
|
||||||
}
|
}
|
||||||
@@ -72,23 +79,22 @@ unsafe fn phys_to_virt(phys: PhysAddr) -> VirtAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_apic() {
|
pub fn enable_apic() {
|
||||||
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
|
let apic_base_physical_addr = get_apic_base();
|
||||||
let mut frame_allocator = FRAME_ALLOCATOR.get().unwrap().lock();
|
set_apic_base_enable(apic_base_physical_addr);
|
||||||
|
|
||||||
let apic_phys_addr = get_apic_base();
|
debugln!("{:?}", apic_base_physical_addr);
|
||||||
set_apic_base_enable(apic_phys_addr);
|
enable_timer();
|
||||||
// map virt address of apic
|
|
||||||
let apic_virt = unsafe { phys_to_virt(apic_phys_addr) };
|
|
||||||
|
|
||||||
serial_println!("Trying to map: {:?} -> {:?}", apic_virt, apic_phys_addr);
|
write_apic_register(
|
||||||
|
&apic_base_physical_addr,
|
||||||
|
0xF0,
|
||||||
|
read_apic_register(&apic_base_physical_addr, 0xF0) | 0x1FF
|
||||||
|
);
|
||||||
|
|
||||||
// FIXME: this causes a page fault
|
|
||||||
// TODO: map to virtual memory
|
|
||||||
|
|
||||||
let reg = read_apic_register(&apic_phys_addr, 0xF0);
|
|
||||||
write_apic_register(&apic_phys_addr, 0xF0, reg | 0x100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Apic {}
|
pub fn enable_timer() {
|
||||||
|
let apic_base = get_apic_base();
|
||||||
pub enum ApicVector {}
|
let current = read_apic_register(&apic_base, 0x320);
|
||||||
|
write_apic_register(&get_apic_base(), 0x320, (current & 0xFFFFFF00) | 0x20);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
use crate::serial_print;
|
use crate::{debug, serial_print};
|
||||||
use pic8259::ChainedPics;
|
use pic8259::ChainedPics;
|
||||||
use x86_64::registers::control::Cr2;
|
use x86_64::registers::control::Cr2;
|
||||||
use x86_64::structures::idt::{
|
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode};
|
||||||
InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode,
|
|
||||||
};
|
|
||||||
use x86_64::structures::paging::mapper::MapperFlushAll;
|
use x86_64::structures::paging::mapper::MapperFlushAll;
|
||||||
use x86_64::structures::paging::{
|
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB};
|
||||||
FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::gdt;
|
use super::gdt;
|
||||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
||||||
@@ -29,8 +25,7 @@ static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
|
|||||||
idt.page_fault.set_handler_fn(page_fault_handler);
|
idt.page_fault.set_handler_fn(page_fault_handler);
|
||||||
|
|
||||||
idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler);
|
idt[InterruptIndex::Timer.as_u8()].set_handler_fn(timer_interrupt_handler);
|
||||||
idt[InterruptIndex::Keyboard.as_u8()]
|
idt[InterruptIndex::Keyboard.as_u8()].set_handler_fn(keyboard_interrupt_handler);
|
||||||
.set_handler_fn(keyboard_interrupt_handler);
|
|
||||||
idt
|
idt
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,22 +90,19 @@ extern "x86-interrupt" fn double_fault_handler(
|
|||||||
panic!("Exception: Double Fault\n{:#?}", stack_frame);
|
panic!("Exception: Double Fault\n{:#?}", stack_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn keyboard_interrupt_handler(
|
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||||
_stack_frame: InterruptStackFrame,
|
|
||||||
) {
|
|
||||||
use pc_keyboard::{HandleControl, Keyboard, ScancodeSet1, layouts};
|
use pc_keyboard::{HandleControl, Keyboard, ScancodeSet1, layouts};
|
||||||
// use pc_keyboard::DecodedKey;
|
// use pc_keyboard::DecodedKey;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::instructions::port::Port;
|
use x86_64::instructions::port::Port;
|
||||||
|
|
||||||
static KEYBOARD: Lazy<Mutex<Keyboard<layouts::Uk105Key, ScancodeSet1>>> =
|
static KEYBOARD: Lazy<Mutex<Keyboard<layouts::Uk105Key, ScancodeSet1>>> = Lazy::new(|| {
|
||||||
Lazy::new(|| {
|
Mutex::new(Keyboard::new(
|
||||||
Mutex::new(Keyboard::new(
|
ScancodeSet1::new(),
|
||||||
ScancodeSet1::new(),
|
layouts::Uk105Key,
|
||||||
layouts::Uk105Key,
|
HandleControl::Ignore,
|
||||||
HandleControl::Ignore,
|
))
|
||||||
))
|
});
|
||||||
});
|
|
||||||
|
|
||||||
let _keyboard = KEYBOARD.lock();
|
let _keyboard = KEYBOARD.lock();
|
||||||
let mut port = Port::new(0x60);
|
let mut port = Port::new(0x60);
|
||||||
@@ -124,9 +116,8 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "x86-interrupt" fn timer_interrupt_handler(
|
extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
|
||||||
_stack_frame: InterruptStackFrame,
|
debug!("Timer Interrupt");
|
||||||
) {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
PICS.lock()
|
PICS.lock()
|
||||||
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
|
||||||
|
|||||||
@@ -1,27 +1,44 @@
|
|||||||
use crate::arch::x86_64::memory::{HEAP_SIZE, HEAP_VIRTUAL_SPACE};
|
use crate::{debugln, serial_print};
|
||||||
use core::alloc::{GlobalAlloc, Layout};
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use spin::{Mutex, MutexGuard};
|
use spin::{Mutex, MutexGuard};
|
||||||
use x86_64::structures::paging::{Size4KiB, mapper::MapToError};
|
use x86_64::structures::paging::{Size4KiB, mapper::MapToError, PageTableFlags};
|
||||||
|
use x86_64::VirtAddr;
|
||||||
|
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, HEAP_SIZE, HEAP_VIRTUAL_SPACE};
|
||||||
|
use crate::arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
|
||||||
|
use crate::arch::x86_64::memory::units::MemoryUnits;
|
||||||
|
use crate::serial_println;
|
||||||
|
|
||||||
/// We are currently using a linked list heap allocator which uses our
|
/// We are currently using a linked list heap allocator which uses our underlying page allocator.
|
||||||
/// underlying page allocator.
|
|
||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
/// This is now Rust's global allocator, so we can use stuff requiring heap
|
/// This is now Rust's global allocator, so we can use stuff requiring heap allocations.
|
||||||
/// allocations.
|
static ALLOCATOR: Locked<FoundryAllocator> = Locked::new(FoundryAllocator::new());
|
||||||
static ALLOCATOR: Locked<FoundryAllocator> =
|
|
||||||
Locked::new(FoundryAllocator::new());
|
|
||||||
|
|
||||||
/// Sets up the heap using the backing page frame allocator.
|
|
||||||
|
/// Initializes the heap.
|
||||||
|
///
|
||||||
|
/// This function must be called once, before any functions that
|
||||||
|
/// require a heap are called. It sets up the heap by allocating
|
||||||
|
/// the necessary frames from the page allocator. The heap is
|
||||||
|
/// then ready for use.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// We do not check whether the given heap start address and size are actually
|
/// This function must be called only once, and must be called before any types
|
||||||
/// valid.
|
/// are constructed that require dynamic memory allocation.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// None
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// Returns a `Result` containing a `MapToError` if the heap
|
||||||
|
/// could not be initialized, or `Ok` if the heap was
|
||||||
|
/// initialized successfully.
|
||||||
pub unsafe fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
pub unsafe fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// The code to allocate frames is now done in the page fault interrupt
|
// code to allocate frames is now done in the page fault interrupt handler!
|
||||||
// handler!
|
|
||||||
ALLOCATOR.lock().init(HEAP_VIRTUAL_SPACE, HEAP_SIZE);
|
ALLOCATOR.lock().init(HEAP_VIRTUAL_SPACE, HEAP_SIZE);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -68,14 +85,15 @@ impl FoundryAllocator {
|
|||||||
fallback: Locked::new(FoundryFallbackAllocator::new()),
|
fallback: Locked::new(FoundryFallbackAllocator::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Initializes the fallback allocator with the given heap start address and
|
/// Initializes the fallback allocator with the given heap start address and size.
|
||||||
/// size.
|
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is unsafe because it does not check whether the given heap
|
/// This function is unsafe because it does not check whether the given heap start address and size are valid.
|
||||||
/// start address and size are valid.
|
|
||||||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
||||||
|
debugln!(" => Start: {:?}", VirtAddr::new(heap_start as u64));
|
||||||
|
debugln!(" => Size: {}", MemoryUnits::from_bytes(heap_size));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.fallback.lock().init(heap_start, heap_size);
|
self.fallback.lock().init(heap_start, heap_size);
|
||||||
}
|
}
|
||||||
@@ -100,16 +118,16 @@ unsafe impl GlobalAlloc for Locked<FoundryAllocator> {
|
|||||||
match allocator.list_heads[index].take() {
|
match allocator.list_heads[index].take() {
|
||||||
Some(node) => {
|
Some(node) => {
|
||||||
allocator.list_heads[index] = node.next.take();
|
allocator.list_heads[index] = node.next.take();
|
||||||
node as *mut ListNode as *mut u8
|
let ptr = node as *mut ListNode as *mut u8;
|
||||||
|
ensure_mapped(VirtAddr::new(ptr as u64));
|
||||||
|
ptr
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// no block exists in list => allocate new block
|
// no block exists in list => allocate new block
|
||||||
let block_size = BLOCK_SIZES[index];
|
let block_size = BLOCK_SIZES[index];
|
||||||
// only works if all block sizes are a power of 2
|
// only works if all block sizes are a power of 2
|
||||||
let block_align = block_size;
|
let block_align = block_size;
|
||||||
let layout =
|
let layout = Layout::from_size_align(block_size, block_align).unwrap();
|
||||||
Layout::from_size_align(block_size, block_align)
|
|
||||||
.unwrap();
|
|
||||||
unsafe { allocator.fallback_alloc(layout) }
|
unsafe { allocator.fallback_alloc(layout) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,22 +191,24 @@ impl FoundryFallbackAllocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialises the Foundry OS fallback allocator. This is currently a
|
/// Initializes the allocator with a given heap start address and size.
|
||||||
/// linked list allocator pulled from the linked_list_allocator crate.
|
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function assumes you passed a valid `heap_start` and `heap_size`,
|
/// This function is unsafe because it does not check whether the given heap start address and size are valid.
|
||||||
/// as these are unchecked.
|
|
||||||
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
pub unsafe fn init(&mut self, heap_start: usize, heap_size: usize) {
|
||||||
unsafe { self.add_region(heap_start, heap_size) };
|
unsafe { self.add_region(heap_start, heap_size) };
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn add_region(&mut self, addr: usize, size: usize) {
|
unsafe fn add_region(&mut self, addr: usize, size: usize) {
|
||||||
let mut node = FallbackListNode::new(size);
|
|
||||||
node.next = self.head.next.take();
|
|
||||||
let node_ptr = addr as *mut FallbackListNode;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
let mut node = FallbackListNode::new(size);
|
||||||
|
node.next = self.head.next.take();
|
||||||
|
|
||||||
|
let virt_addr = VirtAddr::new(addr as u64);
|
||||||
|
ensure_mapped(virt_addr);
|
||||||
|
|
||||||
|
let node_ptr = addr as *mut FallbackListNode;
|
||||||
node_ptr.write(node);
|
node_ptr.write(node);
|
||||||
self.head.next = Some(&mut *node_ptr);
|
self.head.next = Some(&mut *node_ptr);
|
||||||
}
|
}
|
||||||
@@ -202,9 +222,7 @@ impl FoundryFallbackAllocator {
|
|||||||
let mut current = &mut self.head;
|
let mut current = &mut self.head;
|
||||||
// look for a large enough memory region in linked list
|
// look for a large enough memory region in linked list
|
||||||
while let Some(ref mut region) = current.next {
|
while let Some(ref mut region) = current.next {
|
||||||
if let Ok(alloc_start) =
|
if let Ok(alloc_start) = Self::alloc_from_region(region, size, align) {
|
||||||
Self::alloc_from_region(region, size, align)
|
|
||||||
{
|
|
||||||
// region suitable for allocation -> remove node from list
|
// region suitable for allocation -> remove node from list
|
||||||
let next = region.next.take();
|
let next = region.next.take();
|
||||||
let ret = Some((current.next.take().unwrap(), alloc_start));
|
let ret = Some((current.next.take().unwrap(), alloc_start));
|
||||||
@@ -257,14 +275,15 @@ unsafe impl GlobalAlloc for Locked<FoundryFallbackAllocator> {
|
|||||||
// perform layout adjustments
|
// perform layout adjustments
|
||||||
let (size, align) = FoundryFallbackAllocator::size_align(layout);
|
let (size, align) = FoundryFallbackAllocator::size_align(layout);
|
||||||
|
|
||||||
if let Some((region, alloc_start)) = allocator.find_region(size, align)
|
if let Some((region, alloc_start)) = allocator.find_region(size, align) {
|
||||||
{
|
|
||||||
let alloc_end = alloc_start.checked_add(size).expect("overflow");
|
let alloc_end = alloc_start.checked_add(size).expect("overflow");
|
||||||
let excess_size = region.end_addr() - alloc_end;
|
let excess_size = region.end_addr() - alloc_end;
|
||||||
if excess_size > 0 {
|
if excess_size > 0 {
|
||||||
unsafe { allocator.add_region(alloc_end, excess_size) };
|
unsafe { allocator.add_region(alloc_end, excess_size) };
|
||||||
}
|
}
|
||||||
alloc_start as *mut u8
|
let ptr = alloc_start as *mut u8;
|
||||||
|
ensure_mapped(VirtAddr::new(ptr as u64));
|
||||||
|
ptr
|
||||||
} else {
|
} else {
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
}
|
}
|
||||||
@@ -275,7 +294,13 @@ unsafe impl GlobalAlloc for Locked<FoundryFallbackAllocator> {
|
|||||||
|
|
||||||
// perform layout adjustments
|
// perform layout adjustments
|
||||||
let (size, _) = FoundryFallbackAllocator::size_align(layout);
|
let (size, _) = FoundryFallbackAllocator::size_align(layout);
|
||||||
|
|
||||||
unsafe { allocator.add_region(ptr as usize, size) }
|
unsafe { allocator.add_region(ptr as usize, size) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ensure_mapped(virt_addr: VirtAddr) {
|
||||||
|
if ! FoundryOSFrameAllocator::is_mapped(virt_addr) {
|
||||||
|
let mut foundry_alloc = FRAME_ALLOCATOR.get().unwrap().lock();
|
||||||
|
foundry_alloc.allocate_page(virt_addr, PageTableFlags::PRESENT | PageTableFlags::WRITABLE).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB, Translate};
|
||||||
use limine::memory_map::EntryType;
|
|
||||||
use limine::response::MemoryMapResponse;
|
use limine::response::MemoryMapResponse;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
use x86_64::structures::paging::mapper::MapToError;
|
use limine::memory_map::EntryType;
|
||||||
use x86_64::structures::paging::{
|
|
||||||
FrameAllocator, Mapper, Page, PageTableFlags, PhysFrame, Size4KiB,
|
|
||||||
};
|
|
||||||
use x86_64::{PhysAddr, VirtAddr};
|
use x86_64::{PhysAddr, VirtAddr};
|
||||||
|
use x86_64::structures::paging::mapper::{MapToError, TranslateResult};
|
||||||
|
use crate::arch::x86_64::memory::{FRAME_ALLOCATOR, OFFSET_PAGE_TABLE};
|
||||||
|
|
||||||
pub struct FoundryOSFrameAllocator {
|
pub struct FoundryOSFrameAllocator {
|
||||||
memory_map: &'static MemoryMapResponse,
|
memory_map: &'static MemoryMapResponse,
|
||||||
@@ -29,51 +27,45 @@ impl FoundryOSFrameAllocator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count_usable_frames(&self) -> u32 {
|
pub fn count_usable_frames(&self) -> u64 {
|
||||||
self.usable_frames().count() as u32
|
self.usable_frames().count() as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn available_memory(&self) -> u64 {
|
pub fn available_memory(&self) -> u64 {
|
||||||
(self.memory_map.entries().len() * 4096) as u64 // multiply the number of physical frames by 4096 to get the memory size
|
self.memory_map
|
||||||
|
.entries()
|
||||||
|
.iter()
|
||||||
|
.map(|region| region.base..region.base + region.length)
|
||||||
|
.flat_map(|r| r.step_by(4096)).count() as u64 * 4096
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator over all usable frames in the memory map.
|
/// An iterator over all usable frames in the memory map.
|
||||||
///
|
///
|
||||||
/// Yields one `PhysFrame` for each available 4KiB frame in the memory map.
|
/// Yields one `PhysFrame` for each available 4KiB frame in the memory map.
|
||||||
///
|
///
|
||||||
/// This function is used to allocate frames for the pagemap.
|
/// This function is used to allocate frames for the page map.
|
||||||
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> + use<> {
|
fn usable_frames(&self) -> impl Iterator<Item = PhysFrame> + use<> {
|
||||||
let regions = self.memory_map.entries().iter();
|
let regions = self.memory_map.entries().iter();
|
||||||
let usable_regions =
|
let usable_regions = regions.filter(|region| region.entry_type == EntryType::USABLE);
|
||||||
regions.filter(|region| region.entry_type == EntryType::USABLE);
|
let addr_ranges = usable_regions.map(|region| region.base..region.base + region.length);
|
||||||
let addr_ranges = usable_regions
|
|
||||||
.map(|region| region.base..region.base + region.length);
|
|
||||||
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
let frame_addresses = addr_ranges.flat_map(|r| r.step_by(4096));
|
||||||
frame_addresses.map(|addr| {
|
frame_addresses.map(|addr| PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap())
|
||||||
PhysFrame::from_start_address(PhysAddr::new(addr)).unwrap()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(unused)]
|
pub(crate) fn is_mapped(virt_addr: VirtAddr) -> bool {
|
||||||
fn allocate_page(
|
let mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
|
||||||
&mut self,
|
matches!(mapper.translate(virt_addr), TranslateResult::Mapped { .. })
|
||||||
start_addr: VirtAddr,
|
}
|
||||||
flags: PageTableFlags,
|
|
||||||
) -> Result<(), MapToError<Size4KiB>> {
|
pub(crate) fn allocate_page(&mut self, start_addr: VirtAddr, flags: PageTableFlags) -> Result<(), MapToError<Size4KiB>> {
|
||||||
let page = Page::from_start_address(start_addr)
|
let page = Page::containing_address(start_addr);
|
||||||
.map_err(|_| MapToError::FrameAllocationFailed)?;
|
let frame = self.allocate_frame().ok_or(MapToError::<Size4KiB>::FrameAllocationFailed)?;
|
||||||
let frame = self
|
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
|
||||||
.allocate_frame()
|
|
||||||
.ok_or(MapToError::FrameAllocationFailed)?;
|
unsafe {
|
||||||
let _ = unsafe {
|
mapper.map_to(page, frame, flags, self)?
|
||||||
let mut mapper = OFFSET_PAGE_TABLE.get().unwrap().lock();
|
}.flush();
|
||||||
mapper.map_to(
|
|
||||||
page,
|
|
||||||
frame,
|
|
||||||
flags,
|
|
||||||
&mut *FRAME_ALLOCATOR.get().unwrap().lock(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-30
@@ -12,16 +12,20 @@
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
use crate::arch::x86_64::cpu::apic::enable_apic;
|
|
||||||
use crate::{arch::x86_64::memory::init_page_table, prelude::*};
|
use crate::{arch::x86_64::memory::init_page_table, prelude::*};
|
||||||
use arch::x86_64::memory::allocation::heap_alloc::init_heap;
|
use arch::x86_64::memory::allocation::heap_alloc::init_heap;
|
||||||
use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
|
|
||||||
use arch::x86_64::memory::mapping;
|
use arch::x86_64::memory::mapping;
|
||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use limine::BaseRevision;
|
use limine::BaseRevision;
|
||||||
use std::unwind;
|
use std::unwind;
|
||||||
use std::unwind::eh_info::ELF;
|
use std::unwind::eh_info::ELF;
|
||||||
use x86_64::VirtAddr;
|
use x86_64::VirtAddr;
|
||||||
|
use arch::x86_64::memory::allocation::page_alloc::FoundryOSFrameAllocator;
|
||||||
|
use crate::arch::x86_64::cpu::apic::enable_apic;
|
||||||
|
use crate::arch::x86_64::drivers::ascii::screensize_chars;
|
||||||
|
use crate::arch::x86_64::drivers::framebuffer::display::screensize_px;
|
||||||
|
use crate::arch::x86_64::memory::FRAME_ALLOCATOR;
|
||||||
|
use crate::arch::x86_64::memory::units::MemoryUnits;
|
||||||
|
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
mod panic;
|
mod panic;
|
||||||
@@ -34,7 +38,9 @@ pub mod prelude {
|
|||||||
pub use crate::{
|
pub use crate::{
|
||||||
eprint, eprintln, print, print_log, println, println_log, serial_print,
|
eprint, eprintln, print, print_log, println, println_log, serial_print,
|
||||||
serial_println,
|
serial_println,
|
||||||
std::io::{_print, _print_err, _print_log, _serial_write},
|
debug, debugln,
|
||||||
|
std::io::{_print, _print_log, _serial_write, _print_err},
|
||||||
|
std::debug::_debug,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,53 +80,61 @@ pub fn boot() -> Result<(), &'static str> {
|
|||||||
let memory_map = mapping::get_memory_map();
|
let memory_map = mapping::get_memory_map();
|
||||||
|
|
||||||
print_log!(" Initialising Serial... ");
|
print_log!(" Initialising Serial... ");
|
||||||
if arch::x86_64::drivers::serial::init().is_err() {
|
let res = arch::x86_64::drivers::serial::init();
|
||||||
println_log!("[Not Detected]")
|
serial_print!(" Initialising Serial... ");
|
||||||
|
if res.is_err() {
|
||||||
|
debugln!("[Not Detected]")
|
||||||
} else {
|
} else {
|
||||||
println_log!("[Success]");
|
debugln!("[Success]");
|
||||||
}
|
}
|
||||||
|
|
||||||
print_log!(" Setting Up Global Descriptor Table... ");
|
debugln!(" Display...");
|
||||||
|
let dimensions = screensize_chars();
|
||||||
|
let dimensions2 = screensize_px();
|
||||||
|
debugln!(" => (px) : {}x{} ", dimensions2.0, dimensions2.1);
|
||||||
|
debugln!(" => (chars) : {}x{} ", dimensions.0, dimensions.1);
|
||||||
|
debugln!(" [Success]");
|
||||||
|
|
||||||
|
debug!(" Setting Up Global Descriptor Table... ");
|
||||||
gdt::init();
|
gdt::init();
|
||||||
println_log!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
print_log!(" Setting Up Interrupt Descriptor Table... ");
|
debug!(" Setting Up Interrupt Descriptor Table... ");
|
||||||
interrupts::init_idt();
|
interrupts::init_idt();
|
||||||
println_log!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
print_log!(" Initialising Memory Subsystem... ");
|
debugln!(" Initialising Memory Subsystem... ");
|
||||||
let physical_memory_offset =
|
let physical_memory_offset = VirtAddr::new(*mapping::PHYSICAL_MEMORY_OFFSET);
|
||||||
VirtAddr::new(*mapping::PHYSICAL_MEMORY_OFFSET);
|
|
||||||
init_page_table(physical_memory_offset);
|
init_page_table(physical_memory_offset);
|
||||||
println_log!("[Success]");
|
|
||||||
|
|
||||||
print_log!(" Setting Up Page Table... ");
|
|
||||||
FoundryOSFrameAllocator::init(memory_map);
|
FoundryOSFrameAllocator::init(memory_map);
|
||||||
println_log!("[Success]");
|
let available_bytes = FRAME_ALLOCATOR.get().unwrap().lock().available_memory();
|
||||||
|
debugln!(" => Available Memory: {}", MemoryUnits::from_bytes(available_bytes as usize));
|
||||||
|
|
||||||
print_log!(" Initialising Heap... ");
|
debugln!("[Success]");
|
||||||
|
|
||||||
|
debugln!(" Initialising Heap... ");
|
||||||
if unsafe { init_heap() }.is_err() {
|
if unsafe { init_heap() }.is_err() {
|
||||||
return Err("Failed to initialise heap: error");
|
return Err("Failed to initialise heap: error");
|
||||||
}
|
}
|
||||||
println_log!("[Success]");
|
debugln!(" [Success]");
|
||||||
|
|
||||||
// print_log!(" Enabling PICs... ");
|
// debug!(" Enabling PICs... ");
|
||||||
// interrupts::enable_pic();
|
// interrupts::enable_pic();
|
||||||
// println_log!("[Success]");
|
// debugln!("[Success]");
|
||||||
|
|
||||||
// print_log!(" Disabling PICs... ");
|
debug!(" Disabling PICs... ");
|
||||||
// interrupts::disable_pic();
|
interrupts::disable_pic();
|
||||||
// println_log!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
print_log!(" Initialising APIC... ");
|
debug!(" Initialising APIC... ");
|
||||||
enable_apic();
|
enable_apic();
|
||||||
println_log!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
print_log!(" Enabling Interrupts... ");
|
debug!(" Enabling Interrupts... ");
|
||||||
x86_64::instructions::interrupts::enable();
|
x86_64::instructions::interrupts::enable();
|
||||||
println_log!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
print_log!(" Setting up stack unwinder, panic handler... ");
|
debug!(" Setting up stack unwinder, panic handler... ");
|
||||||
// Setup stack traces and proper panic handler. TODO: Handle panics
|
// Setup stack traces and proper panic handler. TODO: Handle panics
|
||||||
// differently if not initialised.
|
// differently if not initialised.
|
||||||
let eh_frame_ptr = ELF
|
let eh_frame_ptr = ELF
|
||||||
@@ -129,7 +143,7 @@ pub fn boot() -> Result<(), &'static str> {
|
|||||||
|
|
||||||
let _eh_info =
|
let _eh_info =
|
||||||
unsafe { unwind::eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) };
|
unsafe { unwind::eh_info::EhInfo::from_hdr_ptr(eh_frame_ptr) };
|
||||||
println_log!("[Success]");
|
debugln!("[Success]");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-7
@@ -15,13 +15,7 @@ extern "C" fn kmain() -> ! {
|
|||||||
panic!("{}", err);
|
panic!("{}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
println_log!("[ Kernel Initialised Successfully ] ");
|
println_log!(" [ Kernel Initialised Successfully ] ");
|
||||||
|
|
||||||
let dimensions = screensize_chars();
|
|
||||||
let dimensions2 = screensize_px();
|
|
||||||
|
|
||||||
println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1);
|
|
||||||
println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1);
|
|
||||||
|
|
||||||
// println!("TESTING :: Allocation");
|
// println!("TESTING :: Allocation");
|
||||||
// let somevec = vec![0; 1_000_000];
|
// let somevec = vec![0; 1_000_000];
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
use core::fmt;
|
||||||
|
use x86_64::instructions::interrupts;
|
||||||
|
use crate::prelude::{_print_log, _serial_write};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debugln {
|
||||||
|
() => ($crate::print_log!("\n"));
|
||||||
|
($($arg:tt)*) => ($crate::debug!("{}\n", format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug {
|
||||||
|
($($arg:tt)*) => ($crate::prelude::_debug(format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _debug(args: fmt::Arguments) {
|
||||||
|
interrupts::without_interrupts(|| {
|
||||||
|
_print_log(args);
|
||||||
|
_serial_write(args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,3 +4,4 @@ pub mod elf;
|
|||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod maths;
|
pub mod maths;
|
||||||
pub mod unwind;
|
pub mod unwind;
|
||||||
|
pub mod debug;
|
||||||
|
|||||||
@@ -94,6 +94,15 @@ check_test_res() {
|
|||||||
|
|
||||||
trap 'check_test_res "tests completed"' ERR
|
trap 'check_test_res "tests completed"' ERR
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE(ali): For some reason the values in `boot_flags` were causing issues
|
||||||
|
# on WSL, so they've been eradicated.
|
||||||
|
systemInfo=$(uname -r)
|
||||||
|
if [[ $systemInfo == *"WSL"* ]]; then
|
||||||
|
echo "Running on WSL2"
|
||||||
|
boot_flags=""
|
||||||
|
fi
|
||||||
|
|
||||||
cd "$project_root"
|
cd "$project_root"
|
||||||
qemu-system-x86_64 -M q35 \
|
qemu-system-x86_64 -M q35 \
|
||||||
-cdrom "$build_dir/image.iso" \
|
-cdrom "$build_dir/image.iso" \
|
||||||
|
|||||||
Reference in New Issue
Block a user