mirror of
https://github.com/drasko/codezero.git
synced 2026-01-11 18:33:16 +01:00
Updated the timer service to introduce irq handling.
This commit is contained in:
@@ -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)
|
||||
|
||||
18
conts/baremetal/timer_service/include/thread.h
Normal file
18
conts/baremetal/timer_service/include/thread.h
Normal 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__ */
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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();
|
||||
|
||||
11
conts/baremetal/timer_service/src/new_thread.S
Normal file
11
conts/baremetal/timer_service/src/new_thread.S
Normal 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)
|
||||
|
||||
74
conts/baremetal/timer_service/src/thread.c
Normal file
74
conts/baremetal/timer_service/src/thread.c
Normal 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user