Implement heap allocation on page fault
This commit is contained in:
parent
0c224f9066
commit
d8f2439b7b
@ -38,6 +38,9 @@ errval_t paging_init_params(struct spawn_domain_params *params);
|
|||||||
errval_t paging_init_onthread(struct thread *t);
|
errval_t paging_init_onthread(struct thread *t);
|
||||||
|
|
||||||
|
|
||||||
|
errval_t paging_alloc_ext(struct paging_state *st, void **buf, size_t bytes,
|
||||||
|
size_t alignment, bool heap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Find a bit of free virtual address space that is large enough to
|
* \brief Find a bit of free virtual address space that is large enough to
|
||||||
* accomodate a buffer of size `bytes`.
|
* accomodate a buffer of size `bytes`.
|
||||||
|
|||||||
@ -61,7 +61,8 @@ struct pt_t {
|
|||||||
struct pt_vaddr_reg_t {
|
struct pt_vaddr_reg_t {
|
||||||
lvaddr_t base;
|
lvaddr_t base;
|
||||||
size_t size;
|
size_t size;
|
||||||
uint8_t free;
|
uint8_t free:1; // Is the region free?
|
||||||
|
uint8_t heap:1; // Is the region part of the heap?
|
||||||
struct pt_vaddr_reg_t *next;
|
struct pt_vaddr_reg_t *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -205,20 +205,20 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
|
|||||||
|
|
||||||
// TODO MILESTONE 3: register ourselves with init
|
// TODO MILESTONE 3: register ourselves with init
|
||||||
/* allocate lmp channel structure */
|
/* allocate lmp channel structure */
|
||||||
struct lmp_chan *init_chan = malloc(sizeof(struct lmp_chan));
|
static struct lmp_chan init_chan;
|
||||||
lmp_chan_init(init_chan);
|
lmp_chan_init(&init_chan);
|
||||||
/* create local endpoint */
|
/* create local endpoint */
|
||||||
err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &init_chan->local_cap, &init_chan->endpoint);
|
err = endpoint_create(DEFAULT_LMP_BUF_WORDS, &init_chan.local_cap, &init_chan.endpoint);
|
||||||
if (err_is_fail(err)) {
|
if (err_is_fail(err)) {
|
||||||
return err_push(err, LIB_ERR_ENDPOINT_CREATE);
|
return err_push(err, LIB_ERR_ENDPOINT_CREATE);
|
||||||
}
|
}
|
||||||
/* set remote endpoint to init's endpoint */
|
/* set remote endpoint to init's endpoint */
|
||||||
init_chan->remote_cap = cap_initep;
|
init_chan.remote_cap = cap_initep;
|
||||||
/* set receive handler */
|
/* set receive handler */
|
||||||
init_chan_initialized = false;
|
init_chan_initialized = false;
|
||||||
err = lmp_chan_register_recv(init_chan, get_default_waitset(), MKCLOSURE(handle_init_recv, init_chan));
|
err = lmp_chan_register_recv(&init_chan, get_default_waitset(), MKCLOSURE(handle_init_recv, &init_chan));
|
||||||
/* send local ep to init */
|
/* send local ep to init */
|
||||||
err = lmp_chan_send1(init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, init_chan->local_cap, RPC_MTYPE_CHILD_ENDPOINT);
|
err = lmp_chan_send1(&init_chan, LMP_FLAG_YIELD | LMP_FLAG_SYNC, init_chan.local_cap, RPC_MTYPE_CHILD_ENDPOINT);
|
||||||
if (err_is_fail(err)) {
|
if (err_is_fail(err)) {
|
||||||
// should never fail since init listens before invoking the dispatcher
|
// should never fail since init listens before invoking the dispatcher
|
||||||
return err_push(err, LIB_ERR_LMP_CHAN_SEND);
|
return err_push(err, LIB_ERR_LMP_CHAN_SEND);
|
||||||
@ -231,13 +231,13 @@ errval_t barrelfish_init_onthread(struct spawn_domain_params *params)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* initialize init RPC client with lmp channel */
|
/* initialize init RPC client with lmp channel */
|
||||||
struct aos_rpc *init_rpc = malloc(sizeof(struct aos_rpc));
|
static struct aos_rpc init_rpc;
|
||||||
err = aos_rpc_init(init_rpc, init_chan, params->rpc_shared_memory);
|
err = aos_rpc_init(&init_rpc, &init_chan, params->rpc_shared_memory);
|
||||||
if (err_is_fail(err)){
|
if (err_is_fail(err)){
|
||||||
return err_push(err, ERR_NOTIMP);
|
return err_push(err, ERR_NOTIMP);
|
||||||
}
|
}
|
||||||
/* set init RPC client in our program state */
|
/* set init RPC client in our program state */
|
||||||
set_init_rpc(init_rpc);
|
set_init_rpc(&init_rpc);
|
||||||
|
|
||||||
/* TODO MILESTONE 3: now we should have a channel with init set up and can
|
/* TODO MILESTONE 3: now we should have a channel with init set up and can
|
||||||
* use it for the ram allocator */
|
* use it for the ram allocator */
|
||||||
|
|||||||
@ -26,8 +26,8 @@ extern morecore_free_func_t sys_morecore_free;
|
|||||||
|
|
||||||
// this define makes morecore use an implementation that just has a static
|
// this define makes morecore use an implementation that just has a static
|
||||||
// 16MB heap.
|
// 16MB heap.
|
||||||
// TODO (M4): use a dynamic heap instead,
|
// (M4): use a dynamic heap instead,
|
||||||
#define USE_STATIC_HEAP
|
//#define USE_STATIC_HEAP
|
||||||
|
|
||||||
#ifdef USE_STATIC_HEAP
|
#ifdef USE_STATIC_HEAP
|
||||||
|
|
||||||
@ -101,26 +101,39 @@ errval_t morecore_reinit(void)
|
|||||||
*/
|
*/
|
||||||
static void *morecore_alloc(size_t bytes, size_t *retbytes)
|
static void *morecore_alloc(size_t bytes, size_t *retbytes)
|
||||||
{
|
{
|
||||||
USER_PANIC("NYI: implement me (M4)\n");
|
errval_t err;
|
||||||
return NULL;
|
// struct morecore_state *state = get_morecore_state();
|
||||||
|
|
||||||
|
size_t aligned_bytes = ROUND_UP(bytes, LARGE_PAGE_SIZE);
|
||||||
|
void *ret = NULL;
|
||||||
|
err = paging_alloc_ext(get_current_paging_state(), &ret, aligned_bytes, LARGE_PAGE_SIZE, true);
|
||||||
|
if (err_is_fail(err)) {
|
||||||
|
DEBUG_ERR(err, "in morecore_alloc, size=%"PRIuPTR"\n", aligned_bytes);
|
||||||
|
aligned_bytes = 0;
|
||||||
|
}
|
||||||
|
*retbytes = aligned_bytes;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void morecore_free(void *base, size_t bytes)
|
static void morecore_free(void *base, size_t bytes)
|
||||||
{
|
{
|
||||||
USER_PANIC("NYI: implement me (M4)\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errval_t morecore_init(size_t alignment)
|
errval_t morecore_init(size_t alignment)
|
||||||
{
|
{
|
||||||
|
struct morecore_state *state = get_morecore_state();
|
||||||
|
|
||||||
debug_printf("initializing dynamic heap\n");
|
debug_printf("initializing dynamic heap\n");
|
||||||
|
|
||||||
USER_PANIC("NYI: implement me (M4)\n");
|
thread_mutex_init(&state->mutex);
|
||||||
return LIB_ERR_NOT_IMPLEMENTED;
|
|
||||||
|
sys_morecore_alloc = morecore_alloc;
|
||||||
|
sys_morecore_free = morecore_free;
|
||||||
|
return SYS_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
errval_t morecore_reinit(void)
|
errval_t morecore_reinit(void)
|
||||||
{
|
{
|
||||||
USER_PANIC("NYI \n");
|
|
||||||
return SYS_ERR_OK;
|
return SYS_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
112
lib/aos/paging.c
112
lib/aos/paging.c
@ -34,6 +34,9 @@ static struct paging_state current;
|
|||||||
// initial page fault handler stack space
|
// initial page fault handler stack space
|
||||||
static char pt_static_exception_stack[PT_STATIC_EXCEPTION_STACK_SIZE];
|
static char pt_static_exception_stack[PT_STATIC_EXCEPTION_STACK_SIZE];
|
||||||
|
|
||||||
|
static errval_t _paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
|
||||||
|
struct capref frame, size_t bytes, int flags);
|
||||||
|
|
||||||
static char *pt_exception_type_to_string(enum exception_type type, int subtype)
|
static char *pt_exception_type_to_string(enum exception_type type, int subtype)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -63,9 +66,34 @@ static char *pt_exception_type_to_string(enum exception_type type, int subtype)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the page at vaddr is mapped.
|
||||||
|
static bool is_mapped(struct paging_state *st, lvaddr_t vaddr)
|
||||||
|
{
|
||||||
|
capaddr_t l0_index = VMSAv8_64_L0_INDEX(vaddr);
|
||||||
|
capaddr_t l1_index = VMSAv8_64_L1_INDEX(vaddr);
|
||||||
|
capaddr_t l2_index = VMSAv8_64_L2_INDEX(vaddr);
|
||||||
|
capaddr_t l3_index = VMSAv8_64_L3_INDEX(vaddr);
|
||||||
|
|
||||||
|
struct pt_t *l0_pt = &st->l0_pt;
|
||||||
|
if (l0_pt->children == NULL) return false;
|
||||||
|
|
||||||
|
struct pt_t *l1_pt = l0_pt->children[l0_index];
|
||||||
|
if(l1_pt == NULL) return false;
|
||||||
|
|
||||||
|
struct pt_t *l2_pt = l1_pt->children[l1_index];
|
||||||
|
if(l2_pt == NULL) return false;
|
||||||
|
|
||||||
|
struct pt_t *l3_pt = l2_pt->children[l2_index];
|
||||||
|
if(l3_pt == NULL) return false;
|
||||||
|
|
||||||
|
if(l3_pt->children[l3_index] == NULL) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void pt_exception_handler(enum exception_type type, int subtype,
|
static void pt_exception_handler(enum exception_type type, int subtype,
|
||||||
void *addr, arch_registers_state_t *regs)
|
void *addr, arch_registers_state_t *regs)
|
||||||
{
|
{
|
||||||
|
errval_t err;
|
||||||
lvaddr_t ip = registers_get_ip(regs);
|
lvaddr_t ip = registers_get_ip(regs);
|
||||||
|
|
||||||
debug_printf("Page Fault: type=%s, addr=%p, ip=%p\n",
|
debug_printf("Page Fault: type=%s, addr=%p, ip=%p\n",
|
||||||
@ -81,7 +109,41 @@ static void pt_exception_handler(enum exception_type type, int subtype,
|
|||||||
USER_PANIC("[ERROR] NULL pointer dereference");
|
USER_PANIC("[ERROR] NULL pointer dereference");
|
||||||
}
|
}
|
||||||
|
|
||||||
USER_PANIC("[ERROR] Page fault handling not yet implemented");
|
lvaddr_t page_addr = ROUND_DOWN((lvaddr_t)addr, BASE_PAGE_SIZE);
|
||||||
|
struct paging_state *st = get_current_paging_state();
|
||||||
|
|
||||||
|
thread_mutex_lock_nested(&st->lock);
|
||||||
|
|
||||||
|
struct pt_vaddr_reg_t *vaddr_reg = &st->vaddr_head;
|
||||||
|
for (; vaddr_reg != NULL; vaddr_reg = vaddr_reg->next) {
|
||||||
|
if (vaddr_reg->base <= page_addr && page_addr < vaddr_reg->base + vaddr_reg->size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vaddr_reg == NULL || vaddr_reg->free) {
|
||||||
|
USER_PANIC("[ERROR] Page fault ouside allocated address space");
|
||||||
|
}
|
||||||
|
if (!vaddr_reg->heap) {
|
||||||
|
USER_PANIC("[ERROR] Page fault in allocated address space but outside heap");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_mapped(st, page_addr)) {
|
||||||
|
// Page has already been mapped by another thread before we took the lock.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct capref frame;
|
||||||
|
err = frame_alloc(&frame, BASE_PAGE_SIZE, NULL);
|
||||||
|
if (err_is_fail(err)) {
|
||||||
|
USER_PANIC_ERR(err, "Failed to allocate frame in page fault handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
err = _paging_map_fixed_attr(st, page_addr, frame, BASE_PAGE_SIZE, VREGION_FLAGS_READ_WRITE);
|
||||||
|
if (err_is_fail(err)) {
|
||||||
|
USER_PANIC_ERR(err, "Failed to map frame in page fault handler");
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_mutex_unlock(&st->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +228,7 @@ void pt_print_state(struct paging_state *st) {
|
|||||||
debug_printf("ranges:\n");
|
debug_printf("ranges:\n");
|
||||||
struct pt_vaddr_reg_t *reg = &st->vaddr_head;
|
struct pt_vaddr_reg_t *reg = &st->vaddr_head;
|
||||||
while (reg != NULL) {
|
while (reg != NULL) {
|
||||||
debug_printf("- base=%lu, size=%lu, %s\n", reg->base, reg->size, reg->free ? "free" : "in use");
|
debug_printf("- base=%lu, size=%lu, %s%s\n", reg->base, reg->size, reg->free ? "free" : "in use", reg->heap ? ", heap" : "");
|
||||||
reg = reg->next;
|
reg = reg->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,6 +405,7 @@ errval_t paging_init_state(struct paging_state *st, lvaddr_t start_vaddr,
|
|||||||
st->vaddr_head.base = start_vaddr;
|
st->vaddr_head.base = start_vaddr;
|
||||||
st->vaddr_head.size = VADDR_SIZE - start_vaddr;
|
st->vaddr_head.size = VADDR_SIZE - start_vaddr;
|
||||||
st->vaddr_head.free = true;
|
st->vaddr_head.free = true;
|
||||||
|
st->vaddr_head.heap = false;
|
||||||
st->vaddr_head.next = NULL;
|
st->vaddr_head.next = NULL;
|
||||||
|
|
||||||
st->slot_alloc = ca;
|
st->slot_alloc = ca;
|
||||||
@ -392,7 +455,7 @@ errval_t paging_init_params(struct spawn_domain_params *params)
|
|||||||
{
|
{
|
||||||
errval_t err;
|
errval_t err;
|
||||||
// (M2): Call paging_init_state for ¤t
|
// (M2): Call paging_init_state for ¤t
|
||||||
// TODO (M4): initialize self-paging handler
|
// (M4): initialize self-paging handler
|
||||||
// TIP: use thread_set_exception_handler() to setup a page fault handler
|
// TIP: use thread_set_exception_handler() to setup a page fault handler
|
||||||
// TIP: Think about the fact that later on, you'll have to make sure that
|
// TIP: Think about the fact that later on, you'll have to make sure that
|
||||||
// you can handle page faults in any thread of a domain.
|
// you can handle page faults in any thread of a domain.
|
||||||
@ -445,7 +508,7 @@ errval_t paging_init(void)
|
|||||||
*/
|
*/
|
||||||
errval_t paging_init_onthread(struct thread *t)
|
errval_t paging_init_onthread(struct thread *t)
|
||||||
{
|
{
|
||||||
// TODO (M4):
|
// (M4):
|
||||||
// - setup exception handler for thread `t'.
|
// - setup exception handler for thread `t'.
|
||||||
errval_t err;
|
errval_t err;
|
||||||
|
|
||||||
@ -470,8 +533,10 @@ errval_t paging_init_onthread(struct thread *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr_reg_t *target_region, size_t prefix_size, size_t alloc_size)
|
static errval_t paging_insert_vaddr_reg(
|
||||||
{
|
struct paging_state *st, struct pt_vaddr_reg_t *target_region,
|
||||||
|
size_t prefix_size, size_t alloc_size, bool heap
|
||||||
|
) {
|
||||||
assert(target_region->free);
|
assert(target_region->free);
|
||||||
assert(target_region->size >= prefix_size + alloc_size);
|
assert(target_region->size >= prefix_size + alloc_size);
|
||||||
|
|
||||||
@ -507,7 +572,6 @@ static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr
|
|||||||
if (prefix_size > 0) {
|
if (prefix_size > 0) {
|
||||||
prefix_reg->base = base;
|
prefix_reg->base = base;
|
||||||
prefix_reg->size = prefix_size;
|
prefix_reg->size = prefix_size;
|
||||||
prefix_reg->free = true;
|
|
||||||
|
|
||||||
main_reg->next = prefix_reg->next;
|
main_reg->next = prefix_reg->next;
|
||||||
prefix_reg->next = main_reg;
|
prefix_reg->next = main_reg;
|
||||||
@ -518,6 +582,7 @@ static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr
|
|||||||
main_reg->base = base;
|
main_reg->base = base;
|
||||||
main_reg->size = alloc_size;
|
main_reg->size = alloc_size;
|
||||||
main_reg->free = false;
|
main_reg->free = false;
|
||||||
|
main_reg->heap = heap;
|
||||||
|
|
||||||
base += alloc_size;
|
base += alloc_size;
|
||||||
|
|
||||||
@ -525,6 +590,7 @@ static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr
|
|||||||
postfix_reg->base = base;
|
postfix_reg->base = base;
|
||||||
postfix_reg->size = postfix_size;
|
postfix_reg->size = postfix_size;
|
||||||
postfix_reg->free = true;
|
postfix_reg->free = true;
|
||||||
|
postfix_reg->heap = false;
|
||||||
|
|
||||||
postfix_reg->next = main_reg->next;
|
postfix_reg->next = main_reg->next;
|
||||||
main_reg->next = postfix_reg;
|
main_reg->next = postfix_reg;
|
||||||
@ -533,8 +599,10 @@ static errval_t paging_insert_vaddr_reg(struct paging_state *st, struct pt_vaddr
|
|||||||
return SYS_ERR_OK;
|
return SYS_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static errval_t _paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t alignment)
|
static errval_t _paging_alloc_ext(
|
||||||
{
|
struct paging_state *st, void **buf, size_t bytes,
|
||||||
|
size_t alignment, bool heap
|
||||||
|
) {
|
||||||
errval_t err;
|
errval_t err;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -565,7 +633,7 @@ static errval_t _paging_alloc(struct paging_state *st, void **buf, size_t bytes,
|
|||||||
if (vaddr_reg->free && vaddr_reg->size >= prefix_size + bytes) {
|
if (vaddr_reg->free && vaddr_reg->size >= prefix_size + bytes) {
|
||||||
|
|
||||||
// allocate the new region, potentially splitting off a prefix and postfix from the region
|
// allocate the new region, potentially splitting off a prefix and postfix from the region
|
||||||
err = paging_insert_vaddr_reg(st, vaddr_reg, prefix_size, bytes);
|
err = paging_insert_vaddr_reg(st, vaddr_reg, prefix_size, bytes, heap);
|
||||||
if (err_is_fail(err)) {
|
if (err_is_fail(err)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -580,6 +648,17 @@ static errval_t _paging_alloc(struct paging_state *st, void **buf, size_t bytes,
|
|||||||
return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
|
return LIB_ERR_OUT_OF_VIRTUAL_ADDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errval_t paging_alloc_ext(struct paging_state *st, void **buf, size_t bytes, size_t alignment, bool heap)
|
||||||
|
{
|
||||||
|
errval_t err;
|
||||||
|
|
||||||
|
thread_mutex_lock_nested(&st->lock);
|
||||||
|
err = _paging_alloc_ext(st, buf, bytes, alignment, heap);
|
||||||
|
thread_mutex_unlock(&st->lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Find a free region of virtual address space that is large enough to accomodate a
|
* @brief Find a free region of virtual address space that is large enough to accomodate a
|
||||||
* buffer of size 'bytes'.
|
* buffer of size 'bytes'.
|
||||||
@ -593,13 +672,7 @@ static errval_t _paging_alloc(struct paging_state *st, void **buf, size_t bytes,
|
|||||||
*/
|
*/
|
||||||
errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t alignment)
|
errval_t paging_alloc(struct paging_state *st, void **buf, size_t bytes, size_t alignment)
|
||||||
{
|
{
|
||||||
errval_t err;
|
return paging_alloc_ext(st, buf, bytes, alignment, false);
|
||||||
|
|
||||||
thread_mutex_lock_nested(&st->lock);
|
|
||||||
err = _paging_alloc(st, buf, bytes, alignment);
|
|
||||||
thread_mutex_unlock(&st->lock);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static errval_t _paging_map_frame_attr(struct paging_state *st, void **buf, size_t bytes,
|
static errval_t _paging_map_frame_attr(struct paging_state *st, void **buf, size_t bytes,
|
||||||
@ -701,11 +774,12 @@ static errval_t _paging_map_fixed_attr(struct paging_state *st, lvaddr_t vaddr,
|
|||||||
if(vaddr_reg->base <= vaddr && end_vaddr <= vaddr_reg->base + vaddr_reg->size) {
|
if(vaddr_reg->base <= vaddr && end_vaddr <= vaddr_reg->base + vaddr_reg->size) {
|
||||||
if (vaddr_reg->free == true) {
|
if (vaddr_reg->free == true) {
|
||||||
// make sure the virtual memory is not used by anyone else
|
// make sure the virtual memory is not used by anyone else
|
||||||
err = paging_insert_vaddr_reg(st, vaddr_reg, vaddr - vaddr_reg->base, bytes);
|
err = paging_insert_vaddr_reg(st, vaddr_reg, vaddr - vaddr_reg->base, bytes, false);
|
||||||
if (err_is_fail(err)) {
|
if (err_is_fail(err)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if (!(vaddr_reg->base == vaddr && end_vaddr == vaddr_reg->base + vaddr_reg->size)) {
|
} else if (!(vaddr_reg->base == vaddr && end_vaddr == vaddr_reg->base + vaddr_reg->size) &&
|
||||||
|
!vaddr_reg->heap) {
|
||||||
return LIB_ERR_PMAP_ADDR_NOT_FREE;
|
return LIB_ERR_PMAP_ADDR_NOT_FREE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user