mirror of
https://github.com/drasko/codezero.git
synced 2026-03-21 11:31:52 +01:00
Kernel updates since December 2009
This commit is contained in:
51
conts/test_suite0/src/api/api.c
Normal file
51
conts/test_suite0/src/api/api.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* API tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <tests.h>
|
||||
#include <memory.h>
|
||||
#include <api/api.h>
|
||||
|
||||
/*
|
||||
* Tests all api functions by expected and unexpected input
|
||||
*/
|
||||
int test_api(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Initialize free pages */
|
||||
page_pool_init();
|
||||
|
||||
if ((err = test_api_tctrl()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_getid()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_exregs()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_map_unmap()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_ipc()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_mutexctrl()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_cctrl()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_capctrl()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_api_irqctrl()) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
80
conts/test_suite0/src/api/cache.c
Normal file
80
conts/test_suite0/src/api/cache.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Test cache control system call
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include INC_GLUE(memory.h)
|
||||
#include <l4lib/lib/cap.h>
|
||||
#include <l4/api/cache.h>
|
||||
#include <linker.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
|
||||
/* This simply tests that all cache calls are working */
|
||||
int test_cctrl_basic(void)
|
||||
{
|
||||
struct capability *virtcap = cap_get_by_type(CAP_TYPE_MAP_VIRTMEM);
|
||||
void *start = (void *)__pfn_to_addr(virtcap->start);
|
||||
void *end = (void *)__end;
|
||||
int err;
|
||||
|
||||
if ((err = l4_cache_control(start, end, L4_INVALIDATE_ICACHE)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = l4_cache_control(start, end, L4_INVALIDATE_DCACHE)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = l4_cache_control(start, end, L4_CLEAN_INVALIDATE_DCACHE)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = l4_cache_control(start, end, L4_CLEAN_DCACHE)) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = l4_cache_control(start, end, L4_INVALIDATE_TLB)) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_cctrl_sync_caches()
|
||||
{
|
||||
/*
|
||||
* Double-map a physical page and fill it with
|
||||
* mov r0, r0, r0 * PAGE_SIZE - 1
|
||||
* b return_label
|
||||
*/
|
||||
|
||||
/* Flush the Dcache for that page */
|
||||
|
||||
/* Invalidate I cache for that page */
|
||||
|
||||
/* Execute the page */
|
||||
|
||||
/*
|
||||
* Create a new address space and execute the page from
|
||||
* that space
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_api_cctrl(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = test_cctrl_basic()) < 0)
|
||||
goto out_err;
|
||||
|
||||
|
||||
printf("CACHE CONTROL: -- PASSED --\n");
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("CACHE CONTROL: -- FAILED --\n");
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
56
conts/test_suite0/src/api/cap.c
Normal file
56
conts/test_suite0/src/api/cap.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Test capability control system call
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include <l4lib/lib/cap.h>
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
|
||||
#define TOTAL_CAPS 32
|
||||
|
||||
struct capability cap_array[TOTAL_CAPS];
|
||||
|
||||
/*
|
||||
* Read number of capabilities
|
||||
*/
|
||||
int test_cap_read(void)
|
||||
{
|
||||
int ncaps;
|
||||
int err;
|
||||
|
||||
/* Read number of capabilities */
|
||||
if ((err = l4_capability_control(CAP_CONTROL_NCAPS,
|
||||
0, &ncaps)) < 0) {
|
||||
printf("l4_capability_control() reading # of"
|
||||
" capabilities failed.\n Could not "
|
||||
"complete CAP_CONTROL_NCAPS request.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Read all capabilities */
|
||||
if ((err = l4_capability_control(CAP_CONTROL_READ,
|
||||
0, cap_array)) < 0) {
|
||||
printf("l4_capability resource_control() reading of "
|
||||
"capabilities failed.\n Could not "
|
||||
"complete CAP_CONTROL_READ_CAPS request.\n");
|
||||
return err;
|
||||
}
|
||||
//cap_array_print(ncaps, caparray);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int test_api_capctrl(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = test_cap_read()) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
96
conts/test_suite0/src/api/exregs.c
Normal file
96
conts/test_suite0/src/api/exregs.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Test exchange registers system call.
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
|
||||
#include <l4lib/exregs.h>
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <tests.h>
|
||||
|
||||
int test_exregs_read_write(void)
|
||||
{
|
||||
struct task_ids ids;
|
||||
struct exregs_data exregs[2];
|
||||
int err;
|
||||
|
||||
/* Get own space id */
|
||||
l4_getid(&ids);
|
||||
|
||||
/*
|
||||
* Create a thread in the same space.
|
||||
* Thread is not runnable.
|
||||
*/
|
||||
if ((err = l4_thread_control(THREAD_CREATE | TC_SHARE_SPACE,
|
||||
&ids)) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", ids.tid);
|
||||
|
||||
/*
|
||||
* Prepare a context part full of 0xFF
|
||||
*/
|
||||
memset(&exregs[0].context, 0xFF, sizeof(exregs[1].context));
|
||||
exregs[0].valid_vect = 0xFFFFFFFF;
|
||||
|
||||
/* Write to context */
|
||||
if ((err = l4_exchange_registers(&exregs[0], ids.tid)) < 0)
|
||||
goto out;
|
||||
|
||||
/* Set the other as read-all */
|
||||
exregs_set_read(&exregs[1]);
|
||||
exregs[1].valid_vect = 0xFFFFFFFF;
|
||||
if ((err = l4_exchange_registers(&exregs[1],
|
||||
ids.tid)) < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Read back all context and compare results
|
||||
*/
|
||||
if (memcmp(&exregs[0].context, &exregs[1].context,
|
||||
sizeof(exregs[0].context))) {
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Destroy the thread
|
||||
*/
|
||||
if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) {
|
||||
dbg_printf("Thread destroy failed. err=%d\n",
|
||||
err);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int test_api_exregs(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = test_exregs_read_write()) < 0)
|
||||
goto out_err;
|
||||
|
||||
/*
|
||||
* TODO: Should add more tests here, e.g. setting
|
||||
* values of a thread we're not a pager of.
|
||||
*/
|
||||
|
||||
printf("EXCHANGE REGISTERS: -- PASSED --\n");
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("EXCHANGE REGISTERS: -- FAILED --\n");
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
123
conts/test_suite0/src/api/getid.c
Normal file
123
conts/test_suite0/src/api/getid.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Test l4_getid system call.
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <tests.h>
|
||||
|
||||
|
||||
int thread_getid_nullptr(void *arg)
|
||||
{
|
||||
return l4_getid(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass nullptr to l4_getid syscall
|
||||
*
|
||||
* This exercise proves that the kernel does not crash
|
||||
* and validly sends a page fault to offending thread's
|
||||
* pager.
|
||||
*/
|
||||
int test_getid_nullptr(void)
|
||||
{
|
||||
struct l4_thread *thread;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Create a new thread who will attempt
|
||||
* passing null ptr argument
|
||||
*/
|
||||
if ((err = thread_create(thread_getid_nullptr,
|
||||
0, TC_SHARE_SPACE,
|
||||
&thread)) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
/*
|
||||
* Listen on thread for its page fault
|
||||
* ipc. (Recap: Upon illegal access, the kernel sends
|
||||
* a page fault ipc message to thread's pager)
|
||||
*/
|
||||
if ((err = l4_receive(thread->ids.tid)) < 0) {
|
||||
dbg_printf("%s: listening on page fault for "
|
||||
"nullptr thread failed. "
|
||||
"err = %d\n", __FUNCTION__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify ipc was a page fault ipc
|
||||
*/
|
||||
if (l4_get_tag() != L4_IPC_TAG_PFAULT) {
|
||||
dbg_printf("%s: Nullptr thread ipc does not "
|
||||
"have expected page fault tag.\n"
|
||||
"tag=%d, expected=%d\n",
|
||||
__FUNCTION__, l4_get_tag(),
|
||||
L4_IPC_TAG_PFAULT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the thread.
|
||||
*/
|
||||
if ((err = thread_destroy(thread)) < 0) {
|
||||
dbg_printf("%s: Failed destroying thread. "
|
||||
"err= %d, tid = %d\n",
|
||||
__FUNCTION__, err,
|
||||
thread->ids.tid);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_api_getid(void)
|
||||
{
|
||||
struct task_ids ids;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Test valid getid request
|
||||
*/
|
||||
if ((err = l4_getid(&ids)) < 0) {
|
||||
dbg_printf("Getid request failed. err=%d\n", err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Check returned results */
|
||||
if (ids.tid != 1 || ids.spid != 1 || ids.tgid != 1) {
|
||||
dbg_printf("Getid results not as expected. "
|
||||
"tid=%d, spid=%d, tgid=%d\n",
|
||||
ids.tid, ids.spid, ids.tgid);
|
||||
err = -1;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test null pointer argument
|
||||
*/
|
||||
if ((err = test_getid_nullptr()) < 0) {
|
||||
dbg_printf("l4_getid() null pointer test failed."
|
||||
" err=%d\n", err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
printf("GETID: -- PASSED --\n");
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("GETID: -- FAILED --\n");
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
547
conts/test_suite0/src/api/ipc.c
Normal file
547
conts/test_suite0/src/api/ipc.c
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Test ipc system call.
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <l4lib/ipcdefs.h>
|
||||
#include <tests.h>
|
||||
#include <macros.h>
|
||||
#include <fault.h>
|
||||
#include <memory.h>
|
||||
|
||||
struct ipc_ext_data {
|
||||
void *virtual; /* Virtual address to start ipc from */
|
||||
l4id_t partner; /* Partner to do extended ipc */
|
||||
};
|
||||
|
||||
int ipc_extended_sender(void *arg)
|
||||
{
|
||||
struct ipc_ext_data *data = arg;
|
||||
int err;
|
||||
|
||||
if ((err = l4_send_extended(data->partner, 0,
|
||||
SZ_2K, data->virtual)) < 0) {
|
||||
printf("%s: Extended send failed. err=%d\n",
|
||||
__FUNCTION__, err);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_extended_receiver(void *arg)
|
||||
{
|
||||
struct ipc_ext_data *data = arg;
|
||||
int err;
|
||||
|
||||
if ((err = l4_receive_extended(data->partner, SZ_2K,
|
||||
data->virtual)) < 0) {
|
||||
printf("%s: Extended receive failed. err=%d\n",
|
||||
__FUNCTION__, err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the data received
|
||||
*/
|
||||
for (int i = 0; i < SZ_2K; i++) {
|
||||
if (((char *)data->virtual)[i] != 'A' + i)
|
||||
printf("%s: Extended receive buffer has unexpected "
|
||||
"data: Start %p, Offset: %d, "
|
||||
"Data=%d, expected=%d\n", __FUNCTION__,
|
||||
data->virtual, i, ((char *)data->virtual)[i],
|
||||
'A' + i);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_ext_handle_pfault(struct ipc_ext_data *ipc_data,
|
||||
void **virt, void **phys)
|
||||
{
|
||||
u32 mr[MR_UNUSED_TOTAL];
|
||||
struct fault_data fault;
|
||||
int err;
|
||||
|
||||
/* Read mrs not used by syslib */
|
||||
for (int i = 0; i < MR_UNUSED_TOTAL; i++)
|
||||
mr[i] = read_mr(MR_UNUSED_START + i);
|
||||
|
||||
fault.kdata = (fault_kdata_t *)&mr[0];
|
||||
fault.sender = l4_get_sender();
|
||||
|
||||
/* Convert from arch-specific to generic fault data */
|
||||
set_generic_fault_params(&fault);
|
||||
|
||||
/*
|
||||
* Handle the fault using a basic logic - if a virtual index
|
||||
* is faulted, map the corresponding page at same physical index.
|
||||
*/
|
||||
if (page_align(fault.address) == (unsigned long)virt[0]) {
|
||||
if ((err = l4_map(phys[0], virt[0], 1,
|
||||
MAP_USR_RW, fault.sender)) < 0) {
|
||||
printf("%s: Error: l4_map failed. "
|
||||
"phys=%p, virt=%p\n", __FUNCTION__,
|
||||
phys[0], virt[0]);
|
||||
return err;
|
||||
}
|
||||
} else if (page_align(fault.address) == (unsigned long)virt[1]) {
|
||||
if ((err = l4_map(phys[1], virt[1], 1,
|
||||
MAP_USR_RW, fault.sender)) < 0) {
|
||||
printf("%s: Error: l4_map failed. "
|
||||
"phys=%p, virt=%p\n", __FUNCTION__,
|
||||
phys[1], virt[1]);
|
||||
return err;
|
||||
}
|
||||
} else if (page_align(fault.address) == (unsigned long)virt[2]) {
|
||||
if ((err = l4_map(phys[2], virt[2], 1,
|
||||
MAP_USR_RW, fault.sender)) < 0) {
|
||||
printf("%s: Error: l4_map failed. "
|
||||
"phys=%p, virt=%p\n", __FUNCTION__,
|
||||
phys[2], virt[2]);
|
||||
return err;
|
||||
}
|
||||
} else if (page_align(fault.address) == (unsigned long)virt[3]) {
|
||||
if ((err = l4_map(phys[3], virt[3], 1,
|
||||
MAP_USR_RW, fault.sender)) < 0) {
|
||||
printf("%s: Error: l4_map failed. "
|
||||
"phys=%p, virt=%p\n", __FUNCTION__,
|
||||
phys[3], virt[3]);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
printf("%s: Error, page fault occured on an unexpected "
|
||||
"address. adress=0x%x\n", __FUNCTION__,
|
||||
fault.address);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Reply back to fault thread and return */
|
||||
return l4_ipc_return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create two threads who will do page-faulting ipc to each other.
|
||||
* Their parent waits and handles the page faults.
|
||||
*
|
||||
* This test allocates 4 virtual page and 4 physical page addresses.
|
||||
* It fills a total of 2KB of payload starting from the 3rd quarter
|
||||
* of the first page and until the 2nd quarter of the 2nd page to
|
||||
* be sent by the sender thread.
|
||||
*
|
||||
* The payload is copied and the pages deliberately unmapped so that
|
||||
* the sender thread will page fault during the send operation.
|
||||
*
|
||||
* The receive pages are also set up same as above, so the receiving
|
||||
* thread also faults during the receive.
|
||||
*
|
||||
* The main thread starts both ipc threads, and starts waiting on
|
||||
* page faults. It handles the faults and the test succeeds if the
|
||||
* data is transfered safely to receiving end, despite all faults.
|
||||
*/
|
||||
int test_ipc_extended(void)
|
||||
{
|
||||
struct task_ids self_ids;
|
||||
struct ipc_ext_data ipc_data[2];
|
||||
struct l4_thread *thread[2];
|
||||
void *virt[4], *phys[4];
|
||||
int err, tag;
|
||||
|
||||
l4_getid(&self_ids);
|
||||
|
||||
/* Get 4 physical pages */
|
||||
for (int i = 0; i < 4; i++)
|
||||
phys[i] = physical_page_new(1);
|
||||
|
||||
/* Get 2 pairs of virtual pages */
|
||||
virt[0] = virtual_page_new(2);
|
||||
virt[1] = virt[0] + PAGE_SIZE;
|
||||
virt[2] = virtual_page_new(2);
|
||||
virt[3] = virt[2] + PAGE_SIZE;
|
||||
|
||||
/* Map sender pages to self */
|
||||
if ((err = l4_map(phys[0], virt[0], 1,
|
||||
MAP_USR_RW, self_ids.tid)) < 0) {
|
||||
printf("Error: Mapping Sender pages failed. phys: 0x%p,"
|
||||
" virt: 0x%p, tid=%d, err=%d\n", phys[0], virt[0],
|
||||
self_ids.tid, err);
|
||||
return err;
|
||||
}
|
||||
if ((err = l4_map(phys[1], virt[1], 1,
|
||||
MAP_USR_RW, self_ids.tid)) < 0) {
|
||||
printf("Error: Mapping Sender pages failed. phys: 0x%p,"
|
||||
" virt: 0x%p, tid=%d, err=%d\n", phys[0], virt[0],
|
||||
self_ids.tid, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill them with values to be sent
|
||||
* Filling in 3rd KB of first page to 2nd KB of second page
|
||||
*/
|
||||
for (int i = 0; i < SZ_2K; i++)
|
||||
((char *)virt[0] + SZ_1K * 3)[i] = 'A' + i;
|
||||
|
||||
/* Unmap the pages */
|
||||
l4_unmap(virt[0], 2, self_ids.tid);
|
||||
|
||||
/* Create ipc threads but don't start. */
|
||||
if ((err = thread_create(ipc_extended_sender,
|
||||
&ipc_data[0],
|
||||
TC_SHARE_SPACE | TC_NOSTART,
|
||||
&thread[0])) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", thread[0]->ids.tid);
|
||||
|
||||
if ((err = thread_create(ipc_extended_receiver,
|
||||
&ipc_data[1],
|
||||
TC_SHARE_SPACE | TC_NOSTART,
|
||||
&thread[1])) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", thread[1]->ids.tid);
|
||||
|
||||
/*
|
||||
* Set up arguments to sender,
|
||||
* Send offset at 3rd quarter of first page.
|
||||
*/
|
||||
ipc_data[0].virtual = virt[0] + SZ_1K * 3;
|
||||
ipc_data[0].partner = thread[1]->ids.tid;
|
||||
|
||||
/*
|
||||
* Set up arguments to receiver
|
||||
* Receive offset at 3rd quarter of first page.
|
||||
*/
|
||||
ipc_data[1].virtual = virt[1] + SZ_1K * 3;
|
||||
ipc_data[1].partner = thread[0]->ids.tid;
|
||||
|
||||
/* Start the threads */
|
||||
l4_thread_control(THREAD_RUN, &thread[0]->ids);
|
||||
l4_thread_control(THREAD_RUN, &thread[1]->ids);
|
||||
|
||||
/* Expecting 4 faults on 4 pages */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
/* Wait on page fault */
|
||||
if ((err = l4_receive(L4_ANYTHREAD)) < 0) {
|
||||
printf("Error: l4_receive() for page"
|
||||
" fault has failed. err=%d\n",
|
||||
err);
|
||||
}
|
||||
if ((tag = l4_get_tag()) != L4_IPC_TAG_PFAULT) {
|
||||
printf("Error: Parent thread received "
|
||||
"non-page fault ipc tag. tag=%d\n",
|
||||
tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Handle fault */
|
||||
if ((err = ipc_ext_handle_pfault(ipc_data, virt, phys)) < 0) {
|
||||
printf("Error: An error occured during ipc "
|
||||
"page fault handling. err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the ipc threads */
|
||||
for (int i = 0; i < 2; i ++)
|
||||
if ((err = thread_wait(thread[i])) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Unmap and release pages */
|
||||
for (int i = 0; i < 4; i++) {
|
||||
l4_unmap(virt[i], 1, self_ids.tid);
|
||||
virtual_page_free(virt[i], 1);
|
||||
physical_page_free(phys[i], 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_full_thread(void *arg)
|
||||
{
|
||||
l4id_t parent = *((l4id_t *)arg);
|
||||
int err;
|
||||
|
||||
/* Do two full send/receives */
|
||||
for (int i = 0; i < 2; i++) {
|
||||
/* Full receive, return positive if error */
|
||||
if ((err = l4_receive_full(parent)) < 0) {
|
||||
dbg_printf("Full receive failed on new "
|
||||
"thread. err=%d", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Test full utcb received values */
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) {
|
||||
if (read_mr(i) != i) {
|
||||
dbg_printf("IPC full receive on new thread: "
|
||||
"Unexpected message register "
|
||||
"values. MR%d = %d, should be %d\n",
|
||||
i, read_mr(i), i);
|
||||
return 1; /* Exit positive without reply */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset all message registers
|
||||
*/
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++)
|
||||
write_mr(i, 0);
|
||||
|
||||
/* Send full return reply */
|
||||
l4_send_full(parent, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_short_thread(void *arg)
|
||||
{
|
||||
l4id_t parent = *((l4id_t *)arg);
|
||||
int err;
|
||||
|
||||
/* Short receive, return positive if error */
|
||||
if ((err = l4_receive(parent)) < 0) {
|
||||
dbg_printf("Short receive failed on new "
|
||||
"thread. err=%d", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Test received registers */
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) {
|
||||
if (read_mr(i) != i) {
|
||||
dbg_printf("IPC Receive on new thread: "
|
||||
"Unexpected message register "
|
||||
"values.\n"
|
||||
"read = %d, expected = %d\n",
|
||||
read_mr(i), i);
|
||||
l4_print_mrs();
|
||||
return 1; /* Exit positive without reply */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset all message registers
|
||||
*/
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL; i++)
|
||||
write_mr(i, 0);
|
||||
|
||||
/*
|
||||
* Send return reply and exit
|
||||
*/
|
||||
return l4_send(parent, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a thread and do a full ipc to it
|
||||
*/
|
||||
int test_ipc_full(void)
|
||||
{
|
||||
struct task_ids self_ids;
|
||||
struct l4_thread *thread;
|
||||
int err;
|
||||
|
||||
l4_getid(&self_ids);
|
||||
|
||||
/*
|
||||
* Create a thread in the same space
|
||||
*/
|
||||
if ((err = thread_create(ipc_full_thread,
|
||||
&self_ids.tid,
|
||||
TC_SHARE_SPACE,
|
||||
&thread)) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
/*
|
||||
* Try one short and one full send/recv
|
||||
* to test full send/recv occurs on both cases
|
||||
*/
|
||||
|
||||
/*
|
||||
* Write data to full utcb registers
|
||||
*/
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++)
|
||||
write_mr(i, i);
|
||||
|
||||
/*
|
||||
* First, do a full ipc send/recv
|
||||
*/
|
||||
if ((err = l4_sendrecv_full(thread->ids.tid,
|
||||
thread->ids.tid,
|
||||
0)) < 0) {
|
||||
dbg_printf("Full IPC send/recv failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that payload registers are modified to 0
|
||||
*/
|
||||
dbg_printf("%s: After send/recv:\n", __FUNCTION__);
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) {
|
||||
if (read_mr(i) != 0) {
|
||||
dbg_printf("Full IPC send/recv: "
|
||||
"Received payload is not "
|
||||
"as expected.\n "
|
||||
"MR%d = %d, should be %d\n",
|
||||
i, read_mr(i), 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data to full utcb registers
|
||||
*/
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++)
|
||||
write_mr(i, i);
|
||||
|
||||
/*
|
||||
* Try a short ipc send/recv. This should still result
|
||||
* in full ipc since the other side is doing full send/recv.
|
||||
*/
|
||||
if ((err = l4_sendrecv(thread->ids.tid,
|
||||
thread->ids.tid,
|
||||
0)) < 0) {
|
||||
dbg_printf("Full IPC send/recv failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that payload registers are modified to 0
|
||||
*/
|
||||
// dbg_printf("%s: After send/recv:\n", __FUNCTION__);
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL + MR_REST; i++) {
|
||||
// dbg_printf("MR%d: %d\n", i, read_mr(i));
|
||||
if (read_mr(i) != 0) {
|
||||
dbg_printf("Full IPC send/recv: "
|
||||
"Received payload is not "
|
||||
"as expected.\n "
|
||||
"MR%d = %d, should be %d\n",
|
||||
i, read_mr(i), 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the ipc thread to die */
|
||||
if ((err = thread_wait(thread)) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Full IPC send/recv successful.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a thread and do a short ipc to it
|
||||
*/
|
||||
int test_ipc_short(void)
|
||||
{
|
||||
struct task_ids self_ids;
|
||||
struct l4_thread *thread;
|
||||
int err;
|
||||
|
||||
l4_getid(&self_ids);
|
||||
|
||||
/*
|
||||
* Create a thread in the same space
|
||||
*/
|
||||
if ((err = thread_create(ipc_short_thread,
|
||||
&self_ids.tid,
|
||||
TC_SHARE_SPACE,
|
||||
&thread)) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
/*
|
||||
* Write data to short ipc registers
|
||||
*/
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL; i++)
|
||||
write_mr(i, i);
|
||||
|
||||
/*
|
||||
* Do short ipc send/recv and check data is reset
|
||||
*/
|
||||
if ((err = l4_sendrecv(thread->ids.tid,
|
||||
thread->ids.tid,
|
||||
0)) < 0) {
|
||||
dbg_printf("Short IPC send/recv failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that payload registers are reset
|
||||
*/
|
||||
for (int i = MR_UNUSED_START; i < MR_TOTAL; i++) {
|
||||
if (read_mr(i) != 0) {
|
||||
dbg_printf("Short IPC send/recv: "
|
||||
"Received payload is incorrect."
|
||||
"read = %d, expected=%d\n",
|
||||
read_mr(i), 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the ipc thread */
|
||||
if ((err = thread_wait(thread)) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Short IPC send/recv successful.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_api_ipc(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = test_ipc_extended()) < 0)
|
||||
goto out_err;
|
||||
|
||||
if ((err = test_ipc_short()) < 0)
|
||||
goto out_err;
|
||||
|
||||
if ((err = test_ipc_full()) < 0)
|
||||
goto out_err;
|
||||
|
||||
printf("IPC: -- PASSED --\n");
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("IPC: -- FAILED --\n");
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
12
conts/test_suite0/src/api/irq.c
Normal file
12
conts/test_suite0/src/api/irq.c
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Test irq control system call
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
int test_api_irqctrl(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
366
conts/test_suite0/src/api/map.c
Normal file
366
conts/test_suite0/src/api/map.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Test l4_map/unmap system call.
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include INC_GLUE(memory.h)
|
||||
#include <l4/api/errno.h>
|
||||
#include <tests.h>
|
||||
|
||||
#define KERNEL_PAGE 0xF0000000UL
|
||||
#define KIP_PAGE 0xFF000000UL
|
||||
#define SYSCALL_PAGE 0xFFFFF000UL
|
||||
#define VECTOR_PAGE 0xFFFF0000UL
|
||||
|
||||
int test_api_map(void)
|
||||
{
|
||||
int err;
|
||||
unsigned int flags;
|
||||
l4id_t self = self_tid();
|
||||
|
||||
/*
|
||||
* Make a valid mapping, a few pages below
|
||||
* the end of physical and virtual marks
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) < 0) {
|
||||
dbg_printf("sys_map failed on valid request. err=%d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Redo the same mapping. This should be valid.
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) < 0) {
|
||||
dbg_printf("sys_map failed on re-doing "
|
||||
"valid request. err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try mapping outside the virtual range
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded on invalid "
|
||||
"virtual range ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try mapping outside the physical range
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded on invalid "
|
||||
"physical range ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try having them both out of range
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END,
|
||||
(void *)CONFIG_CONT0_VIRT0_END,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"physical and virtual ranges "
|
||||
"supplied ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try out of range by off-by-one page size excess
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
6,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"physical and virtual ranges using "
|
||||
"off-by-one page size."
|
||||
"ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try invalid page size
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
0xFFFFFFFF,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"page size supplied ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try invalid flags
|
||||
*/
|
||||
flags = 0;
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
flags,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"flags supplied flags=%u, ret=%d\n", flags, err);
|
||||
return -1;
|
||||
}
|
||||
flags = MAP_KERN_RWX;
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
0,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"flags supplied flags=%u, ret=%d\n", flags, err);
|
||||
return -1;
|
||||
}
|
||||
flags = MAP_KERN_IO;
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
0,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"flags supplied flags=%u, ret=%d\n", flags, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
flags = MAP_KERN_RX;
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
0,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"flags supplied flags=%u, ret=%d\n", flags, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
flags = 0xF0F0F01;
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
0,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"flags supplied flags=%u, ret=%d\n", flags, err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try passing wraparound values
|
||||
*/
|
||||
if ((err = l4_map((void *)0xFFFFFFFF,
|
||||
(void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"wraparound ranges supplied ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try passing wraparound values
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)0xFFFFF000,
|
||||
2,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when invalid "
|
||||
"wraparound ranges supplied ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try mapping onto kernel
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)0xF0000000,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when trying to "
|
||||
"map onto the kernel ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try mapping to vector page
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)0xFFFF0000,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when trying to "
|
||||
"map to the vectors page ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try mapping to kip
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)0xFF000000,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when trying to "
|
||||
"map to the kip page ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try mapping to syscall page
|
||||
*/
|
||||
if ((err = l4_map((void *)CONFIG_CONT0_PHYS0_END - PAGE_SIZE * 5,
|
||||
(void *)0xFFFFF000,
|
||||
1,
|
||||
MAP_USR_RW,
|
||||
self)) == 0) {
|
||||
dbg_printf("sys_map succeeded when trying to "
|
||||
"map to the kip page ret=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int test_api_unmap(void)
|
||||
{
|
||||
int err;
|
||||
l4id_t self = self_tid();
|
||||
|
||||
/*
|
||||
* Try a valid unmap
|
||||
*/
|
||||
if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
self)) < 0) {
|
||||
dbg_printf("sys_unmap failed on valid request. err=%d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try the same unmap, should return ENOMAP
|
||||
*/
|
||||
if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1,
|
||||
self)) != -ENOMAP) {
|
||||
dbg_printf("sys_unmap did not return ENOMAP "
|
||||
"on second unmap of same region. err=%d\n",
|
||||
err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try unmapping privileged areas
|
||||
*/
|
||||
if ((err = l4_unmap((void *)KERNEL_PAGE, 1, self)) == 0) {
|
||||
dbg_printf("sys_unmap succeeded on invalid "
|
||||
"unmap region. err=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((err = l4_unmap((void *)VECTOR_PAGE, 1, self)) == 0) {
|
||||
dbg_printf("sys_unmap succeeded on invalid "
|
||||
"unmap region. err=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((err = l4_unmap((void *)SYSCALL_PAGE, 1, self)) == 0) {
|
||||
dbg_printf("sys_unmap succeeded on invalid "
|
||||
"unmap region. err=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try unmapping with range rollover
|
||||
*/
|
||||
if ((err = l4_unmap((void *)KERNEL_PAGE, 0xFFFFFFFF, self)) == 0) {
|
||||
dbg_printf("sys_unmap succeeded on invalid "
|
||||
"unmap region. err=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
0xFFFFFFFF, self)) == 0) {
|
||||
dbg_printf("sys_unmap succeeded on invalid "
|
||||
"unmap region. err=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try unmapping zero pages
|
||||
*/
|
||||
if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
0, self)) == 0) {
|
||||
dbg_printf("sys_unmap succeeded on invalid "
|
||||
"unmap region. err=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try unmapping with invalid id
|
||||
*/
|
||||
if ((err = l4_unmap((void *)CONFIG_CONT0_VIRT0_END - PAGE_SIZE * 5,
|
||||
1, 0xFFFFFFFF)) == 0) {
|
||||
dbg_printf("sys_unmap succeeded on invalid "
|
||||
"unmap region. err=%d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_api_map_unmap(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = test_api_map()) < 0)
|
||||
goto out_err;
|
||||
|
||||
if ((err = test_api_unmap()) < 0)
|
||||
goto out_err;
|
||||
|
||||
|
||||
printf("MAP/UNMAP: -- PASSED --\n");
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("MAP/UNMAP: -- FAILED --\n");
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
198
conts/test_suite0/src/api/memory.c
Normal file
198
conts/test_suite0/src/api/memory.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Empty virtual and physical pages for
|
||||
* creating test scenarios
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/lib/addr.h>
|
||||
#include INC_GLUE(memory.h)
|
||||
#include <l4/generic/cap-types.h>
|
||||
#include <l4lib/lib/cap.h>
|
||||
#include <l4/lib/math.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include <linker.h>
|
||||
#include <tests.h>
|
||||
|
||||
/*
|
||||
* Declare a statically allocated char buffer
|
||||
* with enough bitmap size to cover given size
|
||||
*/
|
||||
#define DECLARE_IDPOOL(name, size) \
|
||||
char name[(sizeof(struct id_pool) + ((size >> 12) >> 3))]
|
||||
|
||||
struct address_pool virtual_page_pool, physical_page_pool;
|
||||
|
||||
#define PAGE_POOL_SIZE SZ_16MB
|
||||
|
||||
DECLARE_IDPOOL(virtual_idpool, PAGE_POOL_SIZE);
|
||||
DECLARE_IDPOOL(physical_idpool, PAGE_POOL_SIZE);
|
||||
|
||||
#define virt_to_phys(virtual) ((unsigned long)(virtual) - (unsigned long)(offset))
|
||||
#define phys_to_virt(physical) ((unsigned long)(physical) + (unsigned long)(offset))
|
||||
|
||||
|
||||
#define TEST_POOL_TOTAL 5
|
||||
/*
|
||||
* Test page pool
|
||||
*/
|
||||
void test_page_pool(void)
|
||||
{
|
||||
void *p[TEST_POOL_TOTAL], *v[TEST_POOL_TOTAL];
|
||||
|
||||
/* Allocate test pages */
|
||||
for (int i = 0; i < TEST_POOL_TOTAL; i++) {
|
||||
v[i] = virtual_page_new(1);
|
||||
p[i] = physical_page_new(1);
|
||||
dbg_printf("Test allocated: Virtual%d: 0x%p, "
|
||||
"Physical%d, 0x%p\n",
|
||||
i, v[i], i, p[i]);
|
||||
}
|
||||
|
||||
/* Free test pages */
|
||||
for (int i = 0; i < TEST_POOL_TOTAL; i++) {
|
||||
virtual_page_free(v[i], 1);
|
||||
physical_page_free(p[i], 1);
|
||||
}
|
||||
|
||||
/* Re-allocate test pages */
|
||||
for (int i = 0; i < TEST_POOL_TOTAL; i++) {
|
||||
v[i] = virtual_page_new(1);
|
||||
p[i] = physical_page_new(1);
|
||||
dbg_printf("Test allocated: Virtual%d: 0x%p, "
|
||||
"Physical%d, 0x%p\n",
|
||||
i, v[i], i, p[i]);
|
||||
}
|
||||
|
||||
/* Free test pages */
|
||||
for (int i = 0; i < TEST_POOL_TOTAL; i++) {
|
||||
virtual_page_free(v[i], 1);
|
||||
physical_page_free(p[i], 1);
|
||||
}
|
||||
|
||||
/* Allocate in different lengths */
|
||||
for (int i = 0; i < TEST_POOL_TOTAL; i++) {
|
||||
v[i] = virtual_page_new(i);
|
||||
p[i] = physical_page_new(i);
|
||||
dbg_printf("Test allocated: Virtual%d: 0x%p, "
|
||||
"Physical%d, 0x%p\n",
|
||||
i, v[i], i, p[i]);
|
||||
}
|
||||
|
||||
/* Free test pages in different order */
|
||||
for (int i = TEST_POOL_TOTAL - 1; i >= 0; i--) {
|
||||
virtual_page_free(v[i], 1);
|
||||
physical_page_free(p[i], 1);
|
||||
}
|
||||
|
||||
/* Allocate in different lengths */
|
||||
for (int i = 0; i < TEST_POOL_TOTAL; i++) {
|
||||
v[i] = virtual_page_new(i);
|
||||
p[i] = physical_page_new(i);
|
||||
dbg_printf("Test allocated: Virtual%d: 0x%p, "
|
||||
"Physical%d, 0x%p\n",
|
||||
i, v[i], i, p[i]);
|
||||
}
|
||||
|
||||
/* Free test pages in normal order */
|
||||
for (int i = 0; i < TEST_POOL_TOTAL; i++) {
|
||||
virtual_page_free(v[i], 1);
|
||||
physical_page_free(p[i], 1);
|
||||
}
|
||||
}
|
||||
|
||||
void page_pool_init(void)
|
||||
{
|
||||
struct capability *physcap, *virtcap;
|
||||
unsigned long phys_start, phys_end;
|
||||
unsigned long virt_start, virt_end;
|
||||
|
||||
/*
|
||||
* Get physmem capability (Must be only one)
|
||||
*/
|
||||
if (!(physcap = cap_get_physmem(CAP_TYPE_MAP_PHYSMEM))) {
|
||||
printf("FATAL: Could not find a physical memory"
|
||||
"capability to use as a page pool.\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
/*
|
||||
* Get virtmem capability (Must be only one)
|
||||
*/
|
||||
if (!(virtcap = cap_get_by_type(CAP_TYPE_MAP_VIRTMEM))) {
|
||||
printf("FATAL: Could not find a virtual memory"
|
||||
"capability to use as a page pool.\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
/*
|
||||
* Now initialize physical and virtual page marks
|
||||
* from unused pages. Linker script will help us
|
||||
* on this.
|
||||
*/
|
||||
/*
|
||||
printf("__data_start symbol: %lx\n", (unsigned long)__data_start);
|
||||
printf("__data_end symbol: %lx\n", (unsigned long)__data_end);
|
||||
printf("__bss_start symbol: %lx\n", (unsigned long)__bss_start);
|
||||
printf("__bss_end symbol: %lx\n", (unsigned long)__bss_end);
|
||||
printf("__stack_start symbol: %lx\n", (unsigned long)__stack_start);
|
||||
printf("__stack_end symbol: %lx\n", (unsigned long)__stack_end);
|
||||
printf("__end symbol: %lx\n", (unsigned long)__end);
|
||||
*/
|
||||
|
||||
phys_start = page_align_up(virt_to_phys(__end) +
|
||||
(unsigned long)lma_start);
|
||||
phys_end = __pfn_to_addr(physcap->end);
|
||||
|
||||
dbg_printf("%s: Initializing physical range 0x%lx - 0x%lx\n",
|
||||
__FUNCTION__, phys_start, phys_end);
|
||||
|
||||
virt_start = page_align_up(__end) + (unsigned long)lma_start;
|
||||
virt_end = __pfn_to_addr(virtcap->end);
|
||||
|
||||
dbg_printf("%s: Initializing virtual range 0x%lx - 0x%lx\n",
|
||||
__FUNCTION__, virt_start, virt_end);
|
||||
|
||||
/* Initialize pools, maximum of PAGE_POOL_SIZE size */
|
||||
address_pool_init(&virtual_page_pool,
|
||||
(struct id_pool *)&virtual_idpool,
|
||||
virt_start, min(virt_end,
|
||||
virt_start + PAGE_POOL_SIZE));
|
||||
address_pool_init(&physical_page_pool,
|
||||
(struct id_pool *)&physical_idpool,
|
||||
phys_start, min(phys_end,
|
||||
phys_start + PAGE_POOL_SIZE));
|
||||
|
||||
// test_page_pool();
|
||||
}
|
||||
|
||||
/*
|
||||
* Some tests require page-faulting virtual addresses or
|
||||
* differing virtual addresses that map onto the same
|
||||
* physical page. These functions provide these pages.
|
||||
*/
|
||||
|
||||
void *virtual_page_new(int npages)
|
||||
{
|
||||
return address_new(&virtual_page_pool, npages, PAGE_SIZE);
|
||||
}
|
||||
|
||||
void *physical_page_new(int npages)
|
||||
{
|
||||
return address_new(&physical_page_pool, npages, PAGE_SIZE);
|
||||
}
|
||||
|
||||
void virtual_page_free(void *address, int npages)
|
||||
{
|
||||
address_del(&virtual_page_pool, address,
|
||||
npages, PAGE_SIZE);
|
||||
}
|
||||
|
||||
void physical_page_free(void *address, int npages)
|
||||
{
|
||||
address_del(&physical_page_pool, address,
|
||||
npages, PAGE_SIZE);
|
||||
}
|
||||
|
||||
204
conts/test_suite0/src/api/mutex.c
Normal file
204
conts/test_suite0/src/api/mutex.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Test l4_mutex_control system call.
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <l4lib/mutex.h>
|
||||
#include <tests.h>
|
||||
|
||||
#define MUTEX_NTHREADS 8
|
||||
#define MUTEX_INCREMENTS 200
|
||||
#define MUTEX_VALUE_TOTAL (MUTEX_NTHREADS * MUTEX_INCREMENTS)
|
||||
|
||||
struct mutex_test_data {
|
||||
struct l4_mutex lock;
|
||||
int val;
|
||||
};
|
||||
|
||||
static struct mutex_test_data tdata;
|
||||
|
||||
static void init_test_data(struct mutex_test_data *tdata)
|
||||
{
|
||||
l4_mutex_init(&tdata->lock);
|
||||
tdata->val = 0;
|
||||
}
|
||||
|
||||
|
||||
int mutex_thread_non_contending(void *arg)
|
||||
{
|
||||
struct mutex_test_data *data =
|
||||
(struct mutex_test_data *)arg;
|
||||
l4id_t tid = self_tid();
|
||||
int err = tid;
|
||||
|
||||
for (int i = 0; i < MUTEX_INCREMENTS; i++) {
|
||||
/* Lock the data structure */
|
||||
if ((err = l4_mutex_lock(&data->lock)) < 0) {
|
||||
dbg_printf("Thread %d: Acquiring mutex failed. "
|
||||
"err = %d\n", tid, err);
|
||||
return -err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment and release lock
|
||||
*/
|
||||
data->val++;
|
||||
|
||||
/* Unlock the data structure */
|
||||
if ((err = l4_mutex_unlock(&data->lock)) < 0) {
|
||||
dbg_printf("Thread %d: Releasing the mutex failed. "
|
||||
"err = %d\n", tid, err);
|
||||
return -err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mutex_thread_contending(void *arg)
|
||||
{
|
||||
struct mutex_test_data *data =
|
||||
(struct mutex_test_data *)arg;
|
||||
l4id_t tid = self_tid();
|
||||
int err = tid;
|
||||
|
||||
for (int i = 0; i < MUTEX_INCREMENTS; i++) {
|
||||
/* Lock the data structure */
|
||||
if ((err = l4_mutex_lock(&data->lock)) < 0) {
|
||||
dbg_printf("Thread %d: Acquiring mutex failed. "
|
||||
"err = %d\n", tid, err);
|
||||
return -err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sleep some time to have some
|
||||
* threads blocked on the mutex
|
||||
*/
|
||||
for (int j = 0; j < 3; j++)
|
||||
l4_thread_switch(0);
|
||||
|
||||
/*
|
||||
* Increment and release lock
|
||||
*/
|
||||
data->val++;
|
||||
|
||||
/* Unlock the data structure */
|
||||
if ((err = l4_mutex_unlock(&data->lock)) < 0) {
|
||||
dbg_printf("Thread %d: Releasing the mutex failed. "
|
||||
"err = %d\n", tid, err);
|
||||
return -err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int test_mutex(int (*mutex_thread)(void *))
|
||||
{
|
||||
struct l4_thread *thread[MUTEX_NTHREADS];
|
||||
int err;
|
||||
|
||||
/* Init mutex data */
|
||||
init_test_data(&tdata);
|
||||
|
||||
/*
|
||||
* Lock the mutex so nobody starts working
|
||||
*/
|
||||
if ((err = l4_mutex_lock(&tdata.lock)) < 0) {
|
||||
dbg_printf("Acquiring mutex failed. "
|
||||
"err = %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Create threads */
|
||||
for (int i = 0; i < MUTEX_NTHREADS; i++) {
|
||||
if ((err = thread_create(mutex_thread,
|
||||
&tdata,
|
||||
TC_SHARE_SPACE,
|
||||
&thread[i])) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unlock the mutex and initiate all workers */
|
||||
if ((err = l4_mutex_unlock(&tdata.lock)) < 0) {
|
||||
dbg_printf("Releasing the mutex failed. "
|
||||
"err = %d\n", err);
|
||||
return -err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for all threads to exit successfully
|
||||
*/
|
||||
for (int i = 0; i < MUTEX_NTHREADS; i++) {
|
||||
if ((err = thread_wait(thread[i])) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that lock is in correct state
|
||||
*/
|
||||
if (tdata.lock.lock != L4_MUTEX_UNLOCKED) {
|
||||
dbg_printf("MUTEX is not in unlocked condition "
|
||||
"after tests. lockval = %d, expected = %d\n",
|
||||
tdata.lock.lock, L4_MUTEX_UNLOCKED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that increments have occured correctly
|
||||
*/
|
||||
if (tdata.val != MUTEX_VALUE_TOTAL) {
|
||||
dbg_printf("Lock-protected value incremented incorrectly "
|
||||
"after mutex worker threads.\n"
|
||||
"val = %d, expected = %d\n",
|
||||
tdata.val,
|
||||
MUTEX_VALUE_TOTAL);
|
||||
return -1;
|
||||
}
|
||||
if (tdata.val != MUTEX_VALUE_TOTAL) {
|
||||
dbg_printf("Lock-protected value incremented incorrectly "
|
||||
"after mutex worker threads.\n"
|
||||
"val = %d, expected = %d\n",
|
||||
tdata.val,
|
||||
MUTEX_VALUE_TOTAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbg_printf("Mutex test successful.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_api_mutexctrl(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = test_mutex(mutex_thread_contending)) < 0)
|
||||
goto out_err;
|
||||
|
||||
if ((err = test_mutex(mutex_thread_non_contending)) < 0)
|
||||
goto out_err;
|
||||
|
||||
printf("USERSPACE MUTEX: -- PASSED --\n");
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("USERSPACE MUTEX: -- FAILED --\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
146
conts/test_suite0/src/api/smp.c
Normal file
146
conts/test_suite0/src/api/smp.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Some minimal tests for SMP functionality
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/exregs.h>
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <tests.h>
|
||||
|
||||
static int new_thread_func(void *args)
|
||||
{
|
||||
struct exregs_data exregs;
|
||||
struct task_ids ids;
|
||||
int err;
|
||||
|
||||
l4_getid(&ids);
|
||||
|
||||
#if 0
|
||||
memset(&exregs, 0, sizeof(exregs));
|
||||
exregs_set_read(&exregs);
|
||||
if ((err = l4_exchange_registers(&exregs,
|
||||
ids.tid)) < 0) {
|
||||
printf("SMP test: Exregs call failed on %s\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
|
||||
dbg_printf("New thread running successfully on cpu %d "
|
||||
"tid=%d. Exiting...\n", self_tid(),
|
||||
exregs.cpu_affinity);
|
||||
#endif
|
||||
|
||||
dbg_printf("SMP:New thread running successfully"
|
||||
"tid=%d. Exiting...\n", self_tid());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create 2 threads on different cpus and run them.
|
||||
*
|
||||
* Parent then destroys the child. Parent and child
|
||||
* are on different cpus.
|
||||
*/
|
||||
int test_smp_two_threads(void)
|
||||
{
|
||||
struct exregs_data exregs;
|
||||
struct l4_thread *thread;
|
||||
int err, err2;
|
||||
|
||||
dbg_printf("%s: Creating a new thread\n", __FUNCTION__);
|
||||
/*
|
||||
* Create new thread but don't start it
|
||||
*/
|
||||
if ((err = thread_create(new_thread_func, 0,
|
||||
TC_SHARE_SPACE | TC_NOSTART,
|
||||
&thread)) < 0) {
|
||||
dbg_printf("THREAD_CREATE failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
#if 0
|
||||
dbg_printf("%s: Setting child affinity to %d\n", __FUNCTION__, 1);
|
||||
/*
|
||||
* Set its cpu affinity to cpu = 1
|
||||
*/
|
||||
memset(&exregs, 0, sizeof(exregs));
|
||||
exregs_set_affinity(&exregs, 1);
|
||||
|
||||
/* Write to affinity field */
|
||||
if ((err = l4_exchange_registers(&exregs,
|
||||
thread->ids.tid)) < 0) {
|
||||
printf("%s: Exregs on setting cpu affinity "
|
||||
"failed on newly created thread. err=%d\n",
|
||||
__FUNCTION__, err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
dbg_printf("%s: Running child on other cpu\n", __FUNCTION__);
|
||||
#endif
|
||||
/* Start the thread */
|
||||
l4_thread_control(THREAD_RUN, &thread->ids);
|
||||
|
||||
dbg_printf("%s: Waiting on child\n", __FUNCTION__);
|
||||
/* Wait on the thread */
|
||||
if ((err = thread_wait(thread)) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
goto out_err;
|
||||
} else {
|
||||
dbg_printf("Thread %d exited successfully. ret=%d\n",
|
||||
thread->ids.tid, err);
|
||||
}
|
||||
|
||||
dbg_printf("%s: Child destroyed successfully\n", __FUNCTION__);
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
/*
|
||||
* Destroy the thread from parent
|
||||
*/
|
||||
if ((err2 = thread_destroy(thread)) < 0) {
|
||||
dbg_printf("THREAD_DESTROY failed. "
|
||||
"err=%d\n", err2);
|
||||
return err2;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int test_smp_two_spaces(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_smp_ipc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined (CONFIG_SMP)
|
||||
int test_smp(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = test_smp_two_threads()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_smp_two_spaces()) < 0)
|
||||
return err;
|
||||
|
||||
if ((err = test_smp_ipc()) < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* Not CONFIG_SMP */
|
||||
|
||||
int test_smp(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* Endif */
|
||||
|
||||
249
conts/test_suite0/src/api/thread.c
Normal file
249
conts/test_suite0/src/api/thread.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Test l4_thread_control system call.
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <stdio.h>
|
||||
#include <tests.h>
|
||||
|
||||
/*
|
||||
* A secondary thread that tests
|
||||
* various conditions by taking actions
|
||||
* told by its parent.
|
||||
*/
|
||||
int new_thread_func(void *args)
|
||||
{
|
||||
dbg_printf("New thread running successfully. "
|
||||
"tid=%d\n", self_tid());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread that exits by doing some number of
|
||||
* thread switches to ensure parent has a chance
|
||||
* to wait on it or attempt to destroy it
|
||||
* The purpose is to test parent-wait before self-destroy.
|
||||
*/
|
||||
int delayed_exit_func(void *args)
|
||||
{
|
||||
int x = 5;
|
||||
l4id_t parent = *((l4id_t *)args);
|
||||
|
||||
dbg_printf("%s: thread running successfully. "
|
||||
"tid=%d\n", __FUNCTION__, self_tid());
|
||||
|
||||
/*
|
||||
* Switch to parent a few times to ensure it
|
||||
* runs and begins to wait on us
|
||||
*/
|
||||
while (x--)
|
||||
l4_thread_switch(parent);
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread that exits immediately
|
||||
* Purpose is to test parent-wait after self-destroy.
|
||||
*/
|
||||
int imm_exit_func(void *args)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have 3 thread creation scenarios to test.
|
||||
*/
|
||||
struct l4_thread *test_thread_create()
|
||||
{
|
||||
struct l4_thread *tptr;
|
||||
int err;
|
||||
|
||||
dbg_printf("%s: Creating thread", __FUNCTION__);
|
||||
|
||||
/*
|
||||
* Create a thread in the same space
|
||||
*/
|
||||
if ((err = thread_create(new_thread_func, 0,
|
||||
TC_SHARE_SPACE,
|
||||
&tptr)) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return PTR_ERR(err);
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", tptr->ids.tid);
|
||||
|
||||
return tptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test thread run/resume, suspend
|
||||
*
|
||||
* We don't test recycle as that would delete the current
|
||||
* address space
|
||||
*/
|
||||
int test_thread_actions(struct l4_thread *thread)
|
||||
{
|
||||
int err;
|
||||
|
||||
dbg_printf("Suspending thread "
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
/*
|
||||
* Suspend/resume the thread
|
||||
*/
|
||||
if ((err = l4_thread_control(THREAD_SUSPEND, &thread->ids)) < 0) {
|
||||
dbg_printf("THREAD_SUSPEND failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Suspend OK. Resuming thread "
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
if ((err = l4_thread_control(THREAD_RUN, &thread->ids)) < 0) {
|
||||
dbg_printf("THREAD_RUN failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Resume OK."
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test thread destruction
|
||||
*/
|
||||
int test_thread_destroy(struct l4_thread *thread)
|
||||
{
|
||||
int err;
|
||||
l4id_t id_self = self_tid();
|
||||
|
||||
dbg_printf("Destroying thread."
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
/*
|
||||
* Destroy the thread from parent
|
||||
*/
|
||||
if ((err = thread_destroy(thread)) < 0) {
|
||||
dbg_printf("THREAD_DESTROY failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("%s: Destroy OK\n", __FUNCTION__);
|
||||
|
||||
dbg_printf("%s: Creating new thread\n", __FUNCTION__);
|
||||
|
||||
/*
|
||||
* Create a new thread
|
||||
* and tell it to destroy itself
|
||||
* by adding a delay, then wait on it.
|
||||
*
|
||||
* Delay ensures we test the case that
|
||||
* wait occurs before thread is destroyed.
|
||||
*/
|
||||
if ((err = thread_create(delayed_exit_func, &id_self,
|
||||
TC_SHARE_SPACE,
|
||||
&thread)) < 0) {
|
||||
dbg_printf("THREAD_CREATE failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
dbg_printf("Waiting on thread, "
|
||||
"tid=%d\n", thread->ids.tid);
|
||||
|
||||
/* Wait on the thread */
|
||||
if ((err = thread_wait(thread)) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
} else {
|
||||
dbg_printf("Thread %d exited successfully. ret=%d\n",
|
||||
thread->ids.tid, err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new thread
|
||||
* and tell it to destroy itself
|
||||
* immediately, add a delay and
|
||||
* then wait on it.
|
||||
*
|
||||
* Delay ensures we test the case that
|
||||
* wait occurs after thread is destroyed.
|
||||
*/
|
||||
if ((err = thread_create(imm_exit_func, 0,
|
||||
TC_SHARE_SPACE,
|
||||
&thread)) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Wait on the thread */
|
||||
if ((err = thread_wait(thread)) < 0) {
|
||||
dbg_printf("THREAD_WAIT failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
} else {
|
||||
dbg_printf("Thread %d exited successfully. ret=%d\n",
|
||||
thread->ids.tid, err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: In order to test null pointers a separate
|
||||
* thread who is paged by the main one should attempt
|
||||
* to pass a null ptr.
|
||||
*/
|
||||
int test_thread_invalid(struct l4_thread *thread)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_api_tctrl(void)
|
||||
{
|
||||
struct l4_thread *thread;
|
||||
int err;
|
||||
|
||||
/* Test thread create */
|
||||
if (IS_ERR(thread = test_thread_create())) {
|
||||
err = (int)thread;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Test thread actions */
|
||||
if ((err = test_thread_actions(thread)) < 0)
|
||||
goto out_err;
|
||||
|
||||
/* Test thread destruction */
|
||||
if ((err = test_thread_destroy(thread)) < 0)
|
||||
goto out_err;
|
||||
|
||||
/* Test thread invalid input */
|
||||
if ((err = test_thread_invalid(thread)) < 0)
|
||||
goto out_err;
|
||||
|
||||
printf("THREAD CONTROL: -- PASSED --\n");
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("THREAD CONTROL: -- FAILED --\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
65
conts/test_suite0/src/arch/arm/v5/mm.c
Normal file
65
conts/test_suite0/src/arch/arm/v5/mm.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* ARMv5 specific functions
|
||||
*
|
||||
* Copyright (C) 2008 - 2010 B Labs Ltd.
|
||||
*/
|
||||
#include <task.h>
|
||||
#include <vm_area.h>
|
||||
#include <l4lib/exregs.h>
|
||||
#include __INC_ARCH(mm.h)
|
||||
|
||||
/* Extracts generic protection flags from architecture-specific pte */
|
||||
unsigned int vm_prot_flags(pte_t pte)
|
||||
{
|
||||
unsigned int vm_prot_flags = 0;
|
||||
unsigned int rw_flags = __MAP_USR_RW & PTE_PROT_MASK;
|
||||
unsigned int ro_flags = __MAP_USR_RO & PTE_PROT_MASK;
|
||||
|
||||
/* Clear non-protection flags */
|
||||
pte &= PTE_PROT_MASK;
|
||||
|
||||
if (pte == ro_flags)
|
||||
vm_prot_flags = VM_READ | VM_EXEC;
|
||||
else if (pte == rw_flags)
|
||||
vm_prot_flags = VM_READ | VM_WRITE | VM_EXEC;
|
||||
else
|
||||
vm_prot_flags = VM_NONE;
|
||||
|
||||
return vm_prot_flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* PTE STATES:
|
||||
* PTE type field: 00 (Translation fault)
|
||||
* PTE type field correct, AP bits: None (Read or Write access fault)
|
||||
* PTE type field correct, AP bits: RO (Write access fault)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Extracts arch-specific fault parameters
|
||||
* and puts them into generic format
|
||||
*/
|
||||
void set_generic_fault_params(struct fault_data *fault)
|
||||
{
|
||||
unsigned int prot_flags = vm_prot_flags(fault->kdata->pte);
|
||||
|
||||
fault->reason = 0;
|
||||
fault->pte_flags = prot_flags;
|
||||
|
||||
if (is_prefetch_abort(fault->kdata->fsr)) {
|
||||
fault->reason |= VM_READ;
|
||||
fault->address = fault->kdata->faulty_pc;
|
||||
} else {
|
||||
fault->address = fault->kdata->far;
|
||||
|
||||
/* Always assume read fault first */
|
||||
if (prot_flags & VM_NONE)
|
||||
fault->reason |= VM_READ;
|
||||
else if (prot_flags & VM_READ)
|
||||
fault->reason |= VM_WRITE;
|
||||
else
|
||||
BUG();
|
||||
}
|
||||
arch_print_fault_params(fault);
|
||||
}
|
||||
|
||||
75
conts/test_suite0/src/arch/arm/v7/mm.c
Normal file
75
conts/test_suite0/src/arch/arm/v7/mm.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* ARMv7 specific functions
|
||||
*
|
||||
* Copyright (C) 2008 - 2010 B Labs Ltd.
|
||||
*/
|
||||
#include <macros.h>
|
||||
#include <l4lib/exregs.h>
|
||||
#include <fault.h>
|
||||
#include INC_SUBARCH(mm.h)
|
||||
#include INC_SUBARCH(exception.h)
|
||||
|
||||
/* Get simplified access permissions */
|
||||
int pte_get_access_simple(pte_t pte)
|
||||
{
|
||||
/* Place AP[2] and AP[1] in [1:0] positions and return */
|
||||
return (((pte >> PTE_AP2_BIT) & 1) << 1)
|
||||
| ((pte >> PTE_AP1_BIT) & 1);
|
||||
}
|
||||
|
||||
int is_translation_fault(u32 fsr)
|
||||
{
|
||||
return (fsr & FSR_FS_MASK) == ABORT_TRANSLATION_PAGE;
|
||||
}
|
||||
|
||||
unsigned int vm_prot_flags(pte_t pte, u32 fsr)
|
||||
{
|
||||
unsigned int pte_prot_flags = 0;
|
||||
|
||||
/* Translation fault means no permissions */
|
||||
if (is_translation_fault(fsr))
|
||||
return VM_NONE;
|
||||
|
||||
/* Check simplified permission bits */
|
||||
switch (pte_get_access_simple(pte)) {
|
||||
case AP_SIMPLE_USER_RW_KERN_RW:
|
||||
pte_prot_flags |= VM_WRITE;
|
||||
case AP_SIMPLE_USER_RO_KERN_RO:
|
||||
pte_prot_flags |= VM_READ;
|
||||
|
||||
/* Also, check exec never bit */
|
||||
if (!(pte & (1 << PTE_XN_BIT)))
|
||||
pte_prot_flags |= VM_EXEC;
|
||||
break;
|
||||
case AP_SIMPLE_USER_NONE_KERN_RW:
|
||||
case AP_SIMPLE_USER_NONE_KERN_RO:
|
||||
default:
|
||||
pte_prot_flags = VM_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
return pte_prot_flags;
|
||||
}
|
||||
|
||||
void set_generic_fault_params(struct fault_data *fault)
|
||||
{
|
||||
fault->pte_flags = vm_prot_flags(fault->kdata->pte, fault->kdata->fsr);
|
||||
fault->reason = 0;
|
||||
|
||||
/*
|
||||
* Prefetch fault denotes exec fault.
|
||||
*/
|
||||
if (is_prefetch_abort(fault->kdata->fsr)) {
|
||||
fault->reason |= VM_EXEC;
|
||||
fault->address = fault->kdata->faulty_pc;
|
||||
} else {
|
||||
fault->address = fault->kdata->far;
|
||||
|
||||
/* Write-not-read bit determines fault */
|
||||
if (fault->kdata->fsr & (1 << DFSR_WNR_BIT))
|
||||
fault->reason |= VM_WRITE;
|
||||
else
|
||||
fault->reason |= VM_READ;
|
||||
}
|
||||
}
|
||||
|
||||
106
conts/test_suite0/src/capability.c
Normal file
106
conts/test_suite0/src/capability.c
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Capability-related userspace helpers
|
||||
*
|
||||
* Copyright (C) 2009 B Labs Ltd.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <l4lib/lib/cap.h>
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
|
||||
#if 0
|
||||
static struct capability cap_array[30];
|
||||
|
||||
struct cap_group {
|
||||
struct cap_list virtmem;
|
||||
struct cap_list physmem;
|
||||
struct cap_list threadpool;
|
||||
struct cap_list tctrl;
|
||||
struct cap_list exregs;
|
||||
struct cap_list ipc;
|
||||
struct cap_list mutex;
|
||||
struct cap_list sched;
|
||||
struct cap_list mutexpool;
|
||||
struct cap_list spacepool;
|
||||
struct cap_list cappool;
|
||||
};
|
||||
|
||||
static inline struct capability *cap_get_thread()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline struct capability *cap_get_space()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline struct capability *cap_get_ipc()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline struct capability *cap_get_virtmem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline struct capability *cap_get_physmem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline struct capability *cap_get_physmem(unsigned long phys)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline struct capability *cap_get_virtmem(unsigned long virt)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline struct capability *cap_get_byid(l4id_t id)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void cap_share_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void cap_grant_single(struct capability *orig, struct capability *share, l4id_t target, unsigned int flags)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int caps_read_all(void)
|
||||
{
|
||||
int ncaps;
|
||||
int err;
|
||||
|
||||
/* Read number of capabilities */
|
||||
if ((err = l4_capability_control(CAP_CONTROL_NCAPS,
|
||||
0, &ncaps)) < 0) {
|
||||
printf("l4_capability_control() reading # of"
|
||||
" capabilities failed.\n Could not "
|
||||
"complete CAP_CONTROL_NCAPS request.\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Read all capabilities */
|
||||
if ((err = l4_capability_control(CAP_CONTROL_READ,
|
||||
0, cap_array)) < 0) {
|
||||
printf("l4_capability resource_control() reading of "
|
||||
"capabilities failed.\n Could not "
|
||||
"complete CAP_CONTROL_READ_CAPS request.\n");
|
||||
BUG();
|
||||
}
|
||||
//cap_array_print(ncaps, caparray);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
148
conts/test_suite0/src/captest.c
Normal file
148
conts/test_suite0/src/captest.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#include <thread.h>
|
||||
#include <container.h>
|
||||
#include <capability.h>
|
||||
#include <tests.h>
|
||||
#include <l4/api/errno.h>
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include <l4/api/capability.h>
|
||||
|
||||
int simple_pager_thread(void *arg)
|
||||
{
|
||||
int err;
|
||||
int res = *(int *)arg;
|
||||
struct task_ids ids;
|
||||
int testres = 0;
|
||||
|
||||
l4_getid(&ids);
|
||||
|
||||
printf("Thread spawned from pager, \
|
||||
trying to create new thread.\n");
|
||||
err = l4_thread_control(THREAD_CREATE |
|
||||
TC_SHARE_SPACE, &ids);
|
||||
|
||||
if (res == 0)
|
||||
if (err == -ENOCAP ||
|
||||
err == -ENOMEM) {
|
||||
printf("Creation failed with %d "
|
||||
"as expected.\n", err);
|
||||
testres = 0;
|
||||
} else {
|
||||
printf("Creation was supposed to fail "
|
||||
"with %d or %d, but err = %d\n",
|
||||
-ENOMEM, -ENOCAP, err);
|
||||
testres = 1;
|
||||
}
|
||||
else
|
||||
if (err == 0) {
|
||||
// printf("Creation succeeded as expected.\n");
|
||||
testres = 0;
|
||||
} else {
|
||||
printf("Creation was supposed to succeed, "
|
||||
"but err = %d\n", err);
|
||||
testres = 1;
|
||||
}
|
||||
|
||||
/* Destroy thread we created */
|
||||
if (err == 0 &&
|
||||
res == 0)
|
||||
l4_thread_control(THREAD_DESTROY, &ids);
|
||||
|
||||
/* Destroy self */
|
||||
l4_exit(testres);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wait_check_test(struct task_ids *ids)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Wait for thread to finish */
|
||||
result = l4_thread_control(THREAD_WAIT, ids);
|
||||
if (result < 0) {
|
||||
printf("Waiting on (%d)'s exit failed.\n", ids->tid);
|
||||
return -1;
|
||||
} else if (result > 0) {
|
||||
printf("Top-level test has failed\n");
|
||||
}
|
||||
/* Else it is a success */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int capability_test(void)
|
||||
{
|
||||
int err;
|
||||
struct task_ids ids;
|
||||
int TEST_MUST_FAIL = 0;
|
||||
//int TEST_MUST_SUCCEED = 1;
|
||||
|
||||
/* Read pager capabilities */
|
||||
caps_read_all();
|
||||
|
||||
/*
|
||||
* Create new thread that will attempt
|
||||
* a pager privileged operation
|
||||
*/
|
||||
if ((err = thread_create(simple_pager_thread,
|
||||
&TEST_MUST_FAIL,
|
||||
TC_SHARE_SPACE, &ids)) < 0) {
|
||||
printf("Top-level simple_pager creation failed.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
printf("waititng for result\n");
|
||||
/* Wait for test to finish and check result */
|
||||
if (wait_check_test(&ids) < 0)
|
||||
goto out_err;
|
||||
#if 0
|
||||
|
||||
/* Destroy test thread */
|
||||
if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) {
|
||||
printf("Destruction of top-level simple_pager failed.\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
/*
|
||||
* Share operations with the same thread
|
||||
* group
|
||||
*/
|
||||
if ((err = l4_capability_control(CAP_CONTROL_SHARE,
|
||||
CAP_SHARE_CONTAINER, 0)) < 0) {
|
||||
printf("Sharing capability with thread group failed.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create new thread that will attempt a pager privileged
|
||||
* operation. This should succeed as we shared caps with
|
||||
* the thread group.
|
||||
*/
|
||||
if ((err = thread_create(simple_pager_thread,
|
||||
&TEST_MUST_SUCCEED,
|
||||
TC_SHARE_SPACE |
|
||||
TC_SHARE_GROUP, &ids)) < 0) {
|
||||
printf("Top-level simple_pager creation failed.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Wait for test to finish and check result */
|
||||
if (wait_check_test(&ids) < 0)
|
||||
goto out_err;
|
||||
|
||||
/* Destroy test thread */
|
||||
if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) {
|
||||
printf("Destruction of top-level simple_pager failed.\n");
|
||||
BUG();
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("Capability Sharing Test -- PASSED --\n");
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
printf("Capability Sharing Test -- FAILED --\n");
|
||||
return 0;
|
||||
}
|
||||
53
conts/test_suite0/src/cli_serv/cli_serv.c
Normal file
53
conts/test_suite0/src/cli_serv/cli_serv.c
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Tests client/server style container setup
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <tests.h>
|
||||
|
||||
/*
|
||||
* A container can be set up in many different combinations
|
||||
* of hierarchy where the hierarchical differences between
|
||||
* the threads are determined by a finely grained capability
|
||||
* configuration.
|
||||
*
|
||||
* However, this boils down to two main sets of hierarchical
|
||||
* setup: client/server or multithreaded/standalone entities.
|
||||
*
|
||||
* This test tests the client/server style hierarchical set up.
|
||||
*/
|
||||
int test_cli_serv(void)
|
||||
{
|
||||
/*
|
||||
* Create a child thread in a new address space.
|
||||
* copying current pager's page tables to child
|
||||
*/
|
||||
|
||||
/* Copy current pager's all sections to child pages */
|
||||
|
||||
/*
|
||||
* Set up child's registers to execute the special
|
||||
* child entry function
|
||||
*/
|
||||
|
||||
/*
|
||||
* Start the child
|
||||
*/
|
||||
|
||||
/*
|
||||
* Interact with the child:
|
||||
*
|
||||
* Handle short, full, extended ipc
|
||||
*
|
||||
* Handle page fault
|
||||
*/
|
||||
|
||||
/*
|
||||
* Destroy child
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
220
conts/test_suite0/src/example.c
Normal file
220
conts/test_suite0/src/example.c
Normal file
@@ -0,0 +1,220 @@
|
||||
|
||||
#if 0
|
||||
|
||||
int mutex_user_thread(void *arg)
|
||||
{
|
||||
/* TODO: Create and access a mutex */
|
||||
}
|
||||
|
||||
int independent_thread(void *arg)
|
||||
{
|
||||
/* TODO: Do whatever syscall available */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This example demonstrates how the capability-based
|
||||
* security model can be bypassed and taken out of the
|
||||
* way for the sake of implementing an application that
|
||||
* doesn't worry too much about security.
|
||||
*
|
||||
* The benefit is that the user does neither worry about
|
||||
* capabilities nor using its api to design correctly
|
||||
* secure systems. The downside is that the system is
|
||||
* less security-enforced, i.e. all parties must be
|
||||
* trusted.
|
||||
*/
|
||||
int multi_threaded_nocaps_example(void)
|
||||
{
|
||||
/*
|
||||
* We are the first pager with capabilities to
|
||||
* create new tasks, spaces, in its own container.
|
||||
*/
|
||||
pager_read_caps();
|
||||
|
||||
/*
|
||||
* We have all our capabilities private to us.
|
||||
*
|
||||
* If we create a new task, it won't be able to
|
||||
* any kernel operations that we can do, because
|
||||
* we hold our capabilities privately.
|
||||
*
|
||||
* In order to settle all capability access issues
|
||||
* once and for all threads we will create and manage,
|
||||
* we share our capabilities with the most global
|
||||
* collection possible.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Share all of our capabilities with all threads
|
||||
* in the same container.
|
||||
*
|
||||
* From this point onwards, any thread we create and
|
||||
* manage (i.e. whose container id is equal to our
|
||||
* container id) will have the ability to leverage
|
||||
* all of our capabilities as defined for us at
|
||||
* configuration time.
|
||||
*/
|
||||
l4_cap_share(0, CAP_SHARE_CONTAINER | CAP_SHARE_ALL, self_tid());
|
||||
|
||||
|
||||
/*
|
||||
* Lets try it.
|
||||
*
|
||||
* Create new thread that we don't have any hieararchical
|
||||
* relationship, i.e. one that is a pager of itself, one
|
||||
* that runs in a new address space, and in a new thread
|
||||
* group. All we share is the container.
|
||||
*/
|
||||
if ((err = thread_create(independent_thread, 0,
|
||||
TC_NO_SHARING, &ids)) < 0) {
|
||||
printf("mutex_user_thread creation failed.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can inspect the new thread by doing an ipc to it.
|
||||
* NOTE:
|
||||
*
|
||||
* We are able to send to this thread from the start,
|
||||
* as we had a container-wide ipc capability defined at
|
||||
* config-time.
|
||||
*
|
||||
* But we would not be able to receive from it, if we
|
||||
* did not share this capability with the container. It
|
||||
* would have no rights to do a send to us. But because
|
||||
* we're in the same container, and we shared our
|
||||
* capability, it now can.
|
||||
*/
|
||||
if ((err = l4_recv(ids->tid, ids->tid, 0)) < 0) {
|
||||
print_err("%s: L4 IPC Error: %d.\n", __FUNCTION__, fd);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* From this point onwards we can create more threads
|
||||
* without worrying about whether they have the caps
|
||||
* to do certain ops, and the caps api. because we shared
|
||||
* them all at the beginning.
|
||||
*/
|
||||
|
||||
out_err:
|
||||
BUG();
|
||||
}
|
||||
|
||||
/*
|
||||
* This example demonstrates how a pager would
|
||||
* share part of its capabilities on the system
|
||||
* with its children.
|
||||
*
|
||||
* The example includes sharing of a mutex
|
||||
* capability with a paged-child.
|
||||
*/
|
||||
int multi_threaded_capability_sharing_example(void)
|
||||
{
|
||||
struct capability *mutex_cap;
|
||||
int thread_retval;
|
||||
|
||||
/*
|
||||
* We are the first pager with capabilities to
|
||||
* create new tasks, spaces, in its own container.
|
||||
*/
|
||||
pager_read_caps();
|
||||
|
||||
/*
|
||||
* We have all our capabilities private to us.
|
||||
*
|
||||
* If we create a new task, it won't be able to
|
||||
* create and use userspace mutexes, because we
|
||||
* hold mutex capabilities privately.
|
||||
*
|
||||
* Lets try it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create new thread that will attempt
|
||||
* a mutex operation, and die on us with a
|
||||
* negative return code if it fails.
|
||||
*/
|
||||
if ((err = thread_create(mutex_user_thread, 0,
|
||||
TC_SHARE_SPACE |
|
||||
TC_AS_PAGER, &ids)) < 0) {
|
||||
printf("mutex_user_thread creation failed.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Check on how the thread has done */
|
||||
if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) {
|
||||
print("Waiting on thread %d failed. err = %d\n",
|
||||
ids->tid, err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (thread_retval == 0) {
|
||||
printf("Thread %d returned with success, where "
|
||||
"we expected failure.\n", ids->tid);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Therefore, we share our capabilities with a
|
||||
* collection so that our capabilities may be also
|
||||
* used by them.
|
||||
*/
|
||||
|
||||
/* Get our private mutex cap */
|
||||
mutex_cap = cap_get(CAP_TYPE_MUTEX);
|
||||
|
||||
/* We have ability to create and use this many mutexes */
|
||||
printf("%s: We have ability to create/use %d mutexes\n",
|
||||
self_tid(), mutex_cap->size);
|
||||
|
||||
/* Split it */
|
||||
cap_new = cap_split(mutex_cap, 10, CAP_SPLIT_SIZE);
|
||||
|
||||
/*
|
||||
* Share the split part with paged-children.
|
||||
*
|
||||
* From this point onwards, any thread we create and
|
||||
* manage (i.e. whose pagerid == self_tid()) will have
|
||||
* the ability to use mutexes, as defined by cap_new
|
||||
* we created.
|
||||
*/
|
||||
l4_cap_share(cap_new, CAP_SHARE_PGGROUP, self_tid());
|
||||
|
||||
/*
|
||||
* Create new thread that will attempt
|
||||
* a mutex operation, and die on us with a
|
||||
* negative return code if it fails.
|
||||
*/
|
||||
if ((err = thread_create(mutex_user_thread, 0,
|
||||
TC_SHARE_SPACE |
|
||||
TC_AS_PAGER, &ids)) < 0) {
|
||||
printf("mutex_user_thread creation failed.\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Check on how the thread has done */
|
||||
if ((err = l4_thread_wait_on(ids, &thread_retval)) < 0) {
|
||||
printf("Waiting on thread %d failed. err = %d\n",
|
||||
ids->tid, err);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (thread_retval < 0) {
|
||||
printf("Thread %d returned with failure, where "
|
||||
"we expected success.\n", ids->tid);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
out_err:
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
47
conts/test_suite0/src/mthread/mthread.c
Normal file
47
conts/test_suite0/src/mthread/mthread.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Tests client/server style container setup
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <tests.h>
|
||||
|
||||
/*
|
||||
* A container can be set up in many different combinations
|
||||
* of hierarchy where the hierarchical differences between
|
||||
* the threads are determined by a finely grained capability
|
||||
* configuration.
|
||||
*
|
||||
* However, this boils down to two main sets of hierarchical
|
||||
* setup: client/server or multithreaded/standalone entities.
|
||||
*
|
||||
* This test tests the multithreaded/standalone style container
|
||||
* set up.
|
||||
*/
|
||||
int test_mthread(void)
|
||||
{
|
||||
/* Create multiple threads in same space */
|
||||
|
||||
/*
|
||||
* Set up childs' registers to execute the special
|
||||
* child entry function
|
||||
*/
|
||||
|
||||
/*
|
||||
* Start the child
|
||||
*/
|
||||
|
||||
/*
|
||||
* Run child threads and interact
|
||||
*
|
||||
* Handle short, full, extended ipc
|
||||
*/
|
||||
|
||||
/*
|
||||
* Destroy child
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
58
conts/test_suite0/src/perf/cycles.c
Normal file
58
conts/test_suite0/src/perf/cycles.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Test cpu cycles using platform timer
|
||||
* ticks.
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <l4lib/perfmon.h>
|
||||
#include <perf.h>
|
||||
#include <tests.h>
|
||||
#include <string.h>
|
||||
#include <timer.h>
|
||||
|
||||
|
||||
void platform_measure_cpu_cycles()
|
||||
{
|
||||
/* Initialize the timer */
|
||||
const int load_value = 1000;
|
||||
int mhz_top, mhz_bot, temp;
|
||||
int cyccnt;
|
||||
|
||||
/* Make sure timer is disabled */
|
||||
timer_stop(timer_base);
|
||||
|
||||
/* Load the timer with ticks value */
|
||||
timer_load(load_value, timer_base);
|
||||
|
||||
/* One shot, 32 bits, no irqs */
|
||||
timer_init_oneshot(timer_base);
|
||||
|
||||
/* Start the timer */
|
||||
timer_start(timer_base);
|
||||
|
||||
/* Start counter */
|
||||
perfmon_reset_start_cyccnt();
|
||||
|
||||
/* Wait until 0 */
|
||||
while (timer_read(timer_base) != 0)
|
||||
;
|
||||
|
||||
cyccnt = perfmon_read_cyccnt();
|
||||
|
||||
/* Fixed-point accuracy on bottom digit */
|
||||
temp = cyccnt * 64 * 10 / load_value;
|
||||
mhz_top = temp / 10;
|
||||
mhz_bot = temp - mhz_top * 10;
|
||||
|
||||
//printk("Perfmon: %u cycles/%dMhz\n",
|
||||
// cyccnt * 64, timer_load);
|
||||
printk("%s: %d.%d MHz CPU speed measured by timer REFCLK at 1MHz\n",
|
||||
__KERNELNAME__, mhz_top, mhz_bot);
|
||||
}
|
||||
|
||||
134
conts/test_suite0/src/perf/exregs.c
Normal file
134
conts/test_suite0/src/perf/exregs.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* l4_exchange_registers performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <l4lib/perfmon.h>
|
||||
#include <l4lib/exregs.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <tests.h>
|
||||
#include <perf.h>
|
||||
|
||||
struct perfmon_cycles l4_exregs_cycles;
|
||||
|
||||
#define PERFTEST_EXREGS_COUNT 100
|
||||
|
||||
int perf_measure_exregs(void)
|
||||
{
|
||||
struct task_ids ids;
|
||||
struct exregs_data exregs[2];
|
||||
int err;
|
||||
|
||||
/* Get own space id */
|
||||
l4_getid(&ids);
|
||||
|
||||
/*
|
||||
* Initialize cycle structures
|
||||
*/
|
||||
memset(&l4_exregs_cycles, 0, sizeof (struct perfmon_cycles));
|
||||
l4_exregs_cycles.min = ~0; /* Init as maximum possible */
|
||||
|
||||
/*
|
||||
* Create a thread in the same space.
|
||||
* Thread is not runnable.
|
||||
*/
|
||||
if ((err = l4_thread_control(THREAD_CREATE | TC_SHARE_SPACE,
|
||||
&ids)) < 0) {
|
||||
dbg_printf("Thread create failed. "
|
||||
"err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
dbg_printf("Thread created successfully. "
|
||||
"tid=%d\n", ids.tid);
|
||||
|
||||
/*
|
||||
* Prepare a context part full of 0xFF
|
||||
*/
|
||||
memset(&exregs[0].context, 0xFF, sizeof(exregs[1].context));
|
||||
exregs[0].valid_vect = 0xFFFFFFFF;
|
||||
|
||||
dbg_printf("Starting l4_exregs write measurement\n");
|
||||
for (int i = 0; i < PERFTEST_EXREGS_COUNT; i++) {
|
||||
perfmon_reset_start_cyccnt();
|
||||
/* Write to context */
|
||||
if ((err = l4_exchange_registers(&exregs[0], ids.tid)) < 0)
|
||||
goto out;
|
||||
perfmon_record_cycles(&l4_exregs_cycles,
|
||||
"l4_exchange_registers");
|
||||
}
|
||||
|
||||
/* Calculate average */
|
||||
l4_exregs_cycles.avg = l4_exregs_cycles.total / l4_exregs_cycles.ops;
|
||||
|
||||
/*
|
||||
* Print results
|
||||
*/
|
||||
printf("PERFMON: %s took %llu min, %llu max, %llu avg, "
|
||||
"%llu total microseconds in %llu ops.\n",
|
||||
"l4_exchange_registers()/WRITE",
|
||||
l4_exregs_cycles.min * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.max * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.avg * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.total * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.ops);
|
||||
|
||||
/*
|
||||
* Prepare a context part full of 0xFF
|
||||
*/
|
||||
memset(&exregs[0].context, 0xFF, sizeof(exregs[1].context));
|
||||
exregs[0].valid_vect = 0xFFFFFFFF;
|
||||
|
||||
dbg_printf("Starting l4_exregs read measurement\n");
|
||||
for (int i = 0; i < PERFTEST_EXREGS_COUNT; i++) {
|
||||
/* Set the other as read-all */
|
||||
exregs_set_read(&exregs[1]);
|
||||
exregs[1].valid_vect = 0xFFFFFFFF;
|
||||
|
||||
if ((err = l4_exchange_registers(&exregs[1],
|
||||
ids.tid)) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read back all context and compare results
|
||||
*/
|
||||
if (memcmp(&exregs[0].context, &exregs[1].context,
|
||||
sizeof(exregs[0].context))) {
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Calculate average */
|
||||
l4_exregs_cycles.avg = l4_exregs_cycles.total / l4_exregs_cycles.ops;
|
||||
|
||||
/*
|
||||
* Print results
|
||||
*/
|
||||
printf("PERFMON: %s took %llu min, %llu max, %llu avg, "
|
||||
"%llu total microseconds in %llu ops.\n",
|
||||
"l4_exchange_registers()/READ",
|
||||
l4_exregs_cycles.min * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.max * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.avg * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.total * USEC_MULTIPLIER,
|
||||
l4_exregs_cycles.ops);
|
||||
|
||||
out:
|
||||
/*
|
||||
* Destroy the thread
|
||||
*/
|
||||
if ((err = l4_thread_control(THREAD_DESTROY, &ids)) < 0) {
|
||||
dbg_printf("Thread destroy failed. err=%d\n",
|
||||
err);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
104
conts/test_suite0/src/perf/getid.c
Normal file
104
conts/test_suite0/src/perf/getid.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* l4_getid performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <l4lib/perfmon.h>
|
||||
#include <perf.h>
|
||||
#include <tests.h>
|
||||
#include <string.h>
|
||||
#include <timer.h>
|
||||
|
||||
struct perfmon_cycles l4_getid_cycles;
|
||||
|
||||
#define PERFTEST_GETID_COUNT 100
|
||||
|
||||
/*
|
||||
* Measure l4_getid by timer ticks
|
||||
*/
|
||||
void perf_measure_getid_ticks(void)
|
||||
{
|
||||
const int timer_ldval = 0xFFFFFFFF;
|
||||
unsigned int timer_val, timer_stamp = 0xFFFFFFFF;
|
||||
unsigned int min = ~0, max = 0, last = 0, total = 0, ops = 0;
|
||||
struct task_ids ids;
|
||||
|
||||
/* Make sure timer is disabled */
|
||||
timer_stop(timer_base);
|
||||
|
||||
/* Configure timer as one shot */
|
||||
timer_init_oneshot(timer_base);
|
||||
|
||||
/* Load the timer with ticks value */
|
||||
timer_load(timer_ldval, timer_base);
|
||||
|
||||
/* Start the timer */
|
||||
printf("Starting the l4_getid timer tick test.\n");
|
||||
timer_start(timer_base);
|
||||
|
||||
/* Do the operation */
|
||||
for (int i = 0; i < PERFTEST_GETID_COUNT; i++) {
|
||||
l4_getid(&ids);
|
||||
timer_val = timer_read(timer_base);
|
||||
last = timer_stamp - timer_val;
|
||||
timer_stamp = timer_val;
|
||||
if (min > last)
|
||||
min = last;
|
||||
if (max < last)
|
||||
max = last;
|
||||
ops++;
|
||||
total += last;
|
||||
}
|
||||
|
||||
printf("TIMER: l4_getid took each %u min, %u max, %u avg,\n"
|
||||
"%u total microseconds, and %u total ops\n", min,
|
||||
max, total/ops, total, ops);
|
||||
}
|
||||
|
||||
/*
|
||||
* Measure l4_getid by cpu cycles
|
||||
*/
|
||||
void perf_measure_getid(void)
|
||||
{
|
||||
struct task_ids ids;
|
||||
|
||||
/*
|
||||
* Initialize structures
|
||||
*/
|
||||
memset(&l4_getid_cycles, 0, sizeof (l4_getid_cycles));
|
||||
l4_getid_cycles.min = ~0; /* Init as maximum possible */
|
||||
|
||||
/*
|
||||
* Do the test
|
||||
*/
|
||||
printf("Starting the l4_getid cycle counter test.\n");
|
||||
for (int i = 0; i < PERFTEST_GETID_COUNT; i++) {
|
||||
perfmon_reset_start_cyccnt();
|
||||
l4_getid(&ids);
|
||||
perfmon_record_cycles(&l4_getid_cycles,
|
||||
"l4_getid");
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate average
|
||||
*/
|
||||
l4_getid_cycles.avg = l4_getid_cycles.total / l4_getid_cycles.ops;
|
||||
|
||||
/*
|
||||
* Print results
|
||||
*/
|
||||
printf("PERFMON: %s took %llu min, %llu max, %llu avg, "
|
||||
"%llu total microseconds in %llu ops.\n",
|
||||
"l4_getid()",
|
||||
l4_getid_cycles.min * USEC_MULTIPLIER,
|
||||
l4_getid_cycles.max * USEC_MULTIPLIER,
|
||||
l4_getid_cycles.avg * USEC_MULTIPLIER,
|
||||
l4_getid_cycles.total * USEC_MULTIPLIER,
|
||||
l4_getid_cycles.ops);
|
||||
}
|
||||
12
conts/test_suite0/src/perf/ipc.c
Normal file
12
conts/test_suite0/src/perf/ipc.c
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* l4_ipc performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
|
||||
void perf_measure_ipc(void)
|
||||
{
|
||||
|
||||
}
|
||||
17
conts/test_suite0/src/perf/map.c
Normal file
17
conts/test_suite0/src/perf/map.c
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* l4_map/l4_unmap performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
|
||||
void perf_measure_map(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void perf_measure_unmap(void)
|
||||
{
|
||||
|
||||
}
|
||||
11
conts/test_suite0/src/perf/mutex.c
Normal file
11
conts/test_suite0/src/perf/mutex.c
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* l4_mutex performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
|
||||
void perf_measure_mutex(void)
|
||||
{
|
||||
}
|
||||
32
conts/test_suite0/src/perf/perf.c
Normal file
32
conts/test_suite0/src/perf/perf.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* API performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <tests.h>
|
||||
#include <perf.h>
|
||||
#include <timer.h>
|
||||
|
||||
/*
|
||||
* Tests all api functions by performance
|
||||
*/
|
||||
int test_performance(void)
|
||||
{
|
||||
perf_timer_init();
|
||||
|
||||
platform_measure_cpu_cycles();
|
||||
|
||||
perf_measure_getid_ticks();
|
||||
perf_measure_getid();
|
||||
perf_measure_tctrl();
|
||||
perf_measure_exregs();
|
||||
perf_measure_ipc();
|
||||
perf_measure_map();
|
||||
perf_measure_unmap();
|
||||
perf_measure_mutex();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
56
conts/test_suite0/src/perf/simple.c
Normal file
56
conts/test_suite0/src/perf/simple.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* l4_getid performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <l4lib/perfmon.h>
|
||||
#include <perf.h>
|
||||
#include <tests.h>
|
||||
#include <string.h>
|
||||
|
||||
struct perfmon_cycles simple_cycles;
|
||||
|
||||
#define PERFTEST_SIMPLE_LOOP 2000
|
||||
|
||||
void perf_test_simple(void)
|
||||
{
|
||||
dbg_printf("%s: This will test the cycle count of basic loops.\n",
|
||||
__FUNCTION__);
|
||||
|
||||
/*
|
||||
* Initialize structures
|
||||
*/
|
||||
memset(&simple_cycles, 0, sizeof(struct perfmon_cycles));
|
||||
simple_cycles.min = ~0; /* Init as maximum possible */
|
||||
|
||||
/*
|
||||
* Do the test
|
||||
*/
|
||||
perfmon_reset_start_cyccnt();
|
||||
for (int i = 0; i < PERFTEST_SIMPLE_LOOP; i++)
|
||||
;
|
||||
|
||||
perfmon_record_cycles(&simple_cycles,"empty_loop");
|
||||
|
||||
/*
|
||||
* Calculate average
|
||||
*/
|
||||
simple_cycles.avg = simple_cycles.total / simple_cycles.ops;
|
||||
|
||||
/*
|
||||
* Print results
|
||||
*/
|
||||
printf("%s took %llu min, %llu max, %llu avg, in %llu ops.\n",
|
||||
"simple loop",
|
||||
simple_cycles.min * USEC_MULTIPLIER,
|
||||
simple_cycles.max * USEC_MULTIPLIER,
|
||||
simple_cycles.avg * USEC_MULTIPLIER,
|
||||
simple_cycles.ops);
|
||||
}
|
||||
|
||||
85
conts/test_suite0/src/perf/tctrl.c
Normal file
85
conts/test_suite0/src/perf/tctrl.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* l4_thread_control performance tests
|
||||
*
|
||||
* Author: Bahadir Balban
|
||||
*/
|
||||
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
#include <l4lib/lib/thread.h>
|
||||
#include <l4lib/perfmon.h>
|
||||
#include <perf.h>
|
||||
#include <tests.h>
|
||||
#include <string.h>
|
||||
|
||||
struct perfmon_cycles tctrl_cycles;
|
||||
|
||||
#define PERFTEST_THREAD_CREATE 50
|
||||
|
||||
void perf_measure_tctrl(void)
|
||||
{
|
||||
struct task_ids ids[PERFTEST_THREAD_CREATE];
|
||||
struct task_ids selfids;
|
||||
l4_getid(&selfids);
|
||||
|
||||
/*
|
||||
* Initialize structures
|
||||
*/
|
||||
memset(&tctrl_cycles, 0, sizeof (struct perfmon_cycles));
|
||||
tctrl_cycles.min = ~0; /* Init as maximum possible */
|
||||
|
||||
/*
|
||||
* Thread create test
|
||||
*/
|
||||
for (int i = 0; i < PERFTEST_THREAD_CREATE; i++) {
|
||||
perfmon_reset_start_cyccnt();
|
||||
l4_thread_control(THREAD_CREATE | TC_SHARE_SPACE, &selfids);
|
||||
perfmon_record_cycles(&tctrl_cycles, "THREAD_CREATE");
|
||||
|
||||
/* Copy ids of created task */
|
||||
memcpy(&ids[i], &selfids, sizeof(struct task_ids));
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate average
|
||||
*/
|
||||
tctrl_cycles.avg = tctrl_cycles.total / tctrl_cycles.ops;
|
||||
|
||||
/*
|
||||
* Print results
|
||||
*/
|
||||
printf("%s took %llu min, %llu max, %llu avg, in %llu ops.\n",
|
||||
"THREAD_CREATE",
|
||||
tctrl_cycles.min * USEC_MULTIPLIER,
|
||||
tctrl_cycles.max * USEC_MULTIPLIER,
|
||||
tctrl_cycles.avg * USEC_MULTIPLIER,
|
||||
tctrl_cycles.ops);
|
||||
|
||||
/*
|
||||
* Thread destroy test
|
||||
*/
|
||||
for (int i = 0; i < PERFTEST_THREAD_CREATE; i++) {
|
||||
perfmon_reset_start_cyccnt();
|
||||
l4_thread_control(THREAD_DESTROY, &ids[i]);
|
||||
perfmon_record_cycles(&tctrl_cycles,"THREAD_DESTROY");
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate average
|
||||
*/
|
||||
tctrl_cycles.avg = tctrl_cycles.total / tctrl_cycles.ops;
|
||||
|
||||
/*
|
||||
* Print results
|
||||
*/
|
||||
printf("%s took %llu min, %llu max, %llu avg, in %llu ops.\n",
|
||||
"THREAD_DESTROY",
|
||||
tctrl_cycles.min * USEC_MULTIPLIER,
|
||||
tctrl_cycles.max * USEC_MULTIPLIER,
|
||||
tctrl_cycles.avg * USEC_MULTIPLIER,
|
||||
tctrl_cycles.ops);
|
||||
}
|
||||
|
||||
40
conts/test_suite0/src/perf/timer.c
Normal file
40
conts/test_suite0/src/perf/timer.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Initialize platform timer virtual address
|
||||
*
|
||||
* Copyright (C) 2010 B Labs Ltd.
|
||||
*
|
||||
* Bahadir Balban
|
||||
*/
|
||||
#include <perf.h>
|
||||
#include <linker.h>
|
||||
#include <l4lib/macros.h>
|
||||
#include L4LIB_INC_ARCH(syslib.h)
|
||||
#include L4LIB_INC_ARCH(syscalls.h)
|
||||
|
||||
/* Note this must be obtained from the capability */
|
||||
#define TIMER_PHYSICAL_BASE 0x10012000
|
||||
|
||||
unsigned long timer_base;
|
||||
|
||||
void perf_timer_init(void)
|
||||
{
|
||||
int err;
|
||||
struct task_ids ids;
|
||||
|
||||
l4_getid(&ids);
|
||||
|
||||
/* Initialize timer base */
|
||||
timer_base = page_align_up(__stack);
|
||||
|
||||
/* Map timer base */
|
||||
if ((err = l4_map((void *)TIMER_PHYSICAL_BASE,
|
||||
(void *)timer_base,
|
||||
1, MAP_USR_IO, ids.tid)) < 0) {
|
||||
printf("FATAL: Performance tests: Could not map "
|
||||
"timer.\ntimer must be selected as a "
|
||||
"container capability. err=%d\n",
|
||||
err);
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
0
conts/test_suite0/src/perf/tswitch.c
Normal file
0
conts/test_suite0/src/perf/tswitch.c
Normal file
Reference in New Issue
Block a user