#![no_std]
#![no_main]
#![feature(pointer_is_aligned_to, fn_align)]
extern crate alloc;
mod block;
mod fs;
mod image;
mod logger;
mod memory;
mod pci;
use crate::{
fs::{ramdisk::Ramdisk, Filesystem},
memory::Region,
};
use core::{arch::asm, mem, ptr};
use fdt::Fdt;
use hal::memory::{Flags, FrameAllocator, FrameSize, PAddr, PageTable, Size4KiB, VAddr};
use hal_riscv::{hw::csr::Stvec, platform::PageTableImpl};
use linked_list_allocator::LockedHeap;
use memory::{MemoryManager, MemoryRegions};
use mulch::{linker::LinkerSymbol, math::align_up};
use pci::PciResolver;
use seed::{boot_info::BootInfo, SeedConfig};
use tracing::info;
core::arch::global_asm!(
"
.section .text.start
.global _start
_start:
// Zero the BSS
la t0, _bss_start
la t1, _bss_end
bgeu t0, t1, .bss_zero_loop_end
.bss_zero_loop:
sd zero, (t0)
addi t0, t0, 8
bltu t0, t1, .bss_zero_loop
.bss_zero_loop_end:
la sp, _stack_top
jal seed_main
unimp
"
);
extern "C" {
static _seed_start: LinkerSymbol;
static _bss_start: LinkerSymbol;
static _stack_bottom: LinkerSymbol;
static _stack_top: LinkerSymbol;
static _bss_end: LinkerSymbol;
static _seed_end: LinkerSymbol;
}
static MEMORY_MANAGER: MemoryManager = MemoryManager::new();
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
#[no_mangle]
pub fn seed_main(hart_id: u64, fdt_ptr: *const u8) -> ! {
assert!(fdt_ptr.is_aligned_to(8));
let fdt_address = PAddr::new(fdt_ptr.addr()).unwrap();
let fdt = unsafe { Fdt::from_ptr(fdt_ptr).expect("Failed to parse FDT") };
logger::init(&fdt);
info!("Hello, World!");
info!("HART ID: {}", hart_id);
info!("FDT address: {:?}", fdt_ptr);
Stvec::set(VAddr::new(trap_handler as extern "C" fn() as usize));
let mut memory_regions = MemoryRegions::new(&fdt, fdt_address);
let mut ramdisk = unsafe { Ramdisk::new(usize::from(hal_riscv::platform::memory::RAMDISK_ADDR)) };
if let Some(ref ramdisk) = ramdisk {
let (address, size) = ramdisk.memory_region();
memory_regions.add_region(Region::reserved(
memory::Usage::Ramdisk,
address,
align_up(size, Size4KiB::SIZE),
));
}
info!("Memory regions: {:#?}", memory_regions);
MEMORY_MANAGER.init(memory_regions);
MEMORY_MANAGER.walk_usable_memory();
const HEAP_SIZE: usize = hal::memory::kibibytes(200);
let heap_memory = MEMORY_MANAGER.allocate_n(Size4KiB::frames_needed(HEAP_SIZE));
unsafe {
ALLOCATOR.lock().init(usize::from(heap_memory.start.start) as *mut u8, HEAP_SIZE);
}
let config = if let Some(ref mut ramdisk) = ramdisk {
let config = ramdisk.load("config").expect("No config file found!");
picotoml::from_str::<SeedConfig>(core::str::from_utf8(config.data).unwrap()).unwrap()
} else {
panic!("No config file found!");
};
info!("Config: {:?}", config);
let mut kernel_page_table = PageTableImpl::new(MEMORY_MANAGER.allocate(), VAddr::new(0x0));
let kernel_file = if let Some(ref mut ramdisk) = ramdisk {
ramdisk.load("kernel_riscv").unwrap()
} else {
panic!("No kernel source is present!");
};
let kernel = image::load_kernel(&kernel_file, &mut kernel_page_table, &MEMORY_MANAGER);
let mut next_available_kernel_address = kernel.next_available_address;
PciResolver::initialize(&fdt);
let (boot_info_kernel_address, boot_info) =
create_boot_info(&mut next_available_kernel_address, &mut kernel_page_table);
boot_info.magic = seed::boot_info::BOOT_INFO_MAGIC;
boot_info.fdt_address = Some(PAddr::new(fdt_ptr as usize).unwrap());
for name in &config.user_tasks {
let file = if let Some(ref mut ramdisk) = ramdisk {
ramdisk.load(&name).unwrap()
} else {
panic!("No user tasks source is present!");
};
let info = image::load_image(&file, name, &MEMORY_MANAGER);
boot_info.loaded_images.push(info).unwrap();
}
use hal_riscv::platform::kernel_map::PHYSICAL_MAP_BASE;
const PHYSICAL_MAP_SIZE: usize = hal::memory::gibibytes(16);
kernel_page_table
.map_area(
PHYSICAL_MAP_BASE,
PAddr::new(0x0).unwrap(),
PHYSICAL_MAP_SIZE,
Flags { writable: true, ..Default::default() },
&MEMORY_MANAGER,
)
.unwrap();
alloc_and_map_kernel_heap(&mut next_available_kernel_address, &mut kernel_page_table, boot_info);
let seed_size = align_up(unsafe { _seed_end.ptr() as usize - _seed_start.ptr() as usize }, Size4KiB::SIZE);
info!(
"Mapping Seed: {:#x} to {:#x} ({} bytes)",
PAddr::new(unsafe { _seed_start.ptr() as usize }).unwrap(),
PAddr::new(unsafe { _seed_end.ptr() as usize }).unwrap(),
seed_size,
);
kernel_page_table
.map_area(
VAddr::new(unsafe { _seed_start.ptr() as usize }),
PAddr::new(unsafe { _seed_start.ptr() as usize }).unwrap(),
seed_size,
Flags { writable: false, executable: true, ..Default::default() },
&MEMORY_MANAGER,
)
.unwrap();
MEMORY_MANAGER.populate_memory_map(&mut boot_info.memory_map);
info!("Jumping into the kernel!");
unsafe {
asm!(
"
mv sp, {new_sp}
mv gp, {new_gp}
csrw satp, {new_satp}
sfence.vma
jr {entry_point}
",
new_satp = in(reg) kernel_page_table.satp().raw(),
new_sp = in(reg) usize::from(kernel.stack_top),
new_gp = in(reg) usize::from(kernel.global_pointer),
entry_point = in(reg) usize::from(kernel.entry_point),
in("a0") usize::from(boot_info_kernel_address),
options(nostack, noreturn)
)
}
}
fn create_boot_info<'a>(
next_available_kernel_address: &mut VAddr,
kernel_page_table: &mut PageTableImpl,
) -> (VAddr, &'a mut BootInfo) {
let boot_info_physical_start =
MEMORY_MANAGER.allocate_n(Size4KiB::frames_needed(mem::size_of::<BootInfo>())).start.start;
let identity_boot_info_ptr = usize::from(boot_info_physical_start) as *mut BootInfo;
unsafe {
ptr::write(identity_boot_info_ptr, BootInfo::default());
}
let boot_info_kernel_address = *next_available_kernel_address;
*next_available_kernel_address += align_up(mem::size_of::<BootInfo>(), Size4KiB::SIZE);
kernel_page_table
.map_area(
boot_info_kernel_address,
boot_info_physical_start,
align_up(mem::size_of::<BootInfo>(), Size4KiB::SIZE),
Flags::default(),
&MEMORY_MANAGER,
)
.unwrap();
(boot_info_kernel_address, unsafe { &mut *identity_boot_info_ptr })
}
fn alloc_and_map_kernel_heap(
next_available_kernel_address: &mut VAddr,
kernel_page_table: &mut PageTableImpl,
boot_info: &mut BootInfo,
) {
const KERNEL_HEAP_SIZE: hal::memory::Bytes = hal::memory::kibibytes(800);
boot_info.heap_address = *next_available_kernel_address;
boot_info.heap_size = KERNEL_HEAP_SIZE;
*next_available_kernel_address += KERNEL_HEAP_SIZE;
let kernel_heap_physical_start =
MEMORY_MANAGER.allocate_n(Size4KiB::frames_needed(KERNEL_HEAP_SIZE)).start.start;
kernel_page_table
.map_area(
boot_info.heap_address,
kernel_heap_physical_start,
KERNEL_HEAP_SIZE,
Flags { writable: true, ..Default::default() },
&MEMORY_MANAGER,
)
.unwrap();
}
#[repr(align(4))]
pub extern "C" fn trap_handler() {
use hal_riscv::hw::csr::{Scause, Sepc};
let scause = Scause::read();
let sepc = Sepc::read();
panic!("Trap! Scause = {:?}, sepc = {:?}", scause, sepc);
}