1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-16 18:03:08 +02:00
This commit is contained in:
Bas Wijnen 2009-06-01 01:12:54 +02:00
parent e7f42c6b7e
commit ef1b9bfe10
12 changed files with 1129 additions and 572 deletions

View File

@ -9,7 +9,7 @@ OBJCOPY = $(CROSS)objcopy
OBJDUMP = $(CROSS)objdump OBJDUMP = $(CROSS)objdump
STRIP = $(CROSS)strip STRIP = $(CROSS)strip
kernel_sources = interrupts.cc panic.cc data.cc test.cc alloc.cc memory.cc arch.cc invoke.cc schedule.cc kernel_sources = interrupts.cc panic.cc data.cc test.cc alloc.cc arch.cc invoke.cc schedule.cc
boot_sources = init.cc boot_sources = init.cc
BUILT_SOURCES = $(kernel_sources) $(boot_sources) BUILT_SOURCES = $(kernel_sources) $(boot_sources)

View File

@ -20,6 +20,23 @@ void Memory::unuse ():
for Memory *m = this; m; m = m->address_space: for Memory *m = this; m; m = m->address_space:
--m->used --m->used
unsigned raw_zalloc ():
FreePage *ret = zero_pages
if !ret:
ret = junk_pages
for unsigned i = 1; i < (PAGE_SIZE >> 2); ++i:
((unsigned *)ret)[i] = 0
junk_pages = ret->next
else:
zero_pages = ret->next
ret->next = NULL
return (unsigned)ret
void raw_pfree (unsigned page):
FreePage *p = (FreePage *)page
p->next = junk_pages
junk_pages = p
unsigned Memory::palloc (): unsigned Memory::palloc ():
if !use (): if !use ():
return NULL return NULL
@ -34,23 +51,14 @@ unsigned Memory::palloc ():
unsigned Memory::zalloc (): unsigned Memory::zalloc ():
if !use (): if !use ():
return NULL return NULL
FreePage *ret = zero_pages return raw_zalloc ()
if !ret:
ret = junk_pages
for unsigned i = 1; i < (PAGE_SIZE >> 2); ++i:
((unsigned *)ret)[i] = 0
junk_pages = ret->next
else:
zero_pages = ret->next
ret->next = NULL
return (unsigned)ret
void Memory::pfree (unsigned page): void Memory::pfree (unsigned page):
FreePage *p = (FreePage *)page unuse ()
p->next = junk_pages return raw_pfree (page)
junk_pages = p
void Memory::zfree (unsigned page): void Memory::zfree (unsigned page):
unuse ()
FreePage *p = (FreePage *)page FreePage *p = (FreePage *)page
p->next = zero_pages p->next = zero_pages
zero_pages = p zero_pages = p
@ -177,6 +185,8 @@ Receiver *Memory::alloc_receiver ():
ret->next_owned = NULL ret->next_owned = NULL
ret->capabilities = NULL ret->capabilities = NULL
ret->messages = NULL ret->messages = NULL
ret->reply_protected_data = ~0
ret->protected_only = false
return ret return ret
Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret): Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret):
@ -290,12 +300,17 @@ void Memory::free_capability (Capability *capability):
free_obj (capability) free_obj (capability)
void Capability::invalidate (): void Capability::invalidate ():
if !target:
return
if sibling_prev: if sibling_prev:
sibling_prev->sibling_next = sibling_next sibling_prev->sibling_next = sibling_next
else if target: else if target:
target->capabilities = sibling_next target->capabilities = sibling_next
if sibling_next: if sibling_next:
sibling_next->sibling_prev = sibling_prev sibling_next->sibling_prev = sibling_prev
parent = NULL
sibling_prev = NULL
sibling_next = NULL
Capability *c = this Capability *c = this
while c->children: while c->children:
c = c->children c = c->children
@ -332,3 +347,32 @@ void Memory::free_memory (Memory *mem):
free_memory (mem->memories) free_memory (mem->memories)
Memory_arch_free (mem) Memory_arch_free (mem)
free_obj (mem) free_obj (mem)
void Page::forget ():
if data.share_prev || data.share_next:
if data.share_prev:
((Page *)data.share_prev)->data.share_next = data.share_next
if data.share_next:
((Page *)data.share_next)->data.share_prev = data.share_prev
data.share_prev = NULL
data.share_next = NULL
else:
raw_pfree (data.frame)
data.frame = 0
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED)
Page_arch_update_mapping (this)
void Cappage::forget ():
if data.share_prev || data.share_next:
if data.share_prev:
((Cappage *)data.share_prev)->data.share_next = data.share_next
if data.share_next:
((Cappage *)data.share_next)->data.share_prev = data.share_prev
data.share_prev = NULL
data.share_next = NULL
else:
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
((Capability *)data.frame)[i].invalidate ()
raw_pfree (data.frame)
data.frame = 0
data.flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED)

View File

@ -24,86 +24,96 @@ extern "C" {
#define CAP_RECEIVER_SET_OWNER 1 #define CAP_RECEIVER_SET_OWNER 1
#define CAP_RECEIVER_CREATE_CAPABILITY 2 #define CAP_RECEIVER_CREATE_CAPABILITY 2
#define CAP_RECEIVER_CREATE_CALL_CAPABILITY 3 #define CAP_RECEIVER_CREATE_CALL_CAPABILITY 3
#define CAP_RECEIVER_GET_REPLY_PROTECTED_DATA 4
#define CAP_RECEIVER_SET_REPLY_PROTECTED_DATA 5
#define CAP_RECEIVER_ALL_RIGHTS 0x7f #define CAP_RECEIVER_ALL_RIGHTS 0x7f
/* Not an operation; a capability with this bit set is a call capability. */ /* Not an operation; a capability with this bit set is a call capability. */
#define CAP_RECEIVER_CALL 7 #define CAP_RECEIVER_CALL 7
/* Same thing for reply capability. */ /* Same thing for reply capability. */
#define CAP_RECEIVER_REPLY 8 #define CAP_RECEIVER_REPLY 8
/* If set on a call capability, waiting for only this reply is disabled. */
#define CAP_RECEIVER_CALL_ASYNC 1
#define CAP_MEMORY_CREATE 1 #define CAP_MEMORY_CREATE 1
#define CAP_MEMORY_DESTROY 2 #define CAP_MEMORY_DESTROY 2
#define CAP_MEMORY_LIST 3 #define CAP_MEMORY_LIST 3
#define CAP_MEMORY_MAPPING 4 #define CAP_MEMORY_MAP 4
#define CAP_MEMORY_SET_LIMIT 5 #define CAP_MEMORY_MAPPING 5
#define CAP_MEMORY_GET_LIMIT 6 #define CAP_MEMORY_SET_LIMIT 6
#define CAP_MEMORY_DROP 7 #define CAP_MEMORY_GET_LIMIT 7
#define CAP_MEMORY_DROP 8
#define CAP_MEMORY_ALL_RIGHTS 0x1ff #define CAP_MEMORY_ALL_RIGHTS 0x1ff
#define CAP_THREAD_GET_INFO 1 /* Details of this are arch-specific. */ #define CAP_THREAD_INFO 1 /* Details of this are arch-specific. */
#define CAP_THREAD_SET_INFO 2 /* Details of this are arch-specific. */ #define CAP_THREAD_SCHEDULE 2
#define CAP_THREAD_SCHEDULE 3 #define CAP_THREAD_MAKE_PRIV 6
#define CAP_THREAD_GET_TOP_MEMORY 7 #define CAP_THREAD_GET_TOP_MEMORY 7
#define CAP_THREAD_REGISTER_INTERRUPT 8 #define CAP_THREAD_REGISTER_INTERRUPT 8
#define CAP_THREAD_ALL_RIGHTS 0xff #define CAP_THREAD_ALL_RIGHTS 0x3f
#define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY)) #define CAP_THREAD_ALL_PRIV_RIGHTS (CAP_THREAD_ALL_RIGHTS | (1 << CAP_THREAD_REGISTER_INTERRUPT) | (1 << CAP_THREAD_GET_TOP_MEMORY) | (1 << CAP_THREAD_MAKE_PRIV))
/* These get/set_info are not arch-specific. */ /* These get/set_info are not arch-specific. */
#define CAP_THREAD_INFO_PC ~0 #define CAP_THREAD_INFO_PC ~0
#define CAP_THREAD_INFO_SP ~1 #define CAP_THREAD_INFO_SP ~1
#define CAP_THREAD_INFO_FLAGS ~2 #define CAP_THREAD_INFO_FLAGS ~2
/* Flag values for processor state */ /* Flag values for processor state */
#define THREAD_FLAG_WAITING 0x80000000 #define THREAD_FLAG_PRIV 0x80000000
#define THREAD_FLAG_RUNNING 0x40000000 #define THREAD_FLAG_WAITING 0x40000000
#define THREAD_FLAG_PRIV 0x20000000 #define THREAD_FLAG_RUNNING 0x20000000
#define THREAD_FLAG_USER 0x1fffffff #define THREAD_FLAG_USER 0x1fffffff
#define CAP_PAGE_MAP 1 #define CAP_PAGE_SHARE 1
#define CAP_PAGE_COPY 2 #define CAP_PAGE_FLAGS 2
#define CAP_PAGE_MOVE 3
#define CAP_PAGE_GET_FLAGS 4
#define CAP_PAGE_SET_FLAGS 5
/* Not an operation; a capability without this bit cannot write to the page. */ /* Not an operation; a capability without this bit cannot write to the page. */
#define CAP_PAGE_WRITE 6 #define CAP_PAGE_WRITE 3
#define CAP_PAGE_ALL_RIGHTS 0x1ff #define CAP_PAGE_ALL_RIGHTS 0x1ff
/* Operation details for PAGE_SHARE */
/* Forget the source page during the operation. This makes it a move. */
#define PAGE_SHARE_FORGET 0x10000
/* Make the target unwritable. */
#define PAGE_SHARE_READONLY 0x20000
/* Make the target independent of the source (make a copy if needed). */
#define PAGE_SHARE_COPY 0x40000
/* Flag values for Page and Cappage objects. */ /* Flag values for Page and Cappage objects. */
/* A writable page can be written to. This flag can not be set while the frame is shared. */ /* A writable page can be written to. This flag can not be set while the frame is shared. */
#define PAGE_FLAG_WRITABLE 1 #define PAGE_FLAG_WRITABLE 1
/* When paying, the memory's use is incremented if the page holds a frame. It cannot be lost. Frames are lost when the last payer forgets them. */ /* When paying, the memory's use is incremented if the page holds a frame. It cannot be lost. Frames are lost when the last payer forgets them. */
#define PAGE_FLAG_PAYING 2 #define PAGE_FLAG_PAYING 2
/* Frames can be moved to this Page if they are not shared; copying will always fail. Sharing a page while this flag is set will fail; moving it will move the flag with it. A page is guaranteed to be unshared when this flag is set. Trying to set this flag on a shared page has no effect. */ /* Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems. */
#define PAGE_FLAG_NOSHARE 4 #define PAGE_FLAG_FRAME 4
/* This is a read-only flag, which is set if the Page is shared. */ /* This is a read-only flag, which is set if the Page is shared. */
#define PAGE_FLAG_SHARED 8 #define PAGE_FLAG_SHARED 8
#define CAP_CAPABILITY_GET 1 #define CAP_CAPABILITY_GET 1
#define CAP_CAPABILITY_SET_DEATH_NOTIFY 2
#define CAP_CAPABILITY_ALL_RIGHTS 0x1ff #define CAP_CAPABILITY_ALL_RIGHTS 0x1ff
#define CAPPAGE_SIZE 102 #define CAPPAGE_SIZE 102
/* Cappage has page's operations as well. */ /* Cappage has Page's operations as well. */
#define CAP_CAPPAGE_SET 7 #define CAP_CAPPAGE_SET 4
#define CAP_CAPPAGE_ALL_RIGHTS 0x1ff #define CAP_CAPPAGE_ALL_RIGHTS 0x1ff
#ifndef __KERNEL #ifndef __KERNEL
typedef unsigned __Capability; typedef unsigned Capability;
extern __Capability __my_receiver; extern Capability my_receiver;
extern __Capability __my_thread; extern Capability my_thread;
extern __Capability __my_memory; extern Capability my_memory;
extern __Capability __my_call; extern Capability my_call;
__Capability __cap_copy (__Capability src) Capability cap_copy (Capability src)
{ {
return src | 2; return src | 2;
} }
typedef struct __Message typedef struct Message
{ {
unsigned data[4]; unsigned data[4];
__Capability cap[4]; Capability cap[4];
} __Message; } Message;
static int __invoke (__Capability target, __Message *msg) static int invoke (Capability target, Message *msg)
{ {
register int ret __asm__ ("v0"); register int ret __asm__ ("v0");
register unsigned v0 __asm__ ("v0") = target; register unsigned v0 __asm__ ("v0") = target;
@ -119,7 +129,7 @@ static int __invoke (__Capability target, __Message *msg)
return ret; return ret;
} }
static int __call (__Capability target, __Message *msg) static int call (Capability target, Message *msg)
{ {
register int ret __asm__ ("v0"); register int ret __asm__ ("v0");
register unsigned v0 __asm__ ("v0") = target; register unsigned v0 __asm__ ("v0") = target;
@ -143,242 +153,302 @@ static int __call (__Capability target, __Message *msg)
return ret; return ret;
} }
static int __invoke_01 (__Capability t, unsigned d) static int invoke_01 (Capability t, unsigned d)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.data[0] = d; msg.data[0] = d;
return __invoke (t, &msg); return invoke (t, &msg);
} }
static int __invoke_02 (__Capability t, unsigned d0, unsigned d1) static int invoke_02 (Capability t, unsigned d0, unsigned d1)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.data[0] = d0; msg.data[0] = d0;
msg.data[1] = d1; msg.data[1] = d1;
return __invoke (t, &msg); return invoke (t, &msg);
} }
static int __invoke_04 (__Capability t, unsigned d0, unsigned d1, unsigned d2, unsigned d3) static int invoke_04 (Capability t, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.data[0] = d0; msg.data[0] = d0;
msg.data[1] = d1; msg.data[1] = d1;
msg.data[2] = d2; msg.data[2] = d2;
msg.data[3] = d3; msg.data[3] = d3;
return __invoke (t, &msg); return invoke (t, &msg);
} }
static int __invoke_11 (__Capability t, __Capability c, unsigned d) static int invoke_11 (Capability t, Capability c, unsigned d)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.cap[0] = c; msg.cap[0] = c;
msg.data[0] = d; msg.data[0] = d;
return __invoke (t, &msg); return invoke (t, &msg);
} }
static int __invoke_12 (__Capability t, __Capability c, unsigned d0, unsigned d1) static int invoke_12 (Capability t, Capability c, unsigned d0, unsigned d1)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.cap[0] = c; msg.cap[0] = c;
msg.data[0] = d0; msg.data[0] = d0;
msg.data[1] = d1; msg.data[1] = d1;
return __invoke (t, &msg); return invoke (t, &msg);
} }
static __Capability __call_c01 (__Capability c, unsigned d) static Capability call_c01 (Capability c, unsigned d)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.cap[0] = c; msg.cap[0] = c;
msg.data[0] = d; msg.data[0] = d;
ret = __call (__my_call, &msg); ret = call (my_call, &msg);
return ret ? msg.cap[0] : 0; return ret ? msg.cap[0] : 0;
} }
static __Capability __call_c02 (__Capability c, unsigned d0, unsigned d1) static Capability call_c02 (Capability c, unsigned d0, unsigned d1)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.cap[0] = c; msg.cap[0] = c;
msg.data[0] = d0; msg.data[0] = d0;
msg.data[1] = d1; msg.data[1] = d1;
ret = __call (__my_call, &msg); ret = call (my_call, &msg);
return ret ? msg.cap[0] : 0; return ret ? msg.cap[0] : 0;
} }
static unsigned __call_n02 (__Capability c, unsigned d0, unsigned d1) static Capability call_c12 (Capability c, Capability c1, unsigned d0, unsigned d1)
{ {
__Message msg; Message msg;
int ret; int ret;
msg.cap[0] = c; msg.cap[0] = c;
msg.cap[1] = c1;
msg.data[0] = d0; msg.data[0] = d0;
msg.data[1] = d1; msg.data[1] = d1;
ret = __call (__my_call, &msg); ret = call (my_call, &msg);
return ret ? msg.cap[0] : 0;
}
static unsigned call_n01 (Capability c, unsigned d)
{
Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d;
ret = call (my_call, &msg);
return ret ? msg.data[0] : 0; return ret ? msg.data[0] : 0;
} }
static __Capability __degrade (__Capability src, unsigned mask) static unsigned call_n02 (Capability c, unsigned d0, unsigned d1)
{ {
return __call_c02 (src, CAP_DEGRADE, mask); Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
ret = call (my_call, &msg);
return ret ? msg.data[0] : 0;
} }
static void __schedule () static unsigned call_n03 (Capability c, unsigned d0, unsigned d1, unsigned d2)
{ {
__invoke_01 (__my_thread, CAP_THREAD_SCHEDULE); Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
ret = call (my_call, &msg);
return ret ? msg.data[0] : 0;
} }
static void __register_interrupt (unsigned num) static unsigned call_n04 (Capability c, unsigned d0, unsigned d1, unsigned d2, unsigned d3)
{ {
__invoke_12 (__my_thread, __my_receiver, CAP_THREAD_REGISTER_INTERRUPT, num); Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
msg.data[2] = d2;
msg.data[3] = d3;
ret = call (my_call, &msg);
return ret ? msg.data[0] : 0;
} }
static __Capability __get_top_memory () static Capability degrade (Capability src, unsigned mask)
{ {
return __call_c01 (__my_thread, CAP_THREAD_GET_TOP_MEMORY); return call_c02 (src, CAP_DEGRADE, mask);
} }
static void __unregister_interrupt (unsigned num) static void schedule ()
{ {
__invoke_02 (__my_thread, CAP_THREAD_REGISTER_INTERRUPT, num); invoke_01 (my_thread, CAP_THREAD_SCHEDULE);
} }
static int __receiver_set_owner (__Capability receiver, __Capability owner) static void register_interrupt (unsigned num)
{ {
return __invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER); invoke_12 (my_thread, my_receiver, CAP_THREAD_REGISTER_INTERRUPT, num);
} }
static __Capability __receiver_create_capability (__Capability receiver, unsigned protected_data) static Capability get_top_memory ()
{ {
return __call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data); return call_c01 (my_thread, CAP_THREAD_GET_TOP_MEMORY);
} }
static __Capability __receiver_create_call_capability (__Capability receiver, unsigned protected_data) static void unregister_interrupt (unsigned num)
{ {
return __call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, protected_data); invoke_02 (my_thread, CAP_THREAD_REGISTER_INTERRUPT, num);
} }
static __Capability __memory_create (__Capability memory, unsigned type) static int receiver_set_owner (Capability receiver, Capability owner)
{ {
return __call_c02 (memory, CAP_MEMORY_CREATE, type); return invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER);
} }
static __Capability __memory_create_page (__Capability memory) static Capability receiver_create_capability (Capability receiver, unsigned protected_data)
{ {
return __memory_create (memory, CAPTYPE_PAGE); return call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
} }
static __Capability __memory_create_thread (__Capability memory) static int receiver_get_reply_protected_data (Capability receiver, unsigned data)
{ {
return __memory_create (memory, CAPTYPE_THREAD); return call_n01 (receiver, CAP_RECEIVER_GET_REPLY_PROTECTED_DATA);
} }
static __Capability __memory_create_receiver (__Capability memory) static int receiver_set_reply_protected_data (Capability receiver, unsigned data)
{ {
return __memory_create (memory, CAPTYPE_RECEIVER); return invoke_02 (receiver, CAP_RECEIVER_SET_REPLY_PROTECTED_DATA, data);
} }
static __Capability __memory_create_memory (__Capability memory) static Capability receiver_create_call_capability (Capability receiver)
{ {
return __memory_create (memory, CAPTYPE_MEMORY); return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 0);
} }
static __Capability __memory_create_cappage (__Capability memory) static Capability receiver_create_async_call_capability (Capability receiver)
{ {
return __memory_create (memory, CAPTYPE_CAPPAGE); return call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, 1);
} }
static int __memory_destroy (__Capability memory, __Capability target) static Capability memory_create (Capability memory, unsigned type)
{ {
return __invoke_11 (memory, target, CAP_MEMORY_DESTROY); return call_c02 (memory, CAP_MEMORY_CREATE, type);
}
static Capability memory_create_page (Capability memory)
{
return memory_create (memory, CAPTYPE_PAGE);
}
static Capability memory_create_thread (Capability memory)
{
return memory_create (memory, CAPTYPE_THREAD);
}
static Capability memory_create_receiver (Capability memory)
{
return memory_create (memory, CAPTYPE_RECEIVER);
}
static Capability memory_create_memory (Capability memory)
{
return memory_create (memory, CAPTYPE_MEMORY);
}
static Capability memory_create_cappage (Capability memory)
{
return memory_create (memory, CAPTYPE_CAPPAGE);
}
static int memory_destroy (Capability memory, Capability target)
{
return invoke_11 (memory, target, CAP_MEMORY_DESTROY);
} }
/* TODO: #define CAP_MEMORY_LIST 3 */ /* TODO: #define CAP_MEMORY_LIST 3 */
static __Capability __memory_mapping (__Capability memory, unsigned address) static int memory_map (Capability memory, Capability page, unsigned address)
{ {
return __call_c02 (memory, CAP_MEMORY_MAPPING, address); return invoke_12 (memory, page, CAP_MEMORY_MAP, address);
} }
static void __drop (__Capability cap) static Capability memory_mapping (Capability memory, unsigned address)
{ {
__invoke_11 (__my_memory, cap, CAP_MEMORY_DROP); return call_c02 (memory, CAP_MEMORY_MAPPING, address);
} }
static int __thread_set_info (__Capability thread, unsigned info, unsigned value, unsigned mask) static void drop (Capability cap)
{ {
return __invoke_04 (thread, CAP_THREAD_SET_INFO, info, value, mask); invoke_11 (my_memory, cap, CAP_MEMORY_DROP);
} }
static int __thread_set_pc (__Capability thread, unsigned pc) static Capability thread_make_priv (Capability thread)
{ {
return __thread_set_info (thread, CAP_THREAD_INFO_PC, pc, ~0); return call_c12 (my_thread, thread, CAP_THREAD_MAKE_PRIV, ~0);
} }
static int __thread_set_sp (__Capability thread, unsigned sp) static unsigned thread_info (Capability thread, unsigned info, unsigned value, unsigned mask)
{ {
return __thread_set_info (thread, CAP_THREAD_INFO_SP, sp, ~0); return call_n04 (thread, CAP_THREAD_INFO, info, value, mask);
} }
static int __thread_set_flags (__Capability thread, unsigned value, unsigned mask) static unsigned thread_set_pc (Capability thread, unsigned pc)
{ {
return __thread_set_info (thread, CAP_THREAD_INFO_FLAGS, value, mask); return thread_info (thread, CAP_THREAD_INFO_PC, pc, ~0);
} }
static int __thread_run (__Capability thread, int run) static unsigned thread_set_sp (Capability thread, unsigned sp)
{ {
return __thread_set_flags (thread, run ? THREAD_FLAG_RUNNING : 0, THREAD_FLAG_RUNNING); return thread_info (thread, CAP_THREAD_INFO_SP, sp, ~0);
} }
static int __thread_wait (__Capability thread, int wait) static unsigned thread_flags (Capability thread, unsigned value, unsigned mask)
{ {
return __thread_set_flags (thread, wait ? THREAD_FLAG_WAITING : 0, THREAD_FLAG_WAITING); return thread_info (thread, CAP_THREAD_INFO_FLAGS, value, mask);
} }
static unsigned __thread_get_info (__Capability thread, unsigned info) static unsigned thread_run (Capability thread, int run)
{ {
return __call_n02 (thread, CAP_THREAD_GET_INFO, info); return thread_flags (thread, run ? THREAD_FLAG_RUNNING : 0, THREAD_FLAG_RUNNING);
} }
static unsigned __thread_get_pc (__Capability thread) static unsigned thread_wait (Capability thread, int wait)
{ {
return __thread_get_info (thread, CAP_THREAD_INFO_PC); return thread_flags (thread, wait ? THREAD_FLAG_WAITING : 0, THREAD_FLAG_WAITING);
} }
static unsigned __thread_get_sp (__Capability thread) static unsigned thread_get_pc (Capability thread)
{ {
return __thread_get_info (thread, CAP_THREAD_INFO_SP); return thread_info (thread, CAP_THREAD_INFO_PC, 0, 0);
} }
static unsigned __thread_get_flags (__Capability thread) static unsigned thread_get_sp (Capability thread)
{ {
return __thread_get_info (thread, CAP_THREAD_INFO_FLAGS); return thread_info (thread, CAP_THREAD_INFO_SP, 0, 0);
} }
/* TODO. All except map should also work for cappages. static int page_share (Capability page, Capability target, unsigned flags)
#define CAP_PAGE_MAP 1
#define CAP_PAGE_SHARE 2
#define CAP_PAGE_SHARE_COW 3
#define CAP_PAGE_FORGET 4
*/
static __Capability __capability_get (__Capability cap)
{ {
return __call_c01 (cap, CAP_CAPABILITY_GET); return invoke_12 (page, target, CAP_PAGE_SHARE, flags);
} }
static int __capability_set_death_notify (__Capability source, __Capability target) static unsigned page_flags (Capability page, unsigned new_flags, unsigned mask)
{ {
return __invoke_11 (source, target, CAP_CAPABILITY_SET_DEATH_NOTIFY); return call_n03 (page, CAP_PAGE_FLAGS, new_flags, mask);
} }
static int __capability_cappage_set (__Capability page, __Capability cap, unsigned index) static Capability capability_get (Capability cap)
{ {
return __invoke_12 (page, cap, CAP_CAPPAGE_SET, index); return call_c01 (cap, CAP_CAPABILITY_GET);
}
static int cappage_set (Capability page, Capability cap, unsigned index)
{
return invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
} }
#endif #endif

18
entry.S
View File

@ -13,17 +13,15 @@
addr_000: addr_000:
#if 0 #if 0
// TLB refill // TLB refill
bne $zero, $k0, slow_refill
nop
bne $zero, $k1, slow_refill bne $zero, $k1, slow_refill
nop nop
bne $zero, $k0, slow_refill
lw $k1, -0xd94($zero) lw $k1, -0xd94($zero)
beq $zero, $k1, slow_refill
mfc0 $k0, $CP0_ENTRY_HI mfc0 $k0, $CP0_ENTRY_HI
srl $k0, $k0, 19 srl $k0, $k0, 19
and $k0, $k0, 0x3fc and $k0, $k0, 0x3fc
addu $k0, $k0, $k1 addu $k0, $k0, $k1
beq $zero, $k0, slow_refill0 beq $zero, $k0, zero_refill
lw $k0, 0($k0) lw $k0, 0($k0)
mfc0 $k1, $CP0_ENTRY_HI mfc0 $k1, $CP0_ENTRY_HI
srl $k1, $k1, 10 srl $k1, $k1, 10
@ -33,14 +31,18 @@ addr_000:
mtc0 $k1, $CP0_ENTRY_LO0 mtc0 $k1, $CP0_ENTRY_LO0
lw $k1, 4($k0) lw $k1, 4($k0)
mtc0 $k1, $CP0_ENTRY_LO1 mtc0 $k1, $CP0_ENTRY_LO1
tlbwr 1: tlbwr
move $zero, $k0 move $zero, $k0
move $zero, $k1 move $zero, $k1
eret eret
slow_refill0: zero_refill:
move $k1, $zero mtc0 $zero, $CP_ENTRY_LO0
b 1b
mtc0 $zero, $CP_ENTRY_LO1
slow_refill: slow_refill:
move $k1, $zero
#endif #endif
sw $ra, -0xd88($zero) sw $ra, -0xd88($zero)
bal save_regs bal save_regs
@ -61,7 +63,7 @@ addr_100:
addr_180: addr_180:
// General exception // General exception
// Allow new exceptions to update EPC and friends. // Allow new exceptions to update EPC and friends.
mtc0 $zero, $CP0_STATUS //mtc0 $zero, $CP0_STATUS
sw $ra, -0xd88($zero) sw $ra, -0xd88($zero)
bal save_regs bal save_regs
nop nop

View File

@ -32,6 +32,7 @@ static void init_idle ():
idle_page.prev = NULL idle_page.prev = NULL
idle_page.next = NULL idle_page.next = NULL
idle_page.data.frame = 0x80000000 idle_page.data.frame = 0x80000000
idle_page.data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
idle_page.refs = NULL idle_page.refs = NULL
idle_page.address_space = NULL idle_page.address_space = NULL
current = &idle current = &idle
@ -124,6 +125,7 @@ static void init_threads ():
if !pages[idx]: if !pages[idx]:
pages[idx] = mem->alloc_page () pages[idx] = mem->alloc_page ()
pages[idx]->data.frame = thread_start[i] + (idx << PAGE_BITS) pages[idx]->data.frame = thread_start[i] + (idx << PAGE_BITS)
pages[idx]->data.flags = (writable ? PAGE_FLAG_WRITABLE : 0) | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
++top_memory.limit ++top_memory.limit
if !mem->map (pages[idx], p, writable): if !mem->map (pages[idx], p, writable):
panic (0x22446688, "unable to map initial page") panic (0x22446688, "unable to map initial page")
@ -136,6 +138,7 @@ static void init_threads ():
if !page: if !page:
panic (0x00220022, "out of memory") panic (0x00220022, "out of memory")
page->data.frame = mem->zalloc () page->data.frame = mem->zalloc ()
page->data.flags = (writable ? PAGE_FLAG_WRITABLE : 0) | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
if !page->data.frame || !mem->map (page, p, true): if !page->data.frame || !mem->map (page, p, true):
panic (0x33557799, "unable to map initial bss page") panic (0x33557799, "unable to map initial bss page")
else: else:
@ -154,6 +157,7 @@ static void init_threads ():
top_memory.pfree (thread_start[i] + (p << PAGE_BITS)) top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
Page *stackpage = mem->alloc_page () Page *stackpage = mem->alloc_page ()
stackpage->data.frame = mem->zalloc () stackpage->data.frame = mem->zalloc ()
stackpage->data.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
if !stackpage || !mem->map (stackpage, 0x7ffff000, true): if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
panic (0x13151719, "unable to map initial stack page") panic (0x13151719, "unable to map initial stack page")
Receiver *recv = mem->alloc_receiver () Receiver *recv = mem->alloc_receiver ()
@ -211,9 +215,9 @@ void init ():
init_threads () init_threads ()
// Enable all interrupts and say we're handling an exception. // Say we're handling an exception. Don't enable interrupts; this will happen when handlers are registered.
// Since we're going to enter the idle task, allow access to cp0. // Since we're going to enter the idle task, allow access to cp0.
cp0_set (CP0_STATUS, 0x1000ff13) cp0_set (CP0_STATUS, 0x10000013)
// Done; return to user space (the idle task). // Done; return to user space (the idle task).
__asm__ volatile ("eret") __asm__ volatile ("eret")

1002
invoke.ccp

File diff suppressed because it is too large Load Diff

View File

@ -63,8 +63,11 @@ struct Receiver : public Object <Receiver>:
Receiver *prev_owned, *next_owned Receiver *prev_owned, *next_owned
Capability *capabilities Capability *capabilities
Message *messages Message *messages
unsigned reply_protected_data
bool protected_only
void own (Thread *o) void own (Thread *o)
void orphan () void orphan ()
bool try_deliver ()
bool send_message (unsigned protected_data, unsigned data[4], Capability *cap[4], bool copy[4]) bool send_message (unsigned protected_data, unsigned data[4], Capability *cap[4], bool copy[4])
struct Capability : public Object <Capability>: struct Capability : public Object <Capability>:
@ -85,9 +88,11 @@ struct ShareData :
struct Page : public Object <Page>: struct Page : public Object <Page>:
ShareData data ShareData data
Page_arch arch Page_arch arch
void forget ()
struct Cappage : public Object <Cappage>: struct Cappage : public Object <Cappage>:
ShareData data ShareData data
void forget ()
struct Memory : public Object <Memory>: struct Memory : public Object <Memory>:
Free *frees Free *frees
@ -158,6 +163,10 @@ EXTERN Page idle_page
EXTERN Thread *first_scheduled EXTERN Thread *first_scheduled
EXTERN Thread *current EXTERN Thread *current
// Defined in alloc.cc
unsigned raw_zalloc ()
void raw_pfree (unsigned page)
// Defined in arch.cc // Defined in arch.cc
void Thread_arch_init (Thread *thread) void Thread_arch_init (Thread *thread)
void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4]) void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4])

View File

@ -1,2 +0,0 @@
#pypp 0
#include "kernel.hh"

View File

@ -170,6 +170,18 @@ static void free_page_table (arch_page_table *t, unsigned idx):
mem->arch.directory = NULL mem->arch.directory = NULL
mem->arch.shadow = NULL mem->arch.shadow = NULL
static void tlb_reset (unsigned address, unsigned asid, unsigned value):
cp0_set (CP0_ENTRY_HI, address | asid)
__asm__ volatile ("tlbp")
unsigned idx
cp0_get (CP0_INDEX, idx)
if ~idx & 0x80000000:
if address & (1 << PAGE_BITS):
cp0_set (CP0_ENTRY_LO1, value)
else:
cp0_set (CP0_ENTRY_LO0, value)
__asm__ volatile ("tlbwi")
static void free_page (arch_page_table *t, arch_page *p): static void free_page (arch_page_table *t, arch_page *p):
if p->next: if p->next:
p->next->prev = p->prev p->next->prev = p->prev
@ -183,12 +195,26 @@ static void free_page (arch_page_table *t, arch_page *p):
p->page->arch.first_mapped = p->next_mapped p->page->arch.first_mapped = p->next_mapped
if p->next_mapped: if p->next_mapped:
p->next_mapped->prev_mapped = p->prev_mapped p->next_mapped->prev_mapped = p->prev_mapped
tlb_reset (p->mapping, p->address_space->arch.asid, 0)
unsigned idx = p->mapping >> 21 unsigned idx = p->mapping >> 21
p->address_space->free_obj (p) p->address_space->free_obj (p)
if !t->first_page: if !t->first_page:
free_page_table (t, idx) free_page_table (t, idx)
static unsigned make_entry_lo (Page *page, bool write):
if !page->data.frame:
return 0
unsigned flags
if write:
flags = 0x18 | 0x4 | 0x2
else
flags = 0x18 | 0x2
return ((page->data.frame & ~0x80000000) >> 6) | flags
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write): bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
if address >= 0x80000000:
return false
address &= PAGE_MASK
if !mem->arch.directory: if !mem->arch.directory:
mem->arch.directory = (unsigned **)mem->zalloc () mem->arch.directory = (unsigned **)mem->zalloc ()
if !mem->arch.directory: if !mem->arch.directory:
@ -229,9 +255,9 @@ bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
unsigned idx = (address >> 12) & ((1 << 9) - 1) unsigned idx = (address >> 12) & ((1 << 9) - 1)
if table[idx]: if table[idx]:
mem->unmap ((Page *)table[idx + 0x200], address) mem->unmap ((Page *)table[idx + 0x200], address)
table[idx] = page->data.frame ? ((page->data.frame & ~0x80000000) >> 6) | 0x18 | (write ? 0x4 : 0) | 0x2 : 0 table[idx] = make_entry_lo (page, write)
table[idx + 0x200] = (unsigned)p table[idx + 0x200] = (unsigned)p
p->mapping = address p->mapping = address + write
p->page = page p->page = page
p->next_mapped = page->arch.first_mapped p->next_mapped = page->arch.first_mapped
if p->next_mapped: if p->next_mapped:
@ -250,15 +276,31 @@ void Memory_arch_unmap (Memory *mem, Page *page, unsigned address):
free_page (t, p) free_page (t, p)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable): Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable):
if address >= 0x80000000:
return NULL
unsigned *table = mem->arch.directory[address >> 21] unsigned *table = mem->arch.directory[address >> 21]
unsigned idx = (address >> 12) & ((1 << 9) - 1) unsigned idx = (address >> 12) & ((1 << 9) - 1)
arch_page *page = (arch_page *)table[idx + 0x200] arch_page *page = (arch_page *)table[idx + 0x200]
if writable: if writable:
*writable = (table[idx] & 4 ? 1 : 0) *writable = table[idx] & 4
return page->page return page->page
void Page_arch_update_mapping (Page *page): void Page_arch_update_mapping (Page *page):
// TODO if !page->arch.first_mapped:
return
Memory *as = page->address_space
unsigned target = make_entry_lo (page, page->data.flags & PAGE_FLAG_WRITABLE)
for arch_page *p = page->arch.first_mapped; p; p = p->next_mapped:
unsigned de = p->mapping >> 21
unsigned te = (p->mapping >> 12) & ((1 << 9) - 1)
bool write = p->mapping & 1
unsigned t
if p->mapping & 1:
t = target
else:
t = target & ~0x4
as->arch.directory[de][te] = t
tlb_reset (p->mapping & ~1, as->arch.asid, t)
void arch_invoke (): void arch_invoke ():
Capability *target, *c[4] Capability *target, *c[4]
@ -310,7 +352,11 @@ void arch_invoke ():
void arch_register_interrupt (unsigned num, Receiver *r): void arch_register_interrupt (unsigned num, Receiver *r):
arch_interrupt_receiver[num] = r arch_interrupt_receiver[num] = r
// And enable the interrupt.
unsigned status unsigned status
cp0_get (CP0_STATUS, status) cp0_get (CP0_STATUS, status)
cp0_set (CP0_STATUS, status | (1 << (num + 8))) // And enable or disable the interrupt.
if r:
status |= 1 << (num + 8)
else:
status &= ~(1 << (num + 8))
cp0_set (CP0_STATUS, status)

View File

@ -9,7 +9,8 @@ This document briefly describes the inner workings of my kernel, including the
reasons for the choices that were made. It is meant to be understandable (with reasons for the choices that were made. It is meant to be understandable (with
effort) for people who know nothing of operating systems. On the other hand, effort) for people who know nothing of operating systems. On the other hand,
it should also be readable for people who know about computer architecture, but it should also be readable for people who know about computer architecture, but
want to know about this kernel. want to know about this kernel. It is probably better suited for the latter
category.
\end{abstract} \end{abstract}
\tableofcontents \tableofcontents
@ -126,16 +127,21 @@ any part of the system, except the parts that it really needs to perform its
operation, it cannot leak or damage the other parts of the system either. The operation, it cannot leak or damage the other parts of the system either. The
reason that this is relevant is not that users will run programs that try to reason that this is relevant is not that users will run programs that try to
ruin their system (although this may happen as well), but that programs may ruin their system (although this may happen as well), but that programs may
break and damage random parts of the system, or be taken over by crackers. If break and damage random parts of the system, or be taken over by
the broken or malicious process has fewer rights, it will also do less damage crackers\footnote{Crackers are better known by the public as ``hackers''.
to the system. However, I use this word to describe people who like to play with software (or
sometimes also with other things). Therefore the malicious people who use
hacking skills for evil need a different name.}. If the broken or malicious
process has fewer rights, it will also do less damage to the system.
This leads to the goal of giving each process as little rights as possible. This leads to the goal of giving each process as little rights as possible.
For this, it is best to have rights in a very fine-grained way. Every For this, it is best to have rights in a very fine-grained way. Every
operation of a driver (be it a hardware device driver, or just a shared program operation of a driver (be it a hardware device driver, or just a shared program
such as a file system) should have its own key, which can be given out without such as a file system) should have its own key, which can be given out without
giving keys to the entire driver (or even multiple drivers). Such a key is giving keys to the entire driver (or even multiple drivers). Such a key is
called a capability. called a capability. For example, a capability can allow the holder to access
a single file, or to use one specific network connection, or to see what keys
are typed by the user.
Some operations are performed directly on the kernel itself. For those, the Some operations are performed directly on the kernel itself. For those, the
kernel can provide its own capabilities. Processes can create their own kernel can provide its own capabilities. Processes can create their own
@ -143,9 +149,9 @@ objects which can receive capability calls, and capabilities for those can be
generated by them. Processes can copy capabilities to other processes, if they generated by them. Processes can copy capabilities to other processes, if they
have a channel to send them (using an existing capability). This way, any have a channel to send them (using an existing capability). This way, any
operation of the process with the external world goes through a capability, and operation of the process with the external world goes through a capability, and
only one system call is needed, namely \textit{invoke}. only one system call is needed: \textit{invoke}.
This has a very nice side-effect, namely that it becomes very easy to tap This has a very nice side-effect, which is that it becomes very easy to tap
communication of a task you control. This means that a user can redirect communication of a task you control. This means that a user can redirect
certain requests from programs which don't do exactly what is desired to do certain requests from programs which don't do exactly what is desired to do
nicer things. For example, a program can be prevented from opening pop-up nicer things. For example, a program can be prevented from opening pop-up
@ -155,64 +161,143 @@ This is a very good thing.
\section{Kernel objects} \section{Kernel objects}
This section describes all the kernel objects, and the operations that can be This section describes all the kernel objects, and the operations that can be
performed on them. performed on them. One operation is possible on any kernel object (except a
message and reply and call Capabilities). This operation is \textit{degrade}.
It creates a copy of the capability with some rights removed. This can be
useful when giving away a capability.
\subsection{Memory} \subsection{Memory}
A memory object is a container for storing things. All objects live inside a A Memory object is a container for storing things. All objects live inside a
memory object. A memory object can contain other memory objects, capabilities, Memory object. A Memory object can contain other Memory objects, Capabilities,
receivers, threads and pages. Receivers, Threads, Pages and Cappages.
A memory object is also an address space. Pages can be mapped (and unmapped). A Memory object is also an address space. Pages can be mapped (and unmapped).
Any Thread in a memory object uses this address space while it is running. Any Thread in a Memory object uses this address space while it is running.
Every memory object has a limit. When this limit is reached, no more pages can Every Memory object has a limit. When this limit is reached, no more Pages can
be allocated for it (including pages which it uses to store other objects). be allocated for it (including Pages which it uses to store other objects).
Using a new page in a memory object implies using it in all ancestor memory Using a new Page in a Memory object implies using it in all ancestor Memory
objects. This means that setting a limit which is higher than the parent's objects. This means that setting a limit which is higher than the parent's
limit means that the parent's limit applies anyway. limit means that the parent's limit applies anyway.
Operations on memory objects: Operations on Memory objects:
\begin{itemize} \begin{itemize}
\item \item Create a new item of type Receiver, Memory, Thread, Page, or Cappage.
\item Destroy an item of any type, which is owned by the Memory.
\item List items owned by the Memory, Pages mapped in it, and messages in owned
Receiver's queues.
\item Map a Page at an address.
\item Get the Page which is mapped at a certain address.
\item Get and set the limit, which is checked when allocating pages for this
Memory or any sub-structure.
\item Drop a capability. This can only be done by Threads owned by the Memory,
because only they can present capabilities owned by it.\footnote{The kernel
checks if presented capabilities are owned by the Thread's Memory. If they
aren't, no capability is passed instead. The destroy operation destroys an
object that a capability points to. Drop destroys the capability itself. If a
Thread from an other Memory would try to drop a capability, the kernel would
refuse to send it in the message, or it would not be dropped because it would
be owned by a different Memory.}
\end{itemize} \end{itemize}
\subsection{Page}
A page can be used to store user data. It can be mapped into an address space (a memory object). Threads can then use the data directly.
A page has no operations of itself; mapping a page is achieved using an
operation on a memory object.
\subsection{Receiver} \subsection{Receiver}
A receiver object is used for inter-process communication. Capabilities can be A receiver object is used for inter-process communication. Capabilities can be
created from it. When those are invoked, the receiver can be used to retrieve created from it. When those are invoked, the receiver can be used to retrieve
the message. the message.
Operations on receiver objects: Operations on Receiver objects:
\begin{itemize} \begin{itemize}
\item \item Set the owner. This is the Thread that messages will be sent to when
they arrive. Messages are stored in the receiver until the owner is ready to
accept them. If it is waiting while the message arrives, it is immediately
delivered.
\item Create a capability. The new capability should be given to Threads who
need to send a message to the receiver.
\item Create a call capability. This is an optimization. Because
\textit{calls} happen a lot, where a capability is created, sent in a message,
then a reply is sent over this new capability, and then it is dropped. This
can be done using a call capability. The call capability is invoked instead of
the target, and the target is specified where the reply capability should be.
The message is sent to the call capability (which is handled by the Receiver in
the kernel). It creates a new reply capability and sends the message to the
target with it. When the reply capability is invoked, the message is sent to
the owner, and the capability is dropped. This approach reduces the number of
kernel calls from four (create, call, reply, drop) to two (call, reply).
\end{itemize}
\subsection{Thread}
Thread objects hold the information about the current state of a thread. This
state is used to continue running the thread. The address space is used to map
the memory for the Thread. Different Threads in the same address space have
the same memory mapping. All Threads in one address space (often there is only
one) together are called a process.
Because all threads have a capability to their own Thread object (for claiming
Receivers), this is also used to make some calls which don't actually need an
object. The reason that these are not operations on some fake object which
every process implicitly owns, is that for debugging it may be useful to see
every action of a process. In that case, all its capabilities must be pointing
to the watcher, which will send them through to the actual target (or not).
With such an implicit capability, it would be impossible to intercept these
calls.
Operations on Thread objects:
\begin{itemize}
\item Get information about the thread. Details of this are
architecture-specific. Standard ways are defined for getting and setting some
flags (whether the process is running or waiting for a message, setting these
flags is a way to control this for other Threads), the program counter and the
stack pointer. This call is also used to get the contents of processor
registers and possibly other information which is different per Thread.
\item Let the kernel schedule the next process. This is not thread-specific.
\item Get the top Memory object. This is not thread-specific. Most Threads
are not allowed to perform this operation. It is given to the initial Threads.
They can pass it on to Threads that need it (mostly device drivers).
\item In the same category, register a Receiver for an interrupt. Upon
registration, the interrupt is enabled. When the interrupt arrives, the
registered Receiver gets a message from the kernel and the interrupt is
disabled again. After the Thread has handled the interrupt, it must reregister
it in order to enable it again.
\item And similarly, allow these priviledged operations (or some of them) in an
other thread. This is a property of the caller, because the target thread
normally doesn't have the permission to do this (otherwise the call would not
be needed). The result of this operation is a new Thread capability with all specified rights set. Normally this is inserted in a priviledged process's address space during setup, before it is run (instead of the capability which is obtained during Thread creation).
\end{itemize}
\subsection{Page and Cappage}
A Page can be used to store user data. It can be mapped into an address space
(a Memory object). Threads can then use the data directly. A Cappage is very
similar, in that it is owned by the user. However, the user cannot see its
contents directly. It contains a frame with Capabilities. They can be invoked
like other owned capabilities. The main feature of a Cappage, however, is that
they can be shared. It is a fast way to copy many capabilities to a different
address space. Capabilities in a Cappage are not directly owned by the Memory,
and thus cannot be dropped.
Operations on Page and Cappage objects:
\begin{itemize}
\item Copy or move the frame to a different Page, which is usually in a
different Memory. This way, large amounts of data can be copied between
address spaces without needing to really copy it.
\item Set or get flags, which contain information on whether the page is
shared, is writable, has a frame allocated, and is paying for the frame. Not
all flags can be set in all cases.
\item Cappages can also set a capability in the frame (pointed to with an index).
\end{itemize} \end{itemize}
\subsection{Capability} \subsection{Capability}
A capability object can be invoked to send a message to a receiver or the A capability object can be invoked to send a message to a receiver or the
kernel. The owner cannot see from the capability where it points. This is kernel. The owner cannot see from the capability where it points. This is
important, because the user must be able to substitute the capability for a important, because the user must be able to substitute the capability for a
different one, without the program noticing. different one, without the program noticing. In some cases, it is needed to
say things about capabilities. For example, a Memory can list the Capabilities
owned by it. In such a case, the list consists of Capabilities which point to
other Capabilities. These capabilities can also be used to destroy the target
capability (using an operation on the owning Memory object), for example.
Operations or capability objects: Operations or capability objects:
\begin{itemize} \begin{itemize}
\item \item Get a copy of the capability.
\end{itemize}
\subsection{Thread}
Thread objects hold the information about the current state of a thread. This
state is used to continue running the thread. The address space is used to map
the memory for the thread. Different threads in the same address space have
the same memory mapping. All threads in one address space (often just one)
together are called a process.
Operations on thread objects:
\begin{itemize}
\item
\end{itemize} \end{itemize}
\end{document} \end{document}

View File

@ -80,6 +80,28 @@ document about how to do this. Please read that if you don't have a working
cross-compiler, or if you would like to install libraries for cross-building cross-compiler, or if you would like to install libraries for cross-building
more easily. more easily.
\section{Choosing a language to write in}
Having a cross-compiler, the next thing to do is choose a language. I prefer
to use C++ for most things. I have used C for a previous kernel, though,
because it is more low-level. This time, I decided to try C++. But since I'm
not linking any libraries, I need to avoid things like new and delete. For
performance reasons I also don't use exceptions. They might need library
support as well. So what I use C++ for is classes with member functions, and
default function arguments. I'm not even using these all the time, and the
whole thing is very much like C anyway.
Except for one change I made: I'm using a \textit{pythonic preprocessor} I
wrote. It changes python-style indented code into something a C compiler
accepts. It shouldn't be too hard to understand if you see the kernel source.
Arguments to flow control instructions (if, while, for) do not need
parenthesis, but instead have a colon at the end of the line. After a colon at
the end of a line follows a possibly empty indented block, which is put in
brackets. Indenting a line with respect to the previous one without a colon
will not do anything: it makes it a continuation. Any line which is not empty
or otherwise special gets a semicolon at the end, so you don't need to type
those. When using both spaces and tabs (which I don't recommend), set the tab
width to 8 spaces.
\section{Making things run} \section{Making things run}
For loading a program, it must be a binary executable with a header. The For loading a program, it must be a binary executable with a header. The
header is inserted by mkimage. It needs a load address and an entry point. header is inserted by mkimage. It needs a load address and an entry point.
@ -414,6 +436,27 @@ personal copy of the data without actually copying anything. The result for
the sender is a Page without a frame. Any mappings it has are remembered, but the sender is a Page without a frame. Any mappings it has are remembered, but
until a new frame is requested, no frame will be mapped at the address. A Page until a new frame is requested, no frame will be mapped at the address. A Page
is also able to \textit{forget} its frame, thereby freeing some of its memory is also able to \textit{forget} its frame, thereby freeing some of its memory
quota. quota (if it stops paying for it as well; a payed-for frame costs quota, and is
guaranteed to be allocatable at any time).
Another optimization is to specify a minimum number of bytes for a page move.
If the page needs to be copied, this reduces the time needed to complete that
operation. The rest of the page should not contain secret data: it is possible
that the entire page is copied, for example if it doesn't need to be copied,
but can be reused.
\section{Copy on write}
Another nice optimization is \textit{copy on write}: a page is shared
read-only, and when a page-fault happens, the kernel will copy the contents, so
that the other owner(s) don't see the changes. For the moment, I don't
implemnt this. I'm not sure if I want it in the kernel at all. It can well be
implemented using an exception handler in user space, and is not used enough to
spend kernel space on, I think. But I can change my mind on that later.
\section{Memory listing}
The last thing to do for now is allowing a memory to be listed. That is,
having a suitably priviledged capability to a Memory should allow a program to
see what's in it. In particular, what objects it holds, and where pages are
mapped. Probably also what messages are in a receiver's queue.
\end{document} \end{document}

View File

@ -32,6 +32,10 @@ void Thread::wait ():
if flags & THREAD_FLAG_RUNNING: if flags & THREAD_FLAG_RUNNING:
unrun () unrun ()
flags |= THREAD_FLAG_WAITING flags |= THREAD_FLAG_WAITING
// Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned:
if r->try_deliver ():
break
void Thread::unwait (): void Thread::unwait ():
if !(flags & THREAD_FLAG_WAITING): if !(flags & THREAD_FLAG_WAITING):