mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
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.
This commit is contained in:
50
docs/tls.txt
Normal file
50
docs/tls.txt
Normal file
@@ -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.
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
#include INC_GLUE(context.h)
|
||||
#include <l4/types.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -68,6 +68,8 @@ struct kip {
|
||||
u32 arch_syscall2;
|
||||
u32 arch_syscall3;
|
||||
|
||||
u32 utcb;
|
||||
|
||||
struct kernel_desc kdesc;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -87,7 +87,6 @@
|
||||
_start:
|
||||
ldr sp, =__stack
|
||||
bl platform_init
|
||||
bl __l4_init
|
||||
bl __container_init
|
||||
1:
|
||||
b 1b
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
115
src/api/thread.c
115
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
23
tasks/fs0/container.c
Normal file
23
tasks/fs0/container.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Container entry point for this task
|
||||
*
|
||||
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
||||
*/
|
||||
#include <posix/posix_init.h>
|
||||
#include <l4lib/init.h>
|
||||
#include <l4lib/utcb.h>
|
||||
|
||||
void main(void);
|
||||
|
||||
void __container_init(void)
|
||||
{
|
||||
/* Generic L4 thread initialisation */
|
||||
__l4_init();
|
||||
|
||||
/* FS0 posix-service initialisation */
|
||||
posix_service_init();
|
||||
|
||||
/* Entry to main */
|
||||
main();
|
||||
}
|
||||
|
||||
@@ -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 = .;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <l4/api/errno.h>
|
||||
#include <l4lib/arch/syscalls.h>
|
||||
#include <l4lib/arch/syslib.h>
|
||||
#include <l4lib/arch/utcb.h>
|
||||
#include <l4lib/ipcdefs.h>
|
||||
#include <lib/malloc.h>
|
||||
#include <lib/idpool.h>
|
||||
@@ -20,6 +21,7 @@
|
||||
#include <syscalls.h>
|
||||
#include <globals.h>
|
||||
|
||||
|
||||
extern void *shared_page;
|
||||
|
||||
struct global_list global_tasks = {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifndef __ARM_SYSCALLS_H__
|
||||
#define __ARM_SYSCALLS_H__
|
||||
|
||||
|
||||
#include <l4lib/arch/types.h>
|
||||
#include <l4lib/arch/utcb.h>
|
||||
#include <l4/generic/space.h>
|
||||
@@ -14,6 +15,12 @@
|
||||
#include <l4/api/ipc.h>
|
||||
#include <l4/api/thread.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -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 <l4/arch/arm/types.h>
|
||||
|
||||
#endif
|
||||
#endif /* __L4LIB_ARM_TYPES_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 <l4lib/types.h>
|
||||
@@ -13,27 +16,37 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
6
tasks/libl4/include/l4lib/init.h
Normal file
6
tasks/libl4/include/l4lib/init.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef __L4LIB_INIT__
|
||||
#define __L4LIB_INIT__
|
||||
|
||||
void __l4_init(void);
|
||||
|
||||
#endif
|
||||
14
tasks/libl4/include/l4lib/thread.h
Normal file
14
tasks/libl4/include/l4lib/thread.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __L4_THREAD_H__
|
||||
#define __L4_THREAD_H__
|
||||
|
||||
#include <libl4/arch/utcb.h>
|
||||
#include <libl4/arch/types.h>
|
||||
|
||||
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__ */
|
||||
@@ -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;
|
||||
|
||||
@@ -9,9 +9,18 @@
|
||||
#include <l4/macros.h>
|
||||
#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}
|
||||
|
||||
@@ -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 <l4lib/kip.h>
|
||||
#include <l4lib/arch/syslib.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <l4lib/utcb.h>
|
||||
#include <l4/macros.h>
|
||||
#include INC_GLUE(memory.h)
|
||||
#include <posix_init.h>
|
||||
#include <shpage.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -3,28 +3,20 @@
|
||||
*
|
||||
* Copyright (C) 2007-2009 Bahadir Balban
|
||||
*/
|
||||
|
||||
#include <shpage.h>
|
||||
#include <posix_init.h>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
28
tasks/mm0/container.c
Normal file
28
tasks/mm0/container.c
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Container entry point for pager
|
||||
*
|
||||
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
||||
*/
|
||||
|
||||
#include <posix/posix_init.h>
|
||||
#include <l4lib/init.h>
|
||||
#include <l4lib/utcb.h>
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include INC_GLUE(memlayout.h)
|
||||
#include <l4/lib/list.h>
|
||||
#include <l4lib/arch/types.h>
|
||||
#include <l4lib/arch/syscalls.h>
|
||||
#include <l4lib/utcb.h>
|
||||
#include <lib/addr.h>
|
||||
#include <l4/api/kip.h>
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#define __VM_AREA_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <task.h>
|
||||
#include <l4/macros.h>
|
||||
#include <l4/config.h>
|
||||
#include <l4/types.h>
|
||||
#include <task.h>
|
||||
#include <arch/mm.h>
|
||||
#include <lib/spinlock.h>
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <test.h>
|
||||
#include <boot.h>
|
||||
|
||||
|
||||
/* A separate list than the generic file list that keeps just the boot files */
|
||||
LIST_HEAD(boot_file_list);
|
||||
|
||||
|
||||
27
tasks/mm0/src/utcb.c
Normal file
27
tasks/mm0/src/utcb.c
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Management of task utcb regions and own utcb.
|
||||
*
|
||||
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
||||
*/
|
||||
|
||||
#include <l4lib/arch/utcb.h>
|
||||
#include <l4/macros.h>
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
25
tasks/test0/container.c
Normal file
25
tasks/test0/container.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Container entry point for this task.
|
||||
*
|
||||
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
||||
*/
|
||||
|
||||
#include <l4lib/types.h>
|
||||
#include <l4lib/init.h>
|
||||
#include <l4lib/utcb.h>
|
||||
#include <posix_init.h> /* 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();
|
||||
}
|
||||
|
||||
@@ -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 = .;
|
||||
|
||||
Reference in New Issue
Block a user