mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-16 18:03:08 +02:00
more
This commit is contained in:
parent
e7f42c6b7e
commit
ef1b9bfe10
2
Makefile
2
Makefile
@ -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)
|
||||||
|
|
||||||
|
70
alloc.ccp
70
alloc.ccp
@ -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)
|
||||||
|
@ -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
18
entry.S
@ -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
|
||||||
|
8
init.ccp
8
init.ccp
@ -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
1002
invoke.ccp
File diff suppressed because it is too large
Load Diff
@ -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])
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
#pypp 0
|
|
||||||
#include "kernel.hh"
|
|
58
mips.ccp
58
mips.ccp
@ -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)
|
||||||
|
@ -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}
|
||||||
|
@ -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}
|
||||||
|
@ -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):
|
||||||
|
Loading…
Reference in New Issue
Block a user