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> {