Compare commits
3 Commits
9a5a004243
...
10df1c6cfa
Author | SHA1 | Date |
---|---|---|
fekhesk | 10df1c6cfa | |
fekhesk | 1d810657ff | |
fekhesk | 3bb18ee8f7 |
|
@ -1,7 +0,0 @@
|
|||
[target.'cfg(target_os = "none")']
|
||||
runner = "cargo run --package simple_boot --"
|
||||
|
||||
[alias]
|
||||
kbuild = "build --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem"
|
||||
kimage = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem -- --no-run"
|
||||
krun = "run --target x86_64-custom.json -Zbuild-std=core -Zbuild-std-features=compiler-builtins-mem"
|
|
@ -11,10 +11,12 @@ spin = "0.9.1"
|
|||
x86_64 = "0.14.10"
|
||||
rlibc = "1.0"
|
||||
multiboot2 = { version = "0.14.0", optional = true }
|
||||
linked_list_allocator = { version = "0.9.0", optional = true }
|
||||
[dependencies.lazy_static]
|
||||
version = "1.4.0"
|
||||
features = ["spin_no_std"]
|
||||
|
||||
[features]
|
||||
default = ["f_multiboot2"]
|
||||
f_multiboot2 = ["dep:multiboot2"]
|
||||
default = ["f_multiboot2", "f_ll_alloc"]
|
||||
f_multiboot2 = ["dep:multiboot2"]
|
||||
f_ll_alloc = ["dep:linked_list_allocator"]
|
4
Makefile
4
Makefile
|
@ -22,7 +22,7 @@ clean:
|
|||
run: $(final) $(iso)
|
||||
@qemu-system-$(arch) -bios $(efi_bios) -cdrom $(iso) \
|
||||
-chardev stdio,id=char0,mux=on,logfile=serial.log,signal=off \
|
||||
-serial chardev:char0 -mon chardev=char0
|
||||
-serial chardev:char0 -mon chardev=char0 -m 512M
|
||||
|
||||
quick_invalidate:
|
||||
@echo "quick invalidation"
|
||||
|
@ -44,7 +44,7 @@ $(final): $(kernel) $(linker_script) $(assembly_object_files)
|
|||
--gc-sections
|
||||
|
||||
$(kernel):
|
||||
@RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc
|
||||
@RUST_TARGET_PATH=$(shell pwd) xargo build --target $(target) -Zbuild-std=core,alloc --features "f_multiboot2"
|
||||
|
||||
build/arch/$(arch)/%.o: arch/$(arch)/%.asm
|
||||
@mkdir -p $(shell dirname $@)
|
||||
|
|
|
@ -11,6 +11,16 @@ SECTIONS {
|
|||
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.text .text.*)
|
||||
}
|
||||
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
|
||||
.data.rel.ro :
|
||||
{
|
||||
*(.data.rel.ro.local*) *(.data.rel.ro .data.rel.ro.*)
|
||||
}
|
||||
}
|
23
serial.log
23
serial.log
|
@ -6,16 +6,13 @@ BdsDxe: starting Boot0001 "UEFI QEMU DVD-ROM QM00003 " from PciRoot(0x0)/Pci(0x1
|
|||
|
||||
WARNING: no console will be available to OS
|
||||
error: no suitable video mode found.
|
||||
|
||||
|
||||
|
||||
welcome to wukkOS!
|
||||
(c) 2022 Real Microsoft, LLC
|
||||
initialising memory maps...[OK]
|
||||
memory map:
|
||||
0 - a0000 : Available
|
||||
100000 - 800000 : Available
|
||||
808000 - 80b000 : Available
|
||||
80c000 - 810000 : Available
|
||||
900000 - 78ef000 : Available
|
||||
7bff000 - 7f58000 : Available
|
||||
using serial port 0 as console
|
||||
|
||||
|
||||
|
||||
welcome to wukkOS!
|
||||
(c) 2022 Real Microsoft, LLC
|
||||
initialising mapper...[OK]
|
||||
initialising frame allocator...[OK]
|
||||
initialising heap...[OK]
|
||||
testing heap...[OK]
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::cell::UnsafeCell;
|
||||
use core::ptr::null_mut;
|
||||
use core::sync::atomic::AtomicUsize;
|
||||
use core::sync::atomic::Ordering::SeqCst;
|
||||
|
||||
const ARENA_SIZE: usize = 128 * 1024;
|
||||
const MAX_SUPPORTED_ALIGN: usize = 4096;
|
||||
#[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN
|
||||
struct SimpleAllocator {
|
||||
arena: UnsafeCell<[u8; ARENA_SIZE]>,
|
||||
remaining: AtomicUsize, // we allocate from the top, counting down
|
||||
}
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: SimpleAllocator = SimpleAllocator {
|
||||
arena: UnsafeCell::new([0x55; ARENA_SIZE]),
|
||||
remaining: AtomicUsize::new(ARENA_SIZE),
|
||||
};
|
||||
|
||||
unsafe impl Sync for SimpleAllocator {}
|
||||
|
||||
unsafe impl GlobalAlloc for SimpleAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
let size = layout.size();
|
||||
let align = layout.align();
|
||||
|
||||
// `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
|
||||
// So we can safely use a mask to ensure alignment without worrying about UB.
|
||||
let align_mask_to_round_down = !(align - 1);
|
||||
|
||||
if align > MAX_SUPPORTED_ALIGN {
|
||||
return null_mut();
|
||||
}
|
||||
|
||||
let mut allocated = 0;
|
||||
if self
|
||||
.remaining
|
||||
.fetch_update(SeqCst, SeqCst, |mut remaining| {
|
||||
if size > remaining {
|
||||
return None;
|
||||
}
|
||||
remaining -= size;
|
||||
remaining &= align_mask_to_round_down;
|
||||
allocated = remaining;
|
||||
Some(remaining)
|
||||
})
|
||||
.is_err()
|
||||
{
|
||||
return null_mut();
|
||||
};
|
||||
(self.arena.get() as *mut u8).add(allocated)
|
||||
}
|
||||
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
|
||||
}
|
|
@ -1,27 +1,54 @@
|
|||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
use crate::KernelArgs;
|
||||
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
pub mod multiboot2;
|
||||
use multiboot2::{load, MemoryMapTag, BootInformation};
|
||||
|
||||
pub enum MemoryType {
|
||||
Available,
|
||||
Reserved,
|
||||
AcpiReclaimable,
|
||||
Nvs,
|
||||
BadMemory,
|
||||
Kernel,
|
||||
Bootloader,
|
||||
Unknown(u32)
|
||||
pub struct KernelInfo {
|
||||
kernel_start: u64,
|
||||
kernel_end: u64,
|
||||
safe_mem_start: u64,
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
boot_info: BootInformation,
|
||||
}
|
||||
|
||||
pub struct MemoryArea {
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
pub area_type: MemoryType,
|
||||
}
|
||||
impl KernelInfo {
|
||||
pub fn init_from_kernel_args(args: KernelArgs) -> Self {
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
{
|
||||
let boot_info = unsafe { load(args.multiboot_information_address) }.expect("failed to load multiboot2 information");
|
||||
let elf_sections = boot_info.elf_sections_tag().expect("no elf sections tag");
|
||||
let kernel_start = elf_sections.sections().map(|s| s.start_address()).min().unwrap();
|
||||
let kernel_end = elf_sections.sections().map(|s| s.end_address()).max().unwrap();
|
||||
// get end of multiboot for safe memory
|
||||
let safe_mem_start = boot_info.start_address() + boot_info.total_size();
|
||||
let kernel_info = KernelInfo {
|
||||
kernel_start,
|
||||
kernel_end,
|
||||
safe_mem_start: safe_mem_start as u64,
|
||||
boot_info,
|
||||
};
|
||||
kernel_info
|
||||
}
|
||||
}
|
||||
|
||||
pub trait KernelInfo {
|
||||
fn init_from_kernel_args(&mut self, args: KernelArgs);
|
||||
fn get_memory_areas(&self) -> Vec<MemoryArea>;
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
pub fn get_memory_tag(&self) -> &MemoryMapTag {
|
||||
let mm_tag = self.boot_info.memory_map_tag().expect("no memory map tag").clone();
|
||||
mm_tag
|
||||
}
|
||||
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
pub fn memory_areas(&self) -> impl Iterator<Item = &multiboot2::MemoryArea> {
|
||||
let mm_tag = self.boot_info.memory_map_tag().expect("ERR NO MEM MAP TAG!");
|
||||
mm_tag.all_memory_areas()
|
||||
}
|
||||
|
||||
pub fn is_safe_memory(&self, addr: u64) -> bool {
|
||||
addr >= self.safe_mem_start && addr >= self.kernel_end
|
||||
}
|
||||
|
||||
pub fn safe_memory_start(&self) -> u64 {
|
||||
self.safe_mem_start
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
extern crate multiboot2;
|
||||
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use multiboot2::{BootInformation, load, MemoryAreaType};
|
||||
use crate::boot::{KernelInfo, MemoryArea, MemoryType};
|
||||
use crate::KernelArgs;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Multiboot2Bootloader {
|
||||
pub boot_info: Option<BootInformation>,
|
||||
}
|
||||
|
||||
impl KernelInfo for Multiboot2Bootloader {
|
||||
fn init_from_kernel_args(&mut self, args: KernelArgs) {
|
||||
let boot_info = unsafe {
|
||||
load(args.multiboot_information_address)
|
||||
}.expect("invalid kernel args!");
|
||||
self.boot_info = Some(boot_info);
|
||||
}
|
||||
|
||||
fn get_memory_areas(&self) -> Vec<MemoryArea> {
|
||||
let mut memory_areas = vec![];
|
||||
let boot_info = self.boot_info.as_ref().unwrap();
|
||||
let memory_map_tag = boot_info.memory_map_tag().expect("memory map tag required but not found!");
|
||||
for area in memory_map_tag.memory_areas() {
|
||||
memory_areas.push(MemoryArea {
|
||||
start: area.start_address() as usize,
|
||||
end: area.end_address() as usize,
|
||||
area_type: match area.typ() {
|
||||
MemoryAreaType::Available => MemoryType::Available,
|
||||
MemoryAreaType::Reserved => MemoryType::Reserved,
|
||||
MemoryAreaType::AcpiAvailable => MemoryType::AcpiReclaimable,
|
||||
MemoryAreaType::ReservedHibernate => MemoryType::Reserved,
|
||||
MemoryAreaType::Defective => MemoryType::BadMemory,
|
||||
}
|
||||
})
|
||||
}
|
||||
memory_areas
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ pub extern "x86-interrupt" fn double_fault(stack_frame: InterruptStackFrame, _er
|
|||
loop {}
|
||||
}
|
||||
|
||||
pub extern "x86-interrupt" fn page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) -> ! {
|
||||
pub extern "x86-interrupt" fn page_fault(stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) {
|
||||
println!("---KERNEL FUCKY WUKKY UWU---");
|
||||
println!("page fault!");
|
||||
println!("accessed address: {:?}", Cr2::read());
|
||||
|
|
98
src/lib.rs
98
src/lib.rs
|
@ -1,33 +1,30 @@
|
|||
#![feature(abi_x86_interrupt)]
|
||||
#![feature(default_alloc_error_handler)]
|
||||
#![feature(panic_info_message)]
|
||||
#![feature(asm_const)]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use alloc::format;
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use allocator::*;
|
||||
|
||||
extern crate alloc;
|
||||
extern crate rlibc;
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use spin::Mutex;
|
||||
use core::arch::asm;
|
||||
use core::ops::Deref;
|
||||
use alloc::rc::Rc;
|
||||
use alloc::vec;
|
||||
use lazy_static::lazy_static;
|
||||
use core::panic::PanicInfo;
|
||||
use multiboot2::MemoryAreaType;
|
||||
use spin::Mutex;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
use x86_64::structures::paging::Translate;
|
||||
use crate::boot::KernelInfo;
|
||||
use crate::internals::WhyDoTheyCallItOvenWhenYouOfInTheColdFoodOfOutHotEatTheFood::*;
|
||||
use crate::serial::{Port, potential_serial_ports, terminal_helpers, terminal::ST};
|
||||
use crate::serial::terminal::ST;
|
||||
|
||||
mod font;
|
||||
mod serial;
|
||||
mod internals;
|
||||
mod allocator;
|
||||
mod security;
|
||||
mod boot;
|
||||
mod memory;
|
||||
|
@ -46,28 +43,33 @@ lazy_static! {
|
|||
|
||||
const RAINBOW : [Colour; 6] = [Colour{r:255,g:0,b:0}, Colour{r:255,g:127,b:0}, Colour{r:255,g:255,b:0}, Colour{r:0,g:255,b:0}, Colour{r:0,g:255,b:255}, Colour{r:0,g:0,b:255}];
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
||||
panic!("allocation error: {:?}", layout)
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
ST.logln("---KERNEL FUCKY WUKKY UWU (panic)---");
|
||||
ST.logln(if let Some(s) = info.payload().downcast_ref::<&str>() {
|
||||
format!("panic payload: {s:?}")
|
||||
println!("---KERNEL FUCKY WUKKY UWU (panic)---");
|
||||
if let Some(s) = info.payload().downcast_ref::<&str>() {
|
||||
println!("panic payload: {s:?}")
|
||||
} else {
|
||||
format!("no panic payload")
|
||||
}.as_str());
|
||||
ST.logln(if let Some(msg) = info.message() {
|
||||
format!("panic msg: {}", msg.as_str().unwrap_or("no message"))
|
||||
println!("no panic payload")
|
||||
};
|
||||
if let Some(msg) = info.message() {
|
||||
println!("panic msg: {}", msg.as_str().unwrap_or("no message"))
|
||||
} else {
|
||||
"no message".to_string()
|
||||
}.as_str());
|
||||
ST.logln(if let Some(location) = info.location() {
|
||||
format!("location: file {} line {}", location.file(), location.line())
|
||||
println!("no message");
|
||||
}
|
||||
if let Some(location) = info.location() {
|
||||
println!("location: file {} line {}", location.file(), location.line());
|
||||
} else {
|
||||
"no location".to_string()
|
||||
}.as_str());
|
||||
println!("no location");
|
||||
};
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct KernelArgs {
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
multiboot_information_address: usize
|
||||
|
@ -87,38 +89,38 @@ pub extern fn kernel_main(args: KernelArgs) -> ! {
|
|||
if let Some(i) = console_port {
|
||||
let port = &serial_ports.ports[i];
|
||||
ST.init_from_port(*port);
|
||||
println!("using serial port {} as console", i);
|
||||
}
|
||||
|
||||
let kern_info: Box<dyn boot::KernelInfo> = {
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
{
|
||||
let mut kern_info = boot::multiboot2::Multiboot2Bootloader::default();
|
||||
kern_info.init_from_kernel_args(args);
|
||||
Box::new(kern_info)
|
||||
}
|
||||
};
|
||||
|
||||
println!();
|
||||
println!();
|
||||
println!();
|
||||
println!("welcome to wukkOS!");
|
||||
println!("(c) 2022 Real Microsoft, LLC");
|
||||
print!("initialising memory maps...");
|
||||
let mem_areas = kern_info.get_memory_areas();
|
||||
let kern_info = Mutex::new(KernelInfo::init_from_kernel_args(args));
|
||||
print!("initialising mapper...");
|
||||
let mut mapper = unsafe { memory::init(VirtAddr::new(0)) };
|
||||
println!("[OK]");
|
||||
println!("memory map:");
|
||||
for area in mem_areas {
|
||||
println!("{:x} - {:x} : {}", area.start, area.end, match area.area_type {
|
||||
boot::MemoryType::Available => "Available",
|
||||
boot::MemoryType::Reserved => "Reserved",
|
||||
boot::MemoryType::AcpiReclaimable => "ACPI Reclaimable",
|
||||
boot::MemoryType::Nvs => "NVS",
|
||||
boot::MemoryType::BadMemory => "Bad Memory",
|
||||
boot::MemoryType::Kernel => "Kernel",
|
||||
boot::MemoryType::Bootloader => "Bootloader",
|
||||
boot::MemoryType::Unknown(_) => "Unknown"
|
||||
});
|
||||
print!("initialising frame allocator...");
|
||||
let mut frame_allocator = unsafe { memory::BootInfoFrameAllocator::init(kern_info) };
|
||||
println!("[OK]");
|
||||
print!("initialising heap...");
|
||||
memory::allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap init failed");
|
||||
println!("[OK]");
|
||||
|
||||
print!("testing heap...");
|
||||
let reference_counted = Rc::new(vec![1, 2, 3]);
|
||||
let cloned = reference_counted.clone();
|
||||
let test_1 = Rc::strong_count(&reference_counted) == 2;
|
||||
drop(cloned);
|
||||
let test_2 = Rc::strong_count(&reference_counted) == 1;
|
||||
if test_1 && test_2 {
|
||||
println!("[OK]");
|
||||
} else {
|
||||
println!("[FAIL]");
|
||||
}
|
||||
drop(reference_counted);
|
||||
|
||||
loop {}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
use alloc::fmt::format;
|
||||
use core::fmt;
|
||||
use std::fmt::format;
|
||||
use crate::serial::terminal::ST;
|
||||
|
||||
#[macro_export]
|
||||
|
@ -17,6 +15,5 @@ macro_rules! println {
|
|||
#[doc(hidden)]
|
||||
pub fn _print(args: fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
let string = format(args);
|
||||
ST.log(string.as_str());
|
||||
ST.writer.lock().write_fmt(args).unwrap();
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB};
|
||||
use x86_64::structures::paging::mapper::MapToError;
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
pub const HEAP_START: u64 = 0x_4444_4444_0000;
|
||||
pub const HEAP_SIZE: u64 = 100 * 1024; // 100 KiB
|
||||
|
||||
#[cfg(feature = "f_ll_alloc")]
|
||||
use linked_list_allocator::LockedHeap;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||
|
||||
pub fn init_heap(
|
||||
mapper: &mut impl Mapper<Size4KiB>,
|
||||
frame_allocator: &mut impl FrameAllocator<Size4KiB>,
|
||||
) -> Result<(), MapToError<Size4KiB>> {
|
||||
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 {
|
||||
ALLOCATOR.lock().init(HEAP_START as usize, HEAP_SIZE as usize);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,4 +1,68 @@
|
|||
#[repr(align(4096))]
|
||||
pub struct PageTable {
|
||||
entries: [PageTableEntry; 512],
|
||||
pub mod allocator;
|
||||
|
||||
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB};
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
|
||||
pub unsafe fn init(phys_mem_offset: VirtAddr) -> OffsetPageTable<'static> {
|
||||
let level_4_table = active_level_4_table(phys_mem_offset);
|
||||
OffsetPageTable::new(level_4_table, phys_mem_offset)
|
||||
}
|
||||
|
||||
unsafe fn active_level_4_table(phys_mem_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 = phys_mem_offset + phys.as_u64();
|
||||
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
|
||||
|
||||
unsafe { &mut *page_table_ptr } // unsafe
|
||||
}
|
||||
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
use multiboot2::{MemoryMapTag, BootInformation};
|
||||
use spin::Mutex;
|
||||
use crate::boot::KernelInfo;
|
||||
|
||||
pub struct BootInfoFrameAllocator {
|
||||
kern_info: Mutex<KernelInfo>,
|
||||
next: usize,
|
||||
}
|
||||
|
||||
impl BootInfoFrameAllocator {
|
||||
#[cfg(feature = "f_multiboot2")]
|
||||
pub unsafe fn init(kern_info: Mutex<crate::boot::KernelInfo>) -> Self {
|
||||
Self {
|
||||
kern_info,
|
||||
next: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
|
||||
fn allocate_frame(&mut self) -> Option<PhysFrame> {
|
||||
#[cfg(feature = "f_multiboot2")] {
|
||||
let mut kern_lock = self.kern_info.lock();
|
||||
let mut usable_frames = kern_lock
|
||||
.memory_areas();
|
||||
let mut usable_frames = usable_frames
|
||||
.map(|area| {
|
||||
let frame_addr = area.start_address();
|
||||
let frame_end = area.end_address();
|
||||
let frame_size = frame_end - frame_addr;
|
||||
let num_frames = frame_size / 4096;
|
||||
let start_frame = PhysFrame::containing_address(PhysAddr::new(frame_addr));
|
||||
(0..num_frames).map(move |i| start_frame + i)
|
||||
})
|
||||
.flatten();
|
||||
let frame = usable_frames.nth(self.next).clone();
|
||||
self.next += 1;
|
||||
|
||||
// ensure unlock
|
||||
unsafe { self.kern_info.force_unlock() };
|
||||
|
||||
frame
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
#![feature(asm_const)]
|
||||
|
||||
|
||||
use core::arch::asm;
|
||||
use core::borrow::{Borrow, BorrowMut};
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
use alloc::sync::Arc;
|
||||
use core::fmt;
|
||||
use core::ops::Deref;
|
||||
use lazy_static::lazy_static;
|
||||
use spin::Mutex;
|
||||
use crate::serial::Port;
|
||||
|
||||
pub struct SerialTerminal {
|
||||
pub port: Arc<Mutex<Option<Port>>>,
|
||||
pub port: Mutex<Option<Port>>,
|
||||
pub writer: Mutex<SerialTerminalWriter>,
|
||||
}
|
||||
|
||||
pub struct SerialTerminalWriter {
|
||||
pub port: Mutex<Option<Port>>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref ST: SerialTerminal = {
|
||||
let mut serial_terminal = SerialTerminal {
|
||||
port: Arc::new(Mutex::new(None)),
|
||||
let serial_terminal: SerialTerminal = SerialTerminal {
|
||||
port: Mutex::new(None),
|
||||
writer: Mutex::new(SerialTerminalWriter {
|
||||
port: Mutex::new(None),
|
||||
}),
|
||||
};
|
||||
serial_terminal
|
||||
};
|
||||
|
@ -20,6 +28,7 @@ lazy_static! {
|
|||
impl SerialTerminal {
|
||||
pub fn init_from_port(&self, port: Port) {
|
||||
self.port.lock().replace(port);
|
||||
self.writer.lock().port.lock().replace(port);
|
||||
}
|
||||
|
||||
pub fn log(&self, message: &str) {
|
||||
|
@ -34,4 +43,13 @@ impl SerialTerminal {
|
|||
port.transmit_string("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Write for SerialTerminalWriter {
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
if let Some(port) = self.port.lock().deref() {
|
||||
port.transmit_string(s);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue