Merge branch 'svm', remote branch 'origin/svm' into svm

Conflicts:
	arch/x86/mm/svm.c
This commit is contained in:
Pablo Reble 2011-11-09 07:56:54 -08:00
commit a114e3997d
22 changed files with 890 additions and 224 deletions

View file

@ -536,7 +536,7 @@ FILE_VERSION_FILTER =
# You can optionally specify a file name after the option, if omitted
# DoxygenLayout.xml will be used as the name of the layout file.
LAYOUT_FILE =
LAYOUT_FILE = documentation/tmpl/layout.xml
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@ -606,7 +606,7 @@ INPUT = ./fs \
./libkern \
./mm \
./tools \
./documentation/text/mainpage.dox
./documentation/text
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is

View file

@ -54,12 +54,8 @@
//#define FIX 1024
#define FIX 1
#define USE_STRONG 1
#define USE_LAZYRELEASE 0
#if USE_STRONG && USE_LAZYRELEASE
#error Please, use only one memory model
#endif
#define SVM_TYPE SVM_STRONG
//define SVM_TYPE SVM_LAZYRELEASE
static inline double pow(double a, int b)
{
@ -76,7 +72,6 @@ int laplace(void *arg)
{
//char* argv[] = {"/bin/laplace", "192.168.4.254", "12301", NULL};
//int argc = 3;
uint32_t flags;
#ifdef _USE_GFX
uint32_t ret;
#endif
@ -98,10 +93,8 @@ int laplace(void *arg)
uint64_t start, end;
flags = irq_nested_disable();
my_rank = RCCE_ue();
num_ranks = RCCE_num_ues();
irq_nested_enable(flags);
my_rank = RCCE_IAM;
num_ranks = RCCE_NP;
#ifdef _USE_GFX
kprintf("Laplace calls gfx_init\n");
@ -140,19 +133,15 @@ int laplace(void *arg)
#endif
NewValues = (volatile DATA **)kmalloc((N + 2) * sizeof(DATA *));
#if USE_STRONG
NewValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_STRONG);
#elif USE_LATYRELEASE
NewValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_LAZYRELEASE);
#ifdef SVM_TYPE
NewValues[0] = (DATA *) svm_malloc((N + 2) * (M + 2) * sizeof(DATA), SVM_TYPE);
#else
NewValues[0] = (DATA *) kmalloc((N + 2) * (M + 2) * sizeof(DATA));
#endif
OldValues = (volatile DATA **)kmalloc((N + 2) * sizeof(DATA *));
#if USE_STRONG
OldValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_STRONG);
#elif USE_LATYRELEASE
OldValues[0] = (DATA *) svmmalloc((N + 2) * (M + 2) * sizeof(DATA), SVM_LAZYRELEASE);
#ifdef SVM_TYPE
OldValues[0] = (DATA *) svm_malloc((N + 2) * (M + 2) * sizeof(DATA), SVM_TYPE);
#else
OldValues[0] = (DATA *) kmalloc((N + 2) * (M + 2) * sizeof(DATA));
#endif
@ -169,7 +158,9 @@ int laplace(void *arg)
BufValues[i] = BufValues[i - 1] + (M);
}
RCCE_barrier(&RCCE_COMM_WORLD);
#ifdef SVM_TYPE
svm_barrier(SVM_TYPE);
#endif
kprintf("(%d) Memory allocated!\n", my_rank);
@ -203,16 +194,13 @@ int laplace(void *arg)
}
}
#if USE_LAZYRELEASE
svm_flush();
svm_invalidate();
#ifdef SVM_TYPE
svm_barrier(SVM_TYPE);
#endif
RCCE_barrier(&RCCE_COMM_WORLD);
kprintf("(%d) Arrays initialized!\n", my_rank);
start = rdtsc();
start = rdtsc();
// START ITERATIONS LOOP
for (t = 0; t < TMAX; t++) {
@ -223,30 +211,21 @@ int laplace(void *arg)
for (i = 1; i < n + 1; i++) {
// over all rows
for (j = 1; j < m + 1; j++) {
#if 1
NewValues[I + i][J + j] =
(OldValues[I + i - 1][J + j] +
OldValues[I + i + 1][J + j] +
OldValues[I + i][J + j - 1] +
OldValues[I + i][J + j + 1]) / 4;
//if ( NewValues[I+i][J+j] < 0.0 ) NewValues[I+i][J+j] = 0.0 * FIX;
//else if ( NewValues[I+i][J+j] > 255.0 ) NewValues[I+i][J+j] = 255.0 * FIX;
#else
NewValues[I + i][J + j] = 25 * (DATA) (my_rank + 1);
#endif
}
}
#if USE_LAZYRELEASE
svm_flush();
svm_invalidate();
#endif
tmp = NewValues;
NewValues = OldValues;
OldValues = tmp;
//RCCE_TNS_barrier(&RCCE_COMM_WORLD);
RCCE_barrier(&RCCE_COMM_WORLD);
#ifdef SVM_TYPE
svm_barrier(SVM_TYPE);
#endif
#ifdef _USE_GFX
if ((my_rank == 0) && (t % 50 == 0)) {
@ -269,17 +248,23 @@ int laplace(void *arg)
GFX_draw_data((char *)(BufValues[0]), (N) * (M));
GFX_update();
}
#ifdef SVM_TYPE
svm_barrier(SVM_TYPE);
#endif
#endif
// END ITERATIONS LOOP
}
RCCE_barrier(&RCCE_COMM_WORLD);
#ifdef SVM_TYPE
svm_barrier(SVM_TYPE);
#endif
end = rdtsc();
kprintf("Calculation time: %llu ms (%llu ticks)\n", (end-start)/(1000ULL*get_cpu_frequency()), end-start);
#if USE_STRONG || USE_LAZYRELEASE
#ifdef SVM_TYPE
svm_statistics();
#endif
}

View file

@ -100,7 +100,9 @@ static int foo(void* arg)
static int mail_ping(void* arg) {
//icc_mail_ping();
icc_mail_ping_irq();
icc_mail_ping_jitter();
//icc_irq_ping();
//icc_mail_datarates();
//icc_halt();
return 0;
@ -337,7 +339,7 @@ int test_init(void)
//create_kernel_task(NULL, mail_noise, NULL, NORMAL_PRIO);
create_kernel_task(NULL, svm_test, NULL, NORMAL_PRIO);
//create_kernel_task(NULL, pi, NULL, NORMAL_PRIO);
//create_kernel_task(NULL, laplace, NULL, NORMAL_PRIO);
create_kernel_task(NULL, laplace, NULL, NORMAL_PRIO);
//create_user_task(NULL, "/bin/hello", argv);
//create_user_task(NULL, "/bin/tests", argv);
//create_user_task(NULL, "/bin/jacobi", argv);

View file

@ -43,6 +43,7 @@ enum icc_mail_requests {
PING_REQ=1,
PING_RESP,
SVM_REQUEST,
SVM_RESP,
NOISE,
};
@ -52,7 +53,9 @@ void icc_mail_check(void);
int icc_mail_ping(void);
int icc_send_gic_irq(int core_num);
int icc_mail_ping_irq(void);
int icc_mail_ping_jitter(void);
int icc_mail_noise(void);
void icc_wait(int tag);
#endif

View file

@ -54,13 +54,15 @@ int svm_init(void);
*
* @return Pointer to the new memory range
*/
void* svmmalloc(size_t sizei, uint32_t flags);
void* svm_malloc(size_t sizei, uint32_t flags);
/** @brief Frees memory, which is managed by the SVM subsystem
*
* Like RCCE function, belongs svmfree to the synchronous function.
*/
void svmfree(void* addr, size_t size);
void svm_free(void* addr, size_t size);
int svm_barrier(uint32_t flags);
/** @brief Request for exlusive access
*

View file

@ -34,11 +34,22 @@
#include <asm/icc.h>
#include <asm/svm.h>
#define SHARED_PAGES (RCCE_SHM_SIZE_MAX >> PAGE_SHIFT)
#define SHARED_PAGES ((4*RCCE_SHM_SIZE_MAX) >> PAGE_SHIFT)
#define OWNER_SIZE ((SHARED_PAGES * sizeof(uint8_t) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#define AIREG1 0
#define AIREG2 (AIREG1 + 1)
t_vcharp RC_SHM_BUFFER_START();
typedef struct {
int counter;
int initializer;
} atomic_increg_t;
static volatile atomic_increg_t *incregs = NULL;
static RCCE_FLAG release;
/*
* Details on L2 cache (nedded for flushing)
*/
@ -77,11 +88,16 @@ static size_t dummy_offset = 0;
static volatile uint8_t* page_owner = NULL;
// helper array to convert a physical to a virtual address
static size_t phys2virt[SHARED_PAGES] = {[0 ... SHARED_PAGES-1] = 0};
static size_t shmbegin = 0;
static uint32_t emit[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0};
static uint32_t request[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0};
static uint32_t forward[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0};
static size_t phys2virt[SHARED_PAGES] = {[0 ... SHARED_PAGES-1] = 0};
static size_t shmbegin = 0;
static uint32_t emit[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0};
static uint32_t request[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0};
static uint32_t forward[RCCE_MAXNP] = {[0 ... RCCE_MAXNP-1] = 0};
static uint64_t request_ticks = 0;
static uint64_t emit_ticks = 0;
static uint64_t wait_ticks = 0;
static uint64_t max_wait = 0;
static uint64_t min_wait = (uint64_t) -1;
int svm_init(void)
{
@ -115,10 +131,26 @@ int svm_init(void)
if (!RCCE_IAM)
memset((void*)page_owner, 0x00, OWNER_SIZE);
// initialize svm barrier
incregs = (volatile atomic_increg_t*) map_region(0, 0xF900E000, 2, MAP_KERNEL_SPACE|MAP_NO_CACHE);
if (BUILTIN_EXPECT(!incregs, 0)) {
flags = irq_nested_disable();
RCCE_shfree((t_vcharp) phyaddr);
irq_nested_enable(flags);
return -ENOMEM;
}
kprintf("Map atomic counters at 0x%x\n", incregs);
// iRCCE is not thread save => disable interrupts
flags = irq_nested_disable();
RCCE_barrier(&RCCE_COMM_WORLD);
RCCE_flag_alloc(&release);
irq_nested_enable(flags);
/* INIT: yafbarrier */
incregs[AIREG1].initializer = 0;
incregs[AIREG2].initializer = 0;
RCCE_barrier(&RCCE_COMM_WORLD);
return 0;
}
@ -129,10 +161,12 @@ int svm_init(void)
*/
int svm_access_request(size_t addr)
{
uint64_t start = rdtsc();
size_t phyaddr = virt_to_phys(addr);
uint32_t pageid;
int remote_rank;
uint8_t payload[iRCCE_MAIL_HEADER_PAYLOAD];
int ret;
if (phyaddr < shmbegin)
return -EINVAL;
@ -140,32 +174,40 @@ int svm_access_request(size_t addr)
return -EINVAL;
pageid = (phyaddr-shmbegin) >> PAGE_SHIFT;
if (page_owner[pageid] == RCCE_IAM)
remote_rank = page_owner[pageid];
if (remote_rank == RCCE_IAM)
return 0;
remote_rank = page_owner[pageid];
((size_t*) payload)[0] = RCCE_IAM;
((size_t*) payload)[1] = phyaddr;
/* send ping request */
iRCCE_mail_send(2*sizeof(size_t), SVM_REQUEST, 0, payload, remote_rank);
icc_send_gic_irq(remote_rank);
request[remote_rank]++;
icc_send_gic_irq(remote_rank);
while (page_owner[pageid] != RCCE_IAM) {
icc_mail_check();
NOP8;
}
uint64_t wait_start = rdtsc();
// wait for response
icc_wait(SVM_RESP);
uint64_t res = rdtsc() - wait_start;
wait_ticks += res;
if (min_wait > res)
min_wait = res;
if (max_wait < res)
max_wait = res;
return change_page_permissions(addr, addr+PAGE_SIZE, VMA_READ|VMA_WRITE|VMA_CACHEABLE);
ret = change_page_permissions(addr, addr+PAGE_SIZE, VMA_READ|VMA_WRITE|VMA_CACHEABLE);
request_ticks += rdtsc() - start;
return ret;
}
#if 0
static atomic_int32_t size_counter = ATOMIC_INIT(0);
#endif
void* svmmalloc(size_t size, uint32_t consistency)
void* svm_malloc(size_t size, uint32_t consistency)
{
task_t* task = per_core(current_task);
size_t phyaddr, viraddr, i;
@ -186,7 +228,7 @@ void* svmmalloc(size_t size, uint32_t consistency)
// currently, we allocate memory in page size granulation
size = (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
#if 0 // Workaround for our MARC paper
#if 1 // Workaround for our MARC paper
// iRCCE is not thread save => disable interrupts
flags = irq_nested_disable();
@ -261,7 +303,7 @@ void* svmmalloc(size_t size, uint32_t consistency)
#endif
}
void svmfree(void* addr, size_t size)
void svm_free(void* addr, size_t size)
{
size_t phyaddr, i;
uint32_t flags;
@ -291,8 +333,10 @@ void svmfree(void* addr, size_t size)
* => Interrupt flag is alread cleared.
*/
int svm_emit_page(size_t phyaddr, int ue)
{
{
uint64_t start = rdtsc();
uint32_t pageid;
int remote_rank;
//kprintf("Try to emit page 0x%x to %d\n", phyaddr, ue);
@ -302,14 +346,13 @@ int svm_emit_page(size_t phyaddr, int ue)
return -EINVAL;
pageid = (phyaddr-shmbegin) >> PAGE_SHIFT;
if (page_owner[pageid] != RCCE_IAM) {
remote_rank = page_owner[pageid];
if (remote_rank != RCCE_IAM) {
// Core is nor owner => forward request to new owner
int remote_rank;
uint8_t payload[iRCCE_MAIL_HEADER_PAYLOAD];
kprintf("Ups, core %d is not owner of page 0x%x\n", RCCE_IAM, phyaddr);
remote_rank = page_owner[pageid];
((size_t*) payload)[0] = ue;
((size_t*) payload)[1] = phyaddr;
@ -322,15 +365,20 @@ int svm_emit_page(size_t phyaddr, int ue)
} else {
size_t viraddr;
svm_flush(0);
//svm_flush(phyaddr);
page_owner[pageid] = ue;
svm_flush(phyaddr);
// send response back to ue
// ue is polling for the response => no irq is needed
iRCCE_mail_send(0, SVM_RESP, 0, NULL, ue);
emit[ue]++;
viraddr = phys2virt[(phyaddr - shmbegin) >> PAGE_SHIFT];
viraddr = phys2virt[pageid];
page_owner[pageid] = ue;
change_page_permissions(viraddr, viraddr+PAGE_SIZE, VMA_NOACCESS|VMA_READ|VMA_CACHEABLE);
}
emit_ticks += rdtsc() - start;
return 0;
}
@ -449,6 +497,36 @@ wrong_addr:
}
#endif
int svm_barrier(uint32_t type)
{
int i;
RCCE_COMM *comm = &RCCE_COMM_WORLD;
static int index = 0;
if (type == SVM_LAZYRELEASE) {
svm_flush(0);
svm_invalidate();
}
#if 1
// Lubachevsky barrier with flags
index = !index;
if (incregs[AIREG1].counter > (comm->size - 2)) {
incregs[AIREG1].initializer = 0;
while(incregs[AIREG1].initializer);
for (i = 0; i < comm->size; i++)
RCCE_flag_write(&release, index, comm->member[i]);
} else RCCE_wait_until(release, index);
#else
RCCE_barrier(&RCCE_COMM_WORLD);
#endif
return 0;
}
extern uint64_t check_ticks;
extern uint64_t recv_ticks;
int svm_statistics(void)
{
uint32_t i;
@ -463,6 +541,13 @@ int svm_statistics(void)
for(i=0; i<RCCE_MAXNP; i++)
kprintf("\t%u", forward[i]);
kputs("\n");
kprintf("request ticks: %llu\n", request_ticks);
kprintf("wait ticks: %llu\n", wait_ticks);
kprintf("emit ticks: %llu\n", emit_ticks);
kprintf("max wait: %llu\n", max_wait);
kprintf("min wait: %llu\n", min_wait);
kprintf("check_ticks: %llu\n", check_ticks);
kprintf("recv_tick: %llu\n", recv_ticks);
return 0;
}

View file

@ -104,8 +104,7 @@ static int iRCCE_mail_fetch(
if( iRCCE_mail_garbage.first == NULL ) {
iRCCE_mail_garbage.last = NULL;
}
}
else {
} else {
header = (iRCCE_MAIL_HEADER*)kmalloc(sizeof(iRCCE_MAIL_HEADER));
}
@ -120,8 +119,7 @@ static int iRCCE_mail_fetch(
iRCCE_last_mail[rank] = 1;
iRCCE_mailbox_close_one( rank, 0 ); // we can close respective mailbox
iRCCE_mail_release( &header );
}
else {
} else {
// check mail priority
int prio = header->prio;
@ -144,77 +142,63 @@ static int iRCCE_mail_fetch(
}
//------------------------------------------------------------------------------
// FUNCTION: iRCCE_mailbox_check
//------------------------------------------------------------------------------
/**
* @brief routine to check for new mail in mailboxes
*
* This function has to be called from time to time. It empties all mailboxes of
* the participating cores if the corresponding sent-flag is set and the mailbox
* is not closed. After calling iRCCE_mail_fetch the sent-flag has to be reset.
* Here we have to use a little trick because we can only write to the MPB in
* cacheline granularity. We set the appropriate flag to zero and afterwords
* touch the MPB on another cacheline. That causes the write combine buffer to
* write out the data.
*/
//------------------------------------------------------------------------------
iRCCE_MAIL_HEADER dummy_header = {0, 0, 0, NULL, 0, 0, 0, {[0 ... iRCCE_MAIL_HEADER_PAYLOAD-1] = 0} };
static int iRCCE_mailbox_check(void) {
int i,j;
uint32_t flags;
/* disable interrupts */
flags = irq_nested_disable();
for( j=1; j<RCCE_NP; ++j ) {
i = (j+RCCE_IAM)%RCCE_NP;
// only check open mailboxes
if( iRCCE_mailbox_status[i] == iRCCE_MAILBOX_OPEN ) {
RC_cache_invalidate();
if( iRCCE_mailbox_recv[i]->sent ) {
iRCCE_mail_fetch(i);
// reset senders flag
RC_cache_invalidate();
*(iRCCE_mailbox_recv[i]) = dummy_header;
}
}
}
/* enable interrupts */
irq_nested_enable(flags);
return iRCCE_SUCCESS;
}
//------------------------------------------------------------------------------
// FUNCTION: iRCCE_mail_check
//------------------------------------------------------------------------------
/**
* @brief routine to check one specific mailbox
* @param sender is the core ID from which the mailbox is checked
* @brief routine to check one specific mailbox or all
* @param sender is the core ID from which the mailbox is checked use
* iRCCE_MAILBOX_ALL as wildcard to check all mailboxes
*
* This function may be called by the user application to check one specific
* mailbox. It is recommended to use it in combination with an inter core
* interrupt.
* mailbox. It is recommended to use it in combination with an inter-core
* interrupt. It empties one or all mailboxes of the participating cores if the
* corresponding sent-flag is set and the mailbox is not closed. After calling
* iRCCE_mail_fetch the sent-flag has to be reset. Here we have to use a little
* trick because we can only write to the MPB in cacheline granularity. We set
* the appropriate flag to zero and afterwords touch the MPB on another
* cacheline. That causes the write combine buffer to write out the data.
*
*/
//------------------------------------------------------------------------------
const static iRCCE_MAIL_HEADER dummy_header =
{0, 0, 0, NULL, 0, 0, 0, {[0 ... iRCCE_MAIL_HEADER_PAYLOAD-1] = 0} };
int iRCCE_mail_check(int sender) {
uint32_t flags;
int j, i;
int found = 0;
// check all mailboxes in case of wildcard
if( sender == iRCCE_MAILBOX_ALL ) {
iRCCE_mailbox_check();
/* disable interrupts */
flags = irq_nested_disable();
return iRCCE_SUCCESS;
for( j=1; j<RCCE_NP; ++j ) {
i = (j+RCCE_IAM)%RCCE_NP;
// only check open mailboxes
if( iRCCE_mailbox_status[i] == iRCCE_MAILBOX_OPEN ) {
RC_cache_invalidate();
if( iRCCE_mailbox_recv[i]->sent ) {
if( !found ) found = 1;
iRCCE_mail_fetch(i);
// reset senders flag
RC_cache_invalidate();
*(iRCCE_mailbox_recv[i]) = dummy_header;
}
}
}
/* enable interrupts */
irq_nested_enable(flags);
return (found == 1)? iRCCE_SUCCESS : iRCCE_MAILBOX_EMPTY;
}
// verify sender's ID
if( (sender < 0) || (sender > RCCE_NP) || (sender == RCCE_IAM) ) {
if(BUILTIN_EXPECT((sender < 0) || (sender > RCCE_NP) || (sender == RCCE_IAM), 0)) {
return iRCCE_ERROR_SOURCE;
}
@ -238,8 +222,7 @@ int iRCCE_mail_check(int sender) {
irq_nested_enable(flags);
return iRCCE_SUCCESS;
}
else {
} else {
return iRCCE_MAILBOX_EMPTY;
}
@ -256,25 +239,28 @@ int iRCCE_mail_check(int sender) {
*
* The function checks if the receive queue with highest priority (priority 0)
* contains any mail headers. In this case we pop the first element of that list
* in a FIFO maner. Otherwise iRCCE_mailbox_check() has to be called. Afterwards
* the first element of a non-empty receive queue with highest priority is
* returned.
* in a FIFO maner. Afterwards the first element of a non-empty receive queue
* with highest priority is returned.
*/
//------------------------------------------------------------------------------
int iRCCE_mail_recv(
iRCCE_MAIL_HEADER** header // pointer to incoming header
) { // (memory allocated by iRCCE)
int i;
int i, found = 0;
uint32_t flags;
iRCCE_MAIL_HEADER* help_header;
// if no mail queued pointer must be ZERO
*header = NULL;
/* disable interrupts */
flags = irq_nested_disable();
// check priority queues
for( i=0; i<iRCCE_PRIOS; ++i ) {
if ( iRCCE_mailbox_recv_queue[i].first ) {
/* disable interrupts */
flags = irq_nested_disable();
if ( iRCCE_mailbox_recv_queue[i].first ) {
help_header = iRCCE_mailbox_recv_queue[i].first;
iRCCE_mailbox_recv_queue[i].first =
@ -283,23 +269,21 @@ int iRCCE_mail_recv(
if( iRCCE_mailbox_recv_queue[i].first == NULL ) {
iRCCE_mailbox_recv_queue[i].last = NULL;
}
/* prepare return value */
help_header->next = NULL;
*header = help_header;
/* enable interrupts */
irq_nested_enable(flags);
return iRCCE_SUCCESS;
found = 1;
break;
}
}
// no mail queued
*header = NULL;
return iRCCE_MAILBOX_EMPTY;
/* enable interrupts */
irq_nested_enable(flags);
return (found == 1)? iRCCE_SUCCESS : iRCCE_MAILBOX_EMPTY;
}
@ -385,27 +369,35 @@ int iRCCE_mail_send(
uint32_t flags;
// verify sender's ID
if( (dest < 0) || (dest > RCCE_NP) || (dest == RCCE_IAM) ) {
if(BUILTIN_EXPECT((dest < 0) || (dest > RCCE_NP) || (dest == RCCE_IAM),0)) {
return iRCCE_ERROR_TARGET;
}
// if dest mailbox is full, check for incoming mail
RC_cache_invalidate();
while( iRCCE_mailbox_send[dest]->sent ) {
iRCCE_mailbox_check();
// iRCCE_mail_check(iRCCE_MAILBOX_ALL);
RC_cache_invalidate();
NOP8;
NOP8;
NOP8;
}
/* disable interrupts */
flags = irq_nested_disable();
// check if mailbox is closed
RCCE_acquire_lock( dest );
RC_cache_invalidate();
if( iRCCE_mailbox_send[dest]->closed ) {
RCCE_release_lock( dest );
/* enable interrupts */
irq_nested_enable(flags);
return iRCCE_MAILBOX_CLOSED;
}
/* disable interrupts */
// flags = irq_nested_disable();
// prepare header
iRCCE_MAIL_HEADER header = { RCCE_IAM, size, tag, NULL, prio,
RCCE_FLAG_UNSET, RCCE_FLAG_UNSET,
@ -427,11 +419,11 @@ int iRCCE_mail_send(
*(int *)RCCE_fool_write_combine_buffer = 1;
RC_cache_invalidate();
/* enable interrupts */
// irq_nested_enable(flags);
RCCE_release_lock( dest );
/* enable interrupts */
irq_nested_enable(flags);
return iRCCE_SUCCESS;
}
@ -476,7 +468,7 @@ int iRCCE_last_mail_recv(void) {
//------------------------------------------------------------------------------
int iRCCE_mailbox_wait(void) {
while( iRCCE_last_mail_recv() == iRCCE_LAST_MAILS_NOT_RECV ) {
iRCCE_mailbox_check();
iRCCE_mail_check(iRCCE_MAILBOX_ALL);
}
return iRCCE_SUCCESS;
@ -533,7 +525,7 @@ int iRCCE_mailbox_flush(void) {
* last-mail.
*
* This function closes a mailbox of the given rank. If the check flag is set
* an iRCCE_mailbox_check()-call is performed. The close procedure has to be
* an iRCCE_mail_check()-call is performed. The close procedure has to be
* locked to be sure that no UE sends any mail while closing the mailbox.
*/
//------------------------------------------------------------------------------

View file

@ -26,6 +26,7 @@
#include <asm/SCC_API.h>
#include <asm/icc.h>
#include <asm/svm.h>
#include <asm/limits.h>
#define IRQ_STATUS 0xD000
#define IRQ_MASK 0xD200
@ -35,7 +36,6 @@
#include <net/rckemac.h>
bootinfo_t* bootinfo = (bootinfo_t*) SCC_BOOTINFO;
/* PSE bit for Pentium+ equals MPE (message buffer enable) flag in RCK! So, use it to create _PAGE_MPB symbol... */
@ -100,6 +100,8 @@ static inline void icc_mail_check_tag(iRCCE_MAIL_HEADER* mail) {
case SVM_REQUEST:
svm_emit_page(((size_t*) mail->payload)[1], ((size_t*) mail->payload)[0]);
break;
case SVM_RESP:
break;
case NOISE:
// kprintf( "XXX " );
default:
@ -162,9 +164,6 @@ static void icc_handler(struct state *s)
while( iRCCE_mail_recv(&header) == iRCCE_SUCCESS ) {
icc_mail_check_tag(header);
iRCCE_mail_release(&header);
NOP8;
NOP8;
NOP8;
}
}
@ -299,7 +298,7 @@ int icc_halt(void)
#define ROUNDS 1000
#define CORE_A 0 // sender
#define CORE_B 1 // receiver
#define CORE_B 25 // receiver
int icc_send_gic_irq(int core_num) {
volatile uint32_t* irq_request = (volatile uint32_t*)(FPGA_BASE+IRQ_REQUEST+RC_MY_COREID*8);
@ -347,7 +346,7 @@ int icc_mail_ping(void)
/* wait for response */
do {
res = iRCCE_mail_check(CORE_B);
res = iRCCE_mail_check(iRCCE_MAILBOX_ALL);
} while( res != iRCCE_SUCCESS );
/* release mail */
@ -358,7 +357,7 @@ int icc_mail_ping(void)
else {
/* wait for request */
do {
res = iRCCE_mail_check(CORE_A);
res = iRCCE_mail_check(iRCCE_MAILBOX_ALL);
} while( res != iRCCE_SUCCESS );
/* check mail */
@ -440,62 +439,172 @@ int icc_mail_ping_irq(void)
return 0;
}
#define _iRQ_NOISE_ 0
int icc_mail_ping_jitter(void)
{
kprintf( "Hello from gitter_test ... \n" );
/* return if not core A */
if( RCCE_IAM != CORE_A ) return 0;
int icc_mail_noise(void) {
int i, j, res;
int num_ranks = RCCE_num_ues();
iRCCE_MAIL_HEADER* recv_mail = NULL;
uint32_t flags;
uint64_t timer = 0;
uint64_t max = 0;
uint64_t min = ULONG_MAX;
uint64_t sum = 0;
// leave function if not participating
if( !((RCCE_IAM == 4) || (RCCE_IAM == 2) || (RCCE_IAM == CORE_B)) ) {
kprintf( "mail_noise: leaving" );
return -1;
}
int i;
int res;
iRCCE_MAIL_HEADER* recv_header = NULL;
kprintf( "my_rank = %d\n", RCCE_IAM );
kprintf( "rem_rank = %d\n", CORE_B );
kprintf( "rounds = %d\n", ROUNDS );
kprintf( "Hello from icc_mail_noise: my_ue = %d\n", RCCE_IAM );
kprintf( "num_ues = %d\n", num_ranks );
for( i=0; i<10000; ++i ) {
if( !(i%1000) ) kprintf( "%d ", i );
/* send a mail to each UE */
for( j=0; j<num_ranks; ++j ) {
if( !((j == 4) || (j == 2)/* || (j == CORE_B) */) )
continue;
/* send noise mail */
iRCCE_mail_send(0, NOISE, 1, NULL, j);
#ifdef _IRQ_NOISE_
kprintf( "sending irq ... " );
icc_send_gic_irq(j);
#endif
iRCCE_mail_recv(&recv_mail);
icc_mail_check_tag(recv_mail);
if( recv_mail ) iRCCE_mail_release(&recv_mail);
// disable interrupts
flags = irq_nested_disable();
for( i=0; i<ROUNDS+1; ++i ) {
/* start timer */
timer = rdtsc();
/* send ping request */
iRCCE_mail_send(0, PING_REQ, 0, NULL, CORE_B);
/* send interrupt */
icc_send_gic_irq(CORE_B);
/* wait for response */
do {
res = iRCCE_mail_check(CORE_B);
} while( res != iRCCE_SUCCESS );
iRCCE_mail_recv(&recv_header);
iRCCE_mail_release(&recv_header);
/* stop timer and update eval values */
timer = rdtsc() - timer;
if( i > 0 ) {
max = ( max < timer )? timer : max;
min = ( min > timer )? timer : min;
sum += timer;
}
}
kprintf( "XXX XXX XXX" );
do {
iRCCE_mail_check(iRCCE_MAILBOX_ALL);
res = iRCCE_mail_recv(&recv_mail);
icc_mail_check_tag(recv_mail);
if( recv_mail ) iRCCE_mail_release(&recv_mail);
} while( res == iRCCE_SUCCESS );
kprintf( "Average was: %d nsec\n", sum*1000/(2*ROUNDS*533) );
kprintf( "Maximum was: %d nsec\n", max*1000/(2*533) );
kprintf( "Minimum was: %d nsec\n", min*1000/(2*533) );
kprintf( "Jitter was: %d nsec\n", (max-min)*1000/(2*533) );
irq_nested_enable(flags);
return 0;
}
#undef _IRQ_NOISE_
#define NOISE_PRIO 1
int icc_mail_noise(void) {
int i, j, res;
int num_ranks = RCCE_num_ues();
int count = 0;
iRCCE_MAIL_HEADER* recv_mail = NULL;
/* timer vars */
uint64_t timer;
uint64_t tmr;
uint64_t tmr_send = 0;
uint64_t tmr_recv = 0;
uint64_t tmr_release = 0;
uint64_t tmr_chck = 0;
kprintf( "my_ue = %d\n", RCCE_IAM );
// leave function if not participating
// if( (my_ue == CORE_A) || (my_ue == CORE_B) ) {
// kprintf( "mail_noise: leaving" );
// return -1;
// }
kprintf( "Hello from icc_mail_noise: my_ue = %d\n", RCCE_IAM );
kprintf( "num_ues = %d\n", num_ranks );
timer = rdtsc();
for( i=0; i<20000; ++i ) {
if( !(i%1000) ) kprintf( "%d ", i );
tmr = rdtsc();
iRCCE_mail_check(iRCCE_MAILBOX_ALL);
tmr = rdtsc() - tmr;
tmr_chck += tmr;
/* send a mail to each UE */
for( j=0; j<num_ranks; ++j ) {
// if( (j == CORE_A) /* || (j == CORE_B)*/ ) continue;
/* send noise mail */
tmr = rdtsc();
iRCCE_mail_send(0, NOISE, NOISE_PRIO, NULL, j);
tmr = rdtsc() - tmr;
tmr_send += tmr;
tmr = rdtsc();
res = iRCCE_mail_recv(&recv_mail);
tmr = rdtsc() - tmr;
tmr_recv += tmr;
if( res == iRCCE_SUCCESS ) {
icc_mail_check_tag(recv_mail);
tmr = rdtsc();
iRCCE_mail_release(&recv_mail);
tmr = rdtsc() - tmr;
tmr_release += tmr;
count++;
}
}
}
do {
tmr = rdtsc();
iRCCE_mail_check(iRCCE_MAILBOX_ALL);
tmr = rdtsc() - tmr;
tmr_chck += tmr;
tmr = rdtsc();
res = iRCCE_mail_recv(&recv_mail);
tmr = rdtsc() - tmr;
tmr_recv += tmr;
if( res == iRCCE_SUCCESS ) {
icc_mail_check_tag(recv_mail);
tmr = rdtsc();
iRCCE_mail_release(&recv_mail);
tmr = rdtsc() - tmr;
tmr_release += tmr;
count++;
}
} while( res == iRCCE_SUCCESS );
timer = rdtsc() - timer;
kprintf( "Count = %d\n", count );
kprintf( "Time: %d ms\n", timer/(1000*get_cpu_frequency()) );
kprintf( "Time in send: %d ms\n", tmr_send/(1000*get_cpu_frequency()) );
kprintf( "Time in recv: %d ms\n", tmr_recv/(1000*get_cpu_frequency()) );
kprintf( "Time in chck: %d ms\n", tmr_chck/(1000*get_cpu_frequency()) );
kprintf( "Time in release: %d ms\n", tmr_release/(1000*get_cpu_frequency()) );
kprintf( "XXX XXX XXX" );
return 0;
}
/*
* Routine to check mailboxes. If irq = 1 is passed only those boxes are checked that
* refere to the cores with set bit in status register.
*
* Routine to check mailboxes.
*/
void icc_mail_check(void)
{
iRCCE_MAIL_HEADER* header = NULL;
iRCCE_MAIL_HEADER* header = NULL;
uint32_t flags;
/* disable interrupts */
@ -507,13 +616,45 @@ void icc_mail_check(void)
while( iRCCE_mail_recv(&header) == iRCCE_SUCCESS ) {
icc_mail_check_tag(header);
iRCCE_mail_release( &header );
NOP8;
NOP8;
NOP8;
}
/* enable interrupts */
irq_nested_enable(flags);
}
uint64_t check_ticks = 0;
uint64_t recv_ticks = 0;
void icc_wait(int tag)
{
iRCCE_MAIL_HEADER* header = NULL;
uint32_t flags;
uint64_t start;
/* disable interrupts */
flags = irq_nested_disable();
retry:
start = rdtsc();
iRCCE_mail_check(iRCCE_MAILBOX_ALL);
check_ticks += rdtsc() - start;
start = rdtsc();
/* empty mail queue */
while(iRCCE_mail_recv(&header) == iRCCE_SUCCESS ) {
icc_mail_check_tag(header);
if (header->tag == tag) {
iRCCE_mail_release( &header );
goto out;
} else iRCCE_mail_release( &header );
}
recv_ticks += rdtsc() - start;
goto retry;
out:
recv_ticks += rdtsc() - start;
/* enable interrupts */
irq_nested_enable(flags);
}
#endif

BIN
documentation/img/reset.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

BIN
documentation/img/uart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

1
documentation/text/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.h

View file

@ -1,12 +1,141 @@
/**
* @file manual.dox
* @page manual Manual Contents
* @file compilation.dox
* @page compilation Compiling and Running MetalSVM
*
* @section Readme
* @section toc Table of Contents
* - @ref checkout
* - @ref compiling
* - @ref runqemu
* - @ref runscc
* - @ref runsccmc
* - @ref msvmuart
*
* This document contains some explanations about stuff.
* @section checkout Checking out MetalSVM online
*
* The MetalSVM project is hosted in a Git repository. To check it out, just type:
*
* @subsection Compiling
* \verbatim$ git clone gitosis@git.lfbs.rwth-aachen.de:metalsvm.git \endverbatim
*
* If you are asked for a password you are not authorized to clone the repository. In this case you will need to get your public SSH key authorized.
*
* @section compiling Compiling MetalSVM
*
* To compile MetalSVM, you will need a proper Makefile and configuration. To use the example files, just do the following:
*
* \verbatim
$ cd MetalSVM
$ cp Makefile.example Makefile
$ cp include/metalsvm/config.h.example include/metalsvm/config.h \endverbatim
*
* The standard configuration works on usual PC hardware configurations as well as in emulators.
*
* Compiler settings can be edited in the Makefile, while the kernel configuration can be found in the just copied configuration file.
*
* @section runqemu Running MetalSVM in Qemu
*
* There is a Make-target for running MetalSVM in Qemu:
* \verbatim$ make qemu \endverbatim
*
* The emulator is then started with the following parameters:
* \verbatim$ qemu -monitor stdio -smp 2 -net nic,model=rtl8139 -net user,hostfwd=tcp::12345-:7 -net dump -kernel metalsvm.elf -initrd tools/initrd.img \endverbatim
*
* Please note that qemu versions 0.13 and 0.14 have a bug which keeps MetalSVM from booting properly. Used qemu-0.12.5 instead.
*
* @section runscc Running MetalSVM on the Intel SCC
*
* -# Intel recommends to use their cross-compiler for generating code which is guaranteed to be SCC-compatible. Just set the environment variables with the following command:
* \verbatim$ . /opt/compilerSetupFiles/crosscompile.sh \endverbatim
* -# The Makefile needs to be adapted to actually use the cross compiler:
* \verbatim
CC_FOR_TARGET=i386-unknown-linux-gnu-gcc
CXX_FOR_TARGET=i386-unknown-linux-gnu-g++
GCC_FOR_TARGET=i386-unknown-linux-gnu-gcc
AR_FOR_TARGET=i386-unknown-linux-gnu-ar
AS_FOR_TARGET=i386-unknown-linux-gnu-as
LD_FOR_TARGET=i386-unknown-linux-gnu-ld
NM_FOR_TARGET=i386-unknown-linux-gnu-nm
OBJDUMP_FOR_TARGET=i386-unknown-linux-gnu-objdump
OBJCOPY_FOR_TARGET=i386-unknown-linux-gnu-objcopy
RANLIB_FOR_TARGET=i386-unknown-linux-gnu-ranlib
STRIP_FOR_TARGET=i386-unknown-linux-gnu-strip
READELF_FOR_TARGET=i386-unknown-linux-gnu-readelf \endverbatim
* -# Another important change in the Makefile is disabling the "-fno-stack-protector" option. It occurs several times.
* -# The SCC requires a special configuration for the MetalSVM kernel:
* \verbatim
//#define CONFIG_PCI
//#define CONFIG_VGA
//#define CONFIG_UART
//#define CONFIG_KEYBOARD
//#define CONFIG_MULTIBOOT
#define CONFIG_ROCKCREEK
// RCCE specific flags
#define SCC
#define COPPERRIDGE
#define MS_BAREMETAL
//#define GORY
#define SHMADD
#define SHMDBG
//#define SHMADD_CACHEABLE \endverbatim
* -# There is only one core per tile, so it is adequate to reduce overhead by disabling SMP in MetalSVM:
* \verbatim#define MAX_CORES 1 \endverbatim
* -# Cache-line size is 32 byte:
* \verbatim#define CACHE_LINE 32 \endverbatim
* -# MetalSVM can now be built using \c make.
* -# Build the SCC tools:
* \verbatim
$ cd tools
$ make SCC \endverbatim
* -# The \c obj directory was just created, containing the MetalSVM kernel image. It can be loaded into the SCC's memory using \verbatim$ sccBoot -g obj \endverbatim
* -# The default configuration lets MetalSVM run only on core 0. Its reset pin needs to be released:
* \verbatim$ sccReset -r 0x00 \endverbatim
* -# Although the display driver was deactivated, MetalSVM's kprintf-output is written into the memory, where you can read it with the following command:
* \verbatim$ sccDump -d 0x00 0x100000 0x10000 | less \endverbatim
*
*
* @section runsccmc Running MetalSVM on multiple SCC cores
*
* -# Build the kernel like described above (items 1-7) and change to the \c tools directory.
* -# The \c scc_bootinfo.asm file contains boot-information relevant to the SCC-cores.
* It is generated automatically by the \c bootinfo.sh script.\n
* \n
* The following example generates the \c scc_bootinfo.asm file needed for use of the cores 0 and 1:
* \verbatim$ ./bootinfo.sh 0x01000000 initrd.img 2 533 0 1 > scc_bootinfo.asm \endverbatim
* Parameters describe the following:
* -# First parameter describes the address at which the initrd shall be located at later
* -# Second is path to the initrd image file
* -# The other parameters are analogous to RCCE-App-parameters. This example starts MetalSVM on cores 0 and 1, clocked with 533MHz.
* -# Now the file \c metalsvm.mt has to be edited. It defines the layout of the memory image (Where the kernels will be located in the memory later). For the example from above it looks like the following:
* \verbatim# pid mch-route mch-dest-id mch-offset-base testcase
0x00 0x00 6 0x00 metalsvm.obj
0x01 0x00 6 0x01 metalsvm.obj \endverbatim
* This locates two instances of MetalSVM on core 0 and 1, supplied with memory from memory controller 0. See \c sccMerge \c -h for more information.
* -# The final image must be generated then with \code$ make SCC\endcode
* -# A directory \c obj was created, containing the final MetalSVM Image. This image can now be loaded with the following command: \code$ sccBoot -g obj\endcode
* -# Everything has been placed in the cores' memory. To release the reset pins of the corresponding cores, type \code$ sccReset -r 0x00 0x01\endcode
*
* @section msvmuart Enabling UART support
*
* MetalSVM is able to reroute terminal output to port \c 0x2F8. This way it can be displayed in \c sccGui. Too much output stresses the network load, therefore it should be used for debugging purposes only.
*
* How to enable:
* -# Enable UART-support in the kernel's config file \c include/metalsvm/config.h:
* \code#define CONFIG_UART\endcode
* -# Rebuild the kernel. Do not launch it with \c sccBoot - In the following \c sccGui will be used.
* -# Launch \c sccGui.
* -# Enable UART in the gui by klicking <tt>Enable software RAM and UART</tt> in the Menu <tt>Settings/Debug Settings</tt>.
* -# Issue a software interrupt by clicking on the wiper symbol.
* -# Choose the memory image called \c mch_0_0.32.obj from the \c obj folder with <tt>Preload object file</tt>.
* -# Initialize the LUT with <tt>Preload LUT file</tt>. It is called \c lut_init.dat and is located in the same directory.
* -# Both L2 cache and MPB can be reset now, if needed.
* -# Activate the corresponding cores with <tt>Change selected reset(s)</tt>. This opens the following window:
* @image html reset.png
* -# A box being checked means that the reset pin is pulled and the core is \e inactive. The example from the picture will boot MetalSVM only on cores 0 and 1.
*
* After following these steps successfully, a similar image to the following should appear on the gui:
* @image html sccGui.png
*
* Another window will be opened automatically as soon as UART output arrives in the gui. This will be similar to the following:
* @image html uart.png
*
*
*/

View file

@ -0,0 +1,18 @@
/**
* @file config.dox
* @page config The MetalSVM feature configuration file
*
* @section conf MetalSVM's configuration file
*
* MetalSVM's configuration parameters and some features can be configured/activated in the central configuration file located at \c include/metalsvm/config.h.
*
* The \c config.h is a usual C-header file and the configuration items are usual C preprocessor-definitions like the following:
* \code
#define CONFIGURATION_PARAMETER 123value /* A parameter with a value */
#define FEATURE_A /* An activated feature */
//#define FEATURE_B /* A deactivated feature */\endcode
*
* Just like the example suggests, features are deactivated by commenting them out.
*
*
*/

View file

@ -0,0 +1,112 @@
/**
* @file documenting.dox
* @page documenting Documenting MetalSVM with Doxygen
*
* The doxygen project has a nice manual at http://www.stack.nl/~dimitri/doxygen/manual.html \n
* All content on this page is extracted from there.
*
* Please check if the \c doxygen command throws errors on your documented code.
*
* @section inline Documenting code inline
*
* To document your code correctly, you will have to follow some (simple) rules:
*
* Place a comment block like this at the beginning of your source code files you intend to document:
*
* @verbatim
/**
* @author John Doe
* @file path/to/your/file.h
* @brief A brief explanation about what this code does or is supposed to do.
*/@endverbatim
*
* Functions/procedures are commented in the header file just above the
* function/procedure definition:
*
* @verbatim
/** @brief Blocking wait for semaphore [short explanation]
*
* [space for more detailed explanations]
*
* [describing parameters]
* @param s Address of the according sem_t structure
* @param ms Timeout in milliseconds
*
* [describing possible return values in a list]
* @return
* - 0 on success
* - -EINVAL on invalid argument
* - -ETIME on timer expired
*/
inline static int sem_wait(sem_t* s, uint32_t ms); @endverbatim
*
* Documenting structures and their members looks like the following:
* @verbatim
/** @brief The task_t structure */
typedef struct task {
/// Task id = position in the task table
tid_t id;
/// Task status (INVALID, READY, RUNNING, ...)
uint32_t status;
... @endverbatim
*
* @section formatting Formatting text
*
* Although you could use HTML brackets to format your text,
* Doxygen provides special commands. Please use those, since it is possible
* that someone may want to generate CHM, Latex or other formatted output
* from this documentation.
*
* To \e emphasize, \b highlight or \c typewrite text, use the following commands:
* \verbatim To \e emphasize, \b highlight or \c typewrite text... \endverbatim
*
* \verbatim
Preserving the format
of text like
this can be done with \verbatim end \ endverbatim \endverbatim
*
* Code will be color-highlighted with \\code and \\endcode:
* \code
int i;
for (i=0; i < 123; i++)
printf("%d\n", i);
\endcode
*
* It is also easily possible to make listings:
* - item a
* - item b
* - item c
*
* And also enumerated listings:
* -# item a
* -# item b
* -# item c
*
* \verbatim
It is also easily possible to make listings:
- item a
- item b
- item c
And also enumerated listings:
-# item a
-# item b
-# item c \endverbatim
*
* @section docs Writing documents like this one
*
* To write a stand-alone manual like this one, just create
* a file \c your_manual.dox in \c $MSVM/documentation/text/.
*
* This file's content should look like this:
*
* \verbatim
/**
* @file your_manual.dox
* @page your_manual This is your manual's title. It will be displayed in the "Manuals" section.
*
* @section your_section This starts a section with a title
*
* content, content, content!
*/ \endverbatim
*/

View file

@ -0,0 +1,7 @@
/**
* @file kernelspace.dox
* @page kernelspace Development in kernel space
*
* @section kernelthreads Starting kernel threads
*
*/

View file

@ -0,0 +1,7 @@
/**
* @file userspace.dox
* @page userspace Development in user space
*
* @section ownapps Installing and launching your own applications
*
*/

View file

@ -0,0 +1,186 @@
<doxygenlayout version="1.0">
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="Manuals"
intro="This page contains manual articles to help using MetalSVM:"/>
<tab type="modules" visible="yes" title="" intro=""/>
<tab type="namespaces" visible="yes" title="">
<tab type="namespaces" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="yes" title="">
<tab type="classes" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="yes" title="">
<tab type="files" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="dirs" visible="yes" title="" intro=""/>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<allmemberslink visible="yes"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<typedefs title=""/>
<enums title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<dirs visible="yes" title=""/>
<nestedgroups visible="yes" title=""/>
<files visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

View file

@ -849,6 +849,6 @@ dl.bug
.textblock
{
width: 950px;
width: 800px;
textalign: justify;
}

10
fs/fs.c
View file

@ -40,10 +40,8 @@ ssize_t read_fs(fildes_t* file, uint8_t* buffer, size_t size)
if (node->read != 0)
ret = node->read(file, buffer, size);
spinlock_unlock(&node->lock);
} else {
if (node->read != 0)
} else if (node->read != 0)
ret = node->read(file, buffer, size);
}
return ret;
}
@ -62,10 +60,8 @@ ssize_t write_fs(fildes_t* file, uint8_t* buffer, size_t size)
if (node->write != 0)
ret = node->write(file, buffer, size);
spinlock_unlock(&node->lock);
} else {
if (node->write != 0)
} else if (node->write != 0)
ret = node->write(file, buffer, size);
}
return ret;
}
@ -83,7 +79,7 @@ int open_fs(fildes_t* file, const char* name)
if (name[0] == '/')
file_node = fs_root;
while((name[j] != '\0') && (file_node != NULL)) {
while((name[j] != '\0') || ((file_node != NULL) && (file_node->type == FS_DIRECTORY))) {
i = 0;
while((name[j] != '/') && (name[j] != '\0')) {
fname[i] = name[j];

View file

@ -63,7 +63,7 @@ extern "C" {
#define COPPERRIDGE
#define MS_BAREMETAL
//#define GORY
#define SHMADD
//#define SHMADD
#define SHMDBG
//#define SHMADD_CACHEABLE
#define SCC_BOOTINFO 0x80000

View file

@ -65,7 +65,7 @@ typedef int (*entry_point_t)(void*);
typedef int (STDCALL *internal_entry_point_t)(void*);
struct page_dir;
/* @brief The task_t structure */
/** @brief The task_t structure */
typedef struct task {
/// Task id = position in the task table
tid_t id;