From 7a81db8782e9e5cffadddf2c34533742e4e65603 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Wed, 29 Apr 2009 16:53:04 +0300 Subject: [PATCH] Ongoing work for adding per-thread UTCB structures. Added setting of utcb address to l4_thread_control. This is going to be moved to exchange_registers() since we need to pass both the utcb physical and virtual address and exregs fits such context modification better than thread_control. --- docs/tls.txt | 50 ++++++++ include/l4/api/exregs.h | 7 +- include/l4/api/kip.h | 2 + include/l4/api/thread.h | 8 +- include/l4/generic/tcb.h | 5 +- include/l4/glue/arm/memlayout.h | 2 +- include/l4/glue/arm/message.h | 1 + libs/c/crt/sys-userspace/arch-arm/crt0.S | 1 - src/api/syscall.c | 7 ++ src/api/thread.c | 115 ++++++++++++++++-- src/generic/scheduler.c | 3 + tasks/fs0/container.c | 23 ++++ tasks/fs0/include/linker.lds | 5 + tasks/fs0/src/task.c | 2 + tasks/libl4/include/l4lib/arch-arm/syscalls.h | 11 +- tasks/libl4/include/l4lib/arch-arm/types.h | 11 +- tasks/libl4/include/l4lib/arch-arm/utcb.h | 39 ++++-- tasks/libl4/include/l4lib/exregs.h | 1 + tasks/libl4/include/l4lib/init.h | 6 + tasks/libl4/include/l4lib/thread.h | 14 +++ tasks/libl4/src/arm/exregs.c | 9 ++ tasks/libl4/src/arm/syscalls.S | 11 +- tasks/libl4/src/init.c | 14 ++- tasks/libposix/fork.c | 6 +- tasks/libposix/include/posix/posix_init.h | 9 +- tasks/libposix/init.c | 22 ++-- tasks/mm0/container.c | 28 +++++ tasks/mm0/include/linker.lds | 6 +- tasks/mm0/include/task.h | 18 +++ tasks/mm0/include/vm_area.h | 2 +- tasks/mm0/src/init.c | 1 + tasks/mm0/src/utcb.c | 27 ++++ tasks/test0/SConstruct | 2 +- tasks/test0/container.c | 25 ++++ tasks/test0/include/linker.lds | 3 +- 35 files changed, 424 insertions(+), 72 deletions(-) create mode 100644 docs/tls.txt create mode 100644 tasks/fs0/container.c create mode 100644 tasks/libl4/include/l4lib/init.h create mode 100644 tasks/libl4/include/l4lib/thread.h create mode 100644 tasks/mm0/container.c create mode 100644 tasks/mm0/src/utcb.c create mode 100644 tasks/test0/container.c diff --git a/docs/tls.txt b/docs/tls.txt new file mode 100644 index 0000000..09c257a --- /dev/null +++ b/docs/tls.txt @@ -0,0 +1,50 @@ + Thread Local Storage and UTCB Access + +In an L4-like microkernel such as Codezero, there needs to be a way of +accessing the User Thread Control Block (UTCB) in order to push argument +registers and write the IPC payload. This necessitates a convenient method +of accessing the thread-specific utcb structure. Here are some of the +possible methods of accessing a thread local storage in general: + +1.) Keep a global pointer to it. The scheduler updates the pointer to TLS +upon every context switch. + +2.) Map the private physical TLS page to thread address space at same virtual +offset, everytime there is a context switch. + +3.) Manage everything by the run-time library in the application. This includes +the following: + + * Predefine a fixed TLS table area on the address space. + * Possibly allocate local thread ids E.g. [1..n] + * Get current thread id + * Take a lock (on the TLS table) + * Lookup the pointer to the TLS block by thread id + * Release the lock + * Return that pointer + +The third one is least flexible solution since it requires management of the +TLS area, has concurrency issues, and limits the number of TLS areas available. + +Since UTCB concept is at the heart of Codezero IPC mechanisms, it has to be +done neatly and flexibly. In that respect lets evaluate solutions: + +1.) This is most convenient since user applications can simply reference a +pointer to get their unique TLS. By this approach no need to spend excessive +memory by using a page per TLS (in case TLS is less than a page). The downside +is the UTCB region still needs to be defined by a limit in the address space +and managed by the pager, if not by the application. This is because every UTCB +shall be part of an array or a table of unique UTCBs. + +2.) Mapping a per-thread physical page to a fixed virtual address upon a context +switch is the most flexible, since the pager can simply allocate a physical page +as new threads come to life, and map this when they run, without managing utcb +table size. The downside is that a page is wasted per-thread. + +The solution Codezero uses includes a mixture of both (1) and (2). Upon a +context switch, a private page is allocated and mapped by the pager, but also +the UTCB pointer is updated to point at an offset in this page. As an example, +if a UTCB is sized 1/4th of a page, a single page is used by 4 UTCBs. This way, +the pager needs to manage 4 entries per-private page, utcbs utilise page memory +better, and there is no need for a fixed table of utcbs per address space. + diff --git a/include/l4/api/exregs.h b/include/l4/api/exregs.h index f6b50d3..da9044b 100644 --- a/include/l4/api/exregs.h +++ b/include/l4/api/exregs.h @@ -11,9 +11,8 @@ #include INC_GLUE(context.h) #include -enum exregs_flags { - EXREGS_SET_PAGER = 1, -}; +#define EXREGS_SET_PAGER 1 +#define EXREGS_SET_UTCB 2 /* Structure passed by userspace pagers for exchanging registers */ struct exregs_data { @@ -21,6 +20,8 @@ struct exregs_data { u32 valid_vect; u32 flags; l4id_t pagerid; + unsigned long utcb_phys; + unsigned long utcb_virt; }; diff --git a/include/l4/api/kip.h b/include/l4/api/kip.h index 7d45fec..9788f7a 100644 --- a/include/l4/api/kip.h +++ b/include/l4/api/kip.h @@ -68,6 +68,8 @@ struct kip { u32 arch_syscall2; u32 arch_syscall3; + u32 utcb; + struct kernel_desc kdesc; } __attribute__((__packed__)); diff --git a/include/l4/api/thread.h b/include/l4/api/thread.h index 6681d6a..0c5eb45 100644 --- a/include/l4/api/thread.h +++ b/include/l4/api/thread.h @@ -1,7 +1,7 @@ #ifndef __THREAD_H__ #define __THREAD_H__ -#define THREAD_CREATE_MASK 0x00F0 +#define THREAD_CREATE_MASK 0x0030 /* Create new thread and new space */ #define THREAD_NEW_SPACE 0x0010 @@ -12,7 +12,11 @@ /* Create new thread, use given space */ #define THREAD_SAME_SPACE 0x0030 - +/* Shared UTCB, New UTCB, No UTCB */ +#define THREAD_UTCB_MASK 0x00C0 +#define THREAD_UTCB_NEW 0x0040 +#define THREAD_UTCB_SAME 0x0080 +#define THREAD_UTCB_NONE 0x00C0 #define THREAD_ACTION_MASK 0x000F diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index 87d4d80..d1bbaf3 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -70,7 +70,10 @@ struct ktcb { u32 ts_need_resched; /* Scheduling flag */ enum task_state state; struct list_head task_list; /* Global task list. */ - struct utcb *utcb; /* Reference to task's utcb area */ + + /* UTCB related, see utcb.txt in docs */ + unsigned long utcb_virt; /* Virtual ref to task's utcb area */ + unsigned long utcb_phys; /* Physical ref to task's utcb area */ /* Thread times */ u32 kernel_time; /* Ticks spent in kernel */ diff --git a/include/l4/glue/arm/memlayout.h b/include/l4/glue/arm/memlayout.h index 6c0d5d9..1c4aa12 100644 --- a/include/l4/glue/arm/memlayout.h +++ b/include/l4/glue/arm/memlayout.h @@ -43,7 +43,7 @@ #define USER_KIP_PAGE 0xFF000000 /* ARM-specific offset in KIP that tells the address of UTCB page */ -#define UTCB_KIP_OFFSET 0xFF0 +#define UTCB_KIP_OFFSET 0x50 #define IO_AREA0_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*0)) #define IO_AREA1_VADDR (IO_AREA_START + (ARM_SECTION_SIZE*1)) diff --git a/include/l4/glue/arm/message.h b/include/l4/glue/arm/message.h index de3e1e4..f5251de 100644 --- a/include/l4/glue/arm/message.h +++ b/include/l4/glue/arm/message.h @@ -6,6 +6,7 @@ #ifndef __GLUE_ARM_MESSAGE_H__ #define __GLUE_ARM_MESSAGE_H__ +#define MR_REST 56 #define MR_TOTAL 6 #define MR_TAG 0 /* Contains the purpose of message */ #define MR_SENDER 1 /* For anythread receivers to discover sender */ diff --git a/libs/c/crt/sys-userspace/arch-arm/crt0.S b/libs/c/crt/sys-userspace/arch-arm/crt0.S index a5de7c1..a1d6ae3 100644 --- a/libs/c/crt/sys-userspace/arch-arm/crt0.S +++ b/libs/c/crt/sys-userspace/arch-arm/crt0.S @@ -87,7 +87,6 @@ _start: ldr sp, =__stack bl platform_init - bl __l4_init bl __container_init 1: b 1b diff --git a/src/api/syscall.c b/src/api/syscall.c index 2b87701..8b98bf5 100644 --- a/src/api/syscall.c +++ b/src/api/syscall.c @@ -78,6 +78,13 @@ void do_exchange_registers(struct ktcb *task, struct exregs_data *exregs) if (exregs->flags & EXREGS_SET_PAGER) task->pagerid = exregs->pagerid; + /* Set thread's utcb if supplied */ + if (exregs->flags & EXREGS_SET_UTCB) { + BUG(); /* Check that physical and virtual addresses are in range */ + task->utcb_phys = exregs->utcb_phys; + task->utcb_virt = exregs->utcb_virt; + } + } /* diff --git a/src/api/thread.c b/src/api/thread.c index 987a2c7..57a1244 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -164,10 +164,92 @@ int thread_start(struct task_ids *ids) return 0; } -int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig, unsigned int flags) +/* + * Given thread creation flags, determines whether to use a new user + * (pager)-supplied utcb address, the utcb address of the original thread, + * or no utcb at all. Validation of flags done at beginning of thread_create(). + */ +int arch_new_thread_setup_utcb(struct ktcb *new, struct ktcb *orig, unsigned int flags, + unsigned long utcb_address) { + unsigned int create_flags = flags & THREAD_CREATE_MASK; + unsigned int utcb_flags = flags & THREAD_UTCB_MASK; + + /* In case of multiple threads in same address space */ + if (create_flags == THREAD_SAME_SPACE) { + switch (utcb_flags) { + case THREAD_UTCB_SAME: + new->utcb_address = orig->utcb_address; + break; + case THREAD_UTCB_NEW: + new->utcb_address = utcb_address; + break; + case THREAD_UTCB_NONE: + new->utcb_address = 0; + break; + default: + printk("%s: Bad thread creation flags. " + "Incorrect flag validation?\n",__FUNCTION__); + BUG(); + } + } + + /* In case of brand new address space and thread */ + if (create_flags == THREAD_NEW_SPACE) { + switch (utcb_flags) { + case THREAD_UTCB_NEW: + new->utcb_address = utcb_address; + break; + /* + * No UTCB for brand new space means the thread cannot do + * an ipc other than exceptions. This is allowed for now. + */ + case THREAD_UTCB_NONE: + new->utcb_address = 0; + break; + default: + printk("%s: Bad thread creation flags. " + "Incorrect flag validation?\n",__FUNCTION__); + BUG(); + } + } + + /* + * This essentially corresponds to fork() and normally we would expect + * the UTCB to be the same as original thread, since the whole address + * space is an identical image of the original. Nevertheless it doesn't + * do harm to have none or different utcb address and this is left to + * the implementor to decide. + */ + if (create_flags == THREAD_COPY_SPACE) { + switch (utcb_flags) { + case THREAD_UTCB_SAME: + new->utcb_address = orig->utcb_address; + break; + case THREAD_UTCB_NEW: + new->utcb_address = utcb_address; + break; + case THREAD_UTCB_NONE: + new->utcb_address = 0; + break; + default: + printk("%s: Bad thread creation flags. " + "Incorrect flag validation?\n",__FUNCTION__); + BUG(); + } + } + + return 0; +} + +int arch_setup_new_thread(struct ktcb *new, struct ktcb *orig, + unsigned int flags, unsigned long utcb_address) +{ + /* Set up the utcb address */ + arch_new_thread_setup_utcb(new, orig, flags, utcb_address); + /* New threads just need their mode set up */ - if (flags == THREAD_NEW_SPACE) { + if ((flags & THREAD_CREATE_MASK) == THREAD_NEW_SPACE) { BUG_ON(orig); new->context.spsr = ARM_MODE_USR; return 0; @@ -262,12 +344,28 @@ int thread_setup_new_ids(struct task_ids *ids, unsigned int flags, * are respectively used when creating a brand new task, creating a * new thread in an existing address space, or forking a task. */ -int thread_create(struct task_ids *ids, unsigned int flags) +int thread_create(struct task_ids *ids, unsigned int flags, + unsigned long utcb_address) { struct ktcb *task = 0, *new = (struct ktcb *)zalloc_page(); - flags &= THREAD_CREATE_MASK; + unsigned int create_flags = flags & THREAD_CREATE_MASK; + unsigned int utcb_flags = flags & THREAD_UTCB_MASK; - if (flags == THREAD_NEW_SPACE) { + /* Handle error cases. Should have valid flags for each */ + if (!utcb_flags || !create_flags) + return -EINVAL; + + /* Cannot have new space with same utcb */ + else if (create_flags == THREAD_NEW_SPACE && + utcb_flags == THREAD_UTCB_SAME) + return -EINVAL; + + /* Cannot have new utcb with invalid address */ + else if (utcb_flags == THREAD_UTCB_NEW && !utcb_address) + return -EINVAL; + + /* Determine space allocation */ + if (create_flags == THREAD_NEW_SPACE) { /* Allocate new pgd and copy all kernel areas */ new->pgd = alloc_pgd(); copy_pgd_kern_all(new->pgd); @@ -289,7 +387,7 @@ int thread_create(struct task_ids *ids, unsigned int flags) } out: /* Set up new thread's tid, spid, tgid according to flags */ - thread_setup_new_ids(ids, flags, new, task); + thread_setup_new_ids(ids, create_flags, new, task); /* Initialise task's scheduling state and parameters. */ sched_init_task(new, TASK_PRIO_NORMAL); @@ -299,7 +397,7 @@ out: waitqueue_head_init(&new->wqh_recv); waitqueue_head_init(&new->wqh_pager); - arch_setup_new_thread(new, task, flags); + arch_setup_new_thread(new, task, flags, utcb_address); /* Add task to global hlist of tasks */ add_task_global(new); @@ -317,10 +415,11 @@ int sys_thread_control(syscall_context_t *regs) int ret = 0; unsigned int flags = regs->r0; struct task_ids *ids = (struct task_ids *)regs->r1; + unsigned long utcb_address = regs->r2; switch (flags & THREAD_ACTION_MASK) { case THREAD_CREATE: - ret = thread_create(ids, flags); + ret = thread_create(ids, flags, utcb_address); break; case THREAD_RUN: ret = thread_start(ids); diff --git a/src/generic/scheduler.c b/src/generic/scheduler.c index 278728f..46fae2e 100644 --- a/src/generic/scheduler.c +++ b/src/generic/scheduler.c @@ -255,6 +255,9 @@ static inline void context_switch(struct ktcb *next) // printk("(%d) to (%d)\n", cur->tid, next->tid); + /* Update KIP UTCB pointer for new thread to run */ + kip.utcb = next->utcb_address; + /* Flush caches and everything */ arch_hardware_flush(next->pgd); diff --git a/tasks/fs0/container.c b/tasks/fs0/container.c new file mode 100644 index 0000000..8b3311f --- /dev/null +++ b/tasks/fs0/container.c @@ -0,0 +1,23 @@ +/* + * Container entry point for this task + * + * Copyright (C) 2007-2009 Bahadir Bilgehan Balban + */ +#include +#include +#include + +void main(void); + +void __container_init(void) +{ + /* Generic L4 thread initialisation */ + __l4_init(); + + /* FS0 posix-service initialisation */ + posix_service_init(); + + /* Entry to main */ + main(); +} + diff --git a/tasks/fs0/include/linker.lds b/tasks/fs0/include/linker.lds index 684b13a..d555415 100644 --- a/tasks/fs0/include/linker.lds +++ b/tasks/fs0/include/linker.lds @@ -32,6 +32,10 @@ SECTIONS .rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) } .data : AT (ADDR(.data) - offset) { + . = ALIGN(4K); /* Align UTCB to page boundary */ + _start_utcb = .; + *(.utcb) + _end_utcb = .; . = ALIGN(4K); _start_bdev = .; *(.data.memfs) @@ -39,5 +43,6 @@ SECTIONS *(.data) } .bss : AT (ADDR(.bss) - offset) { *(.bss) } + _end = .; } diff --git a/tasks/fs0/src/task.c b/tasks/fs0/src/task.c index 63bddf2..e318a6b 100644 --- a/tasks/fs0/src/task.c +++ b/tasks/fs0/src/task.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include + extern void *shared_page; struct global_list global_tasks = { diff --git a/tasks/libl4/include/l4lib/arch-arm/syscalls.h b/tasks/libl4/include/l4lib/arch-arm/syscalls.h index 035d6dc..2192da3 100644 --- a/tasks/libl4/include/l4lib/arch-arm/syscalls.h +++ b/tasks/libl4/include/l4lib/arch-arm/syscalls.h @@ -6,6 +6,7 @@ #ifndef __ARM_SYSCALLS_H__ #define __ARM_SYSCALLS_H__ + #include #include #include @@ -14,6 +15,12 @@ #include #include +struct task_ids { + int tid; + int spid; + int tgid; +}; + static inline void * l4_kernel_interface(unsigned int *api_version, unsigned int *api_flags, unsigned int *kernel_id) @@ -46,9 +53,9 @@ typedef int (*__l4_unmap_t)(void *virt, unsigned long npages, l4id_t tid); extern __l4_unmap_t __l4_unmap; int l4_unmap(void *virtual, unsigned long numpages, l4id_t tid); -typedef int (*__l4_thread_control_t)(unsigned int action, struct task_ids *ids); +typedef int (*__l4_thread_control_t)(unsigned int action, struct task_ids *ids, void *utcb_address); extern __l4_thread_control_t __l4_thread_control; -int l4_thread_control(unsigned int action, struct task_ids *ids); +int l4_thread_control(unsigned int action, struct task_ids *ids, void *utcb_address); typedef int (*__l4_space_control_t)(unsigned int action, void *kdata); extern __l4_space_control_t __l4_space_control; diff --git a/tasks/libl4/include/l4lib/arch-arm/types.h b/tasks/libl4/include/l4lib/arch-arm/types.h index c7a474a..f01616b 100644 --- a/tasks/libl4/include/l4lib/arch-arm/types.h +++ b/tasks/libl4/include/l4lib/arch-arm/types.h @@ -1,13 +1,8 @@ -#ifndef __L4_ARCH_ARM__ -#define __L4_ARCH_ARM__ +#ifndef __L4LIB_ARM_TYPES_H___ +#define __L4LIB_ARM_TYPES_H__ #define TASK_ID_INVALID -1 -struct task_ids { - int tid; - int spid; - int tgid; -}; #include -#endif +#endif /* __L4LIB_ARM_TYPES_H__ */ diff --git a/tasks/libl4/include/l4lib/arch-arm/utcb.h b/tasks/libl4/include/l4lib/arch-arm/utcb.h index 5b6991e..73c7fdc 100644 --- a/tasks/libl4/include/l4lib/arch-arm/utcb.h +++ b/tasks/libl4/include/l4lib/arch-arm/utcb.h @@ -1,9 +1,12 @@ +/* + * Copyright (C) 2009 Bahadir Bilgehan Balban + */ #ifndef __ARM_UTCB_H__ #define __ARM_UTCB_H__ -#define USER_UTCB_REF 0xFF000FF0 +#define USER_UTCB_REF 0xFF000050 #define L4_KIP_ADDRESS 0xFF000000 -#define UTCB_KIP_OFFSET 0xFF0 +#define UTCB_KIP_OFFSET 0x50 #ifndef __ASSEMBLY__ #include @@ -13,27 +16,37 @@ #include #include +/* UTCB implementation */ + /* * NOTE: In syslib.h the first few mrs are used by data frequently * needed for all ipcs. Those mrs are defined the kernel message.h */ -/* - * This is a per-task private structure where message registers are - * pushed for ipc. Its *not* TLS, but can be part of TLS when it is - * supported. - */ struct utcb { - u32 mr[MR_TOTAL]; - u32 saved_tag; - u32 saved_sender; -} __attribute__((__packed__)); + u32 mr[MR_TOTAL]; /* MRs that are mapped to real registers */ + u32 saved_tag; /* Saved tag field for stacked ipcs */ + u32 saved_sender; /* Saved sender field for stacked ipcs */ + u32 mr_rest[MR_REST]; /* Complete the utcb for up to 64 words */ +}; -extern struct utcb utcb; +extern struct kip *kip; + + +/* + * Pointer to Kernel Interface Page's UTCB pointer offset. + */ +extern struct utcb **kip_utcb_ref; static inline struct utcb *l4_get_utcb() { - return &utcb; + /* + * By double dereferencing, we get the private TLS (aka UTCB). First + * reference is to the KIP's utcb offset, second is to the utcb itself, + * to which the KIP's utcb reference had been updated during context + * switch. + */ + return *kip_utcb_ref; } /* Functions to read/write utcb registers */ diff --git a/tasks/libl4/include/l4lib/exregs.h b/tasks/libl4/include/l4lib/exregs.h index f5489d0..e6e496f 100644 --- a/tasks/libl4/include/l4lib/exregs.h +++ b/tasks/libl4/include/l4lib/exregs.h @@ -7,6 +7,7 @@ void exregs_set_stack(struct exregs_data *s, unsigned long sp); void exregs_set_mr(struct exregs_data *s, int offset, unsigned long val); void exregs_set_pc(struct exregs_data *s, unsigned long pc); void exregs_set_pager(struct exregs_data *s, l4id_t pagerid); +void exregs_set_utcb(struct exregs_data *s, unsigned long phys, unsigned long virt); /* exregs_set_stack(unsigned long sp) diff --git a/tasks/libl4/include/l4lib/init.h b/tasks/libl4/include/l4lib/init.h new file mode 100644 index 0000000..f8efafb --- /dev/null +++ b/tasks/libl4/include/l4lib/init.h @@ -0,0 +1,6 @@ +#ifndef __L4LIB_INIT__ +#define __L4LIB_INIT__ + +void __l4_init(void); + +#endif diff --git a/tasks/libl4/include/l4lib/thread.h b/tasks/libl4/include/l4lib/thread.h new file mode 100644 index 0000000..7c2ed21 --- /dev/null +++ b/tasks/libl4/include/l4lib/thread.h @@ -0,0 +1,14 @@ +#ifndef __L4_THREAD_H__ +#define __L4_THREAD_H__ + +#include +#include + +struct l4_thread_struct { + l4id_t tlid; /* Thread local id */ + struct task_ids ids; /* Thread L4-defined ids */ + struct utcb *utcb; /* Thread utcb */ + unsigned long stack_start; /* Thread start of stack */ +}; + +#endif /* __L4_THREAD_H__ */ diff --git a/tasks/libl4/src/arm/exregs.c b/tasks/libl4/src/arm/exregs.c index 0947289..54faba9 100644 --- a/tasks/libl4/src/arm/exregs.c +++ b/tasks/libl4/src/arm/exregs.c @@ -9,6 +9,7 @@ #include INC_GLUE(message.h) + void exregs_set_mr(struct exregs_data *s, int offset, unsigned long val) { /* Get MR0 */ @@ -30,6 +31,14 @@ void exregs_set_pager(struct exregs_data *s, l4id_t pagerid) s->flags |= EXREGS_SET_PAGER; } +void exregs_set_utcb(struct exregs_data *s, unsigned long phys, + unsigned long virt) +{ + s->utcb_phys = phys; + s->utcb_virt = virt; + s->flags |= EXREGS_SET_UTCB; +} + void exregs_set_stack(struct exregs_data *s, unsigned long sp) { s->context.sp = sp; diff --git a/tasks/libl4/src/arm/syscalls.S b/tasks/libl4/src/arm/syscalls.S index 31ab29b..fb27f93 100644 --- a/tasks/libl4/src/arm/syscalls.S +++ b/tasks/libl4/src/arm/syscalls.S @@ -9,9 +9,18 @@ #include #include INC_GLUE(message.h) +/* Old macro */ +#if 0 .macro utcb_address rx ldr \rx, =utcb .endm +#endif + + /* New macro does double dereference */ + .macro utcb_address rx + ldr \rx, =kip_utcb_ref @ First get pointer to utcb pointer in KIP + ldr \rx, [\rx] @ Get UTCB address from UTCB pointer in KIP + .endm BEGIN_PROC(l4_thread_switch) ldr r12, =__l4_thread_switch @@ -152,7 +161,7 @@ END_PROC(l4_time) /* * System call that controls thread creation, destruction and modification. - * @r0 = thread action, @r1 = &ids + * @r0 = thread action, @r1 = &ids, @r2 = utcb address */ BEGIN_PROC(l4_thread_control) stmfd sp!, {lr} diff --git a/tasks/libl4/src/init.c b/tasks/libl4/src/init.c index 0ddb8c0..1ba3e24 100644 --- a/tasks/libl4/src/init.c +++ b/tasks/libl4/src/init.c @@ -1,7 +1,7 @@ /* - * Initialise system call offsets. + * Initialise system call offsets and utcb reference. * - * Copyright (C) 2007, 2008 Bahadir Balban + * Copyright (C) 2007-2009 Bahadir Bilgehan Balban */ #include #include @@ -27,16 +27,20 @@ __l4_time_t __l4_time = 0; struct kip *kip; /* - * Private UTCB of this task. Used only for pushing/reading ipc - * message registers. + * Reference to private UTCB of this thread. + * Used only for pushing/reading ipc message registers. */ -struct utcb utcb; +struct utcb **kip_utcb_ref; void __l4_init(void) { + /* Kernel interface page */ kip = l4_kernel_interface(0, 0, 0); + /* Reference to utcb field of KIP */ + kip_utcb_ref = (struct utcb **)&kip->utcb; + __l4_ipc = (__l4_ipc_t)kip->ipc; __l4_map = (__l4_map_t)kip->map; __l4_unmap = (__l4_unmap_t)kip->unmap; diff --git a/tasks/libposix/fork.c b/tasks/libposix/fork.c index b604e96..a2f17a5 100644 --- a/tasks/libposix/fork.c +++ b/tasks/libposix/fork.c @@ -12,7 +12,7 @@ #include #include #include INC_GLUE(memory.h) -#include +#include static inline int l4_fork(void) { @@ -43,10 +43,10 @@ int fork(void) /* * If we're a child, we need to initialise the default - * shared page via posix_init() + * shared page via libposix_init() */ if (ret == 0) - posix_init(); + shared_page_init(); return ret; } diff --git a/tasks/libposix/include/posix/posix_init.h b/tasks/libposix/include/posix/posix_init.h index 7abdffe..43a99b2 100644 --- a/tasks/libposix/include/posix/posix_init.h +++ b/tasks/libposix/include/posix/posix_init.h @@ -1,6 +1,7 @@ -#ifndef __POSIX_INIT_H__ -#define __POSIX_INIT_H__ +#ifndef __LIBPOSIX_INIT_H__ +#define __LIBPOSIX_INIT_H__ -void posix_init(void); +void libposix_init(void); +void posix_service_init(void); -#endif /* __POSIX_INIT_H__ */ +#endif /* __LIBPOSIX_INIT_H__ */ diff --git a/tasks/libposix/init.c b/tasks/libposix/init.c index 273eb5b..ca5d44c 100644 --- a/tasks/libposix/init.c +++ b/tasks/libposix/init.c @@ -3,28 +3,20 @@ * * Copyright (C) 2007-2009 Bahadir Balban */ - #include #include -void posix_init(void) +void posix_service_init(void) { /* Non-pager tasks initialise their shared communication page */ - if (self_tid() != PAGER_TID) - shared_page_init(); + BUG_ON(self_tid() != VFS_TID); + shared_page_init(); } -int main(void); - -/* - * Entry point for posix services container. - * - * This is executed by all posix system services and tasks - * that run in this container. - */ -void __container_init(void) +void libposix_init(void) { - posix_init(); - main(); + /* Shall only be run by posix applications */ + BUG_ON(self_tid() == PAGER_TID || self_tid() == VFS_TID); + shared_page_init(); } diff --git a/tasks/mm0/container.c b/tasks/mm0/container.c new file mode 100644 index 0000000..2b7d1f2 --- /dev/null +++ b/tasks/mm0/container.c @@ -0,0 +1,28 @@ +/* + * Container entry point for pager + * + * Copyright (C) 2007-2009 Bahadir Bilgehan Balban + */ + +#include +#include +#include + +/* + * Application specific utcb allocation + * for this container. + * + * Copyright (C) 2007-2009 Bahadir Balban + */ + +void main(void); + +void __container_init(void) +{ + /* Generic L4 initialisation */ + __l4_init(); + + /* Entry to main */ + main(); +} + diff --git a/tasks/mm0/include/linker.lds b/tasks/mm0/include/linker.lds index f6a34f2..3d6d288 100644 --- a/tasks/mm0/include/linker.lds +++ b/tasks/mm0/include/linker.lds @@ -29,7 +29,11 @@ SECTIONS /* rodata is needed else your strings will link at physical! */ .rodata : AT (ADDR(.rodata) - offset) { *(.rodata) } .rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) } - .data : AT (ADDR(.data) - offset) { *(.data) } + .data : AT (ADDR(.data) - offset) + { + *(.data) + } + . = ALIGN(4K); _start_init = .; .init : AT (ADDR(.init) - offset) { *(.init.stack) } . = ALIGN(8); diff --git a/tasks/mm0/include/task.h b/tasks/mm0/include/task.h index 0e7fb63..7e5678c 100644 --- a/tasks/mm0/include/task.h +++ b/tasks/mm0/include/task.h @@ -11,6 +11,7 @@ #include INC_GLUE(memlayout.h) #include #include +#include #include #include #include @@ -53,6 +54,20 @@ struct task_vma_head { int tcb_refs; }; +/* + * TLS and UTCB bookkeeping: + * + * This structure is shared among threads whose utcbs are on the same + * physical page. Threads with utcbs on different physical pages have + * their own utcb_data structure, even though they are in the same + * address space, and share their vm_area_list structure. + */ +struct utcb_data { + unsigned long phys; /* Physical utcb address */ + unsigned long virt; /* Virtual utcb address */ + u32 bit; /* Bitvector of free utcb slots on page */ + struct page *p; /* Physical page */ +}; /* Stores all task information that can be kept in userspace. */ struct tcb { @@ -104,6 +119,9 @@ struct tcb { /* Default ipc-shared-page information */ void *shared_page; + /* Task's utcb data */ + struct utcb_data *utcb; + /* Virtual memory areas */ struct task_vma_head *vm_area_head; diff --git a/tasks/mm0/include/vm_area.h b/tasks/mm0/include/vm_area.h index e9a9742..4292619 100644 --- a/tasks/mm0/include/vm_area.h +++ b/tasks/mm0/include/vm_area.h @@ -7,10 +7,10 @@ #define __VM_AREA_H__ #include -#include #include #include #include +#include #include #include diff --git a/tasks/mm0/src/init.c b/tasks/mm0/src/init.c index 556a51c..0a383bc 100644 --- a/tasks/mm0/src/init.c +++ b/tasks/mm0/src/init.c @@ -18,6 +18,7 @@ #include #include + /* A separate list than the generic file list that keeps just the boot files */ LIST_HEAD(boot_file_list); diff --git a/tasks/mm0/src/utcb.c b/tasks/mm0/src/utcb.c new file mode 100644 index 0000000..39cbb81 --- /dev/null +++ b/tasks/mm0/src/utcb.c @@ -0,0 +1,27 @@ +/* + * Management of task utcb regions and own utcb. + * + * Copyright (C) 2007-2009 Bahadir Bilgehan Balban + */ + +#include +#include + +/* + * UTCB management in Codezero: + * + * 1.) Every task in the system defines an array of utcbs in a special .utcb + * section that is page-aligned and to be kept wired in by the pager. + * 2.) The region marks are written to bootdesc structure at compile-time. + * 3.) Pager reads the bootdesc struct from the microkernel during init. + * 4.) Pager initialises structures to alloc/dealloc new utcbs for every address + * space. + * 5.) Pagers dynamically allocate utcb addresses as each thread is created + * via a thread_control() system call. + * 6.) Each thread in an address space learns their utcb address from a + * well-defined KIP offset. This is updated as each thread becomes runnable. + */ + + + + diff --git a/tasks/test0/SConstruct b/tasks/test0/SConstruct index 47c2226..6312087 100644 --- a/tasks/test0/SConstruct +++ b/tasks/test0/SConstruct @@ -68,7 +68,7 @@ env = Environment(CC = 'arm-none-linux-gnueabi-gcc', CPPFLAGS = "-D__USERSPACE__", CPPPATH = ['#include', libl4_incpath, libposix_incpath, kernel_incpath]) -src = [glob("src/*.c"), glob("*.c"), glob("*.S"), glob("src/arch/arm/*.c")] +src = [glob("src/*.c"), glob("*.c"), glob("*.S"), glob("src/arch/arm/*.c"), glob("../libcont/*.c")] objs = env.Object(src) physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base) crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0) diff --git a/tasks/test0/container.c b/tasks/test0/container.c new file mode 100644 index 0000000..2e145e3 --- /dev/null +++ b/tasks/test0/container.c @@ -0,0 +1,25 @@ +/* + * Container entry point for this task. + * + * Copyright (C) 2007-2009 Bahadir Bilgehan Balban + */ + +#include +#include +#include +#include /* Initialisers for posix library */ + +void main(void); + +void __container_init(void) +{ + /* Generic L4 thread initialisation */ + __l4_init(); + + /* Initialise posix library for application */ + libposix_init(); + + /* Entry to main */ + main(); +} + diff --git a/tasks/test0/include/linker.lds b/tasks/test0/include/linker.lds index 5870d33..efa49eb 100644 --- a/tasks/test0/include/linker.lds +++ b/tasks/test0/include/linker.lds @@ -30,10 +30,9 @@ SECTIONS /* rodata is needed else your strings will link at physical! */ .rodata : AT (ADDR(.rodata) - offset) { *(.rodata) } .rodata1 : AT (ADDR(.rodata1) - offset) { *(.rodata1) } - - . = ALIGN(4K); .data : AT (ADDR(.data) - offset) { + . = ALIGN(4K); _start_test1 = .; *(.test1) _end_test1 = .;