| #![no_std] |
| |
| // Support for loading sel4 & co directly from the tarball. This is only |
| // used when running in simulation where there is no SPI Flash support |
| // (the elfloader capsule calls out to load_sel4 based on whether it |
| // detects fpga hardware or not). |
| |
| use matcha_hal::dprintf; |
| use matcha_hal::mailbox_hal::MailboxHAL; |
| |
| pub mod elf_loader; |
| pub mod tar_loader; |
| |
| pub const SMC_CONTROL_BLOCK: *mut u32 = 0x54020000 as *mut u32; |
| |
| pub const SMC_PAGE_SIZE: usize = 4096; // SMC page size |
| pub const SMC_BEGIN: usize = 0x50000000; // Start of SMC memory in SEC map |
| pub const SMC_END: usize = SMC_BEGIN + (4*1024*1024); // NB: 4MiB of SMC memory |
| |
| // Returns true if the specified page address fits in SMC memory |
| pub fn smc_is_page(addr: usize) -> bool { |
| SMC_BEGIN <= addr && (addr + SMC_PAGE_SIZE) < SMC_END |
| } |
| |
| pub fn round_up_to_page(addr: u32) -> u32 { |
| return (addr + 4095) & !4095; |
| } |
| |
| // TODO(aappleby): Break this down into smaller pieces and move into app/main |
| pub fn load_sel4(mailbox: &'static dyn MailboxHAL) { |
| unsafe { |
| // Look in our tar file for the ELFs we need to boot Shodan. |
| let sel4_elf = elf_loader::find_elf("kernel"); |
| let capdl_elf = elf_loader::find_elf("capdl-loader"); |
| |
| if sel4_elf.is_null() { |
| dprintf!("Boot failure, seL4 kernel ELF missing in FLASH.\n"); |
| return; |
| } |
| |
| if capdl_elf.is_null() { |
| dprintf!("Boot failure capdl-loader ELF missing in FLASH.\n"); |
| return; |
| } |
| |
| // If we found all of them, boot in Shodan mode. |
| dprintf!("Loading seL4 kernel elf\n"); |
| elf_loader::load_elf_segments(sel4_elf.as_ref().unwrap(), 0); |
| |
| let sel4_segments = elf_loader::elf_get_segments(sel4_elf); |
| let capdl_segments = elf_loader::elf_get_segments(capdl_elf); |
| |
| let ui_p_reg_start = round_up_to_page(elf_loader::elf_phys_max(sel4_segments)); |
| |
| dprintf!("Loading capdl-loader to the page after seL4\n"); |
| elf_loader::load_elf_segments( |
| capdl_elf.as_ref().unwrap(), |
| ui_p_reg_start - elf_loader::elf_phys_min(capdl_segments), |
| ); |
| |
| // NB: Renode loads the cantrip-builtins cpioarchive to the SMC memory |
| // carve-out so there's nothing to do here. |
| |
| dprintf!("Starting management core\n"); |
| |
| let entry_point: u32 = (*sel4_elf).e_entry |
| - (elf_loader::elf_virt_min(sel4_segments) - elf_loader::elf_phys_min(sel4_segments)); |
| |
| smc_send_bootmsg(mailbox, [ |
| ui_p_reg_start, |
| ui_p_reg_start |
| + round_up_to_page( |
| elf_loader::elf_phys_max(capdl_segments) |
| - elf_loader::elf_phys_min(capdl_segments), |
| ), |
| ui_p_reg_start - elf_loader::elf_phys_min(capdl_segments), |
| (*capdl_elf).e_entry, |
| ]); |
| |
| SMC_CONTROL_BLOCK.write_volatile(entry_point); |
| } |
| } |
| |
| pub fn smc_send_bootmsg(mailbox: &'static dyn MailboxHAL, message: [u32; 4]) { |
| unsafe { |
| let _ = mailbox.send_message_sync(16, core::mem::transmute(message.as_ref())); |
| } |
| } |
| |
| pub fn smc_ram_memcpy(src: &mut [u8], dst: u32, count: usize) { |
| unsafe { |
| core::ptr::copy_nonoverlapping::<u8>( |
| core::mem::transmute(src.as_ptr()), |
| core::mem::transmute(dst), |
| count, |
| ); |
| } |
| } |
| pub fn smc_ram_zero(dst: u32, count: usize) { |
| unsafe { |
| core::ptr::write_bytes::<u8>(core::mem::transmute(dst), 0, count); |
| } |
| } |