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:
Bahadir Balban
2009-05-15 19:14:40 +03:00
parent 814eba43dd
commit 93368447f9
21 changed files with 289 additions and 49 deletions

View File

@@ -13,8 +13,8 @@
#if defined (__KERNEL__)
/* These are for internally created ipc paths. */
int ipc_send(l4id_t to);
int ipc_sendrecv(l4id_t to, l4id_t from);
int ipc_send(l4id_t to, int full);
int ipc_sendrecv(l4id_t to, l4id_t from, int full);
#endif

View File

@@ -42,7 +42,8 @@ void address_space_remove(struct address_space *space);
void address_space_reference_lock();
void address_space_reference_unlock();
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 /* __SPACE_H__ */

View File

@@ -26,6 +26,9 @@
#define TASK_SUSPENDING (1 << 1)
#define TASK_RESUMING (1 << 2)
/* IPC resulted in a fault error (For ipcs that cannot page fault) */
#define IPC_EFAULT (1 << 3)
/* Task states */
enum task_state {
TASK_INACTIVE = 0,

View File

@@ -83,4 +83,13 @@
#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__ */

View File

@@ -1,7 +1,7 @@
/*
* Inter-process communication
*
* Copyright (C) 2007 Bahadir Balban
* Copyright (C) 2007-2009 Bahadir Bilgehan Balban
*/
#include <l4/generic/tcb.h>
#include <l4/lib/mutex.h>
@@ -14,13 +14,46 @@
#include INC_API(syscall.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 {
IPC_INVALID = 0,
IPC_SEND = 1,
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
* 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
* 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_dst = KTCB_REF_MR0(to);
int ret = 0;
/* NOTE:
* 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)
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)
@@ -61,10 +99,11 @@ int sys_ipc_control(syscall_context_t *regs)
*/
/* 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 waitqueue_head *wqhs, *wqhr;
int ret = 0;
wqhs = &receiver->wqh_send;
wqhr = &receiver->wqh_recv;
@@ -89,14 +128,18 @@ int ipc_send(l4id_t recv_tid)
spin_unlock(&wqhs->slock);
/* 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__,
// current->tid, receiver->tid);
/* Wake it up, we can yield here. */
sched_resume_sync(receiver);
return 0;
return ret;
}
/* 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;
return -EINTR;
}
/* Did ipc fail with a fault error? */
if (current->flags & IPC_EFAULT) {
current->flags &= ~IPC_EFAULT;
return -EFAULT;
}
return 0;
}
int ipc_recv(l4id_t senderid)
int ipc_recv(l4id_t senderid, int full)
{
struct waitqueue_head *wqhs, *wqhr;
int ret = 0;
wqhs = &current->wqh_send;
wqhr = &current->wqh_recv;
@@ -154,12 +204,20 @@ int ipc_recv(l4id_t senderid)
task_unset_wqh(sleeper);
spin_unlock(&wqhr->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__,
// current->tid, sleeper->tid);
sched_resume_sync(sleeper);
return 0;
return ret;
}
}
}
@@ -181,6 +239,13 @@ int ipc_recv(l4id_t senderid)
current->flags &= ~TASK_INTERRUPTED;
return -EINTR;
}
/* Did ipc fail with a fault error? */
if (current->flags & IPC_EFAULT) {
current->flags &= ~IPC_EFAULT;
return -EFAULT;
}
return 0;
}
@@ -198,20 +263,22 @@ int ipc_recv(l4id_t senderid)
* (6) System task calls ipc_send() sending the return result.
* (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;
if (to == from) {
/* Send ipc request */
ipc_send(to);
if ((ret = ipc_send(to, full)) < 0)
return ret;
/*
* Get reply.
* A client would block its server only very briefly
* between these calls.
*/
ipc_recv(from);
if ((ret = ipc_recv(from, full)) < 0)
return ret;
} else {
printk("%s: Unsupported ipc operation.\n", __FUNCTION__);
ret = -ENOSYS;
@@ -225,13 +292,28 @@ static inline int __sys_ipc(l4id_t to, l4id_t from, unsigned int ipc_type)
switch (ipc_type) {
case IPC_SEND:
ret = ipc_send(to);
ret = ipc_send(to, 0);
break;
case IPC_RECV:
ret = ipc_recv(from);
ret = ipc_recv(from, 0);
break;
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;
case IPC_INVALID:
default:
@@ -267,6 +349,7 @@ int sys_ipc(syscall_context_t *regs)
{
l4id_t to = (l4id_t)regs->r0;
l4id_t from = (l4id_t)regs->r1;
unsigned int flags = (unsigned int)regs->r2;
unsigned int ipc_type = 0;
int ret = 0;
@@ -292,6 +375,9 @@ int sys_ipc(syscall_context_t *regs)
/* [1] for Receive, [1:0] for both */
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) {
ret = -EINVAL;
goto error;
@@ -302,7 +388,7 @@ int sys_ipc(syscall_context_t *regs)
return ret;
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;
return ret;
}

View File

@@ -23,19 +23,19 @@ int __sys_kread(int rd, void *dest)
switch(rd) {
case KDATA_PAGE_MAP:
// 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;
memcpy(dest, &page_map, sizeof(page_map));
break;
case KDATA_BOOTDESC:
// 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;
memcpy(dest, bootdesc, bootdesc->desc_size);
break;
case KDATA_BOOTDESC_SIZE:
// 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;
*(unsigned int *)dest = bootdesc->desc_size;
break;

View File

@@ -58,7 +58,7 @@ void fault_ipc_to_pager(u32 faulty_pc, u32 fsr, u32 far)
offsetof(syscall_context_t, r3));
/* 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 !!!

View File

@@ -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
* 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;
@@ -159,20 +159,17 @@ int check_access(unsigned long vaddr, unsigned long size, unsigned int flags)
if (size >= USER_AREA_SIZE)
return -EINVAL;
/* Check if in user range, but this is more up to the pager to decide */
if (current->tid == PAGER_TID) {
if (!(vaddr >= INITTASK_AREA_START && vaddr < INITTASK_AREA_END))
return -EINVAL;
} else {
if (!(vaddr >= USER_AREA_START && vaddr < USER_AREA_END))
return -EINVAL;
/* Check if the address is mapped with given flags */
if (!check_mapping(vaddr, size, flags)) {
/* Is a page in requested? */
if (page_in) {
/* Ask pager if paging in is possible */
if((err = pager_pagein_request(vaddr, size, flags)) < 0)
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;
}

View File

@@ -77,7 +77,7 @@ int sys_time(syscall_context_t *args)
int set = (int)args->r1;
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;
/* Get time */

View File

@@ -53,7 +53,7 @@ END_PROC(l4_kread)
/*
* 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,
* 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.
utcb_address r12 @ Get utcb address.
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
cmp r2, #0
1:
bne 1b
ldr r12, =__l4_ipc
mov lr, pc
ldr pc, [r12] @ Perform the ipc()
@@ -101,6 +106,11 @@ BEGIN_PROC(l4_ipc)
stmfd sp!, {r4-r8,lr} @ Save context.
utcb_address r12 @ Get utcb address.
ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5
cmp r2, #0
1:
bne 1b
ldr r12, =__l4_ipc
mov lr, pc
ldr pc, [r12]

View File

@@ -52,7 +52,7 @@ int fork(void)
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, ...)
{
@@ -74,7 +74,7 @@ int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
write_mr(L4SYS_ARG1, flags);
/* 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);
return ret;
}

View File

@@ -68,11 +68,42 @@ env = Environment(CC = 'arm-none-linux-gnueabi-gcc',
CPPFLAGS = "-D__USERSPACE__",
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")]
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)
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])
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)

View File

@@ -33,9 +33,9 @@ SECTIONS
.data : AT (ADDR(.data) - offset)
{
. = ALIGN(4K);
_start_test1 = .;
*(.test1)
_end_test1 = .;
_start_test_exec = .;
*(.testexec)
_end_test_exec = .;
*(.data)
}
.bss : AT (ADDR(.bss) - offset) { *(.bss) }

View 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 = .;
}

View File

@@ -19,7 +19,7 @@ void wait_pager(l4id_t partner)
for (int i = 0; i < 6; i++)
write_mr(i, i);
l4_send(partner, L4_IPC_TAG_SYNC);
// printf("Pager synced with us.\n");
printf("Pager synced with us.\n");
}
pid_t parent_of_all;

View File

@@ -11,14 +11,14 @@
#include <string.h>
#include <errno.h>
extern char _start_test1[];
extern char _end_test1[];
extern char _start_test_exec[];
extern char _end_test_exec[];
int exectest(void)
{
int fd;
void *exec_start = (void *)_start_test1;
unsigned long size = _end_test1 - _start_test1;
void *exec_start = (void *)_start_test_exec;
unsigned long size = _end_test_exec - _start_test_exec;
int left, cnt;
char *argv[5];
char filename[128];

View 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();
}

Binary file not shown.

View 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);
}

Binary file not shown.

5
tasks/test0/test_exec.S Normal file
View File

@@ -0,0 +1,5 @@
.section .testexec
.align 4
.incbin "test_exec.axf"
.align 4