mirror of
https://github.com/drasko/codezero.git
synced 2026-02-28 01:33:13 +01:00
Added kernel + libl4 changes for full and extended ipc.
- Short ipc working as normal. Full/extended ipc haven't been tested. - Added automated compilation and inclusion of test executable in test0.
This commit is contained in:
@@ -13,8 +13,8 @@
|
|||||||
#if defined (__KERNEL__)
|
#if defined (__KERNEL__)
|
||||||
|
|
||||||
/* These are for internally created ipc paths. */
|
/* These are for internally created ipc paths. */
|
||||||
int ipc_send(l4id_t to);
|
int ipc_send(l4id_t to, int full);
|
||||||
int ipc_sendrecv(l4id_t to, l4id_t from);
|
int ipc_sendrecv(l4id_t to, l4id_t from, int full);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ void address_space_remove(struct address_space *space);
|
|||||||
void address_space_reference_lock();
|
void address_space_reference_lock();
|
||||||
void address_space_reference_unlock();
|
void address_space_reference_unlock();
|
||||||
void init_address_space_list(void);
|
void init_address_space_list(void);
|
||||||
int check_access(unsigned long vaddr, unsigned long size, unsigned int flags);
|
int check_access(unsigned long vaddr, unsigned long size,
|
||||||
|
unsigned int flags, int page_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __SPACE_H__ */
|
#endif /* __SPACE_H__ */
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
#define TASK_SUSPENDING (1 << 1)
|
#define TASK_SUSPENDING (1 << 1)
|
||||||
#define TASK_RESUMING (1 << 2)
|
#define TASK_RESUMING (1 << 2)
|
||||||
|
|
||||||
|
/* IPC resulted in a fault error (For ipcs that cannot page fault) */
|
||||||
|
#define IPC_EFAULT (1 << 3)
|
||||||
|
|
||||||
/* Task states */
|
/* Task states */
|
||||||
enum task_state {
|
enum task_state {
|
||||||
TASK_INACTIVE = 0,
|
TASK_INACTIVE = 0,
|
||||||
|
|||||||
@@ -83,4 +83,13 @@
|
|||||||
|
|
||||||
#include INC_GLUE(memlayout.h)
|
#include INC_GLUE(memlayout.h)
|
||||||
|
|
||||||
|
#if defined (__KERNEL__)
|
||||||
|
struct utcb {
|
||||||
|
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 */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __GLUE_ARM_MESSAGE_H__ */
|
#endif /* __GLUE_ARM_MESSAGE_H__ */
|
||||||
|
|||||||
120
src/api/ipc.c
120
src/api/ipc.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Inter-process communication
|
* Inter-process communication
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007 Bahadir Balban
|
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
|
||||||
*/
|
*/
|
||||||
#include <l4/generic/tcb.h>
|
#include <l4/generic/tcb.h>
|
||||||
#include <l4/lib/mutex.h>
|
#include <l4/lib/mutex.h>
|
||||||
@@ -14,13 +14,46 @@
|
|||||||
#include INC_API(syscall.h)
|
#include INC_API(syscall.h)
|
||||||
#include INC_GLUE(message.h)
|
#include INC_GLUE(message.h)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ipc syscall uses an ipc_type variable and flags and send/recv
|
||||||
|
* details are embedded in this variable.
|
||||||
|
*/
|
||||||
|
#define IPC_TYPE_FLAGS_SHIFT 2
|
||||||
enum IPC_TYPE {
|
enum IPC_TYPE {
|
||||||
IPC_INVALID = 0,
|
IPC_INVALID = 0,
|
||||||
IPC_SEND = 1,
|
IPC_SEND = 1,
|
||||||
IPC_RECV = 2,
|
IPC_RECV = 2,
|
||||||
IPC_SENDRECV = 3
|
IPC_SENDRECV = 3,
|
||||||
|
IPC_SEND_FULL = 5,
|
||||||
|
IPC_RECV_FULL = 6,
|
||||||
|
IPC_SENDRECV_FULL = 7,
|
||||||
|
IPC_SEND_EXTENDED = 9,
|
||||||
|
IPC_RECV_EXTENDED = 10,
|
||||||
|
IPC_SENDRECV_EXTENDED = 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Copy full utcb region from one task to another. */
|
||||||
|
int ipc_full_copy(struct ktcb *to, struct ktcb *from)
|
||||||
|
{
|
||||||
|
struct utcb *from_utcb = (struct utcb *)from->utcb_address;
|
||||||
|
struct utcb *to_utcb = (struct utcb *)to->utcb_address;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Check that utcb memory accesses won't fault us */
|
||||||
|
if ((ret = check_access(to->utcb_address, UTCB_SIZE,
|
||||||
|
MAP_SVC_RW_FLAGS, 0)) < 0)
|
||||||
|
return ret;
|
||||||
|
if ((ret = check_access(to->utcb_address, UTCB_SIZE,
|
||||||
|
MAP_SVC_RW_FLAGS, 0)) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* Directly copy from one utcb to another */
|
||||||
|
memcpy(to_utcb->mr_rest, from_utcb->mr_rest,
|
||||||
|
MR_REST * sizeof(unsigned int));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copies message registers from one ktcb stack to another. During the return
|
* Copies message registers from one ktcb stack to another. During the return
|
||||||
* from system call, the registers are popped from the stack. In the future
|
* from system call, the registers are popped from the stack. In the future
|
||||||
@@ -30,10 +63,11 @@ enum IPC_TYPE {
|
|||||||
* L4_ANYTHREAD. This is done for security since the receiver cannot trust
|
* L4_ANYTHREAD. This is done for security since the receiver cannot trust
|
||||||
* the sender info provided by the sender task.
|
* the sender info provided by the sender task.
|
||||||
*/
|
*/
|
||||||
int ipc_msg_copy(struct ktcb *to, struct ktcb *from)
|
int ipc_msg_copy(struct ktcb *to, struct ktcb *from, int full)
|
||||||
{
|
{
|
||||||
unsigned int *mr0_src = KTCB_REF_MR0(from);
|
unsigned int *mr0_src = KTCB_REF_MR0(from);
|
||||||
unsigned int *mr0_dst = KTCB_REF_MR0(to);
|
unsigned int *mr0_dst = KTCB_REF_MR0(to);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
/* NOTE:
|
/* NOTE:
|
||||||
* Make sure MR_TOTAL matches the number of registers saved on stack.
|
* Make sure MR_TOTAL matches the number of registers saved on stack.
|
||||||
@@ -44,7 +78,11 @@ int ipc_msg_copy(struct ktcb *to, struct ktcb *from)
|
|||||||
if (to->expected_sender == L4_ANYTHREAD)
|
if (to->expected_sender == L4_ANYTHREAD)
|
||||||
mr0_dst[MR_SENDER] = from->tid;
|
mr0_dst[MR_SENDER] = from->tid;
|
||||||
|
|
||||||
return 0;
|
/* Check if full utcb copying is requested and do it */
|
||||||
|
if (full)
|
||||||
|
ret = ipc_full_copy(to, from);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sys_ipc_control(syscall_context_t *regs)
|
int sys_ipc_control(syscall_context_t *regs)
|
||||||
@@ -61,10 +99,11 @@ int sys_ipc_control(syscall_context_t *regs)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Interruptible ipc */
|
/* Interruptible ipc */
|
||||||
int ipc_send(l4id_t recv_tid)
|
int ipc_send(l4id_t recv_tid, int full)
|
||||||
{
|
{
|
||||||
struct ktcb *receiver = tcb_find(recv_tid);
|
struct ktcb *receiver = tcb_find(recv_tid);
|
||||||
struct waitqueue_head *wqhs, *wqhr;
|
struct waitqueue_head *wqhs, *wqhr;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
wqhs = &receiver->wqh_send;
|
wqhs = &receiver->wqh_send;
|
||||||
wqhr = &receiver->wqh_recv;
|
wqhr = &receiver->wqh_recv;
|
||||||
@@ -89,14 +128,18 @@ int ipc_send(l4id_t recv_tid)
|
|||||||
spin_unlock(&wqhs->slock);
|
spin_unlock(&wqhs->slock);
|
||||||
|
|
||||||
/* Copy message registers */
|
/* Copy message registers */
|
||||||
ipc_msg_copy(receiver, current);
|
if ((ret = ipc_msg_copy(receiver, current, full)) < 0) {
|
||||||
|
/* Set ipc error flag in receiver */
|
||||||
|
BUG_ON(ret != -EFAULT);
|
||||||
|
receiver->flags |= IPC_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
// printk("%s: (%d) Waking up (%d)\n", __FUNCTION__,
|
// printk("%s: (%d) Waking up (%d)\n", __FUNCTION__,
|
||||||
// current->tid, receiver->tid);
|
// current->tid, receiver->tid);
|
||||||
|
|
||||||
/* Wake it up, we can yield here. */
|
/* Wake it up, we can yield here. */
|
||||||
sched_resume_sync(receiver);
|
sched_resume_sync(receiver);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The receiver is not ready and/or not expecting us */
|
/* The receiver is not ready and/or not expecting us */
|
||||||
@@ -116,12 +159,19 @@ int ipc_send(l4id_t recv_tid)
|
|||||||
current->flags &= ~TASK_INTERRUPTED;
|
current->flags &= ~TASK_INTERRUPTED;
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Did ipc fail with a fault error? */
|
||||||
|
if (current->flags & IPC_EFAULT) {
|
||||||
|
current->flags &= ~IPC_EFAULT;
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipc_recv(l4id_t senderid)
|
int ipc_recv(l4id_t senderid, int full)
|
||||||
{
|
{
|
||||||
struct waitqueue_head *wqhs, *wqhr;
|
struct waitqueue_head *wqhs, *wqhr;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
wqhs = ¤t->wqh_send;
|
wqhs = ¤t->wqh_send;
|
||||||
wqhr = ¤t->wqh_recv;
|
wqhr = ¤t->wqh_recv;
|
||||||
@@ -154,12 +204,20 @@ int ipc_recv(l4id_t senderid)
|
|||||||
task_unset_wqh(sleeper);
|
task_unset_wqh(sleeper);
|
||||||
spin_unlock(&wqhr->slock);
|
spin_unlock(&wqhr->slock);
|
||||||
spin_unlock(&wqhs->slock);
|
spin_unlock(&wqhs->slock);
|
||||||
ipc_msg_copy(current, sleeper);
|
|
||||||
|
/* Copy message registers */
|
||||||
|
if ((ret = ipc_msg_copy(current, sleeper,
|
||||||
|
full)) < 0) {
|
||||||
|
|
||||||
|
/* Set ipc fault flag on sleeper */
|
||||||
|
BUG_ON(ret != -EFAULT);
|
||||||
|
sleeper->flags |= IPC_EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
// printk("%s: (%d) Waking up (%d)\n", __FUNCTION__,
|
// printk("%s: (%d) Waking up (%d)\n", __FUNCTION__,
|
||||||
// current->tid, sleeper->tid);
|
// current->tid, sleeper->tid);
|
||||||
sched_resume_sync(sleeper);
|
sched_resume_sync(sleeper);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,6 +239,13 @@ int ipc_recv(l4id_t senderid)
|
|||||||
current->flags &= ~TASK_INTERRUPTED;
|
current->flags &= ~TASK_INTERRUPTED;
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Did ipc fail with a fault error? */
|
||||||
|
if (current->flags & IPC_EFAULT) {
|
||||||
|
current->flags &= ~IPC_EFAULT;
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,20 +263,22 @@ int ipc_recv(l4id_t senderid)
|
|||||||
* (6) System task calls ipc_send() sending the return result.
|
* (6) System task calls ipc_send() sending the return result.
|
||||||
* (7) Rendezvous occurs. Both tasks exchange mrs and leave rendezvous.
|
* (7) Rendezvous occurs. Both tasks exchange mrs and leave rendezvous.
|
||||||
*/
|
*/
|
||||||
int ipc_sendrecv(l4id_t to, l4id_t from)
|
int ipc_sendrecv(l4id_t to, l4id_t from, int full)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (to == from) {
|
if (to == from) {
|
||||||
/* Send ipc request */
|
/* Send ipc request */
|
||||||
ipc_send(to);
|
if ((ret = ipc_send(to, full)) < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get reply.
|
* Get reply.
|
||||||
* A client would block its server only very briefly
|
* A client would block its server only very briefly
|
||||||
* between these calls.
|
* between these calls.
|
||||||
*/
|
*/
|
||||||
ipc_recv(from);
|
if ((ret = ipc_recv(from, full)) < 0)
|
||||||
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
printk("%s: Unsupported ipc operation.\n", __FUNCTION__);
|
printk("%s: Unsupported ipc operation.\n", __FUNCTION__);
|
||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
@@ -225,13 +292,28 @@ static inline int __sys_ipc(l4id_t to, l4id_t from, unsigned int ipc_type)
|
|||||||
|
|
||||||
switch (ipc_type) {
|
switch (ipc_type) {
|
||||||
case IPC_SEND:
|
case IPC_SEND:
|
||||||
ret = ipc_send(to);
|
ret = ipc_send(to, 0);
|
||||||
break;
|
break;
|
||||||
case IPC_RECV:
|
case IPC_RECV:
|
||||||
ret = ipc_recv(from);
|
ret = ipc_recv(from, 0);
|
||||||
break;
|
break;
|
||||||
case IPC_SENDRECV:
|
case IPC_SENDRECV:
|
||||||
ret = ipc_sendrecv(to, from);
|
ret = ipc_sendrecv(to, from, 0);
|
||||||
|
break;
|
||||||
|
case IPC_SEND_FULL:
|
||||||
|
ret = ipc_send(to, 1);
|
||||||
|
break;
|
||||||
|
case IPC_RECV_FULL:
|
||||||
|
ret = ipc_recv(from, 1);
|
||||||
|
break;
|
||||||
|
case IPC_SENDRECV_FULL:
|
||||||
|
ret = ipc_sendrecv(to, from, 1);
|
||||||
|
break;
|
||||||
|
case IPC_SEND_EXTENDED:
|
||||||
|
break;
|
||||||
|
case IPC_RECV_EXTENDED:
|
||||||
|
break;
|
||||||
|
case IPC_SENDRECV_EXTENDED:
|
||||||
break;
|
break;
|
||||||
case IPC_INVALID:
|
case IPC_INVALID:
|
||||||
default:
|
default:
|
||||||
@@ -267,6 +349,7 @@ int sys_ipc(syscall_context_t *regs)
|
|||||||
{
|
{
|
||||||
l4id_t to = (l4id_t)regs->r0;
|
l4id_t to = (l4id_t)regs->r0;
|
||||||
l4id_t from = (l4id_t)regs->r1;
|
l4id_t from = (l4id_t)regs->r1;
|
||||||
|
unsigned int flags = (unsigned int)regs->r2;
|
||||||
unsigned int ipc_type = 0;
|
unsigned int ipc_type = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@@ -292,6 +375,9 @@ int sys_ipc(syscall_context_t *regs)
|
|||||||
/* [1] for Receive, [1:0] for both */
|
/* [1] for Receive, [1:0] for both */
|
||||||
ipc_type |= ((from != L4_NILTHREAD) << 1);
|
ipc_type |= ((from != L4_NILTHREAD) << 1);
|
||||||
|
|
||||||
|
/* Short, full or extended ipc set here. Bits [3:2] */
|
||||||
|
ipc_type |= (flags & L4_IPC_FLAGS_MASK) << IPC_TYPE_FLAGS_SHIFT;
|
||||||
|
|
||||||
if (ipc_type == IPC_INVALID) {
|
if (ipc_type == IPC_INVALID) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto error;
|
goto error;
|
||||||
@@ -302,7 +388,7 @@ int sys_ipc(syscall_context_t *regs)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
printk("Erroneous ipc by: %d. Err: %d\n", current->tid, ret);
|
// printk("Erroneous ipc by: %d. Err: %d\n", current->tid, ret);
|
||||||
ipc_type = IPC_INVALID;
|
ipc_type = IPC_INVALID;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,19 +23,19 @@ int __sys_kread(int rd, void *dest)
|
|||||||
switch(rd) {
|
switch(rd) {
|
||||||
case KDATA_PAGE_MAP:
|
case KDATA_PAGE_MAP:
|
||||||
// printk("Handling KDATA_PAGE_MAP request.\n");
|
// printk("Handling KDATA_PAGE_MAP request.\n");
|
||||||
if (check_access(vaddr, sizeof(page_map), MAP_USR_RW_FLAGS) < 0)
|
if (check_access(vaddr, sizeof(page_map), MAP_USR_RW_FLAGS, 1) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
memcpy(dest, &page_map, sizeof(page_map));
|
memcpy(dest, &page_map, sizeof(page_map));
|
||||||
break;
|
break;
|
||||||
case KDATA_BOOTDESC:
|
case KDATA_BOOTDESC:
|
||||||
// printk("Handling KDATA_BOOTDESC request.\n");
|
// printk("Handling KDATA_BOOTDESC request.\n");
|
||||||
if (check_access(vaddr, bootdesc->desc_size, MAP_USR_RW_FLAGS) < 0)
|
if (check_access(vaddr, bootdesc->desc_size, MAP_USR_RW_FLAGS, 1) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
memcpy(dest, bootdesc, bootdesc->desc_size);
|
memcpy(dest, bootdesc, bootdesc->desc_size);
|
||||||
break;
|
break;
|
||||||
case KDATA_BOOTDESC_SIZE:
|
case KDATA_BOOTDESC_SIZE:
|
||||||
// printk("Handling KDATA_BOOTDESC_SIZE request.\n");
|
// printk("Handling KDATA_BOOTDESC_SIZE request.\n");
|
||||||
if (check_access(vaddr, sizeof(unsigned int), MAP_USR_RW_FLAGS) < 0)
|
if (check_access(vaddr, sizeof(unsigned int), MAP_USR_RW_FLAGS, 1) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
*(unsigned int *)dest = bootdesc->desc_size;
|
*(unsigned int *)dest = bootdesc->desc_size;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far)
|
|||||||
offsetof(syscall_context_t, r3));
|
offsetof(syscall_context_t, r3));
|
||||||
|
|
||||||
/* Send ipc to the task's pager */
|
/* Send ipc to the task's pager */
|
||||||
ipc_sendrecv(current->pagerid, current->pagerid);
|
ipc_sendrecv(current->pagerid, current->pagerid, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: CHECK TASK KILL REPLY !!!
|
* FIXME: CHECK TASK KILL REPLY !!!
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ struct address_space *address_space_create(struct address_space *orig)
|
|||||||
* If its not mapped-in, it generates a page-in request to the thread's
|
* If its not mapped-in, it generates a page-in request to the thread's
|
||||||
* pager. If fault hasn't cleared, aborts.
|
* pager. If fault hasn't cleared, aborts.
|
||||||
*/
|
*/
|
||||||
int check_access(unsigned long vaddr, unsigned long size, unsigned int flags)
|
int check_access(unsigned long vaddr, unsigned long size, unsigned int flags, int page_in)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -159,20 +159,17 @@ int check_access(unsigned long vaddr, unsigned long size, unsigned int flags)
|
|||||||
if (size >= USER_AREA_SIZE)
|
if (size >= USER_AREA_SIZE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Check if in user range, but this is more up to the pager to decide */
|
/* Check if the address is mapped with given flags */
|
||||||
if (current->tid == PAGER_TID) {
|
if (!check_mapping(vaddr, size, flags)) {
|
||||||
if (!(vaddr >= INITTASK_AREA_START && vaddr < INITTASK_AREA_END))
|
/* Is a page in requested? */
|
||||||
return -EINVAL;
|
if (page_in) {
|
||||||
} else {
|
/* Ask pager if paging in is possible */
|
||||||
if (!(vaddr >= USER_AREA_START && vaddr < USER_AREA_END))
|
if((err = pager_pagein_request(vaddr, size, flags)) < 0)
|
||||||
return -EINVAL;
|
return err;
|
||||||
|
} else
|
||||||
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If not mapped, ask pager whether this is possible */
|
|
||||||
if (!check_mapping(vaddr, size, flags))
|
|
||||||
if((err = pager_pagein_request(vaddr, size, flags)) < 0)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ int sys_time(syscall_context_t *args)
|
|||||||
int set = (int)args->r1;
|
int set = (int)args->r1;
|
||||||
int retries = 20;
|
int retries = 20;
|
||||||
|
|
||||||
if (check_access((unsigned long)tv, sizeof(*tv), MAP_USR_RW_FLAGS) < 0)
|
if (check_access((unsigned long)tv, sizeof(*tv), MAP_USR_RW_FLAGS, 1) < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Get time */
|
/* Get time */
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ END_PROC(l4_kread)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* For clone() we need special assembler handling
|
* For clone() we need special assembler handling
|
||||||
* Same signature as ipc(): @r0 = to, @r1 = from
|
* Same signature as ipc(): @r0 = to, @r1 = from @r2 = flags
|
||||||
*
|
*
|
||||||
* NOTE: Note that this breaks l4 system call interface,
|
* NOTE: Note that this breaks l4 system call interface,
|
||||||
* this should be moved elsewhere and modified using existing l4 mechanisms.
|
* this should be moved elsewhere and modified using existing l4 mechanisms.
|
||||||
@@ -62,6 +62,11 @@ BEGIN_PROC(arch_clone)
|
|||||||
stmfd sp!, {r4-r8,lr} @ Save context.
|
stmfd sp!, {r4-r8,lr} @ Save context.
|
||||||
utcb_address r12 @ Get utcb address.
|
utcb_address r12 @ Get utcb address.
|
||||||
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
|
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
|
||||||
|
|
||||||
|
cmp r2, #0
|
||||||
|
1:
|
||||||
|
bne 1b
|
||||||
|
|
||||||
ldr r12, =__l4_ipc
|
ldr r12, =__l4_ipc
|
||||||
mov lr, pc
|
mov lr, pc
|
||||||
ldr pc, [r12] @ Perform the ipc()
|
ldr pc, [r12] @ Perform the ipc()
|
||||||
@@ -101,6 +106,11 @@ BEGIN_PROC(l4_ipc)
|
|||||||
stmfd sp!, {r4-r8,lr} @ Save context.
|
stmfd sp!, {r4-r8,lr} @ Save context.
|
||||||
utcb_address r12 @ Get utcb address.
|
utcb_address r12 @ Get utcb address.
|
||||||
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
|
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
|
||||||
|
|
||||||
|
cmp r2, #0
|
||||||
|
1:
|
||||||
|
bne 1b
|
||||||
|
|
||||||
ldr r12, =__l4_ipc
|
ldr r12, =__l4_ipc
|
||||||
mov lr, pc
|
mov lr, pc
|
||||||
ldr pc, [r12]
|
ldr pc, [r12]
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ int fork(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int arch_clone(l4id_t to, l4id_t from);
|
extern int arch_clone(l4id_t to, l4id_t from, unsigned int flags);
|
||||||
|
|
||||||
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
|
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
|
|||||||
write_mr(L4SYS_ARG1, flags);
|
write_mr(L4SYS_ARG1, flags);
|
||||||
|
|
||||||
/* Perform an ipc but with different return logic. See implementation. */
|
/* Perform an ipc but with different return logic. See implementation. */
|
||||||
if ((ret = arch_clone(PAGER_TID, PAGER_TID)) < 0) {
|
if ((ret = arch_clone(PAGER_TID, PAGER_TID, 0)) < 0) {
|
||||||
print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, ret);
|
print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,11 +68,42 @@ env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
|
|||||||
CPPFLAGS = "-D__USERSPACE__",
|
CPPFLAGS = "-D__USERSPACE__",
|
||||||
CPPPATH = ['#include', libl4_incpath, libposix_incpath, kernel_incpath])
|
CPPPATH = ['#include', libl4_incpath, libposix_incpath, kernel_incpath])
|
||||||
|
|
||||||
|
|
||||||
|
test_exec_ld_script = "include/test_exec_linker.lds"
|
||||||
|
# The kernel build environment:
|
||||||
|
test_exec_env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
|
||||||
|
# We don't use -nostdinc because sometimes we need standard headers,
|
||||||
|
# such as stdarg.h e.g. for variable args, as in printk().
|
||||||
|
CCFLAGS = ['-O3', '-nostdlib', '-ffreestanding', '-std=gnu99', '-Wall', '-Werror'],
|
||||||
|
LINKFLAGS = ['-nostdlib', '-T' + test_exec_ld_script, "-L" + libc_libpath, "-L" + libl4_path, \
|
||||||
|
'-L' + libposix_libpath],
|
||||||
|
ASFLAGS = ['-D__ASSEMBLY__'],
|
||||||
|
PROGSUFFIX = '.axf', # The suffix to use for final executable
|
||||||
|
ENV = {'PATH' : os.environ['PATH']}, # Inherit shell path
|
||||||
|
LIBS = [libc_name, 'gcc', libc_name, 'libl4', 'libposix', libc_name],
|
||||||
|
CPPFLAGS = "-D__USERSPACE__",
|
||||||
|
CPPPATH = ['#include', libl4_incpath, libposix_incpath, kernel_incpath])
|
||||||
|
|
||||||
src = [glob("src/*.c"), glob("*.c"), glob("*.S"), glob("src/arch/arm/*.c"), glob("../libcont/*.c")]
|
src = [glob("src/*.c"), glob("*.c"), glob("*.S"), glob("src/arch/arm/*.c"), glob("../libcont/*.c")]
|
||||||
objs = env.Object(src)
|
objs = env.Object(src)
|
||||||
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
|
physical_base = env.Command(physical_base_ld_script, prev_image, get_physical_base)
|
||||||
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
|
crt0_copied = env.Command("crt0.o", libc_crt0, copy_crt0)
|
||||||
|
|
||||||
|
test_exec_src = [glob("src/test_exec/*.c")]
|
||||||
|
test_exec_objs = test_exec_env.Object(test_exec_src)
|
||||||
|
test_exec_name = "test_exec"
|
||||||
|
test_exec = test_exec_env.Program(test_exec_name, test_exec_objs + [crt0_copied])
|
||||||
|
test_exec_env.Alias(test_exec_name, test_exec)
|
||||||
|
|
||||||
|
env.Depends(objs, test_exec)
|
||||||
task = env.Program(task_name, objs + [crt0_copied])
|
task = env.Program(task_name, objs + [crt0_copied])
|
||||||
env.Alias(task_name, task)
|
env.Alias(task_name, task)
|
||||||
|
|
||||||
|
# I find this to be a BUG related to SCons. SCons is still good compared to
|
||||||
|
# notoriously horrible makefiles, but it could have been better.
|
||||||
|
# if test_exec doesn't depend on physical_base, test_exec is compiled but
|
||||||
|
# task complains that physical_base is not there. However we already declared
|
||||||
|
# its dependency below.
|
||||||
|
|
||||||
|
env.Depends(test_exec, physical_base)
|
||||||
env.Depends(task, physical_base)
|
env.Depends(task, physical_base)
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ SECTIONS
|
|||||||
.data : AT (ADDR(.data) - offset)
|
.data : AT (ADDR(.data) - offset)
|
||||||
{
|
{
|
||||||
. = ALIGN(4K);
|
. = ALIGN(4K);
|
||||||
_start_test1 = .;
|
_start_test_exec = .;
|
||||||
*(.test1)
|
*(.testexec)
|
||||||
_end_test1 = .;
|
_end_test_exec = .;
|
||||||
*(.data)
|
*(.data)
|
||||||
}
|
}
|
||||||
.bss : AT (ADDR(.bss) - offset) { *(.bss) }
|
.bss : AT (ADDR(.bss) - offset) { *(.bss) }
|
||||||
|
|||||||
37
tasks/test0/include/test_exec_linker.lds
Normal file
37
tasks/test0/include/test_exec_linker.lds
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Simple linker script for userspace or svc tasks.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Bahadir Balban
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The only catch with this linker script is that everything
|
||||||
|
* is linked starting at virtual_base, and loaded starting
|
||||||
|
* at physical_base. virtual_base is the predefined region
|
||||||
|
* of virtual memory for userland applications. physical_base
|
||||||
|
* is determined at build-time, it is one of the subsequent pages
|
||||||
|
* that come after the kernel image's load area.
|
||||||
|
*/
|
||||||
|
/* USER_AREA_START, see memlayout.h */
|
||||||
|
virtual_base = 0x10000000;
|
||||||
|
__stack = (0x20000000 - 0x1000 - 8); /* First page before the env/args */
|
||||||
|
INCLUDE "include/physical_base.lds"
|
||||||
|
|
||||||
|
/* physical_base = 0x228000; */
|
||||||
|
offset = virtual_base - physical_base;
|
||||||
|
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = virtual_base;
|
||||||
|
_start_text = .;
|
||||||
|
.text : AT (ADDR(.text) - offset) { crt0.o(.text) *(.text) }
|
||||||
|
/* 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) { *(.data) }
|
||||||
|
.bss : AT (ADDR(.bss) - offset) { *(.bss) }
|
||||||
|
_end = .;
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ void wait_pager(l4id_t partner)
|
|||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
write_mr(i, i);
|
write_mr(i, i);
|
||||||
l4_send(partner, L4_IPC_TAG_SYNC);
|
l4_send(partner, L4_IPC_TAG_SYNC);
|
||||||
// printf("Pager synced with us.\n");
|
printf("Pager synced with us.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t parent_of_all;
|
pid_t parent_of_all;
|
||||||
|
|||||||
@@ -11,14 +11,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
extern char _start_test1[];
|
extern char _start_test_exec[];
|
||||||
extern char _end_test1[];
|
extern char _end_test_exec[];
|
||||||
|
|
||||||
int exectest(void)
|
int exectest(void)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
void *exec_start = (void *)_start_test1;
|
void *exec_start = (void *)_start_test_exec;
|
||||||
unsigned long size = _end_test1 - _start_test1;
|
unsigned long size = _end_test_exec - _start_test_exec;
|
||||||
int left, cnt;
|
int left, cnt;
|
||||||
char *argv[5];
|
char *argv[5];
|
||||||
char filename[128];
|
char filename[128];
|
||||||
|
|||||||
25
tasks/test0/src/test_exec/container.c
Normal file
25
tasks/test0/src/test_exec/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();
|
||||||
|
}
|
||||||
|
|
||||||
BIN
tasks/test0/src/test_exec/container.o
Normal file
BIN
tasks/test0/src/test_exec/container.o
Normal file
Binary file not shown.
36
tasks/test0/src/test_exec/test_exec.c
Normal file
36
tasks/test0/src/test_exec/test_exec.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Some tests for posix syscalls.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Bahadir Balban
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <l4lib/arch/syslib.h>
|
||||||
|
#include <l4lib/kip.h>
|
||||||
|
#include <l4lib/utcb.h>
|
||||||
|
#include <l4lib/ipcdefs.h>
|
||||||
|
#include <tests.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
void wait_pager(l4id_t partner)
|
||||||
|
{
|
||||||
|
// printf("%s: Syncing with pager.\n", __TASKNAME__);
|
||||||
|
for (int i = 0; i < 6; i++)
|
||||||
|
write_mr(i, i);
|
||||||
|
l4_send(partner, L4_IPC_TAG_SYNC);
|
||||||
|
// printf("Pager synced with us.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
wait_pager(0);
|
||||||
|
if (getpid() == 2) {
|
||||||
|
printf("EXECVE TEST -- PASSED --\n", getpid());
|
||||||
|
printf("\n(Thread %d): Continues to sync with the pager...\n", getpid());
|
||||||
|
while (1)
|
||||||
|
wait_pager(0);
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
BIN
tasks/test0/src/test_exec/test_exec.o
Normal file
BIN
tasks/test0/src/test_exec/test_exec.o
Normal file
Binary file not shown.
5
tasks/test0/test_exec.S
Normal file
5
tasks/test0/test_exec.S
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.section .testexec
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
.incbin "test_exec.axf"
|
||||||
|
.align 4
|
||||||
Reference in New Issue
Block a user