diff --git a/conts/test/SConscript b/conts/test/SConscript index 4f5e381..64c707d 100644 --- a/conts/test/SConscript +++ b/conts/test/SConscript @@ -32,7 +32,7 @@ linker_lds = Command('include/linker.lds', 'include/linker.lds.in', generate_lin container_h = Command('include/container.h', 'include/container.h.in', generate_container_h) -src = [Glob('*.[cS]') + Glob('src/*.[cS]')] +src = [Glob('*.[cS]') + Glob('src/*.[cS]') + Glob('src/arch/*.[cS]')] env.Append(LINKFLAGS = ['-T' + linker_lds[0].path, '-u_start']) env.Append(CPPPATH = [CONTAINER_INCLUDE]) diff --git a/conts/test/hello.c b/conts/test/hello.c deleted file mode 100644 index 054adc9..0000000 --- a/conts/test/hello.c +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Autogenerated hello world print function - */ - -#include -#include - -int print_hello_world(void) -{ - printf("%s: Hello world from %s!\n", __CONTAINER__, __CONTAINER_NAME__); - return 0; -} - diff --git a/conts/test/include/capability.h b/conts/test/include/capability.h new file mode 100644 index 0000000..84962e8 --- /dev/null +++ b/conts/test/include/capability.h @@ -0,0 +1,14 @@ +#ifndef __CAPABILITY_H__ +#define __CAPABILITY_H__ + +#include +#include +#include + +void print_capability(struct capability *cap); + +int read_pager_capabilities(); + + + +#endif /* __CAPABILITY_H__ */ diff --git a/conts/test/include/tests.h b/conts/test/include/tests.h new file mode 100644 index 0000000..43283a1 --- /dev/null +++ b/conts/test/include/tests.h @@ -0,0 +1,7 @@ +#ifndef __TESTS_H__ +#define __TESTS_H__ + + +int capability_test(void); + +#endif /* __TESTS_H__ */ diff --git a/conts/test/include/thread.h b/conts/test/include/thread.h new file mode 100644 index 0000000..f8cf59e --- /dev/null +++ b/conts/test/include/thread.h @@ -0,0 +1,18 @@ +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include +#include +#include +#include + + +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct task_ids *new_ids); + +/* For same space */ +#define STACK_SIZE 0x1000 + +#define THREADS_TOTAL 10 + +#endif /* __THREAD_H__ */ diff --git a/conts/test/main.c b/conts/test/main.c index 24f57bc..34331bc 100644 --- a/conts/test/main.c +++ b/conts/test/main.c @@ -1,342 +1,20 @@ /* - * Main function for this container + * Main function for all tests */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include - -static struct capability cap_array[30]; -static int total_caps; - -void print_capability(struct capability *cap) -{ - printf("Capability id:\t\t\t%d\n", cap->capid); - printf("Capability resource id:\t\t%d\n", cap->resid); - printf("Capability owner id:\t\t%d\n",cap->owner); - - switch (cap_type(cap)) { - case CAP_TYPE_TCTRL: - printf("Capability type:\t\t%s\n", "Thread Control"); - break; - case CAP_TYPE_EXREGS: - printf("Capability type:\t\t%s\n", "Exchange Registers"); - break; - case CAP_TYPE_MAP: - printf("Capability type:\t\t%s\n", "Map"); - break; - case CAP_TYPE_IPC: - printf("Capability type:\t\t%s\n", "Ipc"); - break; - case CAP_TYPE_UMUTEX: - printf("Capability type:\t\t%s\n", "Mutex"); - break; - case CAP_TYPE_QUANTITY: - printf("Capability type:\t\t%s\n", "Quantitative"); - break; - default: - printf("Capability type:\t\t%s\n", "Unknown"); - break; - } - - switch (cap_rtype(cap)) { - case CAP_RTYPE_THREAD: - printf("Capability resource type:\t%s\n", "Thread"); - break; - case CAP_RTYPE_TGROUP: - printf("Capability resource type:\t%s\n", "Thread Group"); - break; - case CAP_RTYPE_SPACE: - printf("Capability resource type:\t%s\n", "Space"); - break; - case CAP_RTYPE_CONTAINER: - printf("Capability resource type:\t%s\n", "Container"); - break; - case CAP_RTYPE_UMUTEX: - printf("Capability resource type:\t%s\n", "Mutex"); - break; - case CAP_RTYPE_VIRTMEM: - printf("Capability resource type:\t%s\n", "Virtual Memory"); - break; - case CAP_RTYPE_PHYSMEM: - printf("Capability resource type:\t%s\n", "Physical Memory"); - break; - case CAP_RTYPE_THREADPOOL: - printf("Capability resource type:\t%s\n", "Thread Pool"); - break; - case CAP_RTYPE_SPACEPOOL: - printf("Capability resource type:\t%s\n", "Space Pool"); - break; - case CAP_RTYPE_MUTEXPOOL: - printf("Capability resource type:\t%s\n", "Mutex Pool"); - break; - case CAP_RTYPE_MAPPOOL: - printf("Capability resource type:\t%s\n", "Map Pool (PMDS)"); - break; - case CAP_RTYPE_CPUPOOL: - printf("Capability resource type:\t%s\n", "Cpu Pool"); - break; - case CAP_RTYPE_CAPPOOL: - printf("Capability resource type:\t%s\n", "Capability Pool"); - break; - default: - printf("Capability resource type:\t%s\n", "Unknown"); - break; - } - printf("\n"); -} - -/* For same space */ -#define STACK_SIZE 0x1000 -#define THREADS_TOTAL 10 - -char stack[THREADS_TOTAL][STACK_SIZE] ALIGN(8); -char *__stack_ptr = &stack[1][0]; - -char utcb[THREADS_TOTAL][UTCB_SIZE] ALIGN(8); -char *__utcb_ptr = &utcb[1][0]; - -extern void setup_new_thread(void); - -int thread_create(int (*func)(void *), void *args, unsigned int flags, - struct task_ids *new_ids) -{ - struct task_ids ids; - struct exregs_data exregs; - int err; - - l4_getid(&ids); - - /* Shared space only */ - if (!(TC_SHARE_SPACE & flags)) { - printf("%s: This function allows only " - "shared space thread creation.\n", - __FUNCTION__); - return -EINVAL; - } - - /* Create thread */ - if ((err = l4_thread_control(THREAD_CREATE | flags, &ids)) < 0) - return err; - - /* Check if more stack/utcb available */ - if ((unsigned long)__utcb_ptr == - (unsigned long)&utcb[THREADS_TOTAL][0]) - return -ENOMEM; - if ((unsigned long)__stack_ptr == - (unsigned long)&stack[THREADS_TOTAL][0]) - return -ENOMEM; - - /* First word of new stack is arg */ - ((unsigned long *)__stack_ptr)[-1] = (unsigned long)args; - - /* Second word of new stack is function address */ - ((unsigned long *)__stack_ptr)[-2] = (unsigned long)func; - - /* Setup new thread pc, sp, utcb */ - memset(&exregs, 0, sizeof(exregs)); - exregs_set_stack(&exregs, (unsigned long)__stack_ptr); - exregs_set_utcb(&exregs, (unsigned long)__utcb_ptr); - exregs_set_pc(&exregs, (unsigned long)setup_new_thread); - - if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) - return err; - - /* Update utcb, stack pointers */ - __stack_ptr += STACK_SIZE; - __utcb_ptr += UTCB_SIZE; - - /* Start the new thread */ - if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0) - return err; - - memcpy(new_ids, &ids, sizeof(ids)); - - return 0; -} - -int read_pager_capabilities() -{ - int ncaps; - int err; - - /* Read number of capabilities */ - if ((err = l4_capability_control(CAP_CONTROL_NCAPS, - 0, &ncaps)) < 0) { - printf("l4_capability_control() reading # of" - " capabilities failed.\n Could not " - "complete CAP_CONTROL_NCAPS request.\n"); - BUG(); - } - total_caps = ncaps; - - /* Read all capabilities */ - if ((err = l4_capability_control(CAP_CONTROL_READ, - 0, cap_array)) < 0) { - printf("l4_capability resource_control() reading of " - "capabilities failed.\n Could not " - "complete CAP_CONTROL_READ_CAPS request.\n"); - BUG(); - } - - for (int i = 0; i < total_caps; i++) - print_capability(&cap_array[i]); - - return 0; -} - -int result = 1; - -int simple_pager_thread(void *arg) -{ - int err; - int res = *(int *)arg; - struct task_ids ids; - int testres; - - l4_getid(&ids); - - //printf("Thread spawned from pager, " - // "trying to create new thread.\n"); - err = l4_thread_control(THREAD_CREATE | - TC_SHARE_SPACE | - TC_AS_PAGER, &ids); - - if (res == 0) - if (err == -ENOCAP || - err == -ENOMEM) { - //printf("Creation failed with %d " - // "as expected.\n", err); - testres = 0; - } else { - printf("Creation was supposed to fail " - "with %d or %d, but err = %d\n", - -ENOMEM, -ENOCAP, err); - testres = -1; - } - else - if (err == 0) { - // printf("Creation succeeded as expected.\n"); - testres = 0; - } else { - printf("Creation was supposed to succeed, " - "but err = %d\n", err); - testres = -1; - } - - /* Destroy thread we created */ - if (err == 0 && - res == 0) - l4_thread_control(THREAD_DESTROY, &ids); - - result = testres; - - /* Destroy self */ - l4_getid(&ids); - l4_thread_control(THREAD_DESTROY, &ids); - - return 0; -} - -int wait_check_test(void) -{ - /* Wait for thread to finish */ - while (result > 0) - ; - //l4_thread_switch(0); - - if (result != 0) { - printf("Top-level test has failed\n"); - return -1; - } - result = 1; - return 0; -} +#include +#include +#include int main(void) { - int err; - struct task_ids ids; - int TEST_MUST_FAIL = 0; - int TEST_MUST_SUCCEED = 1; printf("%s: Container %s started\n", __CONTAINER__, __CONTAINER_NAME__); - /* Read pager capabilities */ - read_pager_capabilities(); + capability_test(); - /* - * Create new thread that will attempt - * a pager privileged operation - */ - if ((err = thread_create(simple_pager_thread, - &TEST_MUST_FAIL, - TC_SHARE_SPACE | - TC_AS_PAGER, &ids)) < 0) { - printf("Top-level simple_pager creation failed.\n"); - goto out_err; - } - - /* Wait for test to finish and check result */ - if (wait_check_test() < 0) - goto out_err; - -#if 0 - /* Destroy test thread */ - if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { - printf("Destruction of top-level simple_pager failed.\n"); - BUG(); - } -#endif - - /* - * Share operations with the same thread - * group - */ - if ((err = l4_capability_control(CAP_CONTROL_SHARE, - CAP_SHARE_GROUP, 0)) < 0) { - printf("Sharing capability with thread group failed.\n"); - goto out_err; - } - - /* - * Create new thread that will attempt a pager privileged - * operation. This should succeed as we shared caps with - * the thread group. - */ - if ((err = thread_create(simple_pager_thread, - &TEST_MUST_SUCCEED, - TC_SHARE_SPACE | - TC_SHARE_GROUP, &ids)) < 0) { - printf("Top-level simple_pager creation failed.\n"); - goto out_err; - } - - /* Wait for test to finish and check result */ - if (wait_check_test() < 0) - goto out_err; - -#if 0 - /* Destroy test thread */ - if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { - printf("Destruction of top-level simple_pager failed.\n"); - BUG(); - } -#endif - - printf("Capability Sharing Test -- PASSED --\n"); - - return 0; - -out_err: - printf("Capability Sharing Test -- FAILED --\n"); return 0; } + diff --git a/conts/test/src/arch b/conts/test/src/arch new file mode 120000 index 0000000..85405c2 --- /dev/null +++ b/conts/test/src/arch @@ -0,0 +1 @@ +arch-arm \ No newline at end of file diff --git a/conts/test/src/arch-arm/new_thread.S b/conts/test/src/arch-arm/new_thread.S new file mode 100644 index 0000000..2dbaaf2 --- /dev/null +++ b/conts/test/src/arch-arm/new_thread.S @@ -0,0 +1,11 @@ +#include + + +BEGIN_PROC(setup_new_thread) + ldr r0, [sp, #-4]! @ Load first argument. + mov lr, pc @ Save return address + ldr pc, [sp, #-4]! @ Load function pointer from stack +new_thread_exit: + b new_thread_exit @ We infinitely loop for now. +END_PROC(setup_new_thread) + diff --git a/conts/test/src/capability.c b/conts/test/src/capability.c new file mode 100644 index 0000000..497956a --- /dev/null +++ b/conts/test/src/capability.c @@ -0,0 +1,114 @@ +#include +#include +#include + +static struct capability cap_array[30]; +static int total_caps; + +void print_capability(struct capability *cap) +{ + printf("Capability id:\t\t\t%d\n", cap->capid); + printf("Capability resource id:\t\t%d\n", cap->resid); + printf("Capability owner id:\t\t%d\n",cap->owner); + + switch (cap_type(cap)) { + case CAP_TYPE_TCTRL: + printf("Capability type:\t\t%s\n", "Thread Control"); + break; + case CAP_TYPE_EXREGS: + printf("Capability type:\t\t%s\n", "Exchange Registers"); + break; + case CAP_TYPE_MAP: + printf("Capability type:\t\t%s\n", "Map"); + break; + case CAP_TYPE_IPC: + printf("Capability type:\t\t%s\n", "Ipc"); + break; + case CAP_TYPE_UMUTEX: + printf("Capability type:\t\t%s\n", "Mutex"); + break; + case CAP_TYPE_QUANTITY: + printf("Capability type:\t\t%s\n", "Quantitative"); + break; + default: + printf("Capability type:\t\t%s\n", "Unknown"); + break; + } + + switch (cap_rtype(cap)) { + case CAP_RTYPE_THREAD: + printf("Capability resource type:\t%s\n", "Thread"); + break; + case CAP_RTYPE_TGROUP: + printf("Capability resource type:\t%s\n", "Thread Group"); + break; + case CAP_RTYPE_SPACE: + printf("Capability resource type:\t%s\n", "Space"); + break; + case CAP_RTYPE_CONTAINER: + printf("Capability resource type:\t%s\n", "Container"); + break; + case CAP_RTYPE_UMUTEX: + printf("Capability resource type:\t%s\n", "Mutex"); + break; + case CAP_RTYPE_VIRTMEM: + printf("Capability resource type:\t%s\n", "Virtual Memory"); + break; + case CAP_RTYPE_PHYSMEM: + printf("Capability resource type:\t%s\n", "Physical Memory"); + break; + case CAP_RTYPE_THREADPOOL: + printf("Capability resource type:\t%s\n", "Thread Pool"); + break; + case CAP_RTYPE_SPACEPOOL: + printf("Capability resource type:\t%s\n", "Space Pool"); + break; + case CAP_RTYPE_MUTEXPOOL: + printf("Capability resource type:\t%s\n", "Mutex Pool"); + break; + case CAP_RTYPE_MAPPOOL: + printf("Capability resource type:\t%s\n", "Map Pool (PMDS)"); + break; + case CAP_RTYPE_CPUPOOL: + printf("Capability resource type:\t%s\n", "Cpu Pool"); + break; + case CAP_RTYPE_CAPPOOL: + printf("Capability resource type:\t%s\n", "Capability Pool"); + break; + default: + printf("Capability resource type:\t%s\n", "Unknown"); + break; + } + printf("\n"); +} + +int read_pager_capabilities() +{ + int ncaps; + int err; + + /* Read number of capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_NCAPS, + 0, &ncaps)) < 0) { + printf("l4_capability_control() reading # of" + " capabilities failed.\n Could not " + "complete CAP_CONTROL_NCAPS request.\n"); + BUG(); + } + total_caps = ncaps; + + /* Read all capabilities */ + if ((err = l4_capability_control(CAP_CONTROL_READ, + 0, cap_array)) < 0) { + printf("l4_capability resource_control() reading of " + "capabilities failed.\n Could not " + "complete CAP_CONTROL_READ_CAPS request.\n"); + BUG(); + } + + for (int i = 0; i < total_caps; i++) + print_capability(&cap_array[i]); + + return 0; +} + diff --git a/conts/test/src/captest.c b/conts/test/src/captest.c new file mode 100644 index 0000000..10d9b51 --- /dev/null +++ b/conts/test/src/captest.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +static int result = 1; + +int simple_pager_thread(void *arg) +{ + int err; + int res = *(int *)arg; + struct task_ids ids; + int testres; + + l4_getid(&ids); + + //printf("Thread spawned from pager, " + // "trying to create new thread.\n"); + err = l4_thread_control(THREAD_CREATE | + TC_SHARE_SPACE | + TC_AS_PAGER, &ids); + + if (res == 0) + if (err == -ENOCAP || + err == -ENOMEM) { + //printf("Creation failed with %d " + // "as expected.\n", err); + testres = 0; + } else { + printf("Creation was supposed to fail " + "with %d or %d, but err = %d\n", + -ENOMEM, -ENOCAP, err); + testres = -1; + } + else + if (err == 0) { + // printf("Creation succeeded as expected.\n"); + testres = 0; + } else { + printf("Creation was supposed to succeed, " + "but err = %d\n", err); + testres = -1; + } + + /* Destroy thread we created */ + if (err == 0 && + res == 0) + l4_thread_control(THREAD_DESTROY, &ids); + + result = testres; + + /* Destroy self */ + l4_getid(&ids); + l4_thread_control(THREAD_DESTROY, &ids); + + return 0; +} + +int wait_check_test(void) +{ + /* Wait for thread to finish */ + while (result > 0) + ; + //l4_thread_switch(0); + + if (result != 0) { + printf("Top-level test has failed\n"); + return -1; + } + result = 1; + return 0; +} + +int capability_test(void) +{ + int err; + struct task_ids ids; + int TEST_MUST_FAIL = 0; + int TEST_MUST_SUCCEED = 1; + + /* Read pager capabilities */ + read_pager_capabilities(); + + /* + * Create new thread that will attempt + * a pager privileged operation + */ + if ((err = thread_create(simple_pager_thread, + &TEST_MUST_FAIL, + TC_SHARE_SPACE | + TC_AS_PAGER, &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } + + /* Wait for test to finish and check result */ + if (wait_check_test() < 0) + goto out_err; + +#if 0 + /* Destroy test thread */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + printf("Destruction of top-level simple_pager failed.\n"); + BUG(); + } +#endif + + /* + * Share operations with the same thread + * group + */ + if ((err = l4_capability_control(CAP_CONTROL_SHARE, + CAP_SHARE_GROUP, 0)) < 0) { + printf("Sharing capability with thread group failed.\n"); + goto out_err; + } + + /* + * Create new thread that will attempt a pager privileged + * operation. This should succeed as we shared caps with + * the thread group. + */ + if ((err = thread_create(simple_pager_thread, + &TEST_MUST_SUCCEED, + TC_SHARE_SPACE | + TC_SHARE_GROUP, &ids)) < 0) { + printf("Top-level simple_pager creation failed.\n"); + goto out_err; + } + + /* Wait for test to finish and check result */ + if (wait_check_test() < 0) + goto out_err; + +#if 0 + /* Destroy test thread */ + if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) { + printf("Destruction of top-level simple_pager failed.\n"); + BUG(); + } +#endif + + printf("Capability Sharing Test -- PASSED --\n"); + + return 0; + +out_err: + printf("Capability Sharing Test -- FAILED --\n"); + return 0; +} diff --git a/conts/test/src/thread.c b/conts/test/src/thread.c new file mode 100644 index 0000000..6235dfb --- /dev/null +++ b/conts/test/src/thread.c @@ -0,0 +1,73 @@ +/* + * Thread creation userspace helpers + * + * Copyright (C) 2009 B Labs Ltd. + */ +#include +#include + +char stack[THREADS_TOTAL][STACK_SIZE] ALIGN(8); +char *__stack_ptr = &stack[1][0]; + +char utcb[THREADS_TOTAL][UTCB_SIZE] ALIGN(8); +char *__utcb_ptr = &utcb[1][0]; + +extern void setup_new_thread(void); + +int thread_create(int (*func)(void *), void *args, unsigned int flags, + struct task_ids *new_ids) +{ + struct task_ids ids; + struct exregs_data exregs; + int err; + + l4_getid(&ids); + + /* Shared space only */ + if (!(TC_SHARE_SPACE & flags)) { + printf("%s: This function allows only " + "shared space thread creation.\n", + __FUNCTION__); + return -EINVAL; + } + + /* Create thread */ + if ((err = l4_thread_control(THREAD_CREATE | flags, &ids)) < 0) + return err; + + /* Check if more stack/utcb available */ + if ((unsigned long)__utcb_ptr == + (unsigned long)&utcb[THREADS_TOTAL][0]) + return -ENOMEM; + if ((unsigned long)__stack_ptr == + (unsigned long)&stack[THREADS_TOTAL][0]) + return -ENOMEM; + + /* First word of new stack is arg */ + ((unsigned long *)__stack_ptr)[-1] = (unsigned long)args; + + /* Second word of new stack is function address */ + ((unsigned long *)__stack_ptr)[-2] = (unsigned long)func; + + /* Setup new thread pc, sp, utcb */ + memset(&exregs, 0, sizeof(exregs)); + exregs_set_stack(&exregs, (unsigned long)__stack_ptr); + exregs_set_utcb(&exregs, (unsigned long)__utcb_ptr); + exregs_set_pc(&exregs, (unsigned long)setup_new_thread); + + if ((err = l4_exchange_registers(&exregs, ids.tid)) < 0) + return err; + + /* Update utcb, stack pointers */ + __stack_ptr += STACK_SIZE; + __utcb_ptr += UTCB_SIZE; + + /* Start the new thread */ + if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0) + return err; + + memcpy(new_ids, &ids, sizeof(ids)); + + return 0; +} + diff --git a/include/l4/api/thread.h b/include/l4/api/thread.h index 31d6ba8..0338b4c 100644 --- a/include/l4/api/thread.h +++ b/include/l4/api/thread.h @@ -1,5 +1,5 @@ -#ifndef __THREAD_H__ -#define __THREAD_H__ +#ifndef __API_THREAD_H__ +#define __API_THREAD_H__ #define THREAD_ACTION_MASK 0x000F #define THREAD_CREATE 0x0000 @@ -19,4 +19,4 @@ #define TC_SHARE_PAGER 0x0400 /* New thread, shared pager */ #define TC_AS_PAGER 0x0800 /* Set new thread as child */ -#endif /* __THREAD_H__ */ +#endif /* __API_THREAD_H__ */ diff --git a/include/l4/generic/capability.h b/include/l4/generic/capability.h index fa54f41..90f15b1 100644 --- a/include/l4/generic/capability.h +++ b/include/l4/generic/capability.h @@ -3,8 +3,8 @@ * * Copyright (C) 2009 Bahadir Balban */ -#ifndef __CAPABILITY_H__ -#define __CAPABILITY_H__ +#ifndef __GENERIC_CAPABILITY_H__ +#define __GENERIC_CAPABILITY_H__ #include @@ -245,4 +245,4 @@ struct capability cap_cpuprio = { #endif -#endif /* __CAPABILITY_H__ */ +#endif /* __GENERIC_CAPABILITY_H__ */ diff --git a/include/l4/generic/thread.h b/include/l4/generic/thread.h index a2779a9..22f0c01 100644 --- a/include/l4/generic/thread.h +++ b/include/l4/generic/thread.h @@ -1,8 +1,8 @@ /* * Copyright (C) 2007 Bahadir Balban */ -#ifndef __THREAD_H__ -#define __THREAD_H__ +#ifndef __GENERIC_THREAD_H__ +#define __GENERIC_THREAD_H__ #include @@ -14,4 +14,4 @@ int thread_id_del(int tid); void task_destroy_current(void); void task_make_zombie(struct ktcb *task); -#endif /* __THREAD_H__ */ +#endif /* __GENERIC_THREAD_H__ */ diff --git a/src/api/SConscript b/src/api/SConscript index fc9de94..819acb3 100644 --- a/src/api/SConscript +++ b/src/api/SConscript @@ -3,7 +3,7 @@ Import('env') Import('symbols') # The set of source files associated with this SConscript file. -src_local = ['kip.c', 'syscall.c', 'thread.c', 'ipc.c', 'space.c', 'mutex.c', 'capability.c'] +src_local = ['kip.c', 'syscall.c', 'thread.c', 'ipc.c', 'map.c', 'mutex.c', 'capability.c', 'exregs.c'] obj = env.Object(src_local) diff --git a/src/api/capability.c b/src/api/capability.c index 9ed1ecb..1e7ff4a 100644 --- a/src/api/capability.c +++ b/src/api/capability.c @@ -158,19 +158,6 @@ struct cap_split_desc { 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; - } } @@ -178,4 +165,28 @@ int capability_split(struct ktcb *recv, struct ktcb *send, struct capability *ca { capability_diff(orig, new, split); } + +int capability_split(struct capability *orig, struct capability *diff, unsigned int valid) +{ + struct capability *new; + + if (!(new = alloc_capability())) + return -ENOMEM; + + if (valid & FIELD_TO_BIT(struct capability, access)) { + new->access = orig->access & diff->access; + orig->access &= ~diff->access; + } + if (valid & FIELD_TO_BIT(struct capability, size)) { + new->size = orig->size - diff->size; + orig->size -= diff->size; + } + if (valid & FIELD_TO_BIT(struct capability, start)) { + /* This gets complicated, may return -ENOSYS for now */ + memcap_unmap(cap, diff->start, diff->end); + new->size = orig->size - split->size; + orig->size -= split->size; + } +} + #endif diff --git a/src/api/exregs.c b/src/api/exregs.c new file mode 100644 index 0000000..43fc13d --- /dev/null +++ b/src/api/exregs.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Copy each register to task's context if its valid bit is set */ +void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs) +{ + task_context_t *context = &task->context; + + if (!exregs->valid_vect) + goto flags; + /* + * NOTE: + * We don't care if register values point at invalid addresses + * since memory protection would prevent any kernel corruption. + * We do however, make sure spsr is not modified + */ + + /* Check register valid bit and copy registers */ + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r0)) + context->r0 = exregs->context.r0; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r1)) + context->r1 = exregs->context.r1; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r2)) + context->r2 = exregs->context.r2; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r3)) + context->r3 = exregs->context.r3; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r4)) + context->r4 = exregs->context.r4; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r5)) + context->r5 = exregs->context.r5; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r6)) + context->r6 = exregs->context.r6; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r7)) + context->r7 = exregs->context.r7; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r8)) + context->r8 = exregs->context.r8; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r9)) + context->r9 = exregs->context.r9; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r10)) + context->r10 = exregs->context.r10; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r11)) + context->r11 = exregs->context.r11; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r12)) + context->r12 = exregs->context.r12; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, sp)) + context->sp = exregs->context.sp; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, lr)) + context->lr = exregs->context.lr; + if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, pc)) + context->pc = exregs->context.pc; + +flags: + /* Set thread's pager if one is supplied */ + if (exregs->flags & EXREGS_SET_PAGER) + task->pagerid = exregs->pagerid; + + /* Set thread's utcb if supplied */ + if (exregs->flags & EXREGS_SET_UTCB) { + task->utcb_address = exregs->utcb_address; + + /* + * If task is the one currently runnable, + * update kip utcb reference + */ + if (task == current) + task_update_utcb(task); + } +} + +/* + * exchange_registers() + * + * This call is used by the pagers to set (and in the future read) + * the register context of a thread. The thread's registers that are + * set by this call are loaded whenever the thread gets a chance to + * run in user mode. + * + * It is ensured that whenever this call is made, the thread is + * either already running in user mode, or has been suspended in + * kernel mode, just before returning to user mode. + * + * A newly created thread that is the copy of another thread (forked + * or cloned) will also be given its user mode context on the first + * chance to execute so such threads can also be modified by this + * call before execution. + * + * A thread executing in the kernel cannot be modified since this + * would compromise the kernel. Also the thread must be in suspended + * condition so that the scheduler does not execute it as we modify + * its context. + * + * FIXME: Still looks like suspended threads in the kernel + * need to be made immutable. see src/glue/arm/systable.c + */ +int sys_exchange_registers(struct exregs_data *exregs, l4id_t tid) +{ + int err = 0; + struct ktcb *task; + + if ((err = check_access((unsigned long)exregs, + sizeof(*exregs), + MAP_USR_RW_FLAGS, 1)) < 0) + return err; + + /* Find tcb from its list */ + if (!(task = tcb_find(tid))) + return -ESRCH; + + /* + * This lock ensures task is not + * inadvertently resumed by a syscall + */ + if (!mutex_trylock(&task->thread_control_lock)) + return -EAGAIN; + + /* + * Now check that the task is suspended. + * + * Only modification of non-register fields are + * allowed on active tasks and those tasks must + * be the pagers making the call on themselves. + */ + if (task->state != TASK_INACTIVE && exregs->valid_vect && + current != task && task->pager->tcb != current) { + err = -EACTIVE; + goto out; + } + + /* + * FIXME: + * Capability Check. + * Whose clist are we ought to check? Pager's or threads? + * Need to check exregs capability + * Need to check utcb capability if present. + * if ((exregs->flags & EXREGS_SET_UTCB) && + */ + + /* Copy registers */ + do_exchange_registers(task, exregs); + +out: + /* Unlock and return */ + mutex_unlock(&task->thread_control_lock); + return err; +} + diff --git a/src/api/space.c b/src/api/map.c similarity index 100% rename from src/api/space.c rename to src/api/map.c diff --git a/src/api/syscall.c b/src/api/syscall.c index 80ec5f8..1ff2769 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -30,149 +30,6 @@ void print_syscall_context(struct ktcb *t) r->r5, r->r6, r->r7, r->r8, r->sp_usr, r->lr_usr); } -/* Copy each register to task's context if its valid bit is set */ -void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs) -{ - task_context_t *context = &task->context; - - if (!exregs->valid_vect) - goto flags; - /* - * NOTE: - * We don't care if register values point at invalid addresses - * since memory protection would prevent any kernel corruption. - * We do however, make sure spsr is not modified - */ - - /* Check register valid bit and copy registers */ - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r0)) - context->r0 = exregs->context.r0; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r1)) - context->r1 = exregs->context.r1; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r2)) - context->r2 = exregs->context.r2; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r3)) - context->r3 = exregs->context.r3; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r4)) - context->r4 = exregs->context.r4; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r5)) - context->r5 = exregs->context.r5; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r6)) - context->r6 = exregs->context.r6; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r7)) - context->r7 = exregs->context.r7; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r8)) - context->r8 = exregs->context.r8; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r9)) - context->r9 = exregs->context.r9; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r10)) - context->r10 = exregs->context.r10; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r11)) - context->r11 = exregs->context.r11; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, r12)) - context->r12 = exregs->context.r12; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, sp)) - context->sp = exregs->context.sp; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, lr)) - context->lr = exregs->context.lr; - if (exregs->valid_vect & FIELD_TO_BIT(exregs_context_t, pc)) - context->pc = exregs->context.pc; - -flags: - /* Set thread's pager if one is supplied */ - if (exregs->flags & EXREGS_SET_PAGER) - task->pagerid = exregs->pagerid; - - /* Set thread's utcb if supplied */ - if (exregs->flags & EXREGS_SET_UTCB) { - task->utcb_address = exregs->utcb_address; - - /* - * If task is the one currently runnable, - * update kip utcb reference - */ - if (task == current) - task_update_utcb(task); - } -} - -/* - * exchange_registers() - * - * This call is used by the pagers to set (and in the future read) - * the register context of a thread. The thread's registers that are - * set by this call are loaded whenever the thread gets a chance to - * run in user mode. - * - * It is ensured that whenever this call is made, the thread is - * either already running in user mode, or has been suspended in - * kernel mode, just before returning to user mode. - * - * A newly created thread that is the copy of another thread (forked - * or cloned) will also be given its user mode context on the first - * chance to execute so such threads can also be modified by this - * call before execution. - * - * A thread executing in the kernel cannot be modified since this - * would compromise the kernel. Also the thread must be in suspended - * condition so that the scheduler does not execute it as we modify - * its context. - * - * FIXME: Still looks like suspended threads in the kernel - * need to be made immutable. see src/glue/arm/systable.c - */ -int sys_exchange_registers(struct exregs_data *exregs, l4id_t tid) -{ - int err = 0; - struct ktcb *task; - - if ((err = check_access((unsigned long)exregs, - sizeof(*exregs), - MAP_USR_RW_FLAGS, 1)) < 0) - return err; - - /* Find tcb from its list */ - if (!(task = tcb_find(tid))) - return -ESRCH; - - /* - * This lock ensures task is not - * inadvertently resumed by a syscall - */ - if (!mutex_trylock(&task->thread_control_lock)) - return -EAGAIN; - - /* - * Now check that the task is suspended. - * - * Only modification of non-register fields are - * allowed on active tasks and those tasks must - * be the pagers making the call on themselves. - */ - if (task->state != TASK_INACTIVE && exregs->valid_vect && - current != task && task->pager->tcb != current) { - err = -EACTIVE; - goto out; - } - - /* - * FIXME: - * Capability Check. - * Whose clist are we ought to check? Pager's or threads? - * Need to check exregs capability - * Need to check utcb capability if present. - * if ((exregs->flags & EXREGS_SET_UTCB) && - */ - - /* Copy registers */ - do_exchange_registers(task, exregs); - -out: - /* Unlock and return */ - mutex_unlock(&task->thread_control_lock); - return err; -} - int sys_schedule(void) { printk("(SVC) %s called. Tid (%d)\n", __FUNCTION__, current->tid);