diff --git a/conts/posix/mm0/mm/init.c b/conts/posix/mm0/mm/init.c index 7ece723..c957b80 100644 --- a/conts/posix/mm0/mm/init.c +++ b/conts/posix/mm0/mm/init.c @@ -200,7 +200,7 @@ int read_pager_capabilities() caparray = alloc_bootmem(sizeof(struct capability) * ncaps, 0); /* Read all capabilities */ - if ((err = l4_capability_control(CAP_CONTROL_READ_CAPS, + if ((err = l4_capability_control(CAP_CONTROL_READ, 0, caparray)) < 0) { printf("l4_capability_control() reading of " "capabilities failed.\n Could not " diff --git a/include/l4/api/capability.h b/include/l4/api/capability.h index ba1933a..add7651 100644 --- a/include/l4/api/capability.h +++ b/include/l4/api/capability.h @@ -8,6 +8,11 @@ /* Capability syscall request types */ #define CAP_CONTROL_NCAPS 0 -#define CAP_CONTROL_READ_CAPS 1 +#define CAP_CONTROL_READ 1 +#define CAP_CONTROL_SHARE 2 + +#define CAP_SHARE_WITH_SPACE 1 +#define CAP_SHARE_WITH_CONTAINER 2 +#define CAP_SHARE_WITH_TGROUP 4 #endif /* __API_CAPABILITY_H__ */ diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index ac95cce..fa54f41 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -8,6 +8,16 @@ #include +/* + * Some resources that capabilities possess don't + * have unique ids or need ids at all. + * + * E.g. a threadpool does not need a resource id. + * A virtual memory capability does not require + * a resource id, its capid is sufficient. + */ +#define CAP_RESID_NONE -1 + /* * A capability is a unique representation of security * qualifiers on a particular resource. @@ -65,6 +75,7 @@ struct capability { }; struct cap_list { + int ktcb_refs; int ncaps; struct link caps; }; @@ -87,12 +98,43 @@ static inline void cap_list_insert(struct capability *cap, clist->ncaps++; } +/* Detach a whole list of capabilities from list head */ +static inline struct capability * +cap_list_detach(struct cap_list *clist) +{ + struct link *list = list_detach(&clist->caps); + clist->ncaps = 0; + return link_to_struct(list, struct capability, list); +} + +/* Attach a whole list of capabilities to list head */ +static inline void cap_list_attach(struct capability *cap, + struct cap_list *clist) +{ + /* Attach as if cap is the list and clist is the element */ + list_insert(&clist->caps, &cap->list); + + /* Count the number of caps attached */ + list_foreach_struct(cap, &clist->caps, list) + clist->ncaps++; +} + +static inline void cap_list_move(struct cap_list *to, + struct cap_list *from) +{ + struct capability *cap_head = cap_list_detach(from); + cap_list_attach(cap_head, to); +} + +struct ktcb; /* 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, +struct capability *capability_find_by_rtype(struct ktcb *task, unsigned int rtype); +struct capability *cap_list_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/container.h b/include/l4/generic/container.h index 4b86e5a..369119e 100644 --- a/include/l4/generic/container.h +++ b/include/l4/generic/container.h @@ -48,6 +48,7 @@ struct container { struct id_pool *space_id_pool; struct mutex_queue_head mutex_queue_head; /* Userspace mutex list */ + struct cap_list cap_list; /* Capabilities shared by whole container */ /* * Capabilities that apply to this container diff --git a/include/l4/generic/space.h b/include/l4/generic/space.h index 73d9c7f..1fc0a7a 100644 --- a/include/l4/generic/space.h +++ b/include/l4/generic/space.h @@ -24,6 +24,7 @@ #include #include #include +#include #include INC_SUBARCH(mm.h) /* A simple page table with a reference count */ @@ -32,6 +33,9 @@ struct address_space { struct link list; struct mutex lock; pgd_table_t *pgd; + + /* Capabilities shared by threads in same space */ + struct cap_list cap_list; int ktcb_refs; }; diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 4cfa5eb..19babdc 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -102,9 +102,9 @@ struct ktcb { struct container *container; struct pager *pager; - /* Capability list */ - struct cap_list *cap_list_ptr; + /* Capability lists */ struct cap_list cap_list; + struct cap_list tgr_cap_list; /* Fields for ipc rendezvous */ struct waitqueue_head wqh_recv; diff --git a/include/l4/lib/list.h b/include/l4/lib/list.h index d8186fa..9601e06 100644 --- a/include/l4/lib/list.h +++ b/include/l4/lib/list.h @@ -73,6 +73,18 @@ static inline void list_remove_init(struct link *link) link->prev = link; } +/* Cuts the whole list from head and returns it */ +static inline struct link *list_detach(struct link *head) +{ + struct link *next = head->next; + + /* Detach head from rest of the list */ + list_remove_init(head); + + /* Return detached list */ + return next; +} + static inline int list_empty(struct link *list) { return list->prev == list && list->next == list; diff --git a/src/api/capability.c b/src/api/capability.c index 4dabe4e..27f684c 100644 --- a/src/api/capability.c +++ b/src/api/capability.c @@ -10,10 +10,10 @@ #include #include #include +#include #include #include INC_API(syscall.h) - int read_task_capabilities(void *userbuf) { int copy_size, copy_offset = 0; @@ -28,24 +28,56 @@ int read_task_capabilities(void *userbuf) return -EPERM; /* Determine size of pager capabilities */ - copy_size = current->cap_list_ptr->ncaps * sizeof(*cap); + copy_size = current->cap_list.ncaps * sizeof(*cap); /* Validate user buffer for this copy size */ - if ((err = check_access((unsigned long)userbuf, copy_size, + if ((err = check_access((unsigned long)userbuf, + copy_size, MAP_USR_RW_FLAGS, 1)) < 0) return err; /* Copy capabilities from list to buffer */ - list_foreach_struct(cap, - ¤t->cap_list_ptr->caps, + list_foreach_struct(cap, ¤t->cap_list.caps, list) { - memcpy(userbuf + copy_offset, cap, sizeof(*cap)); + memcpy(userbuf + copy_offset, + cap, sizeof(*cap)); copy_offset += sizeof(*cap); } return 0; } +/* + * Currently shares _all_ capabilities of a task + * with a collection of threads + * + * FIXME: Check ownership for sharing. + */ +int capability_share(unsigned int share_flags) +{ + switch (share_flags) { + case CAP_SHARE_WITH_SPACE: + cap_list_move(¤t->space->cap_list, + ¤t->cap_list); + break; + case CAP_SHARE_WITH_CONTAINER: + cap_list_move(&curcont->cap_list, + ¤t->cap_list); + break; + case CAP_SHARE_WITH_TGROUP: { + struct ktcb *tgr_leader; + + BUG_ON(!(tgr_leader = tcb_find(current->tgid))); + cap_list_move(&tgr_leader->cap_list, + ¤t->cap_list); + break; + } + default: + return -EINVAL; + } + return 0; +} + /* * Read, manipulate capabilities. Currently only capability read support. */ @@ -59,19 +91,22 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf) if (current != current->pager->tcb) return -EPERM; - if ((err = check_access((unsigned long)userbuf, sizeof(int), + if ((err = check_access((unsigned long)userbuf, + sizeof(int), MAP_USR_RW_FLAGS, 1)) < 0) return err; /* Copy ncaps value */ - *((int *)userbuf) = current->cap_list_ptr->ncaps; + *((int *)userbuf) = current->cap_list.ncaps; break; /* Return all capabilities as an array of capabilities */ - case CAP_CONTROL_READ_CAPS: + case CAP_CONTROL_READ: err = read_task_capabilities(userbuf); break; - + case CAP_CONTROL_SHARE: + err = capability_share(flags); + break; default: /* Invalid request id */ return -EINVAL; @@ -80,7 +115,42 @@ int sys_capability_control(unsigned int req, unsigned int flags, void *userbuf) } +#if 0 +int capability_grant(struct ktcb *recv, struct ktcb *send, struct capability *cap) +{ + list_del(&cap->list); + list_add(&cap->list, &recv->cap_list); +} +struct cap_split_desc { + unsigned int valid; + unsigned int access; + unsigned long size; + unsigned long start; + unsigned long end; +}; +struct capability *capability_diff(struct capability *cap, struct cap_split_desc *split) +{ + if (split->valid & FIELD_TO_BIT(struct cap_split_desc, access)) { + new->access = orig->access & split->access; + orig->access &= ~split->access; + } + if (split->valid & FIELD_TO_BIT(struct cap_split_desc, size)) { + new->size = orig->size - split->size; + orig->size -= split->size; + } + if (split->valid & FIELD_TO_BIT(struct cap_split_desc, start)) { + memcap_unmap(cap, split->start, split->end); + new->size = orig->size - split->size; + orig->size -= split->size; + } +} + +int capability_split(struct ktcb *recv, struct ktcb *send, struct capability *cap, struct cap_split_desc *split) +{ + capability_diff(orig, new, split); +} +#endif diff --git a/src/generic/capability.c b/src/generic/capability.c index ba21dc4..b2d7ef0 100644 --- a/src/generic/capability.c +++ b/src/generic/capability.c @@ -5,7 +5,9 @@ */ #include #include +#include #include +#include #include #include @@ -53,16 +55,99 @@ int capability_free(struct capability *cap, int quantity) return 0; } +struct capability *cap_list_find_by_rtype(struct cap_list *cap_list, + unsigned int rtype) +{ + struct capability *cap; + + list_foreach_struct(cap, &cap_list->caps, list) + if (cap_rtype(cap) == rtype) + return cap; + + return 0; +} + /* * Find a capability from a list by its resource type + * Search all capability lists that task is allowed. + * + * FIXME: + * Tasks won't always search for a capability randomly. Consider + * mutexes, if a mutex is freed, it needs to be accounted to private + * pool first if that is not full, because freeing it into shared + * pool may lose the mutex right to another task. */ -struct capability *capability_find_by_rtype(struct cap_list *clist, +struct capability *capability_find_by_rtype(struct ktcb *task, unsigned int rtype) { struct capability *cap; - list_foreach_struct(cap, &clist->caps, list) - if ((cap->type & CAP_RTYPE_MASK) == rtype) + /* Search task's own list */ + list_foreach_struct(cap, &task->cap_list.caps, list) + if (cap_rtype(cap) == rtype) return cap; + + /* Search space list */ + list_foreach_struct(cap, &task->space->cap_list.caps, list) + if (cap_rtype(cap) == rtype) + return cap; + + /* Search thread group list */ + list_foreach_struct(cap, &task->tgr_cap_list.caps, list) + if (cap_rtype(cap) == rtype) + return cap; + + /* Search container list */ + list_foreach_struct(cap, &task->container->cap_list.caps, list) + if (cap_rtype(cap) == rtype) + return cap; + return 0; } + +/* + * FIXME: + * + * Capability resource ids + * + * Currently the kernel cinfo has no resource id field. This is + * because resources are dynamically assigned an id at run-time. + * + * However, this prevents the user to specify capabilities on + * particular resources since resources aren't id-able at + * configuration time. There's also no straightforward way to + * determine which id was meant at run-time. + * + * As a solution, resources that are id-able and that are targeted + * by capabilities at configuration time should be assigned static + * ids at configuration time. Any other id-able resources that are + * subject to capabilities by run-time sharing/delegation/derivation + * etc. should be assigned their ids dynamically. + * + * Example: + * + * A capability to ipc to a particular container. + * + * When this capability is defined at configuration time, it is only + * meaningful if the container id is also supplied statically. + * + * If a pager later on generates a capability to ipc to a thread + * that it created at run-time, and grant it to another container's + * pager, (say a container thread would like to talk to another + * container's thread) it should assign the dynamically assigned + * target thread id as the capability resource id and hand it over. + */ +int capability_set_resource_id(struct capability *cap) +{ + /* Identifiable resources */ + switch(cap_rtype(cap)) { + case CAP_RTYPE_THREAD: + case CAP_RTYPE_TGROUP: + case CAP_RTYPE_SPACE: + case CAP_RTYPE_CONTAINER: + case CAP_RTYPE_UMUTEX: + break; + } + return 0; +} + diff --git a/src/generic/container.c b/src/generic/container.c index 69cfbd1..c8fa5b9 100644 --- a/src/generic/container.c +++ b/src/generic/container.c @@ -22,6 +22,7 @@ int container_init(struct container *c) init_address_space_list(&c->space_list); init_ktcb_list(&c->ktcb_list); init_mutex_queue_head(&c->mutex_queue_head); + cap_list_init(&c->cap_list); /* Init pager structs */ for (int i = 0; i < CONFIG_MAX_PAGERS_USED; i++) @@ -73,15 +74,14 @@ int init_pager(struct pager *pager, struct ktcb *task; struct address_space *space; int first = !!current_pgd; + struct capability *cap; /* - * Initialize dummy current capability list pointer - * so that capability accounting can be done as normal - * - * FYI: We're still on bootstack instead of current's - * real stack. Hence this is a dummy. + * Set up dummy current cap_list so that cap accounting + * can be done to this pager. Note, that we're still on + * bootstack. */ - current->cap_list_ptr = &pager->cap_list; + cap_list_move(¤t->cap_list, &pager->cap_list); /* New ktcb allocation is needed */ task = tcb_alloc_init(); @@ -112,7 +112,25 @@ int init_pager(struct pager *pager, task->pager = pager; task->pagerid = task->tid; task->container = cont; - task->cap_list_ptr = &pager->cap_list; + + /* Initialize uninitialized capability fields while on dummy */ + list_foreach_struct(cap, ¤t->cap_list.caps, list) { + /* Initialize owner */ + cap->owner = task->tid; + + /* + * Initialize resource id, if possible. + * Currently this is a temporary hack where + * we allow only container ids and _assume_ + * that container is pager's own container. + * + * See capability resource ids for info + */ + if (cap_rtype(cap) == CAP_RTYPE_CONTAINER) + cap->resid = task->container->cid; + else + cap->resid = CAP_RESID_NONE; + } printk("%s: Mapping %lu pages from 0x%lx to 0x%lx for %s\n", __KERNELNAME__, @@ -124,6 +142,9 @@ int init_pager(struct pager *pager, page_align_up(pager->memsize), MAP_USR_DEFAULT_FLAGS, TASK_PGD(task)); + /* Move capability list from dummy to task's cap list */ + cap_list_move(&task->cap_list, ¤t->cap_list); + /* Initialize task scheduler parameters */ sched_init_task(task, TASK_PRIO_PAGER); diff --git a/src/generic/resource.c b/src/generic/resource.c index 267dccb..514619e 100644 --- a/src/generic/resource.c +++ b/src/generic/resource.c @@ -24,7 +24,7 @@ pmd_table_t *alloc_pmd(void) { struct capability *cap; - if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + if (!(cap = capability_find_by_rtype(current, CAP_RTYPE_MAPPOOL))) return 0; @@ -38,7 +38,7 @@ struct address_space *alloc_space(void) { struct capability *cap; - if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + if (!(cap = capability_find_by_rtype(current, CAP_RTYPE_SPACEPOOL))) return 0; @@ -60,7 +60,7 @@ struct ktcb *alloc_ktcb(void) { struct capability *cap; - if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + if (!(cap = capability_find_by_rtype(current, CAP_RTYPE_THREADPOOL))) return 0; @@ -73,7 +73,8 @@ struct ktcb *alloc_ktcb(void) /* * This version is boot-time only and it has no * capability checking. Imagine the case where the - * initial capabilities are created. + * initial capabilities are created and there is no + * capability to check this allocation. */ struct capability *boot_alloc_capability(void) { @@ -84,7 +85,7 @@ struct capability *alloc_capability(void) { struct capability *cap; - if (!(cap = capability_find_by_rtype(current->cap_list_ptr, + if (!(cap = capability_find_by_rtype(current, CAP_RTYPE_CAPPOOL))) return 0; @@ -103,7 +104,7 @@ struct mutex_queue *alloc_user_mutex(void) { struct capability *cap; - if (!(cap = capability_find_by_rtype(current->pager->tcb->cap_list_ptr, + if (!(cap = capability_find_by_rtype(current, CAP_RTYPE_MUTEXPOOL))) return 0; @@ -122,7 +123,7 @@ void free_pmd(void *addr) { struct capability *cap; - BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + BUG_ON(!(cap = capability_find_by_rtype(current, CAP_RTYPE_MAPPOOL))); capability_free(cap, 1); @@ -133,7 +134,7 @@ void free_space(void *addr) { struct capability *cap; - BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + BUG_ON(!(cap = capability_find_by_rtype(current, CAP_RTYPE_SPACEPOOL))); capability_free(cap, 1); @@ -144,7 +145,7 @@ void free_ktcb(void *addr) { struct capability *cap; - BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + BUG_ON(!(cap = capability_find_by_rtype(current, CAP_RTYPE_THREADPOOL))); capability_free(cap, 1); @@ -155,7 +156,7 @@ void free_capability(void *addr) { struct capability *cap; - BUG_ON(!(cap = capability_find_by_rtype(current->cap_list_ptr, + BUG_ON(!(cap = capability_find_by_rtype(current, CAP_RTYPE_CAPPOOL))); capability_free(cap, 1); @@ -171,7 +172,7 @@ void free_user_mutex(void *addr) { struct capability *cap; - BUG_ON(!(cap = capability_find_by_rtype(current->pager->tcb->cap_list_ptr, + BUG_ON(!(cap = capability_find_by_rtype(current, CAP_RTYPE_MUTEXPOOL))); capability_free(cap, 1); @@ -399,6 +400,7 @@ void init_kernel_resources(struct kernel_resources *kres) memcap_unmap(&kres->physmem_free, kernel_area->start, kernel_area->end); + /* Initialize zombie pager list */ init_ktcb_list(&kres->zombie_list); /* TODO: @@ -443,8 +445,8 @@ int copy_pager_info(struct pager *pager, struct pager_info *pinfo) * Find pager's capability capability, check its * current use count and initialize it */ - cap = capability_find_by_rtype(&pager->cap_list, - CAP_RTYPE_CAPPOOL); + cap = cap_list_find_by_rtype(&pager->cap_list, + CAP_RTYPE_CAPPOOL); /* Verify that we did not excess allocated */ if (!cap || cap->size < pinfo->ncaps) { @@ -497,6 +499,14 @@ void setup_containers(struct boot_resources *bootres, */ current_pgd = realloc_page_tables(); + /* Move it back + * + * FIXME: Merge until this part of code with + * kres_setup_capabilities and init_system_resources + * it doesn't look good. + */ + cap_list_move(&kres->non_memory_caps, ¤t->cap_list); + /* Create all containers but leave pagers */ for (int i = 0; i < bootres->nconts; i++) { /* Allocate & init container */ @@ -575,7 +585,7 @@ void kres_setup_capabilities(struct boot_resources *bootres, cap_list_insert(cap, &kres->non_memory_caps); /* Set up dummy current cap-list for below functions to use */ - current->cap_list_ptr = &kres->non_memory_caps; + cap_list_move(¤t->cap_list, &kres->non_memory_caps); copy_boot_capabilities(&kres->physmem_used); copy_boot_capabilities(&kres->physmem_free); @@ -836,8 +846,6 @@ int setup_boot_resources(struct boot_resources *bootres, } /* - * FIXME: Add error handling - * * Initializes all system resources and handling of those * resources. First descriptions are done by allocating from * boot memory, once memory caches are initialized, boot @@ -845,7 +853,6 @@ int setup_boot_resources(struct boot_resources *bootres, */ int init_system_resources(struct kernel_resources *kres) { - /* FIXME: Count kernel resources */ struct boot_resources bootres; memset(&bootres, 0, sizeof(bootres)); diff --git a/src/generic/space.c b/src/generic/space.c index c1e7173..5aa2d28 100644 --- a/src/generic/space.c +++ b/src/generic/space.c @@ -107,6 +107,7 @@ struct address_space *address_space_create(struct address_space *orig) /* Initialize space structure */ link_init(&space->list); + cap_list_init(&space->cap_list); mutex_init(&space->lock); space->pgd = pgd; diff --git a/src/generic/tcb.c b/src/generic/tcb.c index 16f68f6..6a5aa9b 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -30,7 +30,8 @@ void tcb_init(struct ktcb *new) link_init(&new->task_list); mutex_init(&new->thread_control_lock); - link_init(&new->cap_list.caps); + cap_list_init(&new->cap_list); + cap_list_init(&new->tgr_cap_list); /* Initialise task's scheduling state and parameters. */ sched_init_task(new, TASK_PRIO_NORMAL); diff --git a/tools/replace_words b/tools/replace_words index 3cbfae4..7c1b9e0 100755 --- a/tools/replace_words +++ b/tools/replace_words @@ -5,18 +5,20 @@ replacement=(w x y z) # Test that we have both arguments if [ -z "$1" ]; then - echo Usage: replace_words ORIGINAL REPLACEMENT + echo Usage: replace_words DIRNAME ORIGINAL REPLACEMENT exit fi for ((i=0;i<1;i++)); do - orig=${original[$i]} - repl=${replacement[$i]} - echo $orig to $repl + #orig=${original[$i]} + #repl=${replacement[$i]} + orig=$2 + repl=$3 for filename in `find $1 -name '*.[ch]'` do + echo Replacing $orig with $repl in $filename sed -i -e "s/$orig/$repl/g" $filename done done