/// Makes sure the process' vspace is backed for the regions
/// reported by the ELF loader as loadable.
///
/// Our strategy is to first figure out how much space we need,
/// then allocate a single chunk of physical memory and
/// map the individual pieces of it with different access rights.
/// This has the advantage that our address space is
/// all a very simple 1:1 mapping of physical memory.
Makes sure the process' vspace is backed for the regions
reported by the ELF loader as loadable.

Our strategy is to first figure out how much space we need,
then allocate a single chunk of physical memory and
map the individual pieces of it with different access rights.
This has the advantage that our address space is
all a very simple 1:1 mapping of physical memory.
Makes sure the process ' vspace is backed for the regions reported by the ELF loader as loadable . Our strategy is to first figure out how much space we need then allocate a single chunk of physical memory and map the individual pieces of it with different access rights . This has the advantage that our address space is all a very simple 1 : 1 mapping of physical memory .
fn allocate(
        &mut self,
        load_headers: elfloader::LoadableHeaders,
    ) -> Result<(), elfloader::ElfLoaderErr> {
        for header in load_headers.into_iter() {
            let base = header.virtual_addr();
            let size = header.mem_size() as usize;
            let align_to = header.align();
            let flags = header.flags();
            // Calculate the offset and align to page boundaries
            // We can't expect to get something that is page-aligned from ELF
            let page_mask = (LARGE_PAGE_SIZE - 1) as u64;
            let page_base: VAddr = VAddr::from(base & !page_mask); // Round down to nearest page-size
            let size_page = round_up!(size + (base & page_mask) as usize, LARGE_PAGE_SIZE as usize);
            assert!(size_page >= size);
            assert_eq!(size_page % LARGE_PAGE_SIZE, 0);
            assert_eq!(page_base % LARGE_PAGE_SIZE, 0);
            let map_action = match (flags.is_execute(), flags.is_write(), flags.is_read()) {
                (false, false, false) => panic!("MapAction::None"),
                (true, false, false) => panic!("MapAction::None"),
                (false, true, false) => panic!("MapAction::None"),
                (false, false, true) => MapAction::ReadUser,
                (true, false, true) => MapAction::ReadExecuteUser,
                (true, true, false) => panic!("MapAction::None"),
                (false, true, true) => MapAction::ReadWriteUser,
                (true, true, true) => MapAction::ReadWriteExecuteUser,
            };
            info!(
                "ELF Allocate: {:#x} -- {:#x} align to {:#x} with flags {:?} ({:?})",
                page_base,
                page_base + size_page,
                align_to,
                flags,
                map_action
            );
            let large_pages = size_page / LARGE_PAGE_SIZE;
            debug!("page_base {} lps: {}", page_base, large_pages);
            // TODO(correctness): add 20 as estimate of worst case pt requirements
            KernelAllocator::try_refill_tcache(20, large_pages, MemType::Mem)
                .expect("Refill didn't work");
            let kcb = crate::kcb::get_kcb();
            // TODO(correctness): Will this work (we round-up and map large-pages?)
            // TODO(efficiency): What about wasted memory
            // TODO(hard-coded replication assumptions): We assume that we only have 1 data section
            // that is read-write and that fits within data_frame (so replication works out)
            // We should probably return an error and request more bigger data frames if what
            // we provide initially doesn't work out...
            let mut wsection_idx = 0;
            for i in 0..large_pages {
                let frame = if flags.is_write() {
                    // Writeable program-headers we can't replicate:
                    assert!(
                        wsection_idx < self.writeable_sections.len(),
                        "Didn't pass enough frames for writeable sections to process create."
                    );
                    assert_eq!(
                        self.writeable_sections[wsection_idx].size(),
                        LARGE_PAGE_SIZE,
                        "We expect writeable sections frame to be a large-page."
                    );
                    let frame = self.writeable_sections[wsection_idx];
                    wsection_idx += 1;
                    frame
                } else {
                    // A read-only program header we can replicate:
                    assert!(
                        map_action == MapAction::ReadUser
                            || map_action == MapAction::ReadExecuteUser
                    );
                    let mut pmanager = kcb.mem_manager();
                    pmanager
                        .allocate_large_page()
                        .expect("We refilled so allocation should work.")
                };
                trace!(
                    "process load vspace from {:#x} with {:?}",
                    self.offset + page_base + i * LARGE_PAGE_SIZE,
                    frame
                );
                self.vspace
                    .map_frame(
                        self.offset + page_base + i * LARGE_PAGE_SIZE,
                        frame,
                        map_action,
                    )
                    .expect("Can't map ELF region");
            }
        }
        info!(
            "Binary loaded at address: {:#x} entry {:#x}",
            self.offset, self.entry_point
        );
        Ok(())
    }
fn allocate ( & mut self , load_headers : elfloader :: LoadableHeaders , ) -> Result < ( ) , elfloader :: ElfLoaderErr > { for header in load_headers . into_iter ( ) { let base = header . virtual_addr ( ) ; let size = header . mem_size ( ) as usize ; let align_to = header . align ( ) ; let flags = header . flags ( ) ; // Calculate the offset and align to page boundaries // We can't expect to get something that is page-aligned from ELF let page_mask = ( LARGE_PAGE_SIZE - 1 ) as u64 ; let page_base : VAddr = VAddr :: from ( base & ! page_mask ) ; // Round down to nearest page-size let size_page = round_up ! ( size ( base page_mask ) as usize LARGE_PAGE_SIZE as usize ) ; assert ! ( size_page size ) ; assert_eq ! ( size_page LARGE_PAGE_SIZE 0 ) ; assert_eq ! ( page_base LARGE_PAGE_SIZE 0 ) ; let map_action = match ( flags . is_execute ( ) , flags . is_write ( ) , flags . is_read ( ) ) { ( false , false , false ) => panic ! ( " " ) , ( true , false , false ) => panic ! ( " " ) , ( false , true , false ) => panic ! ( " " ) , ( false , false , true ) => MapAction :: ReadUser , ( true , false , true ) => MapAction :: ReadExecuteUser , ( true , true , false ) => panic ! ( " " ) , ( false , true , true ) => MapAction :: ReadWriteUser , ( true , true , true ) => MapAction :: ReadWriteExecuteUser , } ; info ! ( " " page_base page_base size_page align_to flags map_action ) ; let large_pages = size_page / LARGE_PAGE_SIZE ; debug ! ( " " page_base large_pages ) ; // TODO(correctness): add 20 as estimate of worst case pt requirements KernelAllocator :: try_refill_tcache ( 20 , large_pages , MemType :: Mem ) . expect ( " " ) ; let kcb = crate :: kcb :: get_kcb ( ) ; // TODO(correctness): Will this work (we round-up and map large-pages?) // TODO(efficiency): What about wasted memory // TODO(hard-coded replication assumptions): We assume that we only have 1 data section // that is read-write and that fits within data_frame (so replication works out) // We should probably return an error and request more bigger data frames if what // we provide initially doesn't work out... let mut wsection_idx = 0 ; for i in 0 .. large_pages { let frame = if flags . is_write ( ) { // Writeable program-headers we can't replicate: assert ! ( wsection_idx self writeable_sections len ( ) " " ) ; assert_eq ! ( self writeable_sections [ wsection_idx ] size ( ) LARGE_PAGE_SIZE " " ) ; let frame = self . writeable_sections [ wsection_idx ] ; wsection_idx += 1 ; frame } else { // A read-only program header we can replicate: assert ! ( map_action MapAction ReadUser map_action MapAction ReadExecuteUser ) ; let mut pmanager = kcb . mem_manager ( ) ; pmanager . allocate_large_page ( ) . expect ( " " ) } ; trace ! ( " " self offset page_base i LARGE_PAGE_SIZE frame ) ; self . vspace . map_frame ( self . offset + page_base + i * LARGE_PAGE_SIZE , frame , map_action , ) . expect ( " " ) ; } } info ! ( " " self offset self entry_point ) ; Ok ( ( ) ) }
Makes sure the process' vspace is backed for the regions
reported by the ELF loader as loadable.
Makes sure the process ' vspace is backed for the regions reported by the ELF loader as loadable .
&mut self
load_headers
elfloader::LoadableHeaders