elfloader: major overhaul to support non-seL4 images Overhaul the ELF loader support to handle loading ELF images unlike seL4 (e.g. many ELF load segments, no capdl-loader) and cleanup some code. With these changes CHERIoT firmware images load. - add support for loading multiple ELF load segments - handle a missing capdl-loader; e.g. when starting the SMC do not post the boot message to the mailbox - improve loading unaligned ELF segments; still does not handle all cases but it's unclear if they matter (will panic) - handle running out of space for ELF phdrs more gracefully - change SEL4State to have only one instance of "offset" & "headers" to save memory, especially when we grow the "headers" array to handle more complex ELF images - combine the FindFile, LoadElfHeaders, and LoadElf tasks into a single LoadElf task; this better safeguards SEL4State that was shared between the tasks and clobbered if the old tasks were mis-ordered - reduce the task array size after combining FindFile & co - add a Noop task for initializing/padding the task array - cleanup SEL4State handling; e.g. move calculations derived from the ELF phdrs to immediately after the full set of headers are read; this safeguards against clobbering shared state between task phases - change ELF segment log msgs to include the segment # and to only log non-zero size segments (file-data, bss) - use the tar magic marker to identify EOF (when present) - remove a bunch of dead code - replace panic(<line-number>) by unreachable! calls since the line numbers were (wrong and) unmtaintable - increase the tock app memory layout for the changes (we were right on the edge) Fix: 331955054 Change-Id: Iecb00e5545c9cf5e603d49e3f2c7669ed36581e3
diff --git a/app/layout_matcha.ld b/app/layout_matcha.ld index 57e2378..906aaaa 100644 --- a/app/layout_matcha.ld +++ b/app/layout_matcha.ld
@@ -10,7 +10,7 @@ * the kernel binary, check for the actual address of APP_MEMORY! */ FLASH (rx) : ORIGIN = 0x20080040, LENGTH = 0x80000 - 0x40 - SRAM (rwx) : ORIGIN = 0x10006800, LENGTH = 0x19800 + SRAM (rwx) : ORIGIN = 0x10007800, LENGTH = 0x18800 } MPU_MIN_ALIGN = 1K;
diff --git a/capsules/src/elfloader_capsule.rs b/capsules/src/elfloader_capsule.rs index 22ec75a..af19523 100644 --- a/capsules/src/elfloader_capsule.rs +++ b/capsules/src/elfloader_capsule.rs
@@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Trivial Shodan elf loader capsule - -// TODO(sleffler): cleanup panic msgs (currently fuzzy line numbers) +//! Shodan ELF loader capsule use core::cell::Cell; use core::marker::PhantomData; @@ -30,6 +28,7 @@ use matcha_utils::tar_loader::TarHeader; const PT_LOAD: u32 = 1; // Loadable segment +const INVALID_LOAD_OFFSET: u32 = 0; pub struct ElfLoaderCapsule<'a, F: hil::flash::Flash + 'static> { mailbox_hal: Option<&'static dyn MailboxHAL>, @@ -40,48 +39,32 @@ page_len: u32, state: Cell<ElfLoaderState>, phantom: PhantomData<&'a ()>, - tasks: Cell<[(LoadTasks, bool); 7]>, + tasks: Cell<[(LoadTasks, bool); 3]>, current_task: OptionalCell<LoadTasks>, sel4_state: Cell<SEL4State>, } #[derive(Clone, Copy, PartialEq)] enum LoadTasks { - FindFile(&'static str /* name */), - LoadElfHeaders(&'static str /* name */), + Noop, LoadElf(&'static str /* name */), StartSmc, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Default)] struct SEL4State { - kernel_offset: u32, - capdl_loader_offset: u32, - kernel_entry_point: u32, - capdl_loader_entry_point: u32, - kernel_headers: [Option<Elf32Phdr>; 4], - capdl_loader_headers: [Option<Elf32Phdr>; 4], - kernel_bss_start: u32, - kernel_bss_size: u32, - capdl_bss_start: u32, - capdl_bss_size: u32, -} + // State for current file being loaded. + load_offset: u32, // File offset + phdrs: [Option<Elf32Phdr>; 20], // ELF phdrs -impl Default for SEL4State { - fn default() -> SEL4State { - SEL4State { - kernel_offset: 0, - capdl_loader_offset: 0, - kernel_entry_point: 0, - capdl_loader_entry_point: 0, - kernel_headers: [None, None, None, None], - capdl_loader_headers: [None, None, None, None], - kernel_bss_start: 0, - kernel_bss_size: 0, - capdl_bss_start: 0, - capdl_bss_size: 0, - } - } + // Saved state for the "kernel" image. + kernel_entry_point: u32, + kernel_phys_max: u32, + + // Saved state for the "capdl-loader" image. + capdl_loader_entry_point: u32, + capdl_phys_min: u32, + capdl_phys_max: u32, } #[derive(Clone, Copy, PartialEq)] @@ -96,7 +79,6 @@ u16, /* index */ ), LoadSegmentsNew( - &'static str, /* name */ Elf32Phdr, /* phdr */ usize, /* index */ u32, /* cursor */ @@ -106,6 +88,33 @@ ), } +fn print_segment(index: usize, cursor: u32, offset: u32, phdr: &Elf32Phdr) { + if phdr.p_filesz > 0 { + dprintf!( + "seg {:2}:{:X} -> {:X}:{:X} ({} bytes)\r\n", + index, + cursor, + phdr.p_paddr + offset, + phdr.p_paddr + offset + phdr.p_filesz, + { phdr.p_filesz }, + ); + } + let bss_size = phdr.p_memsz - phdr.p_filesz; + if bss_size > 0 { + let bss_start = phdr.p_paddr + offset + phdr.p_filesz; + let bss_end = bss_start + bss_size; + + dprintf!( + "bss {:2}:{:X} -> {:X}:{:X} ({} bytes)\r\n", + index, + cursor, + bss_start, + bss_end, + bss_size + ); + } +} + impl<'a, F: hil::flash::Flash> ElfLoaderCapsule<'a, F> { pub fn new() -> Self { Self { @@ -117,15 +126,7 @@ page_len: 0, state: Cell::new(ElfLoaderState::Idle), phantom: PhantomData, - tasks: Cell::new([ - (LoadTasks::FindFile("kernel"), false), - (LoadTasks::FindFile("capdl-loader"), false), - (LoadTasks::LoadElfHeaders("kernel"), false), - (LoadTasks::LoadElfHeaders("capdl-loader"), false), - (LoadTasks::LoadElf("kernel"), false), - (LoadTasks::LoadElf("capdl-loader"), false), - (LoadTasks::StartSmc, false), - ]), + tasks: Cell::new([(LoadTasks::Noop, true); 3]), current_task: OptionalCell::empty(), sel4_state: Cell::new(SEL4State::default()), } @@ -173,210 +174,166 @@ loop {} }, |task| match task { - LoadTasks::FindFile(file) => { + LoadTasks::LoadElf(file) => { self.find_file(file); } - LoadTasks::LoadElfHeaders(file) => { - self.load_elf_headers(file); - } - LoadTasks::LoadElf("kernel") => { - dprintf!("Loading seL4 kernel\r\n"); - self.load_elf("kernel", 0); - } - LoadTasks::LoadElf("capdl-loader") => { - dprintf!("Loading capdl-loader to the page after seL4\r\n"); - let sel4_pend = - matcha_utils::round_up_to_page(matcha_utils::elf_loader::elf_phys_max_opt( - &self.sel4_state.get().kernel_headers, - )); - let offset = sel4_pend - - matcha_utils::elf_loader::elf_phys_min_opt( - &self.sel4_state.get().capdl_loader_headers, - ); - self.load_elf("capdl-loader", offset); - } LoadTasks::StartSmc => { - // NB: ui_p_reg_start & co. come from the code in seL4 - // the processes these values. - let ui_p_reg_start = - matcha_utils::round_up_to_page(matcha_utils::elf_loader::elf_phys_max_opt( - &self.sel4_state.get().kernel_headers, - )); - let ui_p_reg_end = ui_p_reg_start - + matcha_utils::round_up_to_page( - matcha_utils::elf_loader::elf_phys_max_opt( - &self.sel4_state.get().capdl_loader_headers, - ) - matcha_utils::elf_loader::elf_phys_min_opt( - &self.sel4_state.get().capdl_loader_headers, - ), + let sel4_state = self.sel4_state.get(); + if sel4_state.capdl_phys_max > 0 { + // If capdl-loader was loaded we are running seL4 and + // it will expect a boot message to be waiting in the + // mailbox FIFO telling it how to setup the kernel and + // the rootserver. + + // NB: ui_p_reg_start & co. come from the code in seL4 + // that processes these values. + let ui_p_reg_start = + matcha_utils::round_up_to_page(sel4_state.kernel_phys_max); + let ui_p_reg_end = ui_p_reg_start + + matcha_utils::round_up_to_page( + sel4_state.capdl_phys_max - sel4_state.capdl_phys_min + ); + let pv_offset = ui_p_reg_start - sel4_state.capdl_phys_min; + let v_entry = sel4_state.capdl_loader_entry_point; + /* + dprintf!( + "StartSmc: ui_p_reg {:X}:{:X} pv_offset {:X} v_entry {:X}\r\n", + ui_p_reg_start, + ui_p_reg_end, + pv_offset, + v_entry ); - let pv_offset = ui_p_reg_start - - matcha_utils::elf_loader::elf_phys_min_opt( - &self.sel4_state.get().capdl_loader_headers, - ); - let v_entry = self.sel4_state.get().capdl_loader_entry_point; -/* - dprintf!( - "{:X} {:X} {:X} {:X}\r\n", - ui_p_reg_start, - ui_p_reg_end, - pv_offset, - v_entry - ); - dprintf!( - "{:X} {:X} {:X}\r\n", - ui_p_reg_start, - matcha_utils::elf_loader::elf_phys_max_opt( - &self.sel4_state.get().capdl_loader_headers - ), - matcha_utils::elf_loader::elf_phys_min_opt( - &self.sel4_state.get().capdl_loader_headers - ), - ); -*/ - matcha_utils::smc_ram_zero( - self.sel4_state.get().kernel_bss_start, - self.sel4_state.get().kernel_bss_size as usize - ); - matcha_utils::smc_ram_zero( - self.sel4_state.get().capdl_bss_start, - self.sel4_state.get().capdl_bss_size as usize - ); - match self.smc_ctrl_hal { - Some(smc_ctrl) => { - self.mailbox_hal.map(|mb| { - matcha_utils::smc_send_bootmsg(mb, [ - ui_p_reg_start, - ui_p_reg_end, - pv_offset, - v_entry, - ]) - }); - smc_ctrl.smc_ctrl_start(); - } - None => { - panic!("221"); - } + */ + // XXX suppress if not seL4? + self.mailbox_hal.map(|mb| { + matcha_utils::smc_send_bootmsg(mb, [ + ui_p_reg_start, + ui_p_reg_end, + pv_offset, + v_entry, + ]) + }); } + + assert!(self.smc_ctrl_hal.is_some()); + self.smc_ctrl_hal.unwrap().smc_ctrl_start(); } - _ => panic!("225"), + _ => unreachable!(), }, ); } + // Load seL4 state machine. pub fn load_sel4(&self) { - // Reset task list to start over. - let mut tasks = self.tasks.get(); - for i in 0..tasks.len() { - tasks[i].1 = false; - } - self.tasks.replace(tasks); + self.tasks.replace([ + (LoadTasks::LoadElf("kernel"), false), + (LoadTasks::LoadElf("capdl-loader"), false), + (LoadTasks::StartSmc, false), + ]); self.run_next_task(); } - fn load_elf_headers(&self, name: &'static str) { - match name { - "kernel" => self.state.set(ElfLoaderState::LoadElfHeader( - self.sel4_state.get().kernel_offset, - )), - "capdl-loader" => self.state.set(ElfLoaderState::LoadElfHeader( - self.sel4_state.get().capdl_loader_offset, - )), - _ => panic!("207"), - } - match self.state.get() { - ElfLoaderState::LoadElfHeader(cursor) => self.read_page(cursor), - _ => panic!("214"), - } + // Reads the data at flash address |page|. |read_complete| (below) + // dispatchs the callback depending on the current ElfLoaderState. + fn read_page(&self, page: u32) { + self.flash.map(|flash| { + self.read_page.take().map(|read_page| { + self.flash_busy.set(true); + if let Err((_, buf)) = flash.read_page((page / self.page_len) as usize, read_page) { + self.read_page.replace(buf); + } + }); + }); } - fn load_elf(&self, name: &'static str, offset: u32) { - let phdr = match name { - "kernel" => self.sel4_state.get().kernel_headers[0].unwrap(), - "capdl-loader" => self.sel4_state.get().capdl_loader_headers[0].unwrap(), - _ => panic!("290"), - }; - let mod_offset = phdr.p_offset % self.page_len; - let div_offset = phdr.p_offset / self.page_len; - let cursor = match name { - "kernel" => self.sel4_state.get().kernel_offset, - "capdl-loader" => self.sel4_state.get().capdl_loader_offset, - _ => panic!("295"), - } + (div_offset * self.page_len); - let new_state = - ElfLoaderState::LoadSegmentsNew(name, phdr, 0, cursor, offset, mod_offset, 0); - self.state.set(new_state); - if phdr.p_type == PT_LOAD && phdr.p_filesz != 0 { - dprintf!( - "seg 0:{:X} -> {:X}:{:X} ({} bytes)\r\n", - cursor, - phdr.p_paddr + offset, - phdr.p_paddr + offset + phdr.p_filesz, - { phdr.p_filesz }, - ); - let bss_size = phdr.p_memsz - phdr.p_filesz; - let bss_start = phdr.p_paddr + offset + phdr.p_filesz; - let bss_end = bss_start + bss_size; - - dprintf!( - "bss 0:{:X} -> {:X}:{:X} ({} bytes)\r\n", - cursor, - bss_start, - bss_end, - bss_size - ); - match name { - "kernel" => { - let mut sel4_state = self.sel4_state.get(); - sel4_state.kernel_bss_start = bss_start; - sel4_state.kernel_bss_size = bss_size; - self.sel4_state.replace(sel4_state); - }, - "capdl-loader" => { - let mut sel4_state = self.sel4_state.get(); - sel4_state.capdl_bss_start = bss_start; - sel4_state.capdl_bss_size = bss_size; - self.sel4_state.replace(sel4_state); - }, - _ => panic!("349"), - }; - // matcha_utils::smc_ram_zero(bss_start, bss_size as usize); - self.read_page(cursor); - } else { - panic!("295"); - } - } - + // Initiates a file lookup. fn find_file(&self, name: &'static str) { self.state.set(ElfLoaderState::FindingFile(name, 0)); self.read_page(0); } + // Callback from |read_complete| for a file lookup. If the file was + // found start loading the ELF headers; otherwise advance the file + // lookup mechanism (to stride through the tar file). If the search + // was unsuccessful log to the console and advance to the next task. + fn find_file_callback(&self) { + self.read_page.map(|page| { + let mut_page = page.as_mut(); + let tar_header = TarHeader::from_bytes(mut_page); + match self.state.get() { + ElfLoaderState::FindingFile(name, cursor) => { + if tar_header.name().contains(name) { + let mut sel4_state = self.sel4_state.get(); + sel4_state.load_offset = cursor + self.page_len; + self.sel4_state.replace(sel4_state); + self.state.set(ElfLoaderState::Idle); + } else if !tar_header.has_magic() { + // File not found. + dprintf!("{} not found!\r\n", name); + let mut sel4_state = self.sel4_state.get(); + sel4_state.load_offset = INVALID_LOAD_OFFSET; + self.sel4_state.replace(sel4_state); + self.state.set(ElfLoaderState::Idle); + } else { + let new_cursor = + self.page_len + cursor + ((tar_header.size() + 511) & !511); + self.state + .set(ElfLoaderState::FindingFile(name, new_cursor)); + } + } + _ => unreachable!(), + }; + }); + + match self.state.get() { + ElfLoaderState::FindingFile(_, cursor) => self.read_page(cursor), + ElfLoaderState::Idle => { + if self.sel4_state.get().load_offset != INVALID_LOAD_OFFSET { + self.load_elf_headers(); + } else { + self.run_next_task(); + } + } + _ => panic!("507"), + } + } + + // Initiates reading ELF header data for the current file. + // NB: this clobbers program headers so any state derived from a file's + // headers must be recorded below (see |load_elf_header_callback|). + fn load_elf_headers(&self) { + let mut sel4_state = self.sel4_state.get(); + sel4_state.phdrs = SEL4State::default().phdrs; // Reset shared phdrs + let cursor = sel4_state.load_offset; + assert!(cursor != INVALID_LOAD_OFFSET); + self.sel4_state.replace(sel4_state); + self.state.set(ElfLoaderState::LoadElfHeader(cursor)); + self.read_page(cursor); + } + + // Callback from |read_complete| after reading the ELF header. Saves + // the ELF entry point and initiate reading the ELF program headers. fn load_elf_header_callback(&self) { self.read_page.map(|page| { let mut_page = page.as_mut(); let elf_header = Elf32Header::from_bytes(mut_page); - if !elf_header.check_magic() { - dprintf!("bad elf magic\r\n"); - panic!("233"); - } + assert!(elf_header.check_magic()); self.current_task.map(|task| { + let mut sel4_state = self.sel4_state.get(); match task { - LoadTasks::LoadElfHeaders("kernel") => { - let mut sel4_state = self.sel4_state.get(); + LoadTasks::LoadElf("kernel") => { sel4_state.kernel_entry_point = elf_header.e_entry; - self.sel4_state.replace(sel4_state); } - LoadTasks::LoadElfHeaders("capdl-loader") => { - let mut sel4_state = self.sel4_state.get(); + LoadTasks::LoadElf("capdl-loader") => { sel4_state.capdl_loader_entry_point = elf_header.e_entry; - self.sel4_state.replace(sel4_state); } - _ => panic!("290"), + _ => unreachable!(), }; + self.sel4_state.replace(sel4_state); }); match self.state.get() { ElfLoaderState::LoadElfHeader(cursor) => { + // Kick off reading the ELF program headers. self.state.set(ElfLoaderState::LoadProgramHeaderTable( cursor, elf_header.phoff(), @@ -384,16 +341,21 @@ 0, )); } - _ => panic!("245"), + _ => unreachable!(), } }); match self.state.get() { ElfLoaderState::LoadProgramHeaderTable(cursor, ..) => self.read_page(cursor), - _ => panic!("254"), + _ => unreachable!(), } } + // Callback from |read_complete| after reading an ELF program header. + // Saves the header and initiates a read of the next header or, if all + // headers have been read, initiates loading the ELF segments. If all + // headers have been read this also records per-file data based on the + // full set of headers (that may be clobbered if another file is read). fn load_program_header_table_callback(&self) { self.read_page.map(|page| { let mut_page = page.as_mut(); @@ -404,51 +366,25 @@ + (index as usize * core::mem::size_of::<Elf32Phdr>())) as usize)..], ); - if phdr.p_type == PT_LOAD - /* && (phdr.p_filesz != 0)*/ - { - self.current_task.map(|task| { - match task { - LoadTasks::LoadElfHeaders("kernel") => { - let mut sel4_state = self.sel4_state.get(); - let mut next_slot: Option<usize> = None; - for i in 0..sel4_state.kernel_headers.len() { - if sel4_state.kernel_headers[i] == None { - next_slot = Some(i); - break; - } - } - match next_slot { - Some(slot) => { - sel4_state.kernel_headers[slot] = Some(phdr); - } - None => panic!("380"), - } - self.sel4_state.replace(sel4_state); - } - LoadTasks::LoadElfHeaders("capdl-loader") => { - let mut sel4_state = self.sel4_state.get(); - let mut next_slot: Option<usize> = None; - for i in 0..sel4_state.capdl_loader_headers.len() { - if sel4_state.capdl_loader_headers[i] == None { - next_slot = Some(i); - break; - } - } - match next_slot { - Some(slot) => { - sel4_state.capdl_loader_headers[slot] = Some(phdr); - } - None => panic!("380"), - } - self.sel4_state.replace(sel4_state); - } - _ => panic!("317"), - }; - }); +//dprintf!("[{}] {:#08x?}\r\n", index, &phdr); + if phdr.p_type == PT_LOAD { + let mut sel4_state = self.sel4_state.get(); + let mut next_slot: Option<usize> = None; + for i in 0..sel4_state.phdrs.len() { + if sel4_state.phdrs[i] == None { + next_slot = Some(i); + break; + } + } + if let Some(slot) = next_slot { + sel4_state.phdrs[slot] = Some(phdr); + } else { + panic!("Too many ELF program headers"); + } + self.sel4_state.replace(sel4_state); } } - _ => panic!("335"), + _ => unreachable!(), }; }); match self.state.get() { @@ -462,18 +398,64 @@ )); self.read_page(cursor); } else { - self.state.set(ElfLoaderState::Idle); - self.run_next_task(); + // Record state derived from phdrs before they get clobbered. + let mut segment_load_offset = 0; + self.current_task.map(|task| { + let mut sel4_state = self.sel4_state.get(); + match task { + LoadTasks::LoadElf("kernel") => { + // Stash end of kernel for loading capdl-loader + sel4_state.kernel_phys_max = matcha_utils::elf_loader::elf_phys_max_opt(&sel4_state.phdrs); + + dprintf!("Loading seL4 kernel\r\n"); + segment_load_offset = 0; + } + LoadTasks::LoadElf("capdl-loader") => { + sel4_state.capdl_phys_max = matcha_utils::elf_loader::elf_phys_max_opt(&sel4_state.phdrs); + sel4_state.capdl_phys_min = matcha_utils::elf_loader::elf_phys_min_opt(&sel4_state.phdrs); + + dprintf!("Loading capdl-loader to the page after seL4\r\n"); + segment_load_offset = matcha_utils::round_up_to_page( + sel4_state.kernel_phys_max + ) - sel4_state.capdl_phys_min; + } + _ => unreachable!(), + }; + self.sel4_state.replace(sel4_state); + }); + self.load_elf_segments(segment_load_offset); } } - _ => panic!("375"), + _ => unreachable!(), } } + // Initiates loading the ELF segments for the current file. + fn load_elf_segments(&self, offset: u32) { + let phdr = self.sel4_state.get().phdrs[0].unwrap(); + // XXX assumes p_filesz > 0; consolidate with code below + let mod_offset = phdr.p_offset % self.page_len; + let div_offset = phdr.p_offset / self.page_len; + let load_offset = self.sel4_state.get().load_offset; + assert!(load_offset != INVALID_LOAD_OFFSET); + let cursor = load_offset + (div_offset * self.page_len); + let new_state = + ElfLoaderState::LoadSegmentsNew(phdr, 0, cursor, offset, mod_offset, 0); + self.state.set(new_state); + // XXX wrong, but preserve for now + assert!(phdr.p_type == PT_LOAD && phdr.p_filesz > 0); + print_segment(0, cursor, offset, &phdr); + self.read_page(cursor); + } + + // Callback from |read_complete| after reading a page for the current + // loadable program segment. Data may be copied to the SMC memory or + // SMC memory may be zero'd (e.g. for bss). If the segment is completed + // advamce to the next load segment. If all segments have been processed + // advance to the next task. fn load_segment_callback(&self) { match self.state.get() { ElfLoaderState::LoadSegmentsNew( - name, phdr, index, cursor, @@ -481,133 +463,69 @@ mod_offset, loaded, ) => { + // Copy read data to SMC ram. let bytes_in_this_page = self.page_len - mod_offset; - // Copy data into SMC ram. self.read_page.map(|page| { let mut_page = page.as_mut(); + // NB: read_page always reads a full page from flash, maybe copy less + let bytes_to_copy = + if loaded + bytes_in_this_page >= phdr.p_filesz { + phdr.p_filesz - loaded + } else { bytes_in_this_page }; smc_ram_memcpy( &mut mut_page[(mod_offset as usize)..], phdr.p_paddr + offset + loaded, - bytes_in_this_page as usize, + bytes_to_copy as usize, ); }); let progress = loaded + bytes_in_this_page; if progress < phdr.p_filesz { - // Another page - let new_cursor = cursor + self.page_len; + // Same program header, more file data; issue a new read. + let next_cursor = cursor + self.page_len; let new_state = ElfLoaderState::LoadSegmentsNew( - name, phdr, index, new_cursor, offset, 0, progress, + phdr, index, next_cursor, offset, /*mod_offset=*/ 0, progress, ); self.state.set(new_state); - self.read_page(new_cursor); + self.read_page(next_cursor); } else { - let segments = match name { - "kernel" => self.sel4_state.get().kernel_headers, - "capdl-loader" => self.sel4_state.get().capdl_loader_headers, - _ => panic!("461"), - }; + // No more file data to read for this program header. + if phdr.p_filesz < phdr.p_memsz { + // Zero-pad remainder of segment. + let zero_bytes = phdr.p_memsz - phdr.p_filesz; + matcha_utils::smc_ram_zero( + phdr.p_paddr + offset + phdr.p_filesz, + zero_bytes as usize + ); + } + // Current segment is complete, advance to the next segment. let next_index = index + 1; - let mut last_segment = false; - if next_index == segments.len() { - last_segment = true; - } - if !last_segment { - last_segment = match segments[next_index] { - Some(_) => false, - None => true, - }; - } - if last_segment { + if next_index >= self.sel4_state.get().phdrs.len() || + self.sel4_state.get().phdrs[next_index] == None { + // Last load segment, advance to the next task. self.state.set(ElfLoaderState::Idle); self.run_next_task(); } else { - let next_segment = segments[next_index].unwrap(); - if next_segment.p_memsz != 0 && next_segment.p_filesz == 0 { - // some bss segment, let's clear the memory. - matcha_utils::smc_ram_zero(next_segment.p_paddr + offset, next_segment.p_memsz as usize); - } - self.state.set(ElfLoaderState::Idle); - self.run_next_task(); - // TODO(atv): Finish this here. - // panic!("476"); - // let next_segment = segments[next_index]; - // let new_cursor = ?; - // let mod_offset = ?; - // let new_state = ElfLoaderState::LoadSegmentsNew(name, next_segment, next_index, new_cursor, offset, mod_offset, 0); - // self.state.set(new_state); - // self.read_page(new_cursor); + // Setup reading the next load segment. + let next_phdr = self.sel4_state.get().phdrs[next_index].unwrap(); + let (mod_offset, div_offset) = if next_phdr.p_filesz > 0 { + (next_phdr.p_offset % self.page_len, next_phdr.p_offset / self.page_len) + } else { + (self.page_len, 0) + }; + let next_cursor = self.sel4_state.get().load_offset + (div_offset * self.page_len); + + print_segment(next_index, next_cursor, offset, &next_phdr); + + let new_state = + ElfLoaderState::LoadSegmentsNew(next_phdr, next_index, next_cursor, offset, mod_offset, 0); + self.state.set(new_state); + self.read_page(next_cursor); } } } - _ => panic!("445"), + _ => unreachable!(), } } - - fn find_file_callback(&self) { - self.read_page.map(|page| { - let mut_page = page.as_mut(); - let tar_header = TarHeader::from_bytes(mut_page); - match self.state.get() { - ElfLoaderState::FindingFile(name, cursor) => { - let found_file = tar_header.name().contains(name); - self.current_task.map(|task| match task { - LoadTasks::FindFile(_file) => { - if found_file { - let mut sel4_state = self.sel4_state.get(); - match name { - "kernel" => { - sel4_state.kernel_offset = cursor + self.page_len; - } - "capdl-loader" => { - sel4_state.capdl_loader_offset = cursor + self.page_len; - } - _ => {} - } - self.sel4_state.replace(sel4_state); - self.state.set(ElfLoaderState::Idle); - } else { - let new_cursor = - self.page_len + cursor + ((tar_header.size() + 511) & !511); - self.state - .set(ElfLoaderState::FindingFile(name, new_cursor)); - } - } - LoadTasks::LoadElf(_file) => { - if found_file { - self.state - .set(ElfLoaderState::LoadElfHeader(cursor + self.page_len)); - } else { - let new_cursor = - self.page_len + cursor + ((tar_header.size() + 511) & !511); - self.state - .set(ElfLoaderState::FindingFile(name, new_cursor)); - } - } - _ => panic!("487"), - }) - } - _ => panic!("491"), - }; - }); - - match self.state.get() { - ElfLoaderState::FindingFile(_, cursor) => self.read_page(cursor), - ElfLoaderState::LoadElfHeader(cursor) => self.read_page(cursor), - ElfLoaderState::Idle => self.run_next_task(), - _ => panic!("507"), - } - } - - fn read_page(&self, page: u32) { - self.flash.map(|flash| { - self.read_page.take().map(|read_page| { - self.flash_busy.set(true); - if let Err((_, buf)) = flash.read_page((page / self.page_len) as usize, read_page) { - self.read_page.replace(buf); - } - }); - }); - } } impl<'a, F: hil::flash::Flash> Driver for ElfLoaderCapsule<'a, F> {