/// Try to allocate a piece of memory.
Try to allocate a piece of memory.
Try to allocate a piece of memory .
fn try_alloc(&self, layout: Layout) -> Result<ptr::NonNull<u8>, KError> {
        let kcb = kcb::try_get_kcb().ok_or(KError::KcbUnavailable)?;
        match KernelAllocator::allocator_for(layout) {
            AllocatorType::Zone if layout.size() <= ZoneAllocator::MAX_ALLOC_SIZE => {
                // TODO(rust): Silly code duplication follows if/else
                if core::intrinsics::unlikely(kcb.in_panic_mode) {
                    let mut zone_allocator = kcb.ezone_allocator()?;
                    zone_allocator.allocate(layout).map_err(|e| e.into())
                } else {
                    let mut zone_allocator = kcb.zone_allocator()?;
                    zone_allocator.allocate(layout).map_err(|e| e.into())
                }
            }
            AllocatorType::MemManager if layout.size() <= LARGE_PAGE_SIZE => {
                let mut pmanager = kcb.try_mem_manager()?;
                let f = pmanager.allocate_large_page()?;
                unsafe { Ok(ptr::NonNull::new_unchecked(f.kernel_vaddr().as_mut_ptr())) }
            }
            AllocatorType::MapBig => {
                // Big objects are mapped into the kernel address space
                // This needs some <3:
                // * TODO(safety): Assumptions are PML4 slot 129 (big_objects_sbrk) is always free for MapBig
                // * TODO(ugly): 129 is also hard-coded in process creation
                // * TODO(safety): No bounds checking
                // * TODO(smp): Needs a spin-lock for multi-core
                // * TODO(checks): we want this case to be rare so if we end up with more than ~20
                //   big objects we should print ag warning (and start rethinking this)
                // * TODO(limitation): We can't really allocate more than what fits in a TCache
                // Figure out how much we need to map:
                let (mut base, mut large) = KernelAllocator::layout_to_pages(layout);
                // TODO(hack): Fetching more than 254 base pages would exhaust our TCache so might
                // as well get a large-page instead:
                // Slightly better: Should at least have well defined constants for `254`
                // A bit better: TCache should probably have more space base pages (like 2MiB of base pages?)
                // More better: If we need more pages than what fits in the TCache, we should get it directly
                // from the NCache?
                // Even Better: Find a good way to express this API, and maybe the whole GlobalAllocator
                // infrastructure that doesn't require estimating the pages upfront?
                if base > 254 {
                    base = 0;
                    large += 1;
                }
                // TODO(correctness): Make sure we have 20 pages for page-tables
                // so vspace ops don't fail us :/
                self.maybe_refill_tcache(base + 20, large)?;
                // We allocate (large+1) * large-page-size
                // the +1 is to account for space for all the base-pages
                // and to make sure next time we're still aligned to a 2 MiB
                // boundary
                let mut start_at = self.big_objects_sbrk.fetch_add(
                    ((large + 1) * LARGE_PAGE_SIZE) as u64,
                    core::sync::atomic::Ordering::SeqCst,
                );
                trace!(
                    "Got a large allocation {:?}, need bp {} lp {} {:#x}",
                    layout,
                    base,
                    large,
                    start_at
                );
                let base_ptr = unsafe { ptr::NonNull::new_unchecked(start_at as *mut u8) };
                let mut kvspace = kcb.arch.init_vspace();
                for _ in 0..large {
                    let mut pmanager = kcb.try_mem_manager()?;
                    let f = pmanager
                        .allocate_large_page()
                        .expect("Can't run out of memory");
                    drop(pmanager); // `map_generic` might try to re-acquire mem_manager
                    kvspace
                        .map_generic(
                            VAddr::from(start_at),
                            (f.base, f.size()),
                            MapAction::ReadWriteKernel,
                            true,
                        )
                        .expect("Can't create the mapping");
                    start_at += LARGE_PAGE_SIZE as u64;
                }
                for _ in 0..base {
                    let mut pmanager = kcb.try_mem_manager()?;
                    let f = pmanager
                        .allocate_base_page()
                        .expect("Can't run out of memory");
                    drop(pmanager); // `map_generic` might try to re-acquire mem_manager
                    kvspace
                        .map_generic(
                            VAddr::from(start_at),
                            (f.base, f.size()),
                            MapAction::ReadWriteKernel,
                            true,
                        )
                        .expect("Can't create the mapping");
                    start_at += BASE_PAGE_SIZE as u64;
                }
                Ok(base_ptr)
            }
            _ => unimplemented!("Unable to handle this allocation request {:?}", layout),
        }
    }
fn try_alloc ( & self , layout : Layout ) -> Result < ptr :: NonNull < u8 > , KError > { let kcb = kcb :: try_get_kcb ( ) . ok_or ( KError :: KcbUnavailable ) ? ; match KernelAllocator :: allocator_for ( layout ) { AllocatorType :: Zone if layout . size ( ) <= ZoneAllocator :: MAX_ALLOC_SIZE => { // TODO(rust): Silly code duplication follows if/else if core :: intrinsics :: unlikely ( kcb . in_panic_mode ) { let mut zone_allocator = kcb . ezone_allocator ( ) ? ; zone_allocator . allocate ( layout ) . map_err ( | e | e . into ( ) ) } else { let mut zone_allocator = kcb . zone_allocator ( ) ? ; zone_allocator . allocate ( layout ) . map_err ( | e | e . into ( ) ) } } AllocatorType :: MemManager if layout . size ( ) <= LARGE_PAGE_SIZE => { let mut pmanager = kcb . try_mem_manager ( ) ? ; let f = pmanager . allocate_large_page ( ) ? ; unsafe { Ok ( ptr :: NonNull :: new_unchecked ( f . kernel_vaddr ( ) . as_mut_ptr ( ) ) ) } } AllocatorType :: MapBig => { // Big objects are mapped into the kernel address space // This needs some <3: // * TODO(safety): Assumptions are PML4 slot 129 (big_objects_sbrk) is always free for MapBig // * TODO(ugly): 129 is also hard-coded in process creation // * TODO(safety): No bounds checking // * TODO(smp): Needs a spin-lock for multi-core // * TODO(checks): we want this case to be rare so if we end up with more than ~20 //   big objects we should print ag warning (and start rethinking this) // * TODO(limitation): We can't really allocate more than what fits in a TCache // Figure out how much we need to map: let ( mut base , mut large ) = KernelAllocator :: layout_to_pages ( layout ) ; // TODO(hack): Fetching more than 254 base pages would exhaust our TCache so might // as well get a large-page instead: // Slightly better: Should at least have well defined constants for `254` // A bit better: TCache should probably have more space base pages (like 2MiB of base pages?) // More better: If we need more pages than what fits in the TCache, we should get it directly // from the NCache? // Even Better: Find a good way to express this API, and maybe the whole GlobalAllocator // infrastructure that doesn't require estimating the pages upfront? if base > 254 { base = 0 ; large += 1 ; } // TODO(correctness): Make sure we have 20 pages for page-tables // so vspace ops don't fail us :/ self . maybe_refill_tcache ( base + 20 , large ) ? ; // We allocate (large+1) * large-page-size // the +1 is to account for space for all the base-pages // and to make sure next time we're still aligned to a 2 MiB // boundary let mut start_at = self . big_objects_sbrk . fetch_add ( ( ( large + 1 ) * LARGE_PAGE_SIZE ) as u64 , core :: sync :: atomic :: Ordering :: SeqCst , ) ; trace ! ( " " layout base large start_at ) ; let base_ptr = unsafe { ptr :: NonNull :: new_unchecked ( start_at as * mut u8 ) } ; let mut kvspace = kcb . arch . init_vspace ( ) ; for _ in 0 .. large { let mut pmanager = kcb . try_mem_manager ( ) ? ; let f = pmanager . allocate_large_page ( ) . expect ( " " ) ; drop ( pmanager ) ; // `map_generic` might try to re-acquire mem_manager kvspace . map_generic ( VAddr :: from ( start_at ) , ( f . base , f . size ( ) ) , MapAction :: ReadWriteKernel , true , ) . expect ( " " ) ; start_at += LARGE_PAGE_SIZE as u64 ; } for _ in 0 .. base { let mut pmanager = kcb . try_mem_manager ( ) ? ; let f = pmanager . allocate_base_page ( ) . expect ( " " ) ; drop ( pmanager ) ; // `map_generic` might try to re-acquire mem_manager kvspace . map_generic ( VAddr :: from ( start_at ) , ( f . base , f . size ( ) ) , MapAction :: ReadWriteKernel , true , ) . expect ( " " ) ; start_at += BASE_PAGE_SIZE as u64 ; } Ok ( base_ptr ) } _ => unimplemented ! ( " " layout ) , } }
Try to allocate a piece of memory.
Try to allocate a piece of memory .
&self
layout
Layout