L4Re - L4 Runtime Environment
examples/sys/start-with-exc/main.c

This example shows how to start a newly created thread with a defined set of CPU registers.

/*
* (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
* Alexander Warg <warg@os.inf.tu-dresden.de>,
* Björn Döbel <doebel@os.inf.tu-dresden.de>,
* Frank Mehnert <fm3@os.inf.tu-dresden.de>
* economic rights: Technische Universität Dresden (Germany)
*
* This file is part of TUD:OS and distributed under the terms of the
* GNU General Public License 2.
* Please see the COPYING-GPL-2 file for details.
*/
/*
* Start a thread with an exception reply. This example does only work on
* the x86-32 and ARM architectures.
*/
#include <l4/sys/thread.h>
#include <l4/sys/factory.h>
#include <l4/sys/ipc.h>
#include <l4/sys/utcb.h>
#include <l4/util/util.h>
#include <l4/re/env.h>
#include <stdlib.h>
#include <stdio.h>
/* Stack for the thread to be created. 8kB are enough. */
static char thread_stack[8 << 10];
/* The thread to be created. For illustration it will print out its
* register set.
*/
static void L4_STICKY(thread_func(l4_umword_t *d))
{
while (1)
{
printf("hey, I'm a thread\n");
printf("got register values: %ld %ld %ld %ld %ld %ld %ld\n",
d[7], d[6], d[5], d[4], d[2], d[1], d[0]);
l4_sleep(800);
}
}
/* Startup trick for this example. Put all the CPU registers on the stack so
* that the C function above can get it on the stack. */
asm(
".global thread \n\t"
"thread: \n\t"
#ifdef ARCH_x86
" pusha \n\t"
" push %esp \n\t"
" call thread_func \n\t"
#endif
#ifdef ARCH_arm
" push {r0-r7} \n\t"
" mov r0, sp \n\t"
" bl thread_func \n\t"
#endif
);
extern void thread(void);
/* Our main function */
int main(void)
{
/* Get a capability slot for our new thread. */
l4_exc_regs_t *e = l4_utcb_exc_u(u);
int err;
printf("Example showing how to start a thread with an exception.\n");
/* We do not want to implement a pager here, take the shortcut. */
printf("Make sure to start this program with ldr-flags=eager_map\n");
return 1;
/* Create the thread using our default factory */
tag = l4_factory_create_thread(l4re_env()->factory, t1);
if (l4_error(tag))
return 1;
/* Setup the thread by setting the pager and task. */
l4_thread_control_bind((l4_utcb_t *)l4re_env()->first_free_utcb,
L4RE_THIS_TASK_CAP);
if (l4_error(tag))
return 2;
/* Start the thread by finally setting instruction and stack pointer */
(l4_umword_t)thread,
(l4_umword_t)thread_stack + sizeof(thread_stack),
if (l4_error(tag))
return 3;
tag = l4_scheduler_run_thread(l4re_env()->scheduler, t1, &sp);
if (l4_error(tag))
return 4;
/* Receive initial exception from just started thread */
if ((err = l4_ipc_error(tag, u)))
{
printf("Umm, ipc error: %x\n", err);
return 1;
}
/* We expect an exception IPC */
{
printf("PF?: %lx %lx (not prepared to handle this) %ld\n",
l4_utcb_mr_u(u)->mr[0], l4_utcb_mr_u(u)->mr[1], l4_msgtag_label(tag));
return 1;
}
/* Fill out the complete register set of the new thread */
e->sp = (l4_umword_t)(thread_stack + sizeof(thread_stack));
#ifdef ARCH_x86
e->ip = (l4_umword_t)thread;
e->edi = 0;
e->esi = 1;
e->ebp = 2;
e->ebx = 4;
e->edx = 5;
e->ecx = 6;
e->eax = 7;
#endif
#ifdef ARCH_arm
e->pc = (l4_umword_t)thread;
e->r[0] = 0;
e->r[1] = 1;
e->r[2] = 2;
e->r[3] = 3;
e->r[4] = 4;
e->r[5] = 5;
e->r[6] = 6;
e->r[7] = 7;
#endif
/* Send a complete exception */
/* Send reply and start the thread with the defined CPU register set */
tag = l4_ipc_send(t1, u, tag, L4_IPC_NEVER);
if ((err = l4_ipc_error(tag, u)))
printf("Error sending IPC: %x\n", err);
/* Idle around */
while (1)
l4_sleep(10000);
return 0;
}