aos/lib/mm/slot_alloc.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

206 lines
5.8 KiB
C

/**
* \file
* \brief Slot management for the memory allocator.
*/
/*
* Copyright (c) 2007, 2008, 2016, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <aos/aos.h>
#include <mm/mm.h>
#include <mm/slot_alloc.h>
#include <stdio.h>
static errval_t rootcn_alloc(void *st, size_t reqsize, struct capref *ret)
{
return mm_alloc(st, reqsize, ret);
}
/// Allocate a new cnode if needed
errval_t slot_prealloc_refill(void *this)
{
struct slot_prealloc *sa = this;
uint8_t refill = !sa->current;
static bool is_refilling = false;
errval_t err = SYS_ERR_OK;
if (is_refilling) {
return SYS_ERR_OK;
}
if (sa->meta[refill].free == L2_CNODE_SLOTS) {
return SYS_ERR_OK; // Nop
}
is_refilling = true;
// Allocate a ram cap
struct capref ram_cap;
err = mm_alloc(sa->mm, OBJSIZE_L2CNODE, &ram_cap);
if (err_is_fail(err)) {
is_refilling = false;
err = err_push(err, MM_ERR_SLOT_MM_ALLOC);
goto out;
}
// Retype to and build the next cnode
struct capref cnode_cap;
err = slot_alloc_root(&cnode_cap);
if (err_no(err) == LIB_ERR_SLOT_ALLOC_NO_SPACE) {
// resize root slot allocator (and rootcn)
err = root_slot_allocator_refill(rootcn_alloc, sa->mm);
if (err_is_fail(err)) {
err = err_push(err, LIB_ERR_ROOTSA_RESIZE);
goto out;
}
// retry slot_alloc_root
err = slot_alloc_root(&cnode_cap);
}
if (err_is_fail(err)) {
err = err_push(err, LIB_ERR_SLOT_ALLOC);
goto out;
}
err = cnode_create_from_mem(cnode_cap, ram_cap, ObjType_L2CNode,
&sa->meta[refill].cap.cnode, L2_CNODE_SLOTS);
if (err_is_fail(err)) {
err = err_push(err, LIB_ERR_CNODE_CREATE);
goto out;
}
// Set the metadata
sa->meta[refill].cap.slot = 0;
sa->meta[refill].free = L2_CNODE_SLOTS;
out:
is_refilling = false;
return err;
}
errval_t slot_alloc_prealloc(void *inst, uint64_t nslots, struct capref *ret)
{
struct slot_prealloc *this = inst;
assert(nslots < L2_CNODE_SLOTS);
/* Check if enough space */
if (this->meta[this->current].free < nslots) {
/*
debug_printf("slot_prealloc: switching cnodes %d->%d\n",
this->current, !this->current);
*/
// Allocate from next cnode
this->current = !this->current;
}
if (this->meta[this->current].free < nslots) {
return MM_ERR_SLOT_NOSLOTS;
}
/* Return next slot and update */
*ret = this->meta[this->current].cap;
this->meta[this->current].cap.slot += nslots;
this->meta[this->current].free -= nslots;
return SYS_ERR_OK;
}
/**
* \brief Initialise preallocating slot allocator instance
*
* \param this Pointer to area for instance data
* \param initial_cnode First cap in an empty cnode to start allocating from
* \param initial_space Number of slots free in initial cnode
* \param ram_mm Memory allocator to use for RAM caps when creating new CNodes
*/
errval_t slot_prealloc_init(struct slot_prealloc *this,
struct capref initial_cnode,
uint64_t initial_space,
struct mm *ram_mm)
{
this->mm = ram_mm;
assert(initial_space == L2_CNODE_SLOTS);
if (initial_space != L2_CNODE_SLOTS) {
debug_printf("Initial CNode for 2 level preallocating slot allocator needs to be 16kB");
return LIB_ERR_SLOT_ALLOC_INIT;
}
this->current = 0;
this->meta[0].cap = initial_cnode;
this->meta[0].free = initial_space;
this->meta[1].free = 0;
return SYS_ERR_OK;
}
errval_t slot_alloc_basecn_init(struct slot_alloc_basecn *this)
{
// Use ROOTCN_SLOT_SLOT_ALLOC0 as CNode fore basecn allocator
this->cap.cnode.croot = CPTR_ROOTCN;
this->cap.cnode.cnode = ROOTCN_SLOT_ADDR(ROOTCN_SLOT_SLOT_ALLOC0);
this->cap.cnode.level = CNODE_TYPE_OTHER;
this->cap.slot = 0;
this->free = L2_CNODE_SLOTS;
return SYS_ERR_OK;
}
errval_t slot_alloc_basecn(void *inst, uint64_t nslots, struct capref *ret)
{
struct slot_alloc_basecn *this = inst;
errval_t err;
if (nslots > this->free) {
/* XXX: Special case for init, need to get memory from basecn */
struct capref ram;
size_t bits = 1 << (L2_CNODE_BITS + OBJBITS_CTE);
err = ram_alloc(&ram, bits);
if (err_is_fail(err)) {
DEBUG_ERR(err, "ram_alloc in slot_alloc_basecn cannot allocate L2 "
"CNode-sized ram cap");
return err_push(err, LIB_ERR_RAM_ALLOC);
}
/* to conform with 2 level cspace: put new cnode into rootcn */
struct capref cnode;
err = slot_alloc_root(&cnode);
if (err_is_fail(err)) {
DEBUG_ERR(err, "allocating root cnode slot");
return err_push(err, LIB_ERR_SLOT_ALLOC);
}
err = cnode_create_from_mem(cnode, ram, ObjType_L2CNode,
&this->cap.cnode, L2_CNODE_SLOTS);
if (err_is_fail(err)) {
return err_push(err, LIB_ERR_CNODE_CREATE);
}
this->cap.slot = 0;
this->free = L2_CNODE_SLOTS;
}
assert(nslots <= this->free);
*ret = this->cap;
this->cap.slot += nslots;
this->free -= nslots;
return SYS_ERR_OK;
}
/// Requires an instance of range_slot_allocator
errval_t slot_alloc_dynamic(void *alloc, uint64_t nslots, struct capref *ret)
{
return range_slot_alloc(alloc, nslots, ret);
}
errval_t slot_refill_dynamic(void *alloc)
{
return range_slot_alloc_refill(alloc, L2_CNODE_SLOTS);
}