Updated the timer service to introduce irq handling.

This commit is contained in:
Bahadir Balban
2009-12-12 15:17:29 +02:00
parent 41b7176a58
commit 8681c1d8c9
6 changed files with 204 additions and 63 deletions

View File

@@ -65,6 +65,7 @@ env = Environment(CC = config.user_toolchain + 'gcc',
src = Glob('*.[cS]')
src += Glob('src/*.[cS]')
src += Glob('src/arch/*.[cS]')
objs = env.Object(src)
prog = env.Program('main.elf', objs)

View File

@@ -0,0 +1,18 @@
#ifndef __THREAD_H__
#define __THREAD_H__
#include <l4lib/arch/syslib.h>
#include <l4lib/arch/syscalls.h>
#include <l4lib/exregs.h>
#include <l4/api/thread.h>
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__ */

View File

@@ -1,36 +1,23 @@
/*
* Timer details.
*/
#ifndef __TIMER_H__
#define __TIMER_H__
/*
* Timer specific things are here
*/
#include <l4lib/mutex.h>
#include <l4/lib/list.h>
#include <l4lib/types.h>
/*
* Structure representing the sleeping tasks,
* tgid: tgid of sleeping task
* wait_count: time left, in microseconds, after which task
* will be signalled to get out of sleep
*/
struct timer_task {
struct link list;
l4id_t tgid;
unsigned int wait_count;
};
/*
* Timer structure,
* base: base address of sp804 timer encapsulated
* count: Count in microseconds from the start of this timer
* tasklist: list of tasks sleeping for some value of count
* lock: lock protecting the corruption of tasklist
*/
struct sp804_timer {
unsigned int base;
unsigned int count;
struct link tasklist;
struct l4_mutex lock;
* Timer structure
*/
struct timer {
int slot; /* Notify slot on utcb */
unsigned int base; /* Virtual base address */
u64 count; /* Counter */
struct link task_list; /* List of sleepers */
struct l4_mutex lock; /* Lock for structure */
struct capability cap; /* Capability describing timer */
};
#endif /* __TIMER_H__ */

View File

@@ -17,14 +17,15 @@
#include <timer.h>
/* Frequency of timer in MHz */
#define TIMER_FREQUENCY 1
#define TIMER_FREQUENCY 1
#define TIMERS_TOTAL 1
static struct capability caparray[32];
static int total_caps = 0;
struct capability timer_cap[TIMERS_TOTAL];
static struct timer timer[TIMERS_TOTAL];
static int notify_slot = 0;
int cap_read_all()
{
@@ -66,8 +67,8 @@ int timer_probe_devices(void)
/* Match device type */
if (cap_devtype(&caparray[i]) == CAP_DEVTYPE_TIMER) {
/* Copy to correct device index */
memcpy(&timer_cap[cap_devnum(&caparray[i]) - 1],
&caparray[i], sizeof(timer_cap[0]));
memcpy(&timer[cap_devnum(&caparray[i]) - 1].cap,
&caparray[i], sizeof(timer[0].cap));
timers++;
}
}
@@ -80,27 +81,46 @@ int timer_probe_devices(void)
return 0;
}
static struct sp804_timer timer[TIMERS_TOTAL];
struct timer_task *get_timer_task(l4id_t tgid)
void timer_irq_handler(void *arg)
{
/* May be we can prepare a cache for timer_task structs */
struct timer_task *task = (struct timer_task *)kzalloc(sizeof(struct timer_task));
struct timer *timer = (struct timer *)arg;
link_init(&task->list);
task->tgid = tgid;
task->wait_count = timer[0].count;
/* Initialise timer */
sp804_init(timer->base, SP804_TIMER_RUNMODE_PERIODIC,
SP804_TIMER_WRAPMODE_WRAPPING,
SP804_TIMER_WIDTH32BIT, SP804_TIMER_IRQENABLE);
return task;
}
/* Register self for timer irq, using notify slot 0 */
if ((err = l4_irq_control(IRQ_CONTROL_REGISTER, 0,
timer->cap.irqnum)) < 0) {
printf("%s: FATAL: Timer irq could not be registered. "
"err=%d\n", __FUNCTION__, err);
BUG();
}
void free_timer_task(struct timer_task *task)
{
kfree(task);
/* Enable Timer */
sp804_enable(timer->base, 1);
/* Handle irqs forever */
while (1) {
int count;
/* Block on irq */
count = l4_irq_wait(timer->cap.irqnum);
/* Update timer count */
timer->count += count;
/* Print both counter and number of updates on count */
printf("Timer count: %lld, current update: %d\n",
timer->count, count);
}
}
int timer_setup_devices(void)
{
struct task_ids irq_tids;
for (int i = 0; i < TIMERS_TOTAL; i++) {
/* Get one page from address pool */
timer[i].base = (unsigned long)l4_new_virtual(1);
@@ -108,9 +128,9 @@ int timer_setup_devices(void)
link_init(&timer[i].tasklist);
l4_mutex_init(&timer[i].lock);
/* Map timers to a virtual address region */
if (IS_ERR(l4_map((void *)__pfn_to_addr(timer_cap[i].start),
(void *)timer[i].base, timer_cap[i].size,
/* Map timer to a virtual address region */
if (IS_ERR(l4_map((void *)__pfn_to_addr(timer[i].cap.start),
(void *)timer[i].base, timer[i].cap.size,
MAP_USR_IO_FLAGS,
self_tid()))) {
printf("%s: FATAL: Failed to map TIMER device "
@@ -120,14 +140,22 @@ int timer_setup_devices(void)
BUG();
}
/* Initialise timer */
sp804_init(timer[i].base, SP804_TIMER_RUNMODE_PERIODIC, \
SP804_TIMER_WRAPMODE_WRAPPING, SP804_TIMER_WIDTH32BIT, \
SP804_TIMER_IRQDISABLE);
/* Enable Timer */
sp804_enable(timer[i].base, 1);
/*
* Create new timer irq handler thread.
*
* This will initialize its timer argument, register
* itself as its irq handler, initiate the timer and
* wait on irqs.
*/
if ((err = thread_create(timer_irq_handler, &timer[i],
TC_SHARED_SPACE,
&irq_tids)) < 0) {
printf("FATAL: Creation of irq handler "
"thread failed.\n");
BUG();
}
}
return 0;
}
@@ -141,8 +169,8 @@ void init_vaddr_pool(void)
{
for (int i = 0; i < total_caps; i++) {
/* Find the virtual memory region for this process */
if (cap_type(&caparray[i]) == CAP_TYPE_MAP_VIRTMEM &&
__pfn_to_addr(caparray[i].start) ==
if (cap_type(&caparray[i]) == CAP_TYPE_MAP_VIRTMEM
&& __pfn_to_addr(caparray[i].start) ==
(unsigned long)vma_start) {
/*
@@ -159,8 +187,10 @@ void init_vaddr_pool(void)
* We may allocate virtual memory
* addresses from this pool.
*/
address_pool_init(&device_vaddr_pool, page_align_up(__end),
__pfn_to_addr(caparray[i].end), TIMERS_TOTAL);
address_pool_init(&device_vaddr_pool,
page_align_up(__end),
__pfn_to_addr(caparray[i].end),
TIMERS_TOTAL);
return;
} else
goto out_err;
@@ -179,6 +209,24 @@ void *l4_new_virtual(int npages)
return address_new(&device_vaddr_pool, npages, PAGE_SIZE);
}
#if 0
struct timer_task *get_timer_task(l4id_t tgid)
{
/* May be we can prepare a cache for timer_task structs */
struct timer_task *task = (struct timer_task *)kzalloc(sizeof(struct timer_task));
link_init(&task->list);
task->tgid = tgid;
task->wait_count = timer[0].count;
return task;
}
void free_timer_task(struct timer_task *task)
{
kfree(task);
}
void timer_irq_handler(void)
{
struct timer_task *struct_ptr, *temp_ptr;
@@ -221,6 +269,8 @@ void timer_sleep(l4id_t tgid, int sec)
l4_mutex_unlock(&timer[0].lock);
}
#endif
void handle_requests(void)
{
u32 mr[MR_UNUSED_TOTAL];
@@ -256,11 +306,11 @@ void handle_requests(void)
*/
switch (tag) {
case L4_IPC_TAG_TIMER_GETTIME:
mr[0] = timer_gettime();
//mr[0] = timer_gettime();
break;
case L4_IPC_TAG_TIMER_SLEEP:
timer_sleep(senderid, mr[0]);
//timer_sleep(senderid, mr[0]);
/* TODO: Halt the caller for mr[0] seconds */
break;
@@ -326,16 +376,16 @@ void main(void)
/* Initialize virtual address pool for timers */
init_vaddr_pool();
/* Map and initialize timer devices */
timer_setup_devices();
/* Setup own utcb */
/* Setup own static utcb */
if ((err = l4_utcb_setup(&utcb)) < 0) {
printf("FATAL: Could not set up own utcb. "
"err=%d\n", err);
BUG();
}
/* Map and initialize timer devices */
timer_setup_devices();
/* Listen for timer requests */
while (1)
handle_requests();

View File

@@ -0,0 +1,11 @@
#include <l4lib/arch/asm.h>
BEGIN_PROC(local_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(local_setup_new_thread)

View File

@@ -0,0 +1,74 @@
/*
* Thread creation userspace helpers
*
* Copyright (C) 2009 B Labs Ltd.
*/
#include <thread.h>
#include <l4/api/errno.h>
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 local_setup_new_thread(void);
l4id_t 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)local_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 (flags & THREAD_RUN)
if ((err = l4_thread_control(THREAD_RUN, &ids)) < 0)
return err;
memcpy(new_ids, &ids, sizeof(ids));
return 0;
}