From d3d072e47de84a01bf75a838925a4ee3e78ea5f5 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Sat, 22 Aug 2009 12:09:51 +0300 Subject: [PATCH] Capability accounting for quantitative capabilities - First part done. Need to make sure accounting charges correct containers during init. Therefore kernel resource spending must also be accounted for. --- include/l4/api/errno.h | 1 + include/l4/generic/capability.h | 7 ++ include/l4/generic/resource.h | 7 +- include/l4/generic/tcb.h | 1 + src/arch/arm/v5/mm.c | 2 +- src/generic/capability.c | 46 ++++++++++ src/generic/container.c | 40 ++++++++- src/generic/resource.c | 152 ++++++++++++++++++++++++++------ src/generic/tcb.c | 21 ++++- 9 files changed, 240 insertions(+), 37 deletions(-) diff --git a/include/l4/api/errno.h b/include/l4/api/errno.h index 4034804..fc6c1c9 100644 --- a/include/l4/api/errno.h +++ b/include/l4/api/errno.h @@ -138,5 +138,6 @@ /* Codezero specific error codes */ #define EACTIVE 132 /* Task active */ #define ENOIPC 133 /* General IPC error */ +#define ENOCAP 134 /* None or insufficient capability */ #endif /* __ERRNO_H__ */ diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index ed1cf42..ac95cce 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -71,6 +71,7 @@ struct cap_list { void capability_init(struct capability *cap); struct capability *capability_create(void); +struct capability *boot_capability_create(void); static inline void cap_list_init(struct cap_list *clist) @@ -86,6 +87,12 @@ static inline void cap_list_insert(struct capability *cap, clist->ncaps++; } +/* Capability checking for quantitative capabilities */ +int capability_consume(struct capability *cap, int quantity); +int capability_free(struct capability *cap, int quantity); +struct capability *capability_find_by_rtype(struct cap_list *clist, + unsigned int rtype); + #if 0 /* Virtual memory space allocated to container */ struct capability cap_virtmap = { diff --git a/include/l4/generic/resource.h b/include/l4/generic/resource.h index f52e741..8a40378 100644 --- a/include/l4/generic/resource.h +++ b/include/l4/generic/resource.h @@ -17,7 +17,6 @@ struct boot_resources { int nconts; int ncaps; - int nids; int nthreads; int nspaces; int npmds; @@ -27,6 +26,7 @@ struct boot_resources { int nkpmds; int nkpgds; int nkmemcaps; + int nkcaps; }; /* List of containers */ @@ -72,6 +72,9 @@ struct kernel_container { struct cap_list devmem_used; struct cap_list devmem_free; + /* All other caps that belong to the kernel */ + struct cap_list other_caps; + struct mem_cache *pgd_cache; struct mem_cache *pmd_cache; struct mem_cache *ktcb_cache; @@ -95,6 +98,8 @@ pgd_table_t *alloc_pgd(void); pmd_table_t *alloc_pmd(void); struct address_space *alloc_space(void); struct ktcb *alloc_ktcb(void); +struct ktcb *alloc_ktcb_use_capability(struct capability *cap); +struct capability *boot_alloc_capability(void); struct capability *alloc_capability(void); struct container *alloc_container(void); struct mutex_queue *alloc_user_mutex(void); diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 8428dc9..8f3dd46 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -158,6 +158,7 @@ void tcb_remove(struct ktcb *tcb); void tcb_init(struct ktcb *tcb); struct ktcb *tcb_alloc_init(void); +struct ktcb *tcb_alloc_init_use_capability(struct capability *cap); void tcb_delete(struct ktcb *tcb); void init_ktcb_list(struct ktcb_list *ktcb_list); diff --git a/src/arch/arm/v5/mm.c b/src/arch/arm/v5/mm.c index 638e269..1b7e339 100644 --- a/src/arch/arm/v5/mm.c +++ b/src/arch/arm/v5/mm.c @@ -612,7 +612,7 @@ out_error: extern pmd_table_t *pmd_array; /* - * Jumps from boot page tables to tables allocated from the cache. + * Jumps from boot pmd/pgd page tables to tables allocated from the cache. */ pgd_table_t *realloc_page_tables(void) { diff --git a/src/generic/capability.c b/src/generic/capability.c index 890eec5..64e61ac 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -5,6 +5,9 @@ */ #include #include +#include +#include +#include void capability_init(struct capability *cap) { @@ -12,6 +15,19 @@ void capability_init(struct capability *cap) link_init(&cap->list); } +/* + * Boot-time function to create capability without + * capability checking + */ +struct capability *boot_capability_create(void) +{ + struct capability *cap = boot_alloc_capability(); + + capability_init(cap); + + return cap; +} + struct capability *capability_create(void) { struct capability *cap = alloc_capability(); @@ -21,3 +37,33 @@ struct capability *capability_create(void) return cap; } +int capability_consume(struct capability *cap, int quantity) +{ + if (cap->size < cap->used + quantity) + return -ENOCAP; + else + cap->used += quantity; + return 0; +} + +int capability_free(struct capability *cap, int quantity) +{ + BUG_ON((cap->used -= quantity) < 0); + return 0; +} + +/* + * Find a capability from a list by its resource type + */ +struct capability *capability_find_by_rtype(struct cap_list *clist, + unsigned int rtype) +{ + struct capability *cap; + + list_foreach_struct(cap, &clist->caps, list) { + if ((cap->type & CAP_RTYPE_MASK) == rtype) + return cap; + } + return 0; +} + diff --git a/src/generic/container.c b/src/generic/container.c index 863783b..535f2a9 100644 --- a/src/generic/container.c +++ b/src/generic/container.c @@ -254,8 +254,25 @@ int init_first_pager(struct pager *pager, struct container *cont, pgd_table_t *current_pgd) { - struct ktcb *task = tcb_alloc_init(); + struct ktcb *task; struct address_space *space; + struct capability *ktcb_cap; + + /* + * Find capability from pager's list, since + * there is no ktcb, no standard path to check + * per-task capability list yet. + */ + ktcb_cap = capability_find_by_rtype(&pager->cap_list, + CAP_RTYPE_THREADPOOL); + /* Use it to allocate ktcb */ + task = tcb_alloc_init_use_capability(ktcb_cap); + + /* + * Initialize dummy current capability list pointer + * so that capability accounting can be done as normal + */ + current->cap_list_ptr = &pager->cap_list; /* Initialize ktcb */ task_init_registers(task, pager->start_vma); @@ -303,7 +320,6 @@ int init_first_pager(struct pager *pager, return 0; } - /* * Inspects pager parameters defined in the container, * and sets up an execution environment for the pager. @@ -314,7 +330,25 @@ int init_first_pager(struct pager *pager, */ int init_pager(struct pager *pager, struct container *cont) { - struct ktcb *task = tcb_alloc_init(); + struct ktcb *task; + struct capability *ktcb_cap; + + /* + * Find capability from pager's list, since + * there is no ktcb, no standard path to check + * per-task capability list yet. + */ + ktcb_cap = capability_find_by_rtype(&pager->cap_list, + CAP_RTYPE_THREADPOOL); + + /* Use it to allocate ktcb */ + task = tcb_alloc_init_use_capability(ktcb_cap); + + /* + * Initialize dummy current capability list pointer + * so that capability accounting can be done as normal + */ + current->cap_list_ptr = &pager->cap_list; task_init_registers(task, pager->start_vma); diff --git a/src/generic/resource.c b/src/generic/resource.c index 068cef2..b8a4ed5 100644 --- a/src/generic/resource.c +++ b/src/generic/resource.c @@ -22,21 +22,75 @@ pgd_table_t *alloc_pgd(void) pmd_table_t *alloc_pmd(void) { + struct capability *cap; + + if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_MAPPOOL))) + return 0; + + if (capability_consume(cap, 1) < 0) + return 0; + return mem_cache_zalloc(kernel_container.pmd_cache); } struct address_space *alloc_space(void) { + struct capability *cap; + + if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_SPACEPOOL))) + return 0; + + if (capability_consume(cap, 1) < 0) + return 0; + return mem_cache_zalloc(kernel_container.space_cache); } +struct ktcb *alloc_ktcb_use_capability(struct capability *cap) +{ + if (capability_consume(cap, 1) < 0) + return 0; + + return mem_cache_zalloc(kernel_container.ktcb_cache); +} + struct ktcb *alloc_ktcb(void) { + struct capability *cap; + + if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_THREADPOOL))) + return 0; + + if (capability_consume(cap, 1) < 0) + return 0; + return mem_cache_zalloc(kernel_container.ktcb_cache); } +/* + * This version is boot-time only and it has no + * capability checking. Imagine the case where the + * initial capabilities are created. + */ +struct capability *boot_alloc_capability(void) +{ + return mem_cache_zalloc(kernel_container.cap_cache); +} + struct capability *alloc_capability(void) { + struct capability *cap; + + if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_CAPPOOL))) + return 0; + + if (capability_consume(cap, 1) < 0) + return 0; + return mem_cache_zalloc(kernel_container.cap_cache); } @@ -47,6 +101,15 @@ struct container *alloc_container(void) struct mutex_queue *alloc_user_mutex(void) { + struct capability *cap; + + if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_UMUTEX))) + return 0; + + if (capability_consume(cap, 1) < 0) + return 0; + return mem_cache_zalloc(kernel_container.mutex_cache); } @@ -57,21 +120,45 @@ void free_pgd(void *addr) void free_pmd(void *addr) { + struct capability *cap; + + BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_MAPPOOL))); + capability_free(cap, 1); + BUG_ON(mem_cache_free(kernel_container.pmd_cache, addr) < 0); } void free_space(void *addr) { + struct capability *cap; + + BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_SPACEPOOL))); + capability_free(cap, 1); + BUG_ON(mem_cache_free(kernel_container.space_cache, addr) < 0); } void free_ktcb(void *addr) { + struct capability *cap; + + BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_THREADPOOL))); + capability_free(cap, 1); + BUG_ON(mem_cache_free(kernel_container.ktcb_cache, addr) < 0); } void free_capability(void *addr) { + struct capability *cap; + + BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_CAPPOOL))); + capability_free(cap, 1); + BUG_ON(mem_cache_free(kernel_container.cap_cache, addr) < 0); } @@ -82,6 +169,12 @@ void free_container(void *addr) void free_user_mutex(void *addr) { + struct capability *cap; + + BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + CAP_RTYPE_UMUTEX))); + capability_free(cap, 1); + BUG_ON(mem_cache_free(kernel_container.mutex_cache, addr) < 0); } @@ -161,7 +254,6 @@ int memcap_unmap_range(struct capability *cap, return 0; } - /* * Unmaps given memory range from the list of capabilities * by either shrinking, splitting or destroying the @@ -280,6 +372,7 @@ void init_kernel_container(struct kernel_container *kcont) cap_list_init(&kcont->virtmem_free); cap_list_init(&kcont->devmem_used); cap_list_init(&kcont->devmem_free); + cap_list_init(&kcont->other_caps); /* Set up total physical memory as single capability */ physmem = alloc_bootmem(sizeof(*physmem), 0); @@ -316,8 +409,6 @@ void init_kernel_container(struct kernel_container *kcont) /* * Copies cinfo structures to real capabilities for each pager. - * - * FIXME: Check if pager has enough resources to create its caps. */ int copy_pager_info(struct pager *pager, struct pager_info *pinfo) { @@ -330,7 +421,7 @@ int copy_pager_info(struct pager *pager, struct pager_info *pinfo) /* Copy all cinfo structures into real capabilities */ for (int i = 0; i < pinfo->ncaps; i++) { - cap = capability_create(); + cap = boot_capability_create(); cap_info = &pinfo->caps[i]; @@ -344,31 +435,27 @@ int copy_pager_info(struct pager *pager, struct pager_info *pinfo) } /* + * Check if pager has enough resources to create its caps: + * * Find pager's capability capability, check its * current use count and initialize it - * - * FIXME: We may want to do this capability checking - * in a more generic and straightforward place. */ + cap = capability_find_by_rtype(&pager->cap_list, + CAP_RTYPE_CAPPOOL); - list_foreach_struct(cap, &pager->cap_list.caps, list) { - /* Find capability pool capability */ - if ((cap->type & CAP_RTYPE_MASK) == CAP_RTYPE_CAPPOOL) { - /* Verify that we did not excess allocated */ - if (cap->size < pinfo->ncaps) { - printk("FATAL: Pager needs more capabilities " - "than allocated for initialization.\n"); - BUG(); - } - - /* - * Initialize used count. The rest of the checking - * of spending on this cap will be done in the - * cap syscall - */ - cap->used = pinfo->ncaps; - } + /* Verify that we did not excess allocated */ + if (!cap || cap->size < pinfo->ncaps) { + printk("FATAL: Pager needs more capabilities " + "than allocated for initialization.\n"); + BUG(); } + + /* + * Initialize used count. The rest of the spending + * checks on this cap will be done in the cap syscall + */ + cap->used = pinfo->ncaps; + return 0; } @@ -387,6 +474,17 @@ int copy_container_info(struct container *c, struct container_info *cinfo) return 0; } +/* + * TODO: + * + * Rearrange as follows: + * 1.) Move realloc_page_tables to before container_init_pagers() + * 2.) Set up dummy current cap_list_ptr right after real capability list + * has been created. -> Think! since there are many containers!!!!!!! + * 3.) At this point, no need to do alloc_boot_pmd(), and current->cap_list_ptr + * is valid, so no custom alloc functions. + */ + /* * Create real containers from compile-time created cinfo structures */ @@ -404,7 +502,6 @@ void setup_containers(struct boot_resources *bootres, * since we want to avoid allocating an uncertain * amount of memory from the boot allocators. */ - current_pgd = realloc_page_tables(); /* Create all containers but leave pagers */ for (int i = 0; i < bootres->nconts; i++) { @@ -417,6 +514,7 @@ void setup_containers(struct boot_resources *bootres, /* Add it to kernel container list */ kcont_insert_container(container, kcont); } + current_pgd = realloc_page_tables(); /* Initialize pagers */ container_init_pagers(kcont, current_pgd); @@ -697,7 +795,6 @@ int setup_boot_resources(struct boot_resources *bootres, return 0; } - /* * FIXME: Add error handling * @@ -717,13 +814,10 @@ int init_system_resources(struct kernel_container *kcont) init_resource_allocators(&bootres, kcont); - /* Create system containers */ setup_containers(&bootres, kcont); - /* Create real capabilities */ kcont_setup_capabilities(&bootres, kcont); return 0; } - diff --git a/src/generic/tcb.c b/src/generic/tcb.c index d593631..6010f82 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -42,9 +42,24 @@ void tcb_init(struct ktcb *new) waitqueue_head_init(&new->wqh_pager); } -struct ktcb *tcb_alloc(void) + +struct ktcb *tcb_alloc_init_use_capability(struct capability *cap) { - return alloc_ktcb(); + struct ktcb *tcb; + struct task_ids ids; + + if (!(tcb = alloc_ktcb_use_capability(cap))) + return 0; + + ids.tid = id_new(&kernel_container.ktcb_ids); + ids.tgid = L4_NILTHREAD; + ids.spid = L4_NILTHREAD; + + set_task_ids(tcb, &ids); + + tcb_init(tcb); + + return tcb; } struct ktcb *tcb_alloc_init(void) @@ -52,7 +67,7 @@ struct ktcb *tcb_alloc_init(void) struct ktcb *tcb; struct task_ids ids; - if (!(tcb = tcb_alloc())) + if (!(tcb = alloc_ktcb())) return 0; ids.tid = id_new(&kernel_container.ktcb_ids);