mirror of https://github.com/l4ka/hazelnut.git
474 lines
11 KiB
C
474 lines
11 KiB
C
/*********************************************************************
|
|
*
|
|
* Copyright (C) 2001-2002, Karlsruhe University
|
|
*
|
|
* File path: sigma0/sigma0.c
|
|
* Description: old sigma0 implementation
|
|
*
|
|
* @LICENSE@
|
|
*
|
|
* $Id: sigma0.c,v 1.23 2002/05/06 13:52:51 ud3 Exp $
|
|
*
|
|
********************************************************************/
|
|
#include <config.h>
|
|
|
|
#if defined(CONFIG_L4_NEWSIGMA0)
|
|
#include "sigma0-new.c"
|
|
#else
|
|
|
|
#include <l4/l4.h>
|
|
#include <l4io.h>
|
|
|
|
#include "kip.h"
|
|
|
|
#if defined(CONFIG_ARCH_X86)
|
|
#define PAGE_BITS 12
|
|
#define SUPERPAGE_BITS 22
|
|
#endif
|
|
#if defined(CONFIG_ARCH_ARM)
|
|
#define PAGE_BITS 12
|
|
#define SUPERPAGE_BITS 20
|
|
#endif
|
|
|
|
#define PAGE_SIZE (1 << PAGE_BITS)
|
|
#define PAGE_MASK (~(PAGE_SIZE-1))
|
|
#define SUPERPAGE_SIZE (1 << SUPERPAGE_BITS)
|
|
#define SUPERPAGE_MASK (~(SUPERPAGE_SIZE-1))
|
|
|
|
|
|
|
|
#if 1
|
|
extern "C" void memset(char* p, char c, int size)
|
|
{
|
|
for (;size--;)
|
|
*(p++)=c;
|
|
}
|
|
#endif
|
|
|
|
|
|
#define iskernelthread(x) (x.raw < myself.raw)
|
|
#define MB64 64L*1024L*1024L
|
|
#define MB128 128L*1024L*1024L
|
|
#define MB256 256L*1024L*1024L
|
|
#define MB512 512L*1024L*1024L
|
|
|
|
#define MAX_MEM MB256
|
|
static unsigned char page_array[MAX_MEM/PAGE_SIZE];
|
|
|
|
|
|
void dump_kip(kernel_info_page_t* kip)
|
|
{
|
|
|
|
#define kipel(x) printf(" kip: %s=\t%x\n", #x, kip->x);
|
|
|
|
printf("%s: kernel_info_page magic is %c%c%c%c\n", __FUNCTION__,
|
|
((char*) kip)[0],
|
|
((char*) kip)[1],
|
|
((char*) kip)[2],
|
|
((char*) kip)[3]);
|
|
|
|
kipel(main_mem_low); kipel(main_mem_high);
|
|
|
|
//enter_kdebug("foo");
|
|
kipel(sigma0_low); kipel(sigma0_high);
|
|
kipel(root_low); kipel(root_high);
|
|
//enter_kdebug("foo");
|
|
kipel(reserved_mem0_low); kipel(reserved_mem0_high);
|
|
kipel(reserved_mem1_low); kipel(reserved_mem1_high);
|
|
//enter_kdebug("foo");
|
|
kipel(dedicated_mem0_low); kipel(dedicated_mem0_high);
|
|
kipel(dedicated_mem1_low); kipel(dedicated_mem1_high);
|
|
//enter_kdebug("foo");
|
|
printf("\nsigma0: Available main memory: %d MB (%d KB)\n",
|
|
(kip->main_mem_high-kip->main_mem_low)/1024/1024,
|
|
(kip->main_mem_high-kip->main_mem_low)/1024);
|
|
//enter_kdebug("foo");
|
|
}
|
|
|
|
|
|
extern "C" void sigma0_main(kernel_info_page_t* kip)
|
|
{
|
|
|
|
l4_threadid_t client;
|
|
int r;
|
|
l4_msgdope_t result;
|
|
dword_t dw0, dw1, dw2;
|
|
dword_t msg;
|
|
|
|
l4_threadid_t myself = l4_myself();
|
|
|
|
printf("%s: kernel_info_page is at %p\n", __FUNCTION__, kip);
|
|
if ((((char*) kip)[0] != 'L') |
|
|
(((char*) kip)[1] != '4') |
|
|
(((char*) kip)[2] != 0xE6) |
|
|
(((char*) kip)[3] != 'K'))
|
|
enter_kdebug("sigma0: invalid KIP!");
|
|
// dump_kip(kip);
|
|
|
|
dword_t free_mem = kip->main_mem_low;
|
|
dword_t kernel_mem = kip->main_mem_high-PAGE_SIZE;
|
|
|
|
#define IDX(x) ((x)-(kip->main_mem_low/PAGE_SIZE))
|
|
|
|
if (sizeof(page_array) < (kip->main_mem_high-kip->main_mem_low)/PAGE_SIZE)
|
|
{
|
|
printf("sigma0: too much memory - %d < %d\n", sizeof(page_array), (kip->main_mem_high-kip->main_mem_low)/PAGE_SIZE);
|
|
enter_kdebug("too much memory");
|
|
};
|
|
|
|
#define PAGE_SHARED 0xFC
|
|
#define PAGE_GONE 0xFD
|
|
#define PAGE_FREE 0xFE
|
|
#define PAGE_RESERVED 0xFF
|
|
#define PAGE_ROOT 0x04
|
|
|
|
/* initialize the page array */
|
|
for (dword_t i = 0; i < sizeof(page_array); i++)
|
|
page_array[i] = PAGE_RESERVED;
|
|
for (dword_t i = kip->main_mem_low/PAGE_SIZE;
|
|
i < kip->main_mem_high/PAGE_SIZE; i++)
|
|
page_array[IDX(i)] = PAGE_FREE;
|
|
|
|
#define exclude(name,attrib) \
|
|
if ( kip->##name##_high ) { \
|
|
if ((kip->##name##_low >= kip->main_mem_low) && \
|
|
(kip->##name##_high <= kip->main_mem_high)) { \
|
|
for ( dword_t i = kip->##name##_low / PAGE_SIZE; \
|
|
i < (kip->##name##_high) / PAGE_SIZE; \
|
|
i++ ) \
|
|
page_array[IDX(i)] = PAGE_##attrib; } \
|
|
else \
|
|
printf("kip->" #name " is wrong\n"); }
|
|
|
|
exclude(dedicated_mem0, SHARED);
|
|
exclude(dedicated_mem1, SHARED);
|
|
exclude(dedicated_mem2, SHARED);
|
|
exclude(dedicated_mem3, SHARED);
|
|
exclude(dedicated_mem4, SHARED);
|
|
|
|
exclude(reserved_mem0, RESERVED);
|
|
exclude(reserved_mem1, RESERVED);
|
|
exclude(root, ROOT);
|
|
exclude(sigma0, RESERVED);
|
|
exclude(sigma1, RESERVED);
|
|
exclude(kdebug, RESERVED);
|
|
|
|
#if defined(CONFIG_ARCH_X86)
|
|
page_array[IDX(0xb8000/PAGE_SIZE)] = PAGE_SHARED;
|
|
page_array[IDX(0x01000/PAGE_SIZE)] = PAGE_RESERVED;
|
|
#endif
|
|
|
|
dword_t one_shot_break = 0;
|
|
|
|
/*
|
|
macros to figure out request type
|
|
assumption: dw0:dw1:dw2 contains the received message
|
|
*/
|
|
|
|
#define GET_ANY_PAGE (dw0 == 0xFFFFFFFC)
|
|
#define GET_KMEM_PAGES ((dw0 == 1) && ((dw1 & 0xFF) == 0))
|
|
#define GET_INFO_PAGE ((dw0 == 1) && ((dw1 & 0xFF) == 1))
|
|
#define GET_THIS_PAGE_SUPER ((dw0 & 1) && (dw1 == (SUPERPAGE_BITS << 2)))
|
|
|
|
#if defined(CONFIG_ARCH_X86)
|
|
#define GET_THIS_PAGE (dw0 < 0x40000000)
|
|
#endif
|
|
#if defined(CONFIG_ARCH_ARM_EP7211)
|
|
#define GET_THIS_PAGE (1)
|
|
#endif
|
|
|
|
while(1)
|
|
{
|
|
//printf("%s: do ipc_wait\n", __FUNCTION__);
|
|
r = l4_ipc_wait(&client, NULL, &dw0, &dw1, &dw2, L4_IPC_NEVER, &result);
|
|
|
|
while (1)
|
|
{
|
|
if (one_shot_break)
|
|
{
|
|
enter_kdebug("one_shot_break");
|
|
one_shot_break = 0;
|
|
}
|
|
|
|
msg = 2; /* usually we map an fpage */
|
|
|
|
|
|
#if 0
|
|
if (GET_ANY_PAGE)
|
|
{
|
|
if (iskernelthread(client))
|
|
{
|
|
/* grant any page */
|
|
printf("sigma0: s0 receives %x from kthread %x -> ",
|
|
dw0, client.raw);
|
|
while (kernel_mem > 0 &&
|
|
page_array[IDX(kernel_mem/PAGE_SIZE)] != PAGE_FREE)
|
|
kernel_mem -= PAGE_SIZE;
|
|
|
|
if (kernel_mem == 0)
|
|
{
|
|
//enter_kdebug("sigma0 out of memory");
|
|
msg = dw0 = dw1 = dw2 = 0;
|
|
}
|
|
else
|
|
{
|
|
page_array[IDX(kernel_mem/PAGE_SIZE)] = PAGE_GONE;
|
|
dw0 = kernel_mem;
|
|
dw1 = dw0 | (PAGE_BITS << 2) | 3;
|
|
dw2 = 0;
|
|
|
|
printf(" grant: %x\n", dw0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
printf("sigma0: s0 receives %x from %p -> map any page",
|
|
dw0, client);
|
|
#endif
|
|
|
|
while (free_mem < MAX_MEM && page_array[IDX(free_mem/PAGE_SIZE)] != PAGE_FREE)
|
|
free_mem += PAGE_SIZE;
|
|
|
|
if (free_mem >= MAX_MEM)
|
|
{
|
|
//enter_kdebug("sigma0 out of memory");
|
|
msg = dw0 = dw1 = dw2 = 0;
|
|
}
|
|
else
|
|
{
|
|
#if defined(CONFIG_VERSION_X0)
|
|
page_array[IDX(free_mem/PAGE_SIZE)] = client.id.task;
|
|
#elif defined(CONFIG_VERSION_X1)
|
|
page_array[IDX(free_mem/PAGE_SIZE)] = PAGE_GONE;
|
|
#endif
|
|
dw0 = free_mem;
|
|
dw1 = dw0 | (PAGE_BITS << 2) | 2;
|
|
dw2 = 0;
|
|
|
|
// printf(" map: %x\n", dw0);
|
|
|
|
}
|
|
}
|
|
goto done;
|
|
}
|
|
|
|
if (GET_THIS_PAGE)
|
|
|
|
msg = 0;
|
|
printf("ill sigma0 request %x:%x:%x from %x",
|
|
dw0, dw1, dw2, client.raw);
|
|
enter_kdebug("ill_s0_request");
|
|
|
|
|
|
|
|
#else
|
|
if (iskernelthread(client))
|
|
{
|
|
switch (dw0)
|
|
{
|
|
case 0xFFFFFFFC:
|
|
case 0xFFFFFFFE: /* Jochen */
|
|
printf("sigma0: s0 receives %x from a kernel thread -> grant any page\n",
|
|
dw0);
|
|
/* grant any page */
|
|
while (kernel_mem > 0 && page_array[IDX(kernel_mem/PAGE_SIZE)] != PAGE_FREE)
|
|
kernel_mem -= PAGE_SIZE;
|
|
|
|
if (kernel_mem == 0)
|
|
{
|
|
//enter_kdebug("sigma0 out of memory");
|
|
msg = dw0 = dw1 = dw2 = 0;
|
|
}
|
|
else
|
|
{
|
|
page_array[IDX(kernel_mem/PAGE_SIZE)] = PAGE_GONE;
|
|
dw0 = kernel_mem;
|
|
dw1 = dw0 | (PAGE_BITS << 2) | 3;
|
|
dw2 = 0;
|
|
|
|
printf(" grant: %x:%x:%x-%x\n", dw0, dw1, dw2, msg);
|
|
}
|
|
break;
|
|
case 0x00000001:
|
|
printf("sigma0: %x for number of recommended pages\n",
|
|
client.raw);
|
|
if ((dw1 & 0xFF) == 0)
|
|
{
|
|
/* reply number of pages recommended for kernel use */
|
|
msg = 0; dw0 = 0x100;
|
|
}
|
|
else
|
|
msg = dw0 = dw1 = dw2 = 0;
|
|
break;
|
|
default:
|
|
printf("sigma0: unknown request %x:%x:%x from %x\n",
|
|
dw0, dw1, dw2, client.raw);
|
|
msg = dw0 = dw1 = dw2 = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(dw0)
|
|
{
|
|
case 0xFFFFFFFC:
|
|
#if 0
|
|
printf("sigma0: s0 receives %x from %p -> map any page",
|
|
dw0, client);
|
|
#endif
|
|
|
|
while (free_mem < MAX_MEM && page_array[IDX(free_mem/PAGE_SIZE)] != PAGE_FREE)
|
|
free_mem += PAGE_SIZE;
|
|
|
|
if (free_mem >= MAX_MEM)
|
|
{
|
|
//enter_kdebug("sigma0 out of memory");
|
|
msg = dw0 = dw1 = dw2 = 0;
|
|
}
|
|
else
|
|
{
|
|
#if defined(CONFIG_VERSION_X0)
|
|
page_array[IDX(free_mem/PAGE_SIZE)] = client.id.task;
|
|
#elif defined(CONFIG_VERSION_X1)
|
|
page_array[IDX(free_mem/PAGE_SIZE)] = PAGE_GONE;
|
|
#endif
|
|
dw0 = free_mem;
|
|
dw1 = dw0 | (PAGE_BITS << 2) | 2;
|
|
dw2 = 0;
|
|
|
|
// printf(" map: %x\n", dw0);
|
|
}
|
|
break;
|
|
|
|
case 0x00000001:
|
|
if ((dw1 & 0xFF) == 1)
|
|
{
|
|
printf("sigma0: %x requests kernel-info page\n",
|
|
client.raw);
|
|
dw0 = 0;
|
|
dw1 = (((dword_t)kip) & PAGE_MASK) | (PAGE_BITS << 2);
|
|
dw2 = 0;
|
|
}
|
|
else
|
|
msg = dw0 = dw1 = dw2 = 0;
|
|
break;
|
|
|
|
#if defined(CONFIG_ARCH_X86)
|
|
case 0x00000000:
|
|
case 0x00000002 ... 0x40000000:
|
|
#elif defined(CONFIG_ARCH_ARM_EP7211) || defined(CONFIG_ARCH_ARM_BRUTUS)
|
|
case 0xC0000000 ... 0xC0800000:
|
|
#endif
|
|
// printf("sigma0: s0 receives %x,%x from %x\n", dw0, dw1, client.raw);
|
|
if ( (dw0 & 1) && (dw1 & 0xFF) == (SUPERPAGE_BITS << 2) )
|
|
{
|
|
/* map superpage writeable
|
|
and uncacheable !!! */
|
|
|
|
dword_t adr = dw0 & SUPERPAGE_MASK;
|
|
dword_t i;
|
|
for (i = 0; i < SUPERPAGE_SIZE/PAGE_SIZE; i++)
|
|
if (page_array[IDX(adr/PAGE_SIZE + i)] != PAGE_FREE)
|
|
{
|
|
msg = 0;
|
|
break;
|
|
}
|
|
|
|
if (msg)
|
|
{
|
|
for (i = 0; i < 1024; i++)
|
|
#if defined(CONFIG_VERSION_X0)
|
|
page_array[IDX(adr/PAGE_SIZE + i)] = client.id.task;
|
|
#elif defined(CONFIG_VERSION_X1)
|
|
page_array[IDX(adr/PAGE_SIZE + i)] = PAGE_GONE;
|
|
#endif
|
|
|
|
dw0 = adr;
|
|
dw1 = dw0 | (SUPERPAGE_BITS << 2) | 2;
|
|
dw2 = 0;
|
|
printf("sigma0: map 4M page at %x to %x\n", adr, client.raw);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (page_array[IDX(dw0/PAGE_SIZE)] != PAGE_FREE &&
|
|
page_array[IDX(dw0/PAGE_SIZE)] != PAGE_SHARED
|
|
#if defined(CONFIG_VERSION_X0)
|
|
&& page_array[IDX(dw0/PAGE_SIZE)] != client.id.task
|
|
#endif
|
|
)
|
|
{
|
|
#if 1
|
|
printf("sigma0: page %x requested twice, old=%x, new=%x\n", dw0, page_array[IDX(dw0/PAGE_SIZE)], client.id.task);
|
|
// enter_kdebug("page requested twice");
|
|
#endif
|
|
dw0 = dw1 = dw2 = msg = 0;
|
|
}
|
|
else
|
|
{
|
|
/* mark only free pages - ignore the shared!!! */
|
|
if (page_array[IDX(dw0/PAGE_SIZE)] == PAGE_FREE)
|
|
#if defined(CONFIG_VERSION_X0)
|
|
page_array[IDX(dw0/PAGE_SIZE)] = client.id.task;
|
|
#elif defined(CONFIG_VERSION_X1)
|
|
page_array[IDX(dw0/PAGE_SIZE)] = PAGE_GONE;
|
|
#endif
|
|
|
|
/* map 4k page, writeable */
|
|
dw0 &= PAGE_MASK;
|
|
dw1 = dw0 | (PAGE_BITS << 2) | 2;
|
|
dw2 = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
#if defined(CONFIG_ARCH_X86)
|
|
case 0x40000004 ... 0xC0000000:
|
|
#elif defined(CONFIG_ARCH_ARM_EP7211)
|
|
case 0xFFFFFFFF: /* dummy */
|
|
#endif
|
|
{
|
|
printf("sigma0: s0 receives %x from %x\n",
|
|
dw0, client.raw);
|
|
/* map 4M page */
|
|
//enter_kdebug("s0: map superpage");
|
|
|
|
dw0 = (dw0 & SUPERPAGE_MASK) + 0x40000000;
|
|
dw1 = dw0 | (SUPERPAGE_BITS << 2) | 2; /* map superpage writeable
|
|
and uncacheable !!! */
|
|
dw2 = 0;
|
|
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
done:
|
|
#if 1
|
|
//printf("%s: do reply_and_wait\n", __FUNCTION__);
|
|
r = l4_ipc_reply_and_wait(client, (void*) msg,
|
|
dw0, dw1, dw2,
|
|
&client, NULL,
|
|
&dw0, &dw1, &dw2,
|
|
L4_IPC_NEVER, &result);
|
|
//printf("%s: done reply_and_wait\n", __FUNCTION__);
|
|
#endif
|
|
#if 1
|
|
if (L4_IPC_ERROR(result))
|
|
{
|
|
printf("%s: error reply_and_wait (%x)\n", __FUNCTION__, result.raw);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* !CONFIG_L4_NEWSIGMA0 */
|