1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 01:15:29 +03:00

compiling again with new capability scheme

This commit is contained in:
Bas Wijnen 2009-08-17 23:11:15 +02:00
parent 7b99ba0bdf
commit a892e9cfc0
21 changed files with 1616 additions and 2053 deletions

View File

@ -22,7 +22,7 @@ CC = $(CROSS)gcc
LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy
headers = kernel.hh iris.h $(arch_headers)
headers = kernel.hh iris.hh $(arch_headers)
iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
BUILT_SOURCES = $(iris_sources) $(boot_sources)

177
alloc.ccp
View File

@ -21,38 +21,38 @@
// Memory model used for kernel structure storage
// Each Memory object has several pointers, one for each type of objects it contains. These pointers are the start of double-linked lists.
// Each object also has a NEXT and PREV pointer, which point to the next and previous object in the same page. These pointers are 0 for the first (or last) object in a page. There is no pointer to the first object, it always starts at page_base + SIZE.
// The PREV/NEXT-list contains all objects in the page, including Free objects, in the order they appear in the page.
// The PREV/NEXT-list contains all objects in the page, including kFree objects, in the order they appear in the page.
// The prev/next-lists contain only objects of one type, unsorted.
// All pointers are to the start of the object. There is a header of size SIZE before it, containing NEXT and PREV.
#define PREV(x) (((Object **)(x))[-2])
#define NEXT(x) (((Object **)(x))[-1])
#define SIZE (2 * sizeof (Object *))
#define PREV(x) (((kObject **)(x))[-2])
#define NEXT(x) (((kObject **)(x))[-1])
#define SIZE (2 * sizeof (kObject *))
bool Memory::use (unsigned num):
bool kMemory::use (unsigned num):
// Go up to parents, incrementing used.
for Memory *m = this; m; m = m->address_space:
for kMemory *m = this; m; m = m->address_space:
if used + num > limit:
// Not allowed. Restore used for all children.
for Memory *r = this; r != m; r = r->address_space:
for kMemory *r = this; r != m; r = r->address_space:
r->used -= num
return false
m->used += num
return true
void Memory::unuse (unsigned num):
for Memory *m = this; m; m = m->address_space:
void kMemory::unuse (unsigned num):
for kMemory *m = this; m; m = m->address_space:
m->used -= num
// This allocates a new block of memory for use by the kernel.
// size is the requires size of the block (excluding SIZE)
// first is a pointer to the first object pointer of this type.
// The result is a block of size at least size, which is linked as an object in the list of first.
void *Memory::search_free (unsigned size, void **first):
Free *f
void *kMemory::search_free (unsigned size, void **first):
kFree *f
unsigned s = 0
// Let's see if there already is a Free chunk which is large enough.
for f = frees; f; f = (Free *)f->next:
// Let's see if there already is a kFree chunk which is large enough.
for f = frees; f; f = (kFree *)f->next:
if NEXT (f):
s = (unsigned)NEXT (f) - (unsigned)f
else:
@ -67,27 +67,27 @@ void *Memory::search_free (unsigned size, void **first):
if !p:
dbg_log ("no free space: kernel allocation failed")
return NULL
f = (Free *)(p + SIZE)
// Mark it as a Free object.
f = (kFree *)(p + SIZE)
// Mark it as a kFree object.
f->marker = ~0
// Link it in the Free list.
// Link it in the kFree list.
f->next = frees
f->prev = NULL
frees = f
if f->next:
((Free *)f->next)->prev = f
((kFree *)f->next)->prev = f
// There are no other objects in this page.
NEXT (f) = NULL
PREV (f) = NULL
// The size of this block is the entire page.
s = PAGE_SIZE
// We have a free block, possibly too large. The block is linked in frees, and in the page.
if s >= size + sizeof (Free) + 2 * SIZE:
if s >= size + sizeof (kFree) + 2 * SIZE:
// Create the new object at the end and keep the Free.
// f is the start of the free block
// f + (s - SIZE) is the end of the free block, compensated for the header of the next block.
// f + (s - SIZE) - size is the address where the new block should start.
Free *obj = (Free *)((unsigned)f + (s - SIZE) - size)
kFree *obj = (kFree *)((unsigned)f + (s - SIZE) - size)
// Link the new object in the page.
NEXT (obj) = NEXT (f)
if NEXT (obj):
@ -100,16 +100,16 @@ void *Memory::search_free (unsigned size, void **first):
// The block was only just large enough: turn it into a new type. It is already linked into the page.
// Unlink it from the free list.
if f->prev:
((Free *)f->prev)->next = f->next
((kFree *)f->prev)->next = f->next
else:
frees = (Free *)f->next
frees = (kFree *)f->next
if f->next:
((Free *)f->next)->prev = f->prev
((kFree *)f->next)->prev = f->prev
// f is now a block which is linked in the page, but not in any list. Link it into first.
f->next = (Free *)*first
f->next = (kFree *)*first
f->prev = NULL
if f->next:
((Free *)f->next)->prev = f
((kFree *)f->next)->prev = f
*first = f
// Set common initial values.
f->address_space = this
@ -117,45 +117,45 @@ void *Memory::search_free (unsigned size, void **first):
return f
// Free an object; it is still in its list, and it is still in the page list.
void Memory::free_obj (Object *obj, Pointer *first):
Free *self = (Free *)obj
void kMemory::free_obj (kObject *obj, kPointer *first):
kFree *self = (kFree *)obj
// Invalidate references.
while self->refs:
self->refs->invalidate ()
// Free it from its list.
if self->prev:
((Free *)self->prev)->next = self->next
((kFree *)self->prev)->next = self->next
else:
*(Pointer *)first = (Pointer)self->next
*(kPointer *)first = (kPointer)self->next
if self->next:
((Free *)self->next)->prev = self->prev
// Merge with previous, if it exists and is a Free.
((kFree *)self->next)->prev = self->prev
// Merge with previous, if it exists and is a kFree.
if PREV (self) && PREV (self)->is_free ():
self = (Free *)PREV (self)
self = (kFree *)PREV (self)
// Remove the object from the page list.
NEXT (self) = NEXT (obj)
if NEXT (self):
PREV (NEXT (self)) = self
else:
// The previous object is not a Free, so create a new one.
// The previous object is not a kFree, so create a new one.
// It is already linked in the page, but needs to be linked into the free list.
self->next = frees
self->prev = NULL
if self->next:
((Free *)self->next)->prev = self
((kFree *)self->next)->prev = self
frees = self
// Mark it as a Free.
// Mark it as a kFree.
self->marker = ~0
// Merge with next, if it exists and is a Free.
// Merge with next, if it exists and is a kFree.
if NEXT (self) && NEXT (self)->is_free ():
// Unlink the next from the frees list.
Free *n = (Free *)NEXT (self)
kFree *n = (kFree *)NEXT (self)
if n->prev:
((Free *)n->prev)->next = n->next
((kFree *)n->prev)->next = n->next
else:
frees = (Free *)n->next
frees = (kFree *)n->next
if n->next:
((Free *)n->next)->prev = n->prev
((kFree *)n->next)->prev = n->prev
// Unlink the next from the page list.
NEXT (self) = NEXT (NEXT (self))
if NEXT (self):
@ -163,29 +163,29 @@ void Memory::free_obj (Object *obj, Pointer *first):
// Free page if the resulting object is the only thing in it.
if !PREV (self) && !NEXT (self):
if self->next:
((Free *)self->next)->prev = self->prev
((kFree *)self->next)->prev = self->prev
if self->prev:
((Free *)self->prev)->next = self->next
((kFree *)self->prev)->next = self->next
else:
frees = (Free *)self->next
frees = (kFree *)self->next
pfree ((unsigned)self - SIZE)
Page *Memory::alloc_page ():
Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages)
kPage *kMemory::alloc_page ():
kPage *ret = (kPage *)search_free (sizeof (kPage), (void **)&pages)
if !ret:
return NULL
ret->frame = 0
ret->flags = 0
return ret
Thread *Memory::alloc_thread (unsigned size):
Thread *ret = (Thread *)search_free (sizeof (Thread) + (size - 1) * sizeof (CapsP), (void **)&threads)
kThread *kMemory::alloc_thread (unsigned size):
kThread *ret = (kThread *)search_free (sizeof (kThread) + (size - 1) * sizeof (kCapsP), (void **)&threads)
if !ret:
return NULL
ret->receivers = NULL
ret->pc = 0
ret->sp = 0
Thread_arch_init (ret)
kThread_arch_init (ret)
ret->flags = 0
ret->schedule_prev = NULL
ret->schedule_next = NULL
@ -194,16 +194,16 @@ Thread *Memory::alloc_thread (unsigned size):
ret->caps[i] = NULL
return ret
Message *Memory::alloc_message (Receiver *target):
Message *ret = (Message *)search_free (sizeof (Message), (void **)&target->messages)
kMessage *kMemory::alloc_message (kReceiver *target):
kMessage *ret = (kMessage *)search_free (sizeof (kMessage), (void **)&target->messages)
if !ret:
return NULL
if !ret->next:
target->last_message = ret
return ret
Receiver *Memory::alloc_receiver ():
Receiver *ret = (Receiver *)search_free (sizeof (Receiver), (void **)&receivers)
kReceiver *kMemory::alloc_receiver ():
kReceiver *ret = (kReceiver *)search_free (sizeof (kReceiver), (void **)&receivers)
if !ret:
return NULL
ret->owner = NULL
@ -216,19 +216,20 @@ Receiver *Memory::alloc_receiver ():
ret->last_message = NULL
ret->reply_protected_data = ~0
ret->protected_only = false
ret->queue_limit = 0
return ret
Caps *Memory::alloc_caps (unsigned size):
Caps *ret = (Caps *)search_free (sizeof (Caps) + (size - 1) * sizeof (Capability), (void **)&capses)
kCaps *kMemory::alloc_caps (unsigned size):
kCaps *ret = (kCaps *)search_free (sizeof (kCaps) + (size - 1) * sizeof (kCapability), (void **)&capses)
if !ret:
return NULL
ret->size = size
for unsigned i = 0; i < size; ++i:
ret->set (i, NULL, 0, CapRef (), NULL)
ret->set (i, NULL, 0, kCapRef (), NULL)
return ret
Memory *Memory::alloc_memory ():
Memory *ret = (Memory *)search_free (sizeof (Memory), (void **)&memories)
kMemory *kMemory::alloc_memory ():
kMemory *ret = (kMemory *)search_free (sizeof (kMemory), (void **)&memories)
if !ret:
return NULL
ret->frees = NULL
@ -239,57 +240,57 @@ Memory *Memory::alloc_memory ():
ret->memories = NULL
ret->limit = ~0
ret->used = 0
Memory_arch_init (ret)
kMemory_arch_init (ret)
return ret
void Caps::set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr):
void kCaps::set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr):
caps[index].target = target
caps[index].protected_data = pdata
caps[index].cap_protected = pdata
caps[index].parent = parent
caps[index].children.reset ()
caps[index].sibling_prev.reset ()
if parent:
caps[index].sibling_next = parent->children
parent->children = CapRef (this, index)
parent->children = kCapRef (this, index)
else:
if parent_ptr:
caps[index].sibling_next = *parent_ptr
*parent_ptr = CapRef (this, index)
*parent_ptr = kCapRef (this, index)
else:
caps[index].sibling_next.reset ()
if caps[index].sibling_next:
caps[index].sibling_next->sibling_prev = CapRef (this, index)
caps[index].sibling_next->sibling_prev = kCapRef (this, index)
void Caps::clone (unsigned index, CapRef source, bool copy):
void kCaps::clone (unsigned index, kCapRef source, bool copy):
if copy:
if source->parent:
set (index, source->target, source->protected_data, source->parent)
set (index, source->target, source->cap_protected, source->parent)
else if (unsigned)source->target & ~KERNEL_MASK:
set (index, source->target, source->protected_data, CapRef (), &source->target->capabilities)
set (index, source->target, source->cap_protected, kCapRef (), &source->target->capabilities)
else:
set (index, source->target, source->protected_data, CapRef (), &((Object *)source->protected_data)->refs)
set (index, source->target, source->cap_protected, kCapRef (), &((kObject *)source->cap_protected.l)->refs)
else:
set (index, source->target, source->protected_data, source)
set (index, source->target, source->cap_protected, source)
void Memory::free_page (Page *page):
if page->flags & PAGE_FLAG_PAYING:
void kMemory::free_page (kPage *page):
if page->flags & Page::PAYING:
unuse ()
if page->frame:
pfree (page->frame)
free_obj (page, (Pointer *)&pages)
free_obj (page, (kPointer *)&pages)
void Memory::free_thread (Thread *thread):
void kMemory::free_thread (kThread *thread):
thread->unrun ()
while thread->receivers:
thread->receivers->orphan ()
free_obj (thread, (void **)&threads)
void Memory::free_message (Receiver *owner, Message *message):
void kMemory::free_message (kReceiver *owner, kMessage *message):
if !message->next:
owner->last_message = (MessageP)message->prev
owner->last_message = (kMessageP)message->prev
free_obj (message, (void **)&owner->messages)
void Memory::free_receiver (Receiver *receiver):
void kMemory::free_receiver (kReceiver *receiver):
receiver->orphan ()
while receiver->capabilities:
receiver->capabilities->invalidate ()
@ -297,7 +298,7 @@ void Memory::free_receiver (Receiver *receiver):
free_message (receiver, receiver->messages)
free_obj (receiver, (void **)&receivers)
void Receiver::orphan ():
void kReceiver::orphan ():
if prev_owned:
prev_owned->next_owned = next_owned
else:
@ -306,7 +307,7 @@ void Receiver::orphan ():
next_owned->prev_owned = prev_owned
owner = NULL
void Receiver::own (Thread *o):
void kReceiver::own (kThread *o):
if owner:
orphan ()
owner = o
@ -315,7 +316,7 @@ void Receiver::own (Thread *o):
next_owned->prev_owned = this
o->receivers = this
void Capability::invalidate ():
void kCapability::invalidate ():
if !target:
return
if sibling_prev:
@ -323,17 +324,17 @@ void Capability::invalidate ():
else if (unsigned)target & ~KERNEL_MASK:
target->capabilities = sibling_next
else:
((Object *)protected_data)->refs = sibling_next
((kObject *)cap_protected.l)->refs = sibling_next
if sibling_next:
sibling_next->sibling_prev = sibling_prev
parent.reset ()
sibling_prev.reset ()
sibling_next.reset ()
Capability *c = this
kCapability *c = this
while c:
while c->children:
c = c->children.deref ()
Capability *next = c->sibling_next.deref ()
kCapability *next = c->sibling_next.deref ()
if !next:
next = c->parent.deref ()
c->target = NULL
@ -341,15 +342,15 @@ void Capability::invalidate ():
c->children.reset ()
c->sibling_prev.reset ()
c->sibling_next.reset ()
c->protected_data = 0
c->cap_protected = 0
c = next
void Memory::free_caps (Caps *c):
void kMemory::free_caps (kCaps *c):
for unsigned i = 0; i < c->size; ++i:
c->caps[i].invalidate ()
free_obj (c, (void **)&capses)
void Memory::free_memory (Memory *mem):
void kMemory::free_memory (kMemory *mem):
while mem->pages:
free_page (mem->pages)
while mem->capses:
@ -360,12 +361,12 @@ void Memory::free_memory (Memory *mem):
free_memory (mem->memories)
while mem->receivers:
free_receiver (mem->receivers)
Memory_arch_free (mem)
kMemory_arch_free (mem)
if mem->frees:
panic (0, "kernel memory leak: memory still in use")
free_obj (mem, (void **)&memories)
void Page::forget ():
void kPage::forget ():
if share_prev || share_next:
if share_prev:
share_prev->share_next = share_next
@ -375,8 +376,8 @@ void Page::forget ():
share_next = NULL
else:
// If the page has a frame and should be freed, free it.
if !((flags ^ PAGE_FLAG_FRAME) & (PAGE_FLAG_PHYSICAL | PAGE_FLAG_FRAME)):
if !((flags ^ Page::FRAME) & (Page::PHYSICAL | Page::FRAME)):
raw_pfree (frame)
frame = 0
flags &= ~(PAGE_FLAG_FRAME | PAGE_FLAG_SHARED | PAGE_FLAG_PHYSICAL | PAGE_FLAG_UNCACHED)
Page_arch_update_mapping (this)
flags &= ~(Page::FRAME | Page::SHARED | Page::PHYSICAL | Page::UNCACHED)
kPage_arch_update_mapping (this)

View File

@ -1,41 +0,0 @@
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.S: Startup code for initial Threads.
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
.globl __start
.globl __my_receiver
.globl __my_thread
.globl __my_memory
.globl __my_call
.globl __my_parent
.set noreorder
__start:
bal 1f
__hack_label:
nop
.word _gp
1:
lw $gp, 0($ra)
la $t9, main
la $ra, 1f
jr $t9
nop
1:
// This should not be reached: generate an address fault.
b 1b
lw $a0, -4($zero)

117
boot-programs/crt0.ccp Normal file
View File

@ -0,0 +1,117 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/init.S: Startup code for initial Threads.
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "iris.hh"
// For some unknown reason, gcc needs this to be defined.
unsigned __gxx_personality_v0
struct list:
list *prev, *next
static unsigned __slots, __caps
static list *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap
Receiver __my_receiver
Thread __my_thread
Memory __my_memory
Caps __my_caps
Cap __my_call
Cap __my_parent
Caps __tmp_caps
void free_slot (unsigned slot):
__slot_admin[slot].prev = NULL
__slot_admin[slot].next = __first_free_slot
if __slot_admin[slot].next:
__slot_admin[slot].next->prev = &__slot_admin[slot]
__first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap):
list *l = &__cap_admin[cap.idx ()]
l->prev = NULL
l->next = __first_free_cap
if l->next:
l->next->prev = l
__first_free_cap = l
unsigned alloc_slot ():
if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
return ~0
list *ret = __first_free_slot
__first_free_slot = ret->next
if ret->next:
ret->next->prev = NULL
unsigned alloc_cap ():
if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return NO_SLOT.
return ~0
list *ret = __first_free_cap
__first_free_cap = ret->next
if ret->next:
ret->next->prev = NULL
return ret - __slot_admin
extern "C":
void __main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
__slots = slots
__caps = caps
__slot_admin = slot_admin
__cap_admin = cap_admin
__first_free_slot = NULL
for unsigned i = 1; i < __slots; ++i:
free_slot (i)
__first_free_cap = NULL
for unsigned i = 7; i < __caps; ++i:
free_cap (Cap (0, i))
__my_receiver = Cap (0, __receiver_num)
__my_thread = Cap (0, __thread_num)
__my_memory = Cap (0, __memory_num)
__my_caps = Cap (0, __caps_num)
__my_call = Cap (0, __call_num)
__my_parent = Cap (0, __parent_num)
__tmp_caps = Cap (0, __tmp_num)
Num ret = start ()
__my_parent.invoke (~0, ret)
__my_memory.destroy (__my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
while true:
*(volatile unsigned *)~0
__asm__ volatile ("\t.globl __start\n"
"\t.set noreorder\n"
"__start:\n"
"\tbal 1f\n"
"__hack_label:\n"
"\tnop\n"
"\t.word _gp\n"
"1:\n"
"\tlw $gp, 0($ra)\n"
"\tsll $v0, $a0, 3\n"
"\tsll $v1, $a1, 3\n"
"\tsubu $sp, $sp, $v0\n"
"\tmove $a2, $sp\n"
"\tsubu $sp, $sp, $v1\n"
"\tmove $a3, $sp\n"
"\tla $t9, __main\n"
"\tjr $t9\n"
"\tnop\n"
"\t.set reorder")

View File

@ -19,7 +19,7 @@
#ifndef __IRIS_DEVICES_HH
#define __IRIS_DEVICES_HH
#include "iris.h"
#include "iris.hh"
// This shouldn't really be here. But where should it be?
// Requests made by initial threads to tell init about themselves.
@ -27,136 +27,150 @@ enum init_requests:
INIT_SET_GPIO
INIT_SET_LCD
// List interface.
template <typename _T> //
struct List : public Cap:
List (Cap c = Cap ()) : Cap (c):
// TODO
struct String : public Cap:
String (Cap c = Cap ()) : Cap (c):
// TODO
// Keyboard interface.
enum Keyboard_request:
KEYBOARD_SET_CB
KEYBOARD_GET_KEYS
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events.
static __inline__ void keyboard_set_cb (Capability kbd, Capability cb):
invoke_11 (kbd, cb, KEYBOARD_SET_CB)
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
#define KEYBOARD_RELEASE (1 << 31)
// Get a list of keys on this keyboard. The key codes start at zero with no gaps. The returned capability is a read-only list of strings.
static __inline__ void keyboard_get_keys (Capability target, Capability kbd):
call_c01 (kbd, target, KEYBOARD_GET_KEYS)
struct Keyboard : public Cap:
Keyboard (Cap c = Cap ()) : Cap (c):
enum request:
SET_CB
GET_KEYS
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
enum constant:
RELEASE = 1 << 31
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events.
void set_cb (Cap cb):
invoke (cb, CAP_MASTER_DIRECT | SET_CB)
// Get a list of keys on this keyboard. The key codes start at zero with no gaps.
void get_keys (List <String> ret):
call (ret, CAP_MASTER_DIRECT | GET_KEYS)
// Display interface.
// Startup: disp_set_eof_cb, disp_create_fb, disp_use_fb, disp_info
// Register an end-of-frame callback.
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
static __inline__ void display_set_eof_cb (Capability disp_set_eof_cb, Capability cb):
invoke_10 (disp_set_eof_cb, cb)
// Create a framebuffer for the display. When not in use, it can be freed by the user.
// The pages must be cappages holding Page capabilities. They are filled by the display.
// The passed numbers must be 0 or match a mode that the device can use.
// The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer.
static __inline__ unsigned display_create_framebuffer (Capability disp_create_fb, Capability page0, Capability page1 = 0, Capability page2 = 0, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
return call_n33 (disp_create_fb, page0, page1, page2, w, h, mode)
// Use a framebuffer. The address must have been returned from display_create_framebuffer.
// w, h and mode must match the values given at creation time.
// unuse_cb is called the next time this operation is requested.
static __inline__ void display_use_framebuffer (Capability disp_use_fb, unsigned addr, Capability unuse_cb, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
invoke_11 (disp_use_fb, unuse_cb, addr)
// Get information about the display.
static __inline__ void display_get_info (Capability disp_info):
// TODO: Interface is to be designed.
struct Display : public Cap:
Display (Cap c = Cap ()) : Cap (c):
enum request:
EOF_CB
CREATE_FB
USE_FB
GET_INFO
// Register an end-of-frame callback.
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
void set_eof_cb (Cap cb):
invoke (cb, CAP_MASTER_DIRECT | EOF_CB)
// Create a framebuffer for the display. When not in use, it can be freed by the user.
// The pages must be cappages holding Page capabilities. They are filled by the display.
// The passed numbers must be 0 or match a mode that the device can use.
// The returned number is the physical address of the framebuffer. It can be used with display_use_framebuffer.
unsigned create_framebuffer (Caps pages, unsigned w = 0, unsigned h = 0, unsigned mode = 0):
return call (pages, Num (CAP_MASTER_DIRECT | CREATE_FB, 0), Num ((w << 16) | h, mode)).l
// Use a framebuffer. The address must have been returned from display_create_framebuffer.
// w, h and mode must match the values given at creation time.
// unuse_cb is called the next time this operation is requested for this display.
void use_framebuffer (unsigned addr, Cap unuse_cb = Cap (), unsigned w = 0, unsigned h = 0, unsigned mode = 0):
invoke (unuse_cb, Num (CAP_MASTER_DIRECT | USE_FB, addr), Num ((w << 16) | h, mode))
// Get information about the display.
void get_info ():
// TODO: Interface is to be designed.
// File system interface.
// This may not be a server, so there need not be a startup phase. Instead, capabilities can implement certain interfaces: directory, file, stream, seekable file, mappable file. Normal files implement at least stream or seekable file. Directories implement directory.
enum File_request:
FILE_INFO
FILE_CLOSE
FILE_COPY_HANDLE
DIRECTORY_GET_SIZE
DIRECTORY_GET_NAME
DIRECTORY_GET_FILE
DIRECTORY_GET_FILE_INFO
DIRECTORY_CREATE_FILE
DIRECTORY_DELETE_FILE
FILE_STREAM_READ
FILE_STREAM_WRITE
FILE_SEEKABLE_READ
FILE_SEEKABLE_WRITE
FILE_SEEKABLE_TRUNCATE
// File interface.
// Get information about the file.
static __inline__ unsigned long long file_get_info (Capability file, unsigned type):
return call_l02 (file, FILE_INFO, type)
// Close a file. If this is a directory, it implicitly closes all files opened from it.
static __inline__ void file_close (Capability file):
invoke_01 (file, FILE_CLOSE)
// Copy a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
static __inline__ void file_copy_handle (Capability target, Capability file):
call_c01 (file, target, FILE_COPY_HANDLE)
// filesystem-related interfaces: file, directory, stream, seekable, mappable.
// Normal files implement at least stream or seekable file. Directories implement directory.
struct File : public Cap:
File (Cap c = Cap ()) : Cap (c):
enum request:
INFO
CLOSE
MAP_HANDLE
// Get information about the file.
Num get_info (unsigned type, Caps ret = Cap ()):
return call (ret, Num (CAP_MASTER_DIRECT | INFO, type))
// Close a file. If this is a directory, it implicitly closes all files opened from it.
void close ():
invoke (CAP_MASTER_DIRECT | CLOSE)
// Map a file handle. This can be useful for closing all children at once. The new handle itself is a child of the original handle.
File map_handle (File ret):
call (ret, CAP_MASTER_DIRECT | MAP_HANDLE)
// Directory interface.
// Get the number of entries in this directory.
static __inline__ unsigned long long directory_get_size (Capability dir):
return call_l01 (dir, DIRECTORY_GET_SIZE)
// Get the filename. The return value is the size of the string, the page is filled with the string itself.
static __inline__ unsigned directory_get_name (Capability dir, unsigned long long idx, Capability page):
return call_n13 (dir, page, DIRECTORY_GET_NAME, idx & 0xffffffff, idx >> 32)
// Get the file.
static __inline__ void directory_get_file (Capability target, Capability dir, unsigned long long idx, Capability page):
call_c03 (dir, target, DIRECTORY_GET_FILE, idx & 0xffffffff, idx >> 32)
// Get file info. This returns the same information as file_get_info, without opening the file.
static __inline__ unsigned long long directory_get_file_info (Capability dir, unsigned long long idx, unsigned type):
return call_l04 (dir, DIRECTORY_GET_FILE_INFO, idx & 0xffffffff, idx >> 32, type)
// Create a new file. After this, any index may map to a different file.
static __inline__ void directory_create_file (Capability target, Capability dir, unsigned long long idx, Capability page):
call_c03 (dir, target, DIRECTORY_CREATE_FILE, idx & 0xffffffff, idx >> 32)
// Delete a file. After this, any index may map to a different file.
static __inline__ void directory_delete_file (Capability target, Capability dir, unsigned long long idx, Capability page):
call_c03 (dir, target, DIRECTORY_DELETE_FILE, idx & 0xffffffff, idx >> 32)
struct Directory : public File:
Directory (Cap c = Cap ()) : File (c):
enum request:
GET_SIZE
GET_NAME
GET_FILE
GET_FILE_INFO
CREATE_FILE
DELETE_FILE
// Get the number of entries in this directory.
Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename. The return value is the size of the string, the page is filled with the string itself.
void get_name (Num idx, String target):
call (target, CAP_MASTER_DIRECT | GET_NAME, idx)
// Get the file.
void get_file (Num idx, File ret):
call (ret, CAP_MASTER_DIRECT | GET_FILE, idx)
// Get file info. This returns the same information as file_get_info, without opening the file.
Num get_file_info (Num idx, unsigned type, Caps ret = Cap ()):
return call (ret, Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
// Create a new file. After this, any index may map to a different file.
void create_file (String name, File ret):
call (ret, CAP_MASTER_DIRECT | CREATE_FILE)
// Delete a file. After this, any index may map to a different file.
void delete_file (Num idx):
invoke (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Stream interface.
// Try to read size bytes. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_stream_read (Capability file, Capability page, unsigned size):
return call_n12 (file, page, FILE_STREAM_READ, size)
// Try to write size bytes. Returns the number of bytes successfully written. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_stream_write (Capability file, Capability page, unsigned size):
return call_n12 (file, page, FILE_STREAM_WRITE, size)
struct Stream : public File:
Stream (Cap c = Cap ()) : File (c):
enum request:
READ
WRITE
// Try to read size bytes. Returns the number of bytes successfully read.
Num read (Num size, String ret):
return call (ret, CAP_MASTER_DIRECT | READ, size)
// Try to write size bytes. Returns the number of bytes successfully written.
Num write (String s, Num size):
return call (s, CAP_MASTER_DIRECT | WRITE, size)
// Seekable file interface.
// Try to read size bytes from position idx. Returns the number of bytes successfully read. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_seekable_read (Capability file, Capability page, unsigned long long idx, unsigned size):
return call_n14 (file, page, FILE_SEEKABLE_READ, idx & 0xffffffff, idx >> 32, size)
// Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written. It cannot be more than PAGE_SIZE.
static __inline__ unsigned file_seekable_write (Capability file, Capability page, unsigned long long idx, unsigned size):
return call_n14 (file, page, FILE_SEEKABLE_WRITE, idx & 0xffffffff, idx >> 32, size)
// Truncate file to size idx. The file is extended with zeroes if it gets longer.
static __inline__ void file_seekable_truncate (Capability file, unsigned long long idx):
call_n03 (file, FILE_SEEKABLE_TRUNCATE, idx & 0xffffffff, idx >> 32)
struct Seekable : public File:
Seekable (Cap c = Cap ()) : File (c):
enum request:
READ
WRITE
TRUNCATE
// Try to read size bytes from position idx. Returns the number of bytes successfully read.
Num read (Num idx, unsigned size, String ret):
return call (ret, Num (CAP_MASTER_DIRECT | READ, size), idx)
// Try to write size bytes at position idx; the file is extended with zeroes if the write is past the end. Returns the number of bytes successfully written.
Num write (Num idx, String s):
return call (s, CAP_MASTER_DIRECT | WRITE, idx)
// Truncate file to size idx. The file is extended with zeroes if it gets longer.
void truncate (Num idx):
invoke (CAP_MASTER_DIRECT | TRUNCATE, idx)
// Mappable file interface.
// TODO: to be designed.
struct Mappable : public Seekable:
Mappable (Cap c = Cap ()) : Seekable (c):
// TODO: to be designed.
// Block device interface.
// Startup: blk_get_size, blk_get_file.
// Get block size.
static __inline__ unsigned block_get_size (Capability blk_get_size):
return call_n00 (blk_get_size)
// Get file capability. Returns a seekable mappable non-stream file.
static __inline__ void block_get_file (Capability target, Capability blk_get_file):
call_c00 (blk_get_file, target)
struct Block_device : public Mappable:
Block_device (Cap c = Cap ()) : Mappable (c):
// TODO: to be designed.
// TODO.

View File

@ -58,14 +58,17 @@ enum cap_type:
CAP_TOUCHPAD
CAP_LOCKLEDS
CAP_PWM
NUM_EVENT_TYPES
static Caps events = Cap (0, 6)
static void event (event_type type, unsigned data):
invoke_01 (11 + type, data)
Cap (2, type - 32).invoke (data)
static void set_cb (event_type type):
capability_clone (11 + type, 6)
static void set_cb (Cap cap, event_type type):
cap.clone (events, type - 32)
class Keyboard:
class DevKeyboard:
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
unsigned keys[GPIO_KBD_NUM_COLS]
bool scanning
@ -74,7 +77,7 @@ class Keyboard:
if (data ^ keys[col]) & (1 << row):
unsigned code = encode[col][row]
if data & (1 << row):
code |= KEYBOARD_RELEASE
code |= Keyboard::RELEASE
event (KEYBOARD_EVENT, code)
keys[col] = data
// If any keys are pressed, scanning is required.
@ -127,7 +130,7 @@ class Keyboard:
gpio_irq_high (GPIO_KBD_ROW_PORT, i)
// Reenable interrupts.
GPIO_GPIER (GPIO_KBD_ROW_PORT) |= GPIO_KBD_ROW_MASK
Keyboard ():
DevKeyboard ():
// Set all columns to output without pull-ups when set as input.
GPIO_GPPUR (GPIO_KBD_COL_PORT) &= ~GPIO_KBD_COL_MASK
GPIO_GPDIR (GPIO_KBD_COL_PORT) |= GPIO_KBD_COL_MASK
@ -152,9 +155,9 @@ enum Keys:
ESC, INSERT, DELETE, BACKSPACE, PAUSE, FN, ZZZ, MENU, SYSRQ
LSHIFT, RSHIFT, CTRL, ALT
CAPS, NUM
NONE = ~0 & ~KEYBOARD_RELEASE
NONE = ~Keyboard::RELEASE
unsigned const Keyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
unsigned const DevKeyboard::encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS] = {
{ PAUSE, NONE, NONE, NONE, NONE, NONE, CTRL, F5 },
{ Q, TAB, A, ESC, Z, NONE, BACKQUOTE, N1 },
{ W, CAPS, S, EXTRA, X, NONE, NONE, N2 },
@ -251,61 +254,60 @@ class Pwm:
GPIO_GPDR (GPIO_PWM_ENABLE_PORT) &= ~(1 << GPIO_PWM_ENABLE)
// TODO: make it really work as a pwm instead of a switch; check if pwm1 is connected to anything.
int main ():
Num start ():
__my_memory.create_caps (NUM_EVENT_TYPES - 32).clone (__my_caps, 6)
map_gpio ()
map_pwm0 ()
Keyboard kbd
DevKeyboard kbd
Touchpad tp
Lockleds leds
Pwm pwm
// Enable interrupts. All are in port 0.
GPIO_GPIER (GPIO_KBD_ROW_PORT) = (1 << GPIO_TP_LEFT) | (1 << GPIO_TP_RIGHT) | GPIO_KBD_ROW_MASK
register_interrupt (IRQ_GPIO0)
Kernel::register_interrupt (IRQ_GPIO0)
Capability cap_kbd = 7
Capability cap_tp = 8
Capability cap_lockleds = 9
Capability cap_pwm = 10
receiver_create_capability (cap_kbd, __my_receiver, CAP_KEYBOARD)
receiver_create_capability (cap_tp, __my_receiver, CAP_TOUCHPAD)
receiver_create_capability (cap_lockleds, __my_receiver, CAP_LOCKLEDS)
receiver_create_capability (cap_pwm, __my_receiver, CAP_PWM)
Caps c (0, 7)
__my_memory.create_caps (4).clone (__my_caps, 7)
__my_receiver.create_capability (CAP_KEYBOARD).clone (c, 0)
__my_receiver.create_capability (CAP_TOUCHPAD).clone (c, 1)
__my_receiver.create_capability (CAP_LOCKLEDS).clone (c, 2)
__my_receiver.create_capability (CAP_PWM).clone (c, 3)
invoke_41 (__my_parent, cap_copy (cap_kbd), cap_copy (cap_tp), cap_copy (cap_lockleds), cap_copy (cap_pwm), INIT_SET_GPIO)
__my_parent.invoke (c, INIT_SET_GPIO)
if kbd.is_scanning ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
__my_receiver.set_alarm (ALARM_INTERVAL)
while true:
schedule ()
Message msg
wait (&msg, 6, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
switch msg.protected_data:
Kernel::schedule ()
Cap::OMessage msg
Kernel::wait (&msg)
switch (unsigned)msg.cap_protected.value ():
case ~0:
// Alarm.
kbd.scan ()
if kbd.is_scanning ():
receiver_set_alarm (__my_receiver, ALARM_INTERVAL)
__my_receiver.set_alarm (ALARM_INTERVAL)
break
case IRQ_GPIO0:
// Always scan keyboard and touchpad on any interrupt.
kbd.scan ()
tp.check_events ()
// Reregister the interrupt.
register_interrupt (IRQ_GPIO0)
Kernel::register_interrupt (IRQ_GPIO0)
break
case CAP_KEYBOARD:
set_cb (KEYBOARD_EVENT)
set_cb (Cap (__tmp_slot, 0), KEYBOARD_EVENT)
kbd.send_initial ()
break
case CAP_TOUCHPAD:
set_cb (TOUCHPAD_EVENT)
set_cb (Cap (__tmp_slot, 0), TOUCHPAD_EVENT)
tp.send_initial ()
break
case CAP_LOCKLEDS:
leds.set (msg.data[0])
leds.set (msg.data[0].l)
break
case CAP_PWM:
pwm.set_backlight (msg.data[0])
pwm.set_backlight (msg.data[0].l)
break

View File

@ -17,71 +17,70 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "devices.hh"
#include "iris.h"
#include "iris.hh"
static Capability kbd, tp, lockleds, pwm, lcd
static Keyboard kbd, tp
static Display lcd
static Cap lockleds, pwm
// Event types.
enum type:
KBD = 0x10000
TP
static void send (Capability c, unsigned d):
receiver_create_capability (6, __my_receiver, d)
invoke_10 (c, cap_copy (6))
static void setup ():
unsigned state = 0
Capability base = 7
unsigned slot = 2
while true:
Message msg
wait (&msg, base, base + 1, base + 2, base + 3)
switch msg.data[0]:
Cap::OMessage msg
Kernel::wait (&msg, slot)
switch msg.data[0].value ():
case INIT_SET_GPIO:
kdebug ("gpio\n")
kbd = base
tp = base + 1
lockleds = base + 2
pwm = base + 3
base += 4
kbd = Cap (slot, 0)
tp = Cap (slot, 1)
lockleds = Cap (slot, 2)
pwm = Cap (slot, 3)
++slot
++state
break
case INIT_SET_LCD:
kdebug ("lcd\n")
lcd = base
++base
lcd = Cap (slot, 0)
++slot
++state
break
if state == 2:
break
send (kbd, KBD)
send (tp, TP)
invoke_01 (pwm, 1)
kbd.set_cb (__my_receiver.create_capability (KBD).copy ())
tp.set_cb (__my_receiver.create_capability (TP).copy ())
pwm.invoke (1)
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
int main ():
Num start ():
// Set up lcd first
schedule ()
Kernel::schedule ()
kdebug ("start init\n")
setup ()
kdebug ("run init\n")
while true:
Message msg
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
switch msg.protected_data:
Cap::OMessage msg
Kernel::wait (&msg)
switch msg.cap_protected.value ():
case KBD:
unsigned code = msg.data[0]
if code & KEYBOARD_RELEASE:
unsigned code = msg.data[0].l
if code & Keyboard::RELEASE:
break
kdebug_char (decode_kbd[code])
break
case TP:
unsigned leds = 0
if msg.data[0] & 1:
if msg.data[0].l & 1:
leds |= 0x1
else:
leds |= 0x4
if !(msg.data[0] & 0x10000):
if !(msg.data[0].l & Keyboard::RELEASE):
leds |= 0x2
invoke_01 (lockleds, leds)
lockleds.invoke (leds)
break

View File

@ -102,36 +102,37 @@ static void log_str (char const *str):
while *str:
log_char (*str++)
static void log_num (unsigned n):
static void log_num (Num n):
char const *encode = "0123456789abcdef"
log_char ('[')
for unsigned i = 0; i < 8; ++i:
log_char (encode[(n >> (4 * (7 - i))) & 0xf])
log_char (encode[(n.h >> (4 * (7 - i))) & 0xf])
log_char (' ')
for unsigned i = 0; i < 8; ++i:
log_char (encode[(n.l >> (4 * (7 - i))) & 0xf])
log_char (']')
static void log_msg (Message *msg):
log_str ("prot:")
log_num (msg->protected_data)
static void log_msg (Cap::OMessage *msg):
log_str ("cap_prot:")
log_num (msg->cap_protected)
log_str ("data:")
for unsigned i = 0; i < 4; ++i:
for unsigned i = 0; i < 2; ++i:
log_num (msg->data[i])
log_str ("cap:")
for unsigned i = 0; i < 4; ++i:
log_num (msg->cap[i])
log_char ('\n')
int main ():
Num start ():
map_lcd ()
map_cpm ()
Descriptor descriptor __attribute__ ((aligned (16)))
unsigned pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
unsigned physical = alloc_range (__my_memory, pages)
unsigned physical = Kernel::alloc_range (__my_memory, pages)
assert (physical)
for unsigned i = 0; i < pages; ++i:
memory_create_page (6, __my_memory)
alloc_physical (6, physical + i * PAGE_SIZE, 0, 1)
memory_map (__my_memory, 6, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, 1)
Page p = __my_memory.create_page ()
p.alloc_physical (physical + i * PAGE_SIZE, false, true)
__my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + i * PAGE_SIZE, true)
free_cap (p)
for unsigned y = 0; y < 480; ++y:
unsigned g = (y << 6) / 480
unsigned olr = 0, ob = ((25 * y * y) << 5) / (9 * 800 * 800 + 25 * 480 * 480)
@ -148,8 +149,9 @@ int main ():
ob = b
b = 0x1f
LCD_FRAMEBUFFER_BASE[y * 800 + x] = (r << 11) | (g << 5) | (b)
memory_mapping (6, __my_memory, &descriptor)
unsigned physical_descriptor = page_physical_address (cap_copy (6)) + ((unsigned)&descriptor & ~PAGE_MASK)
Page p = __my_memory.mapping (&descriptor)
unsigned physical_descriptor = p.physical_address () + ((unsigned)&descriptor & ~PAGE_MASK)
free_cap (p)
descriptor.next = physical_descriptor
descriptor.frame = physical
descriptor.id = 0xdeadbeef
@ -158,30 +160,26 @@ int main ():
__asm__ volatile ("lw $a0, %0\ncache 0x15, 0($a0)" :: "m"(dptr) : "memory", "a0")
reset (physical_descriptor)
Capability eof_cb = 0
Cap set_eof_cb = __my_receiver.create_capability (LCD_EOF_CB)
__my_parent.invoke (set_eof_cb.copy (), INIT_SET_LCD)
receiver_create_capability (6, __my_receiver, LCD_EOF_CB)
invoke_11 (__my_parent, cap_copy (6), INIT_SET_LCD)
receiver_create_capability (15, __my_receiver, LCD_LOG)
__asm__ volatile ("li $a0, 1\nli $a1, 15\nbreak" ::: "a0", "a1", "memory")
Cap logcap = __my_receiver.create_capability (LCD_LOG)
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
unsigned slot = alloc_slot ()
while true:
Message msg
wait (&msg, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE, CAPABILITY_NONE)
Cap::OMessage msg
Kernel::wait (&msg, slot)
//log_msg (&msg)
switch msg.protected_data:
switch msg.cap_protected.value ():
case IRQ_LCD:
lcd_clr_eof ()
if eof_cb:
register_interrupt (IRQ_LCD)
invoke_00 (eof_cb)
Cap (slot, 0).invoke ()
Cap (slot, 0) = Cap ()
break
case LCD_EOF_CB:
eof_cb = msg.cap[0]
if eof_cb:
register_interrupt (IRQ_LCD)
Kernel::register_interrupt (IRQ_LCD)
break
case LCD_LOG:
log_char (msg.data[0])
log_char (msg.data[0].l)
break

File diff suppressed because it is too large Load Diff

1023
iris.h

File diff suppressed because it is too large Load Diff

514
iris.hhp Normal file
View File

@ -0,0 +1,514 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// iris.hhp: header file for userspace programs.
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef __IRIS_HHP
#define __IRIS_HHP
// Without the standard library, we don't have this definition.
// I preferred ((void*)0), but C++ has too strict type-checking to
// make that work.
#ifndef NULL
#define NULL 0
#endif
// Number of clock interrupts per second.
#define HZ 100
#define PAGE_BITS (12)
#define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1))
enum Exception_code:
NO_ERROR
ERR_WRITE_DENIED
ERR_UNMAPPED_READ
ERR_UNMAPPED_WRITE
ERR_INVALID_ADDRESS_READ
ERR_INVALID_ADDRESS_WRITE
ERR_RESERVED_INSTRUCTION
ERR_COPROCESSOR_UNUSABLE
ERR_OVERFLOW
ERR_TRAP
ERR_WATCHPOINT
ERR_BREAKPOINT
ERR_NO_PAGE_DIRECTORY
ERR_NO_PAGE_TABLE
ERR_OUT_OF_MEMORY
// The following are not raised, but returned.
ERR_INVALID_OPERATION
NUM_EXCEPTION_CODES
#ifndef NDEBUG
static const char *exception_name[NUM_EXCEPTION_CODES] = {
"no error",
"write denied",
"unmapped read",
"unmapped write",
"invalid address read",
"invalid address write",
"reserved instruction",
"coprocessor unusable",
"overflow",
"trap",
"watchpoint",
"breakpoint",
"no page directory",
"no page table",
"out of memory",
"invalid operation"
}
#endif
#define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
#define CAPTYPE_INVALID 0x000
#define CAPTYPE_RECEIVER 0x200
#define CAPTYPE_MEMORY 0x400
#define CAPTYPE_THREAD 0x600
#define CAPTYPE_PAGE 0x800
#define CAPTYPE_CAPS 0xa00
//#define CAPTYPE_??? 0xc00
//#define CAPTYPE_??? 0xe00
// All kernel capabilities have a master capability, which can create others.
#define CAP_MASTER 0
// Create, invoke and forget, with masked data set to 0.
#define CAP_MASTER_DIRECT 0
// Master capabilities can create others.
#define CAP_MASTER_CREATE (1 << 31)
struct Num:
unsigned l, h
Num (unsigned long long n = 0) : l (n), h (n >> 32):
Num (unsigned ll, unsigned hh) : l (ll), h (hh):
unsigned long long value () const:
return ((unsigned long long)h << 32) | l
unsigned &low ():
return l
unsigned &high ():
return h
unsigned const &low () const:
return l
unsigned const &high () const:
return h
// The start function has this prototype (there is no main function).
Num start ()
struct Cap
struct Caps
struct Receiver
struct Thread
struct Page
struct Memory
#define __receiver_num 0
#define __thread_num 1
#define __memory_num 2
#define __caps_num 3
#define __call_num 4
#define __parent_num 5
#define __tmp_num 6
// If this flag is set in a capability, it is copied instead of mapped.
// If it is set in the target capability, the Thread waits after the request.
#define CAP_COPY ((unsigned)0x80000000)
// This constant signifies that no capability is passed.
#define CAP_NONE (~CAP_COPY)
extern Receiver __my_receiver
extern Thread __my_thread
extern Memory __my_memory
extern Cap __my_call
extern Cap __my_parent
extern Caps __my_caps
extern Caps __tmp_caps
unsigned alloc_slot ()
unsigned alloc_cap ()
void free_slot (unsigned slot)
void free_cap (Cap cap)
#define __tmp_slot 1
struct Cap:
unsigned code
inline Cap copy () const
inline Cap ()
explicit inline Cap (unsigned c)
inline Cap (unsigned slot, unsigned idx)
inline unsigned slot () const
inline unsigned idx () const
struct IMessage
struct OMessage
inline void invoke (IMessage const *i, OMessage *o)
inline void call (IMessage *i, OMessage *o)
inline void invoke (Cap c, Num d0 = 0, Num d1 = 0, Caps caps = __tmp_caps)
inline void invoke (Num d0 = 0, Num d1 = 0)
inline Num call (Cap c, Num d0 = 0, Num d1 = 0, Caps caps = __tmp_caps, unsigned slot = ~0)
inline Num call (Num d0 = 0, Num d1 = 0, Caps caps = __tmp_caps, unsigned slot = ~0)
inline void clone (Caps caps, unsigned idx)
struct Caps : public Cap:
Caps (unsigned slot, unsigned idx) : Cap (slot, idx):
Caps (Cap c = Cap ()) : Cap (c):
struct Cap::IMessage:
Num data[2]
Caps caps
unsigned slot
unsigned num, first
Cap *set
struct Cap::OMessage:
Num data[2]
Num cap_protected
Num recv_protected
Cap Cap::copy () const:
return Cap (code | CAP_COPY)
Cap::Cap () : code (CAP_NONE):
Cap::Cap (unsigned c) : code (c):
Cap::Cap (unsigned slot, unsigned idx) : code (idx | (slot << 16)):
unsigned Cap::slot () const:
return code >> 16
unsigned Cap::idx () const:
return code & 0xffff
void Cap::invoke (IMessage const *i, OMessage *o):
switch i->num:
default:
__asm__ volatile ("lw $t9, %0" :: "m"(i->set[9].code) : "t9")
case 9:
__asm__ volatile ("lw $t8, %0" :: "m"(i->set[8].code) : "t8")
case 8:
__asm__ volatile ("lw $t7, %0" :: "m"(i->set[7].code) : "t7")
case 7:
__asm__ volatile ("lw $t6, %0" :: "m"(i->set[6].code) : "t6")
case 6:
__asm__ volatile ("lw $t5, %0" :: "m"(i->set[5].code) : "t5")
case 5:
__asm__ volatile ("lw $t4, %0" :: "m"(i->set[4].code) : "t4")
case 4:
__asm__ volatile ("lw $t3, %0" :: "m"(i->set[3].code) : "t3")
case 3:
__asm__ volatile ("lw $t2, %0" :: "m"(i->set[2].code) : "t2")
case 2:
__asm__ volatile ("lw $t1, %0" :: "m"(i->set[1].code) : "t1")
case 1:
__asm__ volatile ("lw $t0, %0" :: "m"(i->set[0].code) : "t0")
case 0:
break
__asm__ volatile ("lw $v0, %2\n"
"\tlw $a0, 0($v0)\n"
"\tlw $a1, 4($v0)\n"
"\tlw $a2, 8($v0)\n"
"\tlw $a3, 12($v0)\n"
"\tlw $s0, 16($v0)\n"
"\tlw $s1, 20($v0)\n"
"\tlw $s2, 24($v0)\n"
"\tlw $s3, 28($v0)\n"
"\tlw $v0, %1\n"
"\tsyscall\n"
"\tlw $v0, %0\n"
"\tsw $a0, 0($v0)\n"
"\tsw $a1, 4($v0)\n"
"\tsw $a2, 8($v0)\n"
"\tsw $a3, 12($v0)\n"
"\tsw $s0, 16($v0)\n"
"\tsw $s1, 20($v0)\n"
"\tsw $s2, 24($v0)\n"
"\tsw $s3, 28($v0)\n"
: "=m"(o)
: "m"(code), "m"(i)
: "memory", "v0", "s0", "s1", "s2", "s3", "a0", "a1", "a2", "a3")
void Cap::call (IMessage *i, OMessage *o):
i->set[0] = *this
__my_call.copy ().invoke (i, o)
void Cap::invoke (Cap c, Num d0, Num d1, Caps caps):
IMessage i
OMessage o
i.slot = ~0
i.caps = caps
Cap cs[2]
cs[0] = c
i.set = cs
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
void Cap::invoke (Num d0, Num d1):
IMessage i
OMessage o
i.caps = Cap ()
i.slot = ~0
i.num = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
Num Cap::call (Cap c, Num d0, Num d1, Caps caps, unsigned slot):
IMessage i
OMessage o
Cap cs[2]
cs[1] = c
i.set = cs
i.caps = caps
i.slot = slot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
return o.data[0]
Num Cap::call (Num d0, Num d1, Caps caps, unsigned slot):
IMessage i
OMessage o
Cap cs[2]
i.set = cs
i.caps = caps
i.slot = slot
i.num = 2
i.first = 0
i.data[0] = d0
i.data[1] = d1
invoke (&i, &o)
return o.data[0]
void Cap::clone (Caps caps, unsigned idx):
IMessage i
OMessage o
Cap c = this->copy ()
i.set = &c
i.caps = caps
i.first = idx
i.num = 1
i.slot = ~0
i.data[0] = 0
i.data[1] = 0
invoke (&i, &o)
struct Receiver : public Cap:
Receiver (unsigned slot, unsigned idx) : Cap (slot, idx):
Receiver (Cap c = Cap ()) : Cap (c):
enum request:
// Operations
SET_OWNER = 1
CREATE_CAPABILITY
CREATE_CALL_CAPABILITY
CREATE_ASYNC_CALL_CAPABILITY
GET_REPLY_PROTECTED_DATA
SET_REPLY_PROTECTED_DATA
GET_ALARM
SET_ALARM
ADD_ALARM
// Reply capability. This can only be created by invoking a CALL or CALL_ASYNC capability.
REPLY
// A call capability. This can only be created by invoking CREATE_CALL_CAPABILITY.
CALL
// A call capability, waiting for only this reply is disabled. This can only be created by invoking CREATE_CALL_ASYNC_CAPABILITY.
CALL_ASYNC
void set_owner (Cap owner):
invoke (owner, CAP_MASTER_DIRECT | Receiver::SET_OWNER)
Cap create_capability (unsigned protected_data, Cap ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
return ret
Num get_reply_protected_data ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
void set_reply_protected_data (Num data):
invoke (CAP_MASTER_DIRECT | SET_REPLY_PROTECTED_DATA, data)
unsigned get_alarm ():
return call (CAP_MASTER_DIRECT | GET_ALARM).l
unsigned add_alarm (unsigned data):
return call (CAP_MASTER_DIRECT | ADD_ALARM, data).l
void set_alarm (unsigned data):
invoke (CAP_MASTER_DIRECT | SET_ALARM, data)
static inline void sleep (unsigned value, OMessage *ret, unsigned slot = __tmp_slot)
Cap create_call_capability (Cap ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | CREATE_CALL_CAPABILITY)
return ret
Cap create_async_call_capability (Cap ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | CREATE_ASYNC_CALL_CAPABILITY)
return ret
struct Thread : public Cap:
Thread (unsigned slot, unsigned idx) : Cap (slot, idx):
Thread (Cap c = Cap ()) : Cap (c):
enum request:
// Info details are arch-specific.
GET_INFO = 1
SET_INFO
SCHEDULE
PRIV_ALLOC_RANGE
PRIV_PHYSICAL_ADDRESS
PRIV_ALLOC_PHYSICAL
PRIV_MAKE_PRIV
PRIV_GET_TOP_MEMORY
PRIV_REGISTER_INTERRUPT
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
SET_OWNER
// These get/set_info are not arch-specific.
enum info_type:
PC = ~0
SP = ~1
FLAGS = ~2
enum flags:
PRIV = 1 << 31
WAITING = 1 << 30
RUNNING = 1 << 29
USER_FLAGS = ~(PRIV | WAITING | RUNNING)
void make_priv ():
__my_thread.invoke (*this, CAP_MASTER_DIRECT | PRIV_MAKE_PRIV)
unsigned get_info (unsigned info):
return call (Num (CAP_MASTER_DIRECT | GET_INFO, info)).l
void set_info (unsigned info, unsigned value, unsigned mask = ~0):
invoke (Num (CAP_MASTER_DIRECT | SET_INFO, info), Num (value, mask))
void set_pc (unsigned pc):
set_info (PC, pc)
void set_sp (unsigned sp):
set_info (SP, sp)
void set_flags (unsigned value, unsigned mask):
set_info (FLAGS, value, mask)
unsigned get_pc ():
return get_info (PC)
unsigned get_sp ():
return get_info (SP)
unsigned get_flags ():
return get_info (FLAGS)
void run (bool run):
set_flags (run ? RUNNING : 0, RUNNING)
void wait (bool wait):
set_flags (wait ? WAITING : 0, WAITING)
struct Page : public Cap:
Page (unsigned slot, unsigned idx) : Cap (slot, idx):
Page (Cap c = Cap ()) : Cap (c):
enum request:
SHARE = 1
GET_FLAGS
SET_FLAGS
// Not an operation; a capability with this bit cannot write to the page.
READONLY = 8
enum share_detail:
// Operation details for PAGE_SHARE
// Forget the source page during the operation. This makes it a move.
FORGET
// Make the target independent of the source (make a copy if needed).
COPY
// Make the target unwritable.
//READONLY: use the value from request.
enum flag_values:
// This is a read-only flag, which is set if the Page is shared.
SHARED = 1
// When paying, the memory's use is incremented. If a frame is held, it cannot be lost. Frames are lost when the last payer forgets them.
PAYING = 2
// Set if this page has a frame associated with it. This flag is automatically reset if the frame is lost because of payment problems.
FRAME = 4
// A readonly page cannot be written to. This flag can not be reset while the frame is shared. The flag is already defined in request.
//READONLY = 8
// This is a read-only flag, saying if this is physical memory, which mustn't be freed.
PHYSICAL = 0x10
// This is a read-only flag, saying if this is uncachable memory.
UNCACHED = 0x20
void share (Cap target, unsigned flags):
invoke (target, CAP_MASTER_DIRECT | SHARE, flags)
unsigned get_flags ():
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
void set_flags (unsigned new_flags, unsigned mask):
invoke (CAP_MASTER_DIRECT | SET_FLAGS, Num (new_flags, mask))
unsigned physical_address ():
return __my_thread.call (*this, CAP_MASTER_DIRECT | Thread::PRIV_PHYSICAL_ADDRESS).l
void alloc_physical (unsigned address, bool cachable, bool freeable):
__my_thread.invoke (*this, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_PHYSICAL, (address & PAGE_MASK) | (cachable ? 1 : 0) | (freeable ? 2 : 0))
struct Memory : public Cap:
Memory (unsigned slot, unsigned idx) : Cap (slot, idx):
Memory (Cap c = Cap ()) : Cap (c):
enum request:
CREATE = 1
DESTROY
LIST
MAP
MAPPING
GET_LIMIT
SET_LIMIT
Page create_page (Page ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_PAGE))
return ret
Thread create_thread (unsigned slots, Thread ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_THREAD), slots)
return ret
Receiver create_receiver (Receiver ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_RECEIVER))
return ret
Memory create_memory (Memory ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_MEMORY))
return ret
Caps create_caps (unsigned size, Caps ret = Cap (0, alloc_cap ())):
call (ret, Num (CAP_MASTER_DIRECT | CREATE, CAPTYPE_CAPS), size)
return ret
void destroy (Cap target):
invoke (target, CAP_MASTER_DIRECT | DESTROY)
// TODO: LIST
void map (Cap page, unsigned address, bool readonly):
if readonly:
address |= Page::READONLY
invoke (page, CAP_MASTER_DIRECT | MAP, address)
Page mapping (void *address, Page ret = Cap (0, alloc_cap ())):
call (ret, CAP_MASTER_DIRECT | MAPPING, Num ((unsigned)address))
return ret
unsigned get_limit (unsigned limit):
return call (CAP_MASTER_DIRECT | GET_LIMIT).l
void set_limit (unsigned limit):
invoke (CAP_MASTER_DIRECT | SET_LIMIT, limit)
struct Kernel:
static void wait (Cap::OMessage *o, unsigned slot = __tmp_slot):
Cap::IMessage i
i.slot = slot
i.num = 0
Cap ().copy ().invoke (&i, o)
static void schedule ():
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::SCHEDULE)
static void register_interrupt (unsigned num):
__my_thread.invoke (__my_receiver, CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
static void unregister_interrupt (unsigned num):
__my_thread.invoke (CAP_MASTER_DIRECT | Thread::PRIV_REGISTER_INTERRUPT, num)
static Cap get_top_memory ():
__my_thread.call (__tmp_slot, CAP_MASTER_DIRECT | Thread::PRIV_GET_TOP_MEMORY)
return Cap (__tmp_slot, 0)
static unsigned alloc_range (Cap memory, unsigned pages):
__my_thread.call (memory, CAP_MASTER_DIRECT | Thread::PRIV_ALLOC_RANGE, pages)
void Receiver::sleep (unsigned value, OMessage *ret, unsigned slot):
__my_receiver.set_alarm (value)
Kernel::wait (ret, slot)
#if 1
// Use a define instead of an inline function, because this is better visible in disassembly, even when not optimizing.
#define kdebug_char(c) do { unsigned d = (c); __asm__ volatile ("move $a0, $zero\nlw $a1, %0\nbreak" :: "m"(d) : "a0", "a1", "memory"); } while (0)
#else
#define kdebug_char(c) do {} while (0)
#endif
#define kdebug(str) do { const char *s = (str); while (*s) { kdebug_char (*s); ++s; } } while (0)
static void kdebug_num (unsigned n):
unsigned i
const char *encode = "0123456789abcdef"
for i = 0; i < 8; ++i:
kdebug_char (encode[(n >> (4 * (7 - i))) & 0xf])
#endif

View File

@ -21,7 +21,7 @@
// Include definitions which are shared with user space.
#define __KERNEL
#include "iris.h"
#include "iris.hh"
// Normally define all variables in this file as extern.
// Exactly once (in data.ccp), EXTERN is predefined empty.
@ -30,145 +30,146 @@
#define EXTERN extern
#endif
struct Page
struct Thread
struct Message
struct Receiver
struct Capability
struct Caps
struct Memory
struct kPage
struct kThread
struct kMessage
struct kReceiver
struct kCapability
struct kCaps
struct kMemory
typedef Page *PageP
typedef Thread *ThreadP
typedef Message *MessageP
typedef Receiver *ReceiverP
typedef Capability *CapabilityP
typedef Caps *CapsP
typedef Memory *MemoryP
typedef void *Pointer
typedef kPage *kPageP
typedef kThread *kThreadP
typedef kMessage *kMessageP
typedef kReceiver *kReceiverP
typedef kCapability *kCapabilityP
typedef kCaps *kCapsP
typedef kMemory *kMemoryP
typedef void *kPointer
typedef unsigned Protected
struct CapRef:
CapsP caps
struct kCapRef:
kCapsP caps
unsigned index
inline Capability *deref ()
inline kCapability *deref ()
operator bool ():
return deref () != NULL
Capability *operator-> ():
kCapability *operator-> ():
return deref ()
void reset ():
caps = NULL
CapRef (CapsP c, unsigned i) : caps (c), index (i):
CapRef () : caps (NULL), index (~0):
inline void clone (CapRef source, bool copy)
inline void set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL)
kCapRef (kCapsP c, unsigned i) : caps (c), index (i):
kCapRef () : caps (NULL), index (~0):
inline void clone (kCapRef source, bool copy)
inline void set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
struct Object:
CapRef refs
MemoryP address_space
struct kObject:
kCapRef refs
kMemoryP address_space
// Next and previous object of the same type in any page.
Pointer prev, next
kPointer prev, next
inline bool is_free ()
struct Free : public Object:
struct kFree : public kObject:
// This marker is ~0. No other kernel structure may allow this value
// at this point. It is used to recognize free chunks.
unsigned marker
bool Object::is_free ():
return ((Free *)this)->marker == ~0
bool kObject::is_free ():
return ((kFree *)this)->marker == ~0
// Include architecture-specific parts.
#include "arch.hh"
struct Message : public Object:
Protected protected_data
unsigned data[4]
unsigned char capabilities[4]
struct kMessage : public kObject:
Num cap_protected
Num data[2]
kCapsP caps
struct Capability : public Object:
struct kCapability : public kObject:
struct Context:
unsigned data[4]
CapRef cap[4]
bool copy[4]
ReceiverP target
CapRef parent
CapRef children
CapRef sibling_prev, sibling_next
Protected protected_data
void invoke (Context *c)
Num data[2]
kCaps *caps
kReceiverP target
kCapRef parent
kCapRef children
kCapRef sibling_prev, sibling_next
Num cap_protected
inline void invoke (kCapability::Context *c)
void invalidate ()
struct Thread : public Object:
ReceiverP receivers
struct kThread : public kObject:
kReceiverP receivers
unsigned pc, sp
Thread_arch arch
kThread_arch arch
unsigned flags
ThreadP schedule_prev, schedule_next
CapRef rcaps[4]
// caps is an array of slots pointers to Capses.
kThreadP schedule_prev, schedule_next
unsigned recv_slot
// caps is an array of slots pointers to kCapses.
unsigned slots
// TODO: handle freeing of capses which are in use.
CapsP caps[1]
kCapsP caps[1]
void raise (unsigned code, unsigned data)
void run ()
void unrun ()
void wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3)
void wait ()
void unwait ()
bool is_waiting ():
return flags & THREAD_FLAG_WAITING
CapRef find_capability (unsigned code, bool *copy)
return flags & Thread::WAITING
kCapRef find_capability (unsigned code, bool *copy)
void fill_slot (unsigned slot, kCaps *new_caps)
struct Receiver : public Object:
ThreadP owner
ReceiverP prev_owned, next_owned
ReceiverP prev_alarm, next_alarm
struct kReceiver : public kObject:
kThreadP owner
kReceiverP prev_owned, next_owned
kReceiverP prev_alarm, next_alarm
unsigned alarm_count
// random is used like the tlb random register to find invalid caps to store the message to.
unsigned random
CapsP caps
kCapsP caps
// These are capabilities which call this receiver on invoke.
CapRef capabilities
// The message queue. Messages are added at the tail, and removed at the front.
MessageP messages
MessageP last_message
Protected reply_protected_data
kCapRef capabilities
// The message queue. kMessages are added at the tail, and removed at the front.
kMessageP messages
kMessageP last_message
Num recv_protected
Num reply_protected_data
bool protected_only
void own (ThreadP o)
// This limit is for messages stored in its address space. There is unlimited space if senders provide it.
unsigned queue_limit
void own (kThreadP o)
void orphan ()
bool try_deliver ()
bool send_message (Protected protected_data, Capability::Context *c)
bool send_message (Num cap_protected, kCapability::Context *c)
struct Page : public Object:
struct kPage : public kObject:
unsigned frame
unsigned flags
PageP share_first
PageP share_prev, share_next
Page_arch arch
kPageP share_first
kPageP share_prev, share_next
kPage_arch arch
void forget ()
struct Caps : public Object:
struct kCaps : public kObject:
unsigned size
Capability caps[1]
Capability *cap (unsigned idx):
kCapability caps[1]
kCapability *cap (unsigned idx):
return &caps[idx]
void set (unsigned index, Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr = NULL)
void clone (unsigned index, CapRef source, bool copy)
void set (unsigned index, kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
void clone (unsigned index, kCapRef source, bool copy)
struct Memory : public Object:
Free *frees
PageP pages
ThreadP threads
ReceiverP receivers
CapsP capses
MemoryP memories
struct kMemory : public kObject:
kFree *frees
kPageP pages
kThreadP threads
kReceiverP receivers
kCapsP capses
kMemoryP memories
unsigned limit, used
Memory_arch arch
kMemory_arch arch
inline bool map (Page *page, unsigned address, bool write)
inline void unmap (Page *page, unsigned address)
inline Page *get_mapping (unsigned address, bool *writable)
inline bool map (kPage *page, unsigned address, bool write)
inline void unmap (kPage *page, unsigned address)
inline kPage *get_mapping (unsigned address, bool *readonly)
// Allocation of pages.
bool use (unsigned num = 1)
@ -180,28 +181,28 @@ struct Memory : public Object:
// Allocation routines for kernel structures
void *search_free (unsigned size, void **first)
Page *alloc_page ()
Thread *alloc_thread (unsigned size)
Message *alloc_message (Receiver *target)
Receiver *alloc_receiver ()
Caps *alloc_caps (unsigned size)
Memory *alloc_memory ()
kPage *alloc_page ()
kThread *alloc_thread (unsigned size)
kMessage *alloc_message (kReceiver *target)
kReceiver *alloc_receiver ()
kCaps *alloc_caps (unsigned size)
kMemory *alloc_memory ()
void free_page (Page *page)
void free_thread (Thread *thread)
void free_message (Receiver *owner, Message *message)
void free_receiver (Receiver *receiver)
void free_caps (Caps *page)
void free_memory (Memory *mem)
void free_page (kPage *page)
void free_thread (kThread *thread)
void free_message (kReceiver *owner, kMessage *message)
void free_receiver (kReceiver *receiver)
void free_caps (kCaps *page)
void free_memory (kMemory *mem)
void free_obj (Object *obj, void **first)
void free_obj (kObject *obj, void **first)
// Functions which can be called from assembly must not be mangled.
extern "C":
// Panic. n is sent over caps led. message is currently ignored.
void panic_impl (unsigned n, unsigned line, char const *name, char const *message = "")
EXTERN unsigned dbg_code
EXTERN CapRef dbg_cap
EXTERN kCapRef dbg_cap
void dbg_log_char (unsigned ch)
void dbg_log (char const *str)
void dbg_log_num (unsigned num)
@ -212,46 +213,51 @@ extern "C":
void schedule ()
void timer_interrupt ()
EXTERN Memory top_memory
EXTERN ReceiverP first_alarm
EXTERN Thread idle
EXTERN Memory idle_memory
EXTERN Page idle_page
EXTERN ThreadP first_scheduled
EXTERN ThreadP current, old_current
EXTERN kMemory top_memory
EXTERN kReceiverP first_alarm
EXTERN kThread idle
EXTERN kMemory idle_memory
EXTERN kPage idle_page
EXTERN kThreadP first_scheduled
EXTERN kThreadP current, old_current
EXTERN bool do_schedule
// Defined in memory.cc
// Defined in memory.ccp
unsigned init_memory (unsigned mem)
unsigned raw_zalloc ()
void raw_pfree (unsigned page)
unsigned phys_alloc (unsigned num)
void phys_free (unsigned page, unsigned num)
// Defined by architecture-specific files.
void Thread_arch_init (Thread *thread)
void Thread_arch_receive (Thread *thread, Protected protected_data, unsigned *data)
unsigned *Thread_arch_info (Thread *thread, unsigned num)
void Memory_arch_init (Memory *mem)
void Memory_arch_free (Memory *mem)
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write)
void Memory_arch_unmap (Memory *mem, Page *page, unsigned address)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable)
void Page_arch_update_mapping (Page *page)
void arch_register_interrupt (unsigned num, ReceiverP r)
// Defind in invoke.ccp
void invoke (kReceiverP target, Num cap_protected, kCapability::Context *c, kCapability *self)
bool Memory::map (Page *page, unsigned address, bool write):
return Memory_arch_map (this, page, address, write)
void Memory::unmap (Page *page, unsigned address):
Memory_arch_unmap (this, page, address)
Page *Memory::get_mapping (unsigned address, bool *writable):
return Memory_arch_get_mapping (this, address, writable)
Capability *CapRef::deref ():
// Defined by architecture-specific files.
void kThread_arch_init (kThread *thread)
void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data)
unsigned *kThread_arch_info (kThread *thread, unsigned num)
void kMemory_arch_init (kMemory *mem)
void kMemory_arch_free (kMemory *mem)
bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool write)
void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address)
kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly)
void kPage_arch_update_mapping (kPage *page)
void arch_register_interrupt (unsigned num, kReceiverP r)
bool kMemory::map (kPage *page, unsigned address, bool write):
return kMemory_arch_map (this, page, address, write)
void kMemory::unmap (kPage *page, unsigned address):
kMemory_arch_unmap (this, page, address)
kPage *kMemory::get_mapping (unsigned address, bool *readonly):
return kMemory_arch_get_mapping (this, address, readonly)
kCapability *kCapRef::deref ():
return caps ? caps->cap (index) : NULL
void CapRef::clone (CapRef source, bool copy):
void kCapRef::clone (kCapRef source, bool copy):
caps->clone (index, source, copy)
void CapRef::set (Receiver *target, Protected pdata, CapRef parent, CapRef *parent_ptr):
void kCapRef::set (kReceiver *target, Num pdata, kCapRef parent, kCapRef *parent_ptr):
caps->set (index, target, pdata, parent, parent_ptr)
void kCapability::invoke (kCapability::Context *c):
::invoke (target, cap_protected, c, this)
#define assert(x) do { if (!(x)) panic (__LINE__, "assertion failed"); } while (0)

View File

@ -31,22 +31,22 @@ void phys_free (unsigned page, unsigned num):
#else
struct FreePages:
FreePages *prev, *next
struct kFreePages:
kFreePages *prev, *next
unsigned num
static FreePages *first_free
static kFreePages *first_free
unsigned init_memory (unsigned mem):
first_free = (FreePages *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
first_free = (kFreePages *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
first_free->prev = NULL
first_free->next = NULL
first_free->num = ((mem & PAGE_MASK) - ((unsigned)first_free - 0x80000000)) >> PAGE_BITS
return first_free->num
unsigned phys_alloc (unsigned num):
FreePages *choice = NULL
for FreePages *p = first_free; p; p = p->next:
kFreePages *choice = NULL
for kFreePages *p = first_free; p; p = p->next:
if p->num < num:
continue
if choice && choice->num < p->num:
@ -75,7 +75,7 @@ void phys_free (unsigned page, unsigned num):
unsigned size = num << PAGE_BITS
if !first_free || (unsigned)first_free > page:
// This is the first free block.
FreePages *n = (FreePages *)page
kFreePages *n = (kFreePages *)page
n->prev = NULL
if (unsigned)first_free == page + size:
// It fits exactly before the previous first free block.
@ -89,13 +89,13 @@ void phys_free (unsigned page, unsigned num):
if n->next:
n->next->prev = n
return
FreePages *p
kFreePages *p
for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
// Do nothing.
// The new block should be inserted directly after p.
if (unsigned)p->next == page + size:
// It can be merged with the block after it: do that.
FreePages *n = (FreePages *)page
kFreePages *n = (kFreePages *)page
n->prev = p
n->next = p->next->next
if n->next:
@ -115,7 +115,7 @@ void phys_free (unsigned page, unsigned num):
p->num += num
return
// The new block cannot be merged at all.
FreePages *n = (FreePages *)page
kFreePages *n = (kFreePages *)page
n->next = p->next
n->prev = p
if n->next:
@ -130,18 +130,18 @@ unsigned raw_zalloc ():
void raw_pfree (unsigned page):
return phys_free (page, 1)
unsigned Memory::zalloc ():
unsigned kMemory::zalloc ():
if !use ():
dbg_log ("limit reached: allocation not allowed")
return NULL
return raw_zalloc ()
void Memory::pfree (unsigned page):
void kMemory::pfree (unsigned page):
unuse ()
return raw_pfree (page)
unsigned Memory::palloc ():
unsigned kMemory::palloc ():
return zalloc ()
void Memory::zfree (unsigned page):
void kMemory::zfree (unsigned page):
pfree (page)

View File

@ -19,7 +19,7 @@
#define ARCH
#include "../kernel.hh"
void Thread_arch_init (Thread *thread):
void kThread_arch_init (kThread *thread):
thread->arch.at = 0
thread->arch.v0 = 0
thread->arch.v1 = 0
@ -45,14 +45,17 @@ void Thread_arch_init (Thread *thread):
thread->arch.k0 = 0
thread->arch.k1 = 0
void Thread_arch_receive (Thread *thread, unsigned protected_data, unsigned *data):
thread->arch.t0 = data[0]
thread->arch.t1 = data[1]
thread->arch.t2 = data[2]
thread->arch.t3 = data[3]
thread->arch.v0 = protected_data
void kThread_arch_receive (kThread *thread, Num cap_protected, Num recv_protected, Num *data):
thread->arch.a0 = data[0].l
thread->arch.a1 = data[0].h
thread->arch.a2 = data[1].l
thread->arch.a3 = data[1].h
thread->arch.s0 = cap_protected.l
thread->arch.s1 = cap_protected.h
thread->arch.s2 = recv_protected.l
thread->arch.s3 = recv_protected.h
unsigned *Thread_arch_info (Thread *thread, unsigned num):
unsigned *kThread_arch_info (kThread *thread, unsigned num):
switch num:
case 1:
return &thread->arch.at
@ -119,29 +122,29 @@ unsigned *Thread_arch_info (Thread *thread, unsigned num):
default:
return NULL
void Memory_arch_init (Memory *mem):
void kMemory_arch_init (kMemory *mem):
mem->arch.asid = 1
mem->arch.directory = NULL
mem->arch.shadow = NULL
void Memory_arch_free (Memory *mem):
void kMemory_arch_free (kMemory *mem):
while mem->arch.first_page_table:
mem->unmap (mem->arch.first_page_table->first_page->page, mem->arch.first_page_table->first_page->mapping)
if (Memory *)asids[mem->arch.asid] == mem:
if (kMemory *)asids[mem->arch.asid] == mem:
flush_tlb (mem->arch.asid)
asids[mem->arch.asid] = asids[0]
asids[0] = mem->arch.asid
mem->unuse ()
mem->zfree ((unsigned)mem->arch.directory)
static arch_page_table *alloc_page_table (Memory *mem):
static arch_page_table *alloc_page_table (kMemory *mem):
arch_page_table *ret = (arch_page_table *)mem->search_free (sizeof (arch_page_table), (void **)&mem->arch.first_page_table)
if !ret:
return NULL
ret->first_page = NULL
return ret
static arch_page *alloc_page (Memory *mem, arch_page_table *t):
static arch_page *alloc_page (kMemory *mem, arch_page_table *t):
arch_page *ret = (arch_page *)mem->search_free (sizeof (arch_page), (void **)&t->first_page)
if !ret:
return NULL
@ -152,7 +155,7 @@ static arch_page *alloc_page (Memory *mem, arch_page_table *t):
return ret
static void free_page_table (arch_page_table *t, unsigned idx):
Memory *mem = t->address_space
kMemory *mem = t->address_space
mem->zfree ((unsigned)mem->arch.directory[idx])
mem->arch.directory[idx] = NULL
mem->arch.shadow[idx] = NULL
@ -188,19 +191,19 @@ static void free_page (arch_page_table *t, arch_page *p):
if !t->first_page:
free_page_table (t, idx)
static unsigned make_entry_lo (Page *page, bool write):
static unsigned make_entry_lo (kPage *page, bool readonly):
if !page->frame:
return 0
unsigned flags
if page->flags & PAGE_FLAG_UNCACHED:
if page->flags & Page::UNCACHED:
flags = 0x10 | 0x2
else:
flags = 0x18 | 0x2
if write:
if !readonly:
flags |= 0x4
return ((page->frame & ~0x80000000) >> 6) | flags
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
bool kMemory_arch_map (kMemory *mem, kPage *page, unsigned address, bool readonly):
if address >= 0x80000000:
return false
address &= PAGE_MASK
@ -243,10 +246,10 @@ bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
return false
unsigned idx = (address >> 12) & ((1 << 9) - 1)
if table[idx]:
mem->unmap ((Page *)table[idx + 0x200], address)
table[idx] = make_entry_lo (page, write)
mem->unmap ((kPage *)table[idx + 0x200], address)
table[idx] = make_entry_lo (page, readonly)
table[idx + 0x200] = (unsigned)p
p->mapping = address + write
p->mapping = address + readonly
p->page = page
p->next_mapped = page->arch.first_mapped
if p->next_mapped:
@ -254,7 +257,7 @@ bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
page->arch.first_mapped = p
return true
void Memory_arch_unmap (Memory *mem, Page *page, unsigned address):
void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address):
unsigned didx = address >> 21
unsigned tidx = (address >> 12) & ((1 << 9) - 1)
unsigned *table = mem->arch.directory[didx]
@ -264,34 +267,34 @@ void Memory_arch_unmap (Memory *mem, Page *page, unsigned address):
table[tidx + 0x200] = 0
free_page (t, p)
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable):
kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly):
if address >= 0x80000000:
return NULL
unsigned *table = mem->arch.directory[address >> 21]
unsigned idx = (address >> 12) & ((1 << 9) - 1)
arch_page *page = (arch_page *)table[idx + 0x200]
if writable:
*writable = table[idx] & 4
if readonly:
*readonly = !(table[idx] & 4)
return page->page
void Page_arch_update_mapping (Page *page):
void kPage_arch_update_mapping (kPage *page):
if !page->arch.first_mapped:
return
Memory *as = page->address_space
unsigned target = make_entry_lo (page, page->flags & PAGE_FLAG_WRITABLE)
kMemory *as = page->address_space
unsigned target = make_entry_lo (page, page->flags & Page::READONLY)
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
bool readonly = p->mapping & 1
unsigned t
if p->mapping & 1:
t = target
else:
if readonly:
t = target & ~0x4
else:
t = target
as->arch.directory[de][te] = t
tlb_reset (p->mapping & ~1, as->arch.asid, t)
void arch_register_interrupt (unsigned num, Receiver *r):
void arch_register_interrupt (unsigned num, kReceiver *r):
arch_interrupt_receiver[num] = r
// And enable or disable the interrupt.
if r:

View File

@ -68,7 +68,7 @@
#endif
#ifdef __KERNEL
// register save positions in Thread
// register save positions in kThread
#define SAVE_PC (6 * 4)
#define SAVE_SP (SAVE_PC + 4)
#define SAVE_AT (SAVE_SP + 4)
@ -108,7 +108,7 @@
void flush_tlb (unsigned asid)
struct Thread_arch:
struct kThread_arch:
unsigned at, v0, v1, a0, a1, a2, a3
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
unsigned s0, s1, s2, s3, s4, s5, s6, s7
@ -122,41 +122,41 @@ struct Thread_arch:
// bits 12-20 are an index in the page table, bits 21-30
// are an index in the page directory and bit 31 is always 0.
struct arch_page : public Object :
Page *page
struct arch_page : public kObject :
kPage *page
unsigned mapping
arch_page *prev_mapped, *next_mapped
struct arch_page_table : public Object :
struct arch_page_table : public kObject :
arch_page *first_page
struct Page_arch:
struct kPage_arch:
arch_page *first_mapped
struct Memory_arch:
struct kMemory_arch:
unsigned asid
unsigned **directory
arch_page_table **shadow
arch_page_table *first_page_table
// Pointers to Memory when asid is taken, index of next free, or 0, if free.
// Pointers to kMemory when asid is taken, index of next free, or 0, if free.
// asid[0] is used as index to first free asid.
EXTERN unsigned asids[64]
EXTERN Receiver *arch_interrupt_receiver[32]
EXTERN kReceiverP arch_interrupt_receiver[32]
// Functions which can be called from assembly must not be mangled.
extern "C":
// Kernel entry points, called from entry.S.
Thread *interrupt ()
Thread *cache_error ()
Thread *exception ()
Thread *tlb_refill ()
kThread *interrupt ()
kThread *cache_error ()
kThread *exception ()
kThread *tlb_refill ()
#ifdef INIT
// Initialize most things (the rest is done in boot.S)
void init (unsigned mem)
// Start running the idle task for the first time.
void run_idle (Thread *self)
void run_idle (kThread *self)
#endif
// These are "extern", not "EXTERN", because they really are defined elsewhere.

View File

@ -30,7 +30,7 @@ static void init_idle ():
idle.schedule_next = NULL
idle.address_space = &idle_memory
idle.refs.reset ()
idle.flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
idle.flags = Thread::RUNNING | Thread::PRIV
// initialize idle_memory.
idle_memory.prev = NULL
idle_memory.next = NULL
@ -49,7 +49,7 @@ static void init_idle ():
idle_page.prev = NULL
idle_page.next = NULL
idle_page.frame = 0x80000000
idle_page.flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
idle_page.flags = Page::PAYING | Page::FRAME
idle_page.refs.reset ()
idle_page.address_space = NULL
current = &idle
@ -104,15 +104,15 @@ static void init_cp0 ():
// exceptions in the bootup code will fill EPC and friends.
static void init_threads ():
Thread *previous = NULL
kThread *previous = NULL
first_scheduled = NULL
first_alarm = NULL
Receiver *init_receiver = NULL
kReceiver *init_receiver = NULL
for unsigned i = 0; i < NUM_THREADS; ++i:
Memory *mem = top_memory.alloc_memory ()
kMemory *mem = top_memory.alloc_memory ()
assert (mem)
Thread *thread = mem->alloc_thread (3)
Page **pages = (Page **)mem->zalloc ()
kThread *thread = mem->alloc_thread (3)
kPage **pages = (kPage **)mem->zalloc ()
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
@ -139,7 +139,7 @@ static void init_threads ():
Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
continue
bool writable = shdr->sh_flags & SHF_WRITE
bool readonly = !(shdr->sh_flags & SHF_WRITE)
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
if shdr->sh_type != SHT_NOBITS:
unsigned file_offset = shdr->sh_offset >> PAGE_BITS
@ -152,18 +152,18 @@ static void init_threads ():
if !pages[idx]:
pages[idx] = mem->alloc_page ()
pages[idx]->frame = thread_start[i] + (idx << PAGE_BITS)
pages[idx]->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
pages[idx]->flags = Page::PAYING | Page::FRAME
++top_memory.limit
mem->use ()
if !mem->map (pages[idx], p, writable):
if !mem->map (pages[idx], p, readonly):
panic (0x22446688, "unable to map initial page")
return
else:
if !writable:
if readonly:
panic (0x33399993, "unwritable bss section")
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Page *page = mem->get_mapping (p, &writable)
kPage *page = mem->get_mapping (p, &readonly)
if !page:
page = mem->alloc_page ()
if !page:
@ -173,12 +173,12 @@ static void init_threads ():
if !page->frame:
panic (0x02220022, "out of memory");
return
page->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
page->flags = Page::PAYING | Page::FRAME
if !mem->map (page, p, true):
panic (0x33557799, "unable to map initial bss page")
return
else:
if !writable:
if readonly:
panic (0x20203030, "bss section starts on read-only page")
return
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
@ -192,28 +192,26 @@ static void init_threads ():
continue
++top_memory.limit
top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
Page *stackpage = mem->alloc_page ()
kPage *stackpage = mem->alloc_page ()
stackpage->frame = mem->zalloc ()
stackpage->flags = PAGE_FLAG_WRITABLE | PAGE_FLAG_PAYING | PAGE_FLAG_FRAME
stackpage->flags = Page::PAYING | Page::FRAME
if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
panic (0x13151719, "unable to map initial stack page")
return
thread->caps[0] = mem->alloc_caps (16)
for unsigned r = 0; r < 4; ++r:
thread->rcaps[r] = CapRef ()
Receiver *recv = mem->alloc_receiver ()
kReceiver *recv = mem->alloc_receiver ()
recv->owner = thread
thread->receivers = recv
thread->caps[0]->set (__my_receiver, (ReceiverP)(CAPTYPE_RECEIVER | CAP_RECEIVER_ALL_RIGHTS), (Protected)recv, CapRef ())
thread->caps[0]->set (__my_thread, (ReceiverP)(CAPTYPE_THREAD | CAP_THREAD_ALL_PRIV_RIGHTS), (Protected)thread, CapRef ())
thread->caps[0]->set (__my_memory, (ReceiverP)(CAPTYPE_MEMORY | CAP_MEMORY_ALL_RIGHTS), (Protected)mem, CapRef ())
thread->caps[0]->set (__my_call, (ReceiverP)(CAPTYPE_RECEIVER | (1 << CAP_RECEIVER_CALL)), (Protected)recv, CapRef ())
thread->flags = THREAD_FLAG_RUNNING | THREAD_FLAG_PRIV
thread->caps[0]->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->caps[0]->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Num ((unsigned)thread), kCapRef (), &thread->refs)
thread->caps[0]->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Num ((unsigned)mem), kCapRef (), &mem->refs)
thread->caps[0]->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Receiver::CALL), Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->flags = Thread::RUNNING | Thread::PRIV
if !i:
first_scheduled = thread
init_receiver = recv
else:
thread->caps[0]->set (__my_parent, init_receiver, i, CapRef ())
thread->caps[0]->set (__parent_num, init_receiver, i, kCapRef (), &init_receiver->capabilities)
previous->schedule_next = thread
thread->schedule_prev = previous
thread->schedule_next = NULL

View File

@ -29,7 +29,7 @@ static void handle_exit ():
schedule ()
if !current:
current = &idle
if (current->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) != THREAD_FLAG_RUNNING:
if (current->flags & (Thread::RUNNING | Thread::WAITING)) != Thread::RUNNING:
panic (current->flags, "non-scheduled thread running")
if !current:
current = &idle
@ -37,7 +37,7 @@ static void handle_exit ():
return
arch_flush_cache ()
if current != &idle:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if (kMemory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
@ -52,7 +52,7 @@ static void handle_exit ():
asids[current->address_space->arch.asid] = (unsigned)current->address_space
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
directory = current->address_space->arch.directory
if current->flags & THREAD_FLAG_PRIV:
if current->flags & Thread::PRIV:
cp0_set (CP0_STATUS, 0x1000ff13)
else:
cp0_set (CP0_STATUS, 0x0000ff13)
@ -60,7 +60,7 @@ static void handle_exit ():
/// A TLB miss has occurred. This is the slow version. It is only used
/// when k0 or k1 is not 0, or when an error occurs.
/// Otherwise, the ultra-fast code in entry.S is used.
Thread *tlb_refill ():
kThread *tlb_refill ():
old_current = current
if !directory:
unsigned addr
@ -85,7 +85,7 @@ Thread *tlb_refill ():
return current
/// An interrupt which is not an exception has occurred.
Thread *interrupt ():
kThread *interrupt ():
old_current = current
unsigned ipr = INTC_IPR
for unsigned i = 0; i < 32; ++i:
@ -98,11 +98,10 @@ Thread *interrupt ():
intc_ack_irq (i)
// Send message to interrupt handler.
if arch_interrupt_receiver[i]:
Capability::Context c
for unsigned j = 0; j < 4; ++j:
kCapability::Context c
for unsigned j = 0; j < 2; ++j:
c.data[j] = 0
c.cap[j].reset ()
c.copy[j] = false
c.caps = NULL
arch_interrupt_receiver[i]->send_message (i, &c)
arch_interrupt_receiver[i] = NULL
if ipr & (1 << IRQ_OST0):
@ -124,42 +123,49 @@ void flush_tlb (unsigned asid):
__asm__ volatile ("tlbwi")
static void arch_invoke ():
CapRef target
kCapRef target
bool wait
target = old_current->find_capability (old_current->arch.v0, &wait)
do_schedule = false
kCapability::Context msg
unsigned num = old_current->arch.s2
unsigned first = old_current->arch.s3
if num:
if num > 10:
num = 10
bool copy
if old_current->arch.s0 < old_current->slots:
msg.caps = old_current->caps[old_current->arch.s0]
if msg.caps && first < msg.caps->size:
for unsigned i = first; i < num && i < msg.caps->size; ++i:
msg.caps->cap (i)->invalidate ()
kCapRef t = old_current->find_capability ((&old_current->arch.t0)[i], &copy)
if t:
msg.caps->clone (i, t, copy)
else:
msg.caps = NULL
else:
msg.caps = NULL
if wait:
bool dummy
CapRef c0, c1, c2, c3
c0 = old_current->find_capability (old_current->arch.t4, &dummy)
c1 = old_current->find_capability (old_current->arch.t5, &dummy)
c2 = old_current->find_capability (old_current->arch.t6, &dummy)
c3 = old_current->find_capability (old_current->arch.t7, &dummy)
old_current->wait (c0, c1, c2, c3)
old_current->recv_slot = old_current->arch.s1
old_current->wait ()
if !target:
if (old_current->arch.v0 & ~CAPABILITY_COPY) != ~CAPABILITY_COPY:
if (old_current->arch.v0 & ~CAP_COPY) != ~CAP_COPY:
panic (old_current->arch.v0, "debug")
// There must be no action here.
return
Capability::Context c
c.cap[0] = old_current->find_capability (old_current->arch.a0, &c.copy[0])
c.cap[1] = old_current->find_capability (old_current->arch.a1, &c.copy[1])
c.cap[2] = old_current->find_capability (old_current->arch.a2, &c.copy[2])
c.cap[3] = old_current->find_capability (old_current->arch.a3, &c.copy[3])
c.data[0] = old_current->arch.t0
c.data[1] = old_current->arch.t1
c.data[2] = old_current->arch.t2
c.data[3] = old_current->arch.t3
target->invoke (&c)
msg.data[0] = Num (old_current->arch.a0, old_current->arch.a1)
msg.data[1] = Num (old_current->arch.a2, old_current->arch.a3)
target->invoke (&msg)
if do_schedule && !wait:
// If the call was to schedule without wait, it isn't done yet.
schedule ()
else if old_current != current && (old_current->flags & (THREAD_FLAG_RUNNING | THREAD_FLAG_WAITING)) == THREAD_FLAG_RUNNING:
else if old_current != current && (old_current->flags & (Thread::RUNNING | Thread::WAITING)) == Thread::RUNNING:
// If the caller received an immediate reply from the kernel, it is no longer set as current. Don't let it lose its timeslice.
current = old_current
/// A general exception has occurred.
Thread *exception ():
kThread *exception ():
old_current = current
unsigned cause
cp0_get (CP0_CAUSE, cause)
@ -288,7 +294,7 @@ Thread *exception ():
return current
/// There's a cache error. Big trouble. Probably not worth trying to recover.
Thread *cache_error ():
kThread *cache_error ():
panic (0x33333333, "cache error")
old_current = current
handle_exit ()

View File

@ -136,13 +136,13 @@
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000)
// Map IO memory (requires a priviledged __my_thread capability).
#include <iris.h>
#include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping):
memory_create_page (6, __my_memory)
// 0 means not cachable; 0 means don't free when done.
alloc_physical (6, physical, 0, 0)
// 1 means writable.
memory_map (__my_memory, 6, mapping, 1)
Page p = __my_memory.create_page ()
// false means not cachable; false means don't free when done.
p.alloc_physical (physical, 0, 0)
// true means writable.
__my_memory.map (p, mapping, true)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
@ -2323,9 +2323,9 @@ static __inline__ void udelay (unsigned us):
GPIO_GPDR (0) = GPIO_GPDR (0)
#ifndef __KERNEL
static __inline__ void ddelay (unsigned ds):
Message m
my_sleep (ds, &m)
static __inline__ void cdelay (unsigned ds):
__my_receiver.set_alarm (ds * (HZ / 100))
Cap ().call (~0)
#endif
/***************************************************************************
@ -3034,9 +3034,7 @@ static __inline__ void i2c_open ():
// Note that this kills messages from the queue.
static __inline__ void i2c_close ():
Message msg
receiver_set_alarm (__my_receiver, 3 * HZ / 10)
call_00 (0)
cdelay (30)
i2c_disable ()
static __inline__ bool i2c_send (unsigned data):

View File

@ -24,11 +24,10 @@ void dbg_log_char (unsigned ch):
if !dbg_cap:
return
Capability::Context c
for unsigned i = 0; i < 4; ++i:
c.cap[i].reset ()
c.copy[i] = false
c.data[i] = 0
c->recv_memory = NULL
c->caps = NULL
c.data[0] = ch
c.data[1] = 0
dbg_cap->invoke (&c)
if dbg_cap->target->owner:
current = dbg_cap->target->owner

3
plan
View File

@ -1,6 +1,5 @@
kernel capabilities: 1 per aktie; bevat code in plaats van bitmask. CREATE ipv DEGRADE.
activation address in receiver
protected data in receiver
message: a0-a3: data0; data1; protectedL; protectedH
caps is stored in designated (by receiver) slot
caps zonder size limit?
invoke ipc: try sync; try receiver memory; try caller memory; fail.

View File

@ -18,14 +18,14 @@
#include "kernel.hh"
static void run_thread (Thread *thread):
static void run_thread (kThread *thread):
thread->schedule_next = first_scheduled
if thread->schedule_next:
thread->schedule_next->schedule_prev = thread
thread->schedule_prev = NULL
first_scheduled = thread
static void unrun_thread (Thread *thread):
static void unrun_thread (kThread *thread):
if current == thread:
current = thread->schedule_next
if thread->schedule_prev:
@ -35,35 +35,34 @@ static void unrun_thread (Thread *thread):
if thread->schedule_next:
thread->schedule_next->schedule_prev = thread->schedule_prev
void Thread::run ():
if flags & THREAD_FLAG_RUNNING:
void kThread::run ():
if flags & Thread::RUNNING:
return
flags |= THREAD_FLAG_RUNNING
flags |= Thread::RUNNING
if is_waiting ():
return
run_thread (this)
void Thread::unrun ():
if !(flags & THREAD_FLAG_RUNNING):
void kThread::unrun ():
if !(flags & Thread::RUNNING):
return
flags &= ~THREAD_FLAG_RUNNING
flags &= ~Thread::RUNNING
if is_waiting ():
return
unrun_thread (this)
void Thread::unwait ():
flags &= ~THREAD_FLAG_WAITING
if flags & THREAD_FLAG_RUNNING:
void kThread::unwait ():
flags &= ~Thread::WAITING
if flags & Thread::RUNNING:
run_thread (this)
static void alarm_tick (Receiver *recv):
static void alarm_tick (kReceiver *recv):
if !recv->alarm_count:
// Send message and stop counting.
Capability::Context c
for unsigned i = 0; i < 4; ++i:
kCapability::Context c
c.caps = NULL
for unsigned i = 0; i < 2; ++i:
c.data[i] = 0
c.cap[i].reset ()
c.copy[i] = false
recv->send_message (~0, &c)
if recv->prev_alarm:
recv->prev_alarm->next_alarm = recv->next_alarm
@ -74,16 +73,12 @@ static void alarm_tick (Receiver *recv):
// Fall through to let alarm_count be ~0. This is required, because it is the indicator for no running alarm.
--recv->alarm_count
void Thread::wait (CapRef c0, CapRef c1, CapRef c2, CapRef c3):
if flags & THREAD_FLAG_RUNNING:
void kThread::wait ():
if flags & Thread::RUNNING:
unrun_thread (this)
flags |= THREAD_FLAG_WAITING
rcaps[0] = c0
rcaps[1] = c1
rcaps[2] = c2
rcaps[3] = c3
// Try to receive a message from a Receiver immediately.
for Receiver *r = receivers; r; r = r->next_owned:
flags |= Thread::WAITING
// Try to receive a message from a kReceiver immediately.
for kReceiver *r = receivers; r; r = r->next_owned:
if r->try_deliver ():
return
@ -94,8 +89,8 @@ void schedule ():
current = first_scheduled
void timer_interrupt ():
Receiver *recv, *next
kReceiver *recv, *next
for recv = first_alarm; recv; recv = next:
next = (Receiver *)recv->next
next = (kReceiver *)recv->next
alarm_tick (recv)
//schedule ()