#![no_std]
#![feature(
decl_macro,
allocator_api,
alloc_error_handler,
core_intrinsics,
trait_alias,
type_ascription,
naked_functions,
get_mut_unchecked
)]
#[macro_use]
extern crate alloc;
mod heap_allocator;
pub mod memory;
pub mod object;
pub mod pci;
pub mod per_cpu;
pub mod scheduler;
pub mod syscall;
use crate::memory::Stack;
use alloc::{boxed::Box, sync::Arc};
use hal::memory::{FrameSize, PageTable, VAddr};
use heap_allocator::LockedHoleAllocator;
use memory::{KernelStackAllocator, PhysicalMemoryManager};
use object::{address_space::AddressSpace, memory_object::MemoryObject, task::Task, KernelObject};
use pci::PciInfo;
use pci_types::ConfigRegionAccess as PciConfigRegionAccess;
use per_cpu::PerCpu;
use poplar_util::InitGuard;
use scheduler::Scheduler;
use seed::boot_info::LoadedImage;
use spin::{Mutex, RwLock};
#[cfg(not(test))]
#[global_allocator]
pub static ALLOCATOR: LockedHoleAllocator = LockedHoleAllocator::new_uninitialized();
pub static PHYSICAL_MEMORY_MANAGER: InitGuard<PhysicalMemoryManager> = InitGuard::uninit();
pub static FRAMEBUFFER: InitGuard<(poplar::syscall::FramebufferInfo, Arc<MemoryObject>)> = InitGuard::uninit();
pub static PCI_INFO: RwLock<Option<PciInfo>> = RwLock::new(None);
pub static PCI_ACCESS: InitGuard<Option<Mutex<Box<dyn PciConfigRegionAccess + Send>>>> = InitGuard::uninit();
pub trait Platform: Sized + 'static {
type PageTableSize: FrameSize;
type PageTable: PageTable<Self::PageTableSize> + Send;
type PerCpu: PerCpu<Self>;
fn kernel_page_table(&mut self) -> &mut Self::PageTable;
unsafe fn per_cpu<'a>() -> &'a mut Self::PerCpu;
unsafe fn initialize_task_stacks(
kernel_stack: &Stack,
user_stack: &Stack,
task_entry_point: VAddr,
) -> (VAddr, VAddr);
unsafe fn context_switch(current_kernel_stack: *mut VAddr, new_kernel_stack: VAddr);
unsafe fn drop_into_userspace() -> !;
}
pub fn load_task<P>(
scheduler: &mut Scheduler<P>,
image: &LoadedImage,
kernel_page_table: &mut P::PageTable,
allocator: &PhysicalMemoryManager,
kernel_stack_allocator: &mut KernelStackAllocator<P>,
) where
P: Platform,
{
use object::SENTINEL_KERNEL_ID;
let address_space = AddressSpace::new(SENTINEL_KERNEL_ID, kernel_page_table, allocator);
let task = Task::from_boot_info(
SENTINEL_KERNEL_ID,
address_space.clone(),
image,
allocator,
kernel_page_table,
kernel_stack_allocator,
)
.expect("Failed to load initial task");
for segment in &image.segments {
let memory_object = MemoryObject::from_boot_info(task.id(), segment);
address_space.map_memory_object(memory_object, None, allocator).unwrap();
}
scheduler.add_task(task);
}
pub fn create_framebuffer(video_info: &seed::boot_info::VideoModeInfo) {
use hal::memory::{Flags, Size4KiB};
use poplar::syscall::{FramebufferInfo, PixelFormat};
use seed::boot_info::PixelFormat as BootPixelFormat;
const BPP: usize = 4;
let size_in_bytes = video_info.stride * video_info.height * BPP;
let memory_object = MemoryObject::new(
object::SENTINEL_KERNEL_ID,
None,
video_info.framebuffer_address,
poplar_util::math::align_up(size_in_bytes, Size4KiB::SIZE),
Flags { writable: true, user_accessible: true, cached: false, ..Default::default() },
);
let info = FramebufferInfo {
width: video_info.width as u16,
height: video_info.height as u16,
stride: video_info.stride as u16,
pixel_format: match video_info.pixel_format {
BootPixelFormat::Rgb32 => PixelFormat::Rgb32,
BootPixelFormat::Bgr32 => PixelFormat::Bgr32,
},
};
FRAMEBUFFER.initialize((info, memory_object));
}