1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-01 03:11:05 +03:00
This commit is contained in:
Bas Wijnen 2009-05-25 00:31:35 +02:00
parent 12320ef8df
commit 27d9e596ad
14 changed files with 780 additions and 190 deletions

View File

@ -14,9 +14,9 @@ boot_sources = init.cc
BUILT_SOURCES = $(kernel_sources) $(boot_sources)
PYPP = /usr/bin/pypp
%.cc: %.ccp kernel.hh
%.cc: %.ccp
$(PYPP) --name $< < $< > $@
%.hh: %.hhp
%.hh: %.hhp boot-programs/sos.h
$(PYPP) --name $< < $< > $@
# Transform ':' into ';' so vim doesn't think there are errors.
@ -28,12 +28,12 @@ arch.hh: mips.hh
arch.cc: mips.cc
ln -s $< $@ || true
%.o:%.cc Makefile kernel.hh arch.hh
%.o:%.cc Makefile kernel.hh arch.hh boot-programs/sos.h
$(CC) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
entry.o: thread0 thread1
%.o:%.S Makefile
%.o:%.S Makefile arch.hh
$(CC) $(CPPFLAGS) -DKERNEL_STACK_SIZE=0x2000 -c $< -o $@
%: boot-helper.o boot-programs/%.o
@ -52,6 +52,6 @@ junk = mdebug.abi32 reginfo comment pdr
gzip < $< > $@
clean:
rm -f all uimage *.o all.raw.gz arch.hh arch.cc
rm -f all uimage *.o boot-programs/*.o all.raw.gz arch.hh arch.cc
.PHONY: clean

119
alloc.ccp
View File

@ -1,21 +1,24 @@
#pypp 0
#include "kernel.hh"
#define PREV(x) (((Object_base **)(x))[-2])
#define NEXT(x) (((Object_base **)(x))[-1])
#define SIZE (2 * sizeof (unsigned))
bool Memory::use ():
// Go up to parents, incrementing used.
Memory *m
for m = this; m; m = m->parent:
for Memory *m = this; m; m = m->address_space:
if used >= limit:
// Not allowed. Restore used for all children.
for Memory *r = this; r != m; r = r->parent:
for Memory *r = this; r != m; r = r->address_space:
--r->used
return false
++m->used
return true
void Memory::unuse ():
--used
return parent->unuse ()
for Memory *m = this; m; m = m->address_space:
--m->used
unsigned Memory::palloc ():
if !use ():
@ -56,34 +59,35 @@ void *Memory::search_free (unsigned size, void **first):
Free *f
unsigned s = 0
for f = frees; f; f = f->next:
if f->next_obj:
s = (unsigned)f->next_obj - (unsigned)f
if NEXT (f):
s = (unsigned)NEXT (f) - (unsigned)f
else:
s = PAGE_SIZE - ((unsigned)f & ~PAGE_MASK)
if s >= size:
s = PAGE_SIZE - ((unsigned)f & ~PAGE_MASK) + SIZE
if s >= size + SIZE:
break
if !f:
f = (Free *)palloc ()
if !f:
unsigned p = palloc ()
if !p:
return NULL
f = (Free *)(p + SIZE)
f->marker = ~0
f->next = frees
f->prev = NULL
frees = f
if f->next:
f->next->prev = f
f->next_obj = NULL
f->prev_obj = NULL
NEXT (f) = NULL
PREV (f) = NULL
s = PAGE_SIZE
// We have a free block, possibly too large.
if s >= size + sizeof (Free):
if s >= size + sizeof (Free) + SIZE:
// Create the new object at the end and keep the Free.
Free *obj = (Free *)((unsigned)f + s - size)
obj->next_obj = f->next_obj
if obj->next_obj:
obj->next_obj->prev_obj = obj
obj->prev_obj = f
f->next_obj = obj
Free *obj = (Free *)((unsigned)f + s - size - SIZE)
NEXT (obj) = NEXT (f)
if NEXT (obj):
PREV (NEXT (obj)) = obj
PREV (obj) = f
NEXT (f) = obj
f = obj
else:
if f->prev:
@ -92,6 +96,8 @@ void *Memory::search_free (unsigned size, void **first):
frees = f->next
if f->next:
f->next->prev = f->prev
f->address_space = this
f->refs = NULL
f->next = (Free *)*first
f->prev = NULL
if f->next:
@ -99,36 +105,36 @@ void *Memory::search_free (unsigned size, void **first):
*first = f
return f
void Object_base::free_obj (Memory *parent):
void Memory::free_obj (Object_base *obj):
Free *self
// Merge with previous, if it exists and is a Free.
if prev_obj && prev_obj->is_free ():
self = (Free *)prev_obj
self->next_obj = next_obj
if next_obj:
next_obj->prev_obj = self
if PREV (obj) && PREV (obj)->is_free ():
self = (Free *)PREV (obj)
NEXT (self) = NEXT (obj)
if NEXT (obj):
PREV (NEXT (obj)) = self
else:
self = (Free *)this
self->next = parent->frees
self = (Free *)obj
self->next = frees
self->prev = NULL
if self->next:
self->next->prev = self
parent->frees = self
frees = self
self->marker = ~0
// Merge with next, if it exists and is a Free.
if self->next_obj && self->next_obj->is_free ():
self->next_obj = self->next_obj->next_obj
if self->next_obj:
self->next_obj->prev_obj = self
if NEXT (self) && NEXT (self)->is_free ():
NEXT (self) = NEXT (NEXT (self))
if NEXT (self):
PREV (NEXT (self)) = self
// Free page if the resulting object is the only thing in it.
if !self->prev_obj && !self->next_obj:
if !PREV (self) && !NEXT (self):
if self->next:
self->next->prev = self->prev
if self->prev:
self->prev->next = self->next
else:
parent->frees = self->next
parent->pfree ((unsigned)self)
frees = self->next
pfree ((unsigned)(self - SIZE))
Page *Memory::alloc_page ():
Page *ret = (Page *)search_free (sizeof (Page), (void **)&pages)
@ -145,6 +151,7 @@ Thread *Memory::alloc_thread ():
ret->pc = 0
ret->sp = 0
Thread_arch_init (ret)
ret->flags = 0
ret->schedule_prev = NULL
ret->schedule_next = NULL
ret->receivers = NULL
@ -171,19 +178,27 @@ Receiver *Memory::alloc_receiver ():
ret->messages = NULL
return ret
Capability *Memory::alloc_capability (Receiver *target, Capability **parent, unsigned protected_data):
Capability *ret = (Capability *)search_free (sizeof (Capability), (void **)&capabilities)
Capability *Memory::alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret):
if !ret:
return NULL
ret = (Capability *)search_free (sizeof (Capability), (void **)&capabilities)
if !ret:
return NULL
ret->target = target
ret->parent = parent
ret->children = NULL
ret->sibling_prev = NULL
ret->sibling_next = parent ? *parent : NULL
ret->sibling_next = parent_ptr ? *parent_ptr : NULL
if ret->sibling_next:
ret->sibling_next->sibling_prev = ret
ret->protected_data = protected_data
return ret
Capability *Memory::clone_capability (Capability *source, bool copy, Capability *ret):
if copy:
return alloc_capability (source->target, source->parent, source->parent ? &source->parent->children : &source->target->capabilities, source->protected_data, ret)
else:
return alloc_capability (source->target, source, &source->children, source->protected_data, ret)
Cappage *Memory::alloc_cappage ():
Cappage *ret = (Cappage *)search_free (sizeof (Cappage), (void **)&cappages)
if !ret:
@ -198,7 +213,6 @@ Memory *Memory::alloc_memory ():
Memory *ret = (Memory *)search_free (sizeof (Memory), (void **)&memories)
if !ret:
return NULL
ret->parent = this
ret->frees = NULL
ret->pages = NULL
ret->threads = NULL
@ -218,7 +232,7 @@ void Memory::free_page (Page *page):
unuse ()
if page->physical:
pfree (page->physical)
page->free_obj (this)
free_obj (page)
void Memory::free_thread (Thread *thread):
if thread->prev:
@ -236,12 +250,12 @@ void Memory::free_thread (Thread *thread):
thread->schedule_next->schedule_prev = thread->schedule_prev
while thread->receivers:
thread->receivers->orphan ()
thread->free_obj (this)
free_obj (thread)
void Memory::free_message (Message *message):
for unsigned i = 0; i < 4; ++i:
free_capability (message->capabilities[i])
message->free_obj (this)
free_obj (message)
void Memory::free_receiver (Receiver *receiver):
receiver->orphan ()
@ -249,7 +263,7 @@ void Memory::free_receiver (Receiver *receiver):
receiver->capabilities->invalidate ()
while receiver->messages:
free_message (receiver->messages)
receiver->free_obj (this)
free_obj (receiver)
void Receiver::orphan ():
if prev_owned:
@ -271,7 +285,7 @@ void Receiver::own (Thread *o):
void Memory::free_capability (Capability *capability):
capability->invalidate ()
capability->free_obj (this)
free_obj (capability)
void Capability::invalidate ():
if sibling_prev:
@ -280,20 +294,15 @@ void Capability::invalidate ():
target->capabilities = sibling_next
if sibling_next:
sibling_next->sibling_prev = sibling_prev
// The sibling_prev link is used here to point to the parent.
// This method is used to avoid recursion.
sibling_prev = NULL
Capability *c = this
while c->children:
c->children->sibling_prev = c
c = c->children
while c:
Capability *next = c->sibling_next
if !next:
next = c->sibling_prev
if next:
next->sibling_prev = c->sibling_prev
next = c->parent
c->target = NULL
c->parent = NULL
c->children = NULL
c->sibling_prev = NULL
c->sibling_next = NULL
@ -304,7 +313,7 @@ void Memory::free_cappage (Cappage *p):
for unsigned i = 0; i < CAPPAGE_SIZE; ++i:
p->page[i].invalidate ()
zfree ((unsigned)p->page)
p->free_obj (this)
free_obj (p)
void Memory::free_memory (Memory *mem):
if mem->prev:
@ -320,4 +329,4 @@ void Memory::free_memory (Memory *mem):
while mem->memories:
free_memory (mem->memories)
Memory_arch_free (mem)
mem->free_obj (this)
free_obj (mem)

View File

@ -26,3 +26,4 @@ __start:
.comm __top_memory, 4
.comm __my_memory, 4
.comm __my_admin, 4
.comm __my_call, 4

View File

@ -7,6 +7,7 @@ extern "C" {
#define KERNEL_MASK 0xfff
#define CAPTYPE_MASK 0xe00
#define REQUEST_MASK (KERNEL_MASK & ~CAPTYPE_MASK)
#define CAPTYPE_ADMIN 0x000
#define CAPTYPE_RECEIVER 0x200
#define CAPTYPE_MEMORY 0x400
@ -26,30 +27,259 @@ extern "C" {
#define CAP_RECEIVER_SET_OWNER 1
#define CAP_RECEIVER_CREATE_CAPABILITY 2
#define CAP_RECEIVER_CREATE_CALL_CAPABILITY 3
/* Not an operation; a capability with this bit set is a call capability. */
#define CAP_RECEIVER_CALL 4
#define CAP_MEMORY_CREATE 1
#define CAP_MEMORY_DESTROY 2
#define CAP_MEMORY_LIST 3
#define CAP_MEMORY_MAPPING 4
#define CAP_MEMORY_DROP 5
#define CAP_MEMORY_SET_LIMIT 5
#define CAP_MEMORY_GET_LIMIT 6
#define CAP_MEMORY_DROP 7
#define CAP_THREAD_RUN 1
#define CAP_THREAD_RUN_CONDITIONAL 2
#define CAP_THREAD_SLEEP 3
#define CAP_THREAD_GET_INFO 4 /* Details of this are arch-specific. */
#define CAP_THREAD_SET_INFO 5 /* Details of this are arch-specific. */
#define CAP_THREAD_GET_INFO 2 /* Details of this are arch-specific. */
#define CAP_THREAD_SET_INFO 3 /* Details of this are arch-specific. */
/* Flag values for processor state */
#define THREAD_FLAG_WAITING 0x80000000
#define THREAD_FLAG_RUNNING 0x40000000
#define CAP_PAGE_MAP 1
#define CAP_PAGE_SHARE 2
#define CAP_PAGE_SHARE_COW 3
#define CAP_PAGE_FORGET 4
// Not an operation; a capability without this bit cannot write to the page. */
#define CAP_PAGE_WRITE 5
#define CAP_CAPABILITY_GET 1
#define CAP_CAPABILITY_SET_DEATH_NOTIFY 2
#define CAPPAGE_SIZE 113
#define CAP_CAPPAGE_SET 1
#define CAP_CAPPAGE_GET 2
#define CAPPAGE_SIZE 102
/* Cappage has page's operations as well. */
#define CAP_CAPPAGE_SET 6
#ifndef __KERNEL
typedef unsigned __Capability;
extern __Capability __my_receiver;
extern __Capability __my_admin;
extern __Capability __my_memory;
extern __Capability __my_call;
__Capability __cap_copy (__Capability src)
{
return src | 2;
}
typedef struct __Message
{
unsigned data[4];
__Capability cap[4];
} __Message;
static int __invoke (__Capability target, __Message *msg)
{
register int ret __asm__ ("v0");
register unsigned v0 __asm__ ("v0") = target;
register unsigned a0 __asm__ ("a0") = msg->cap[0];
register unsigned a1 __asm__ ("a1") = msg->cap[1];
register unsigned a2 __asm__ ("a2") = msg->cap[2];
register unsigned a3 __asm__ ("a3") = msg->cap[3];
register unsigned t0 __asm__ ("t0") = msg->data[0];
register unsigned t1 __asm__ ("t1") = msg->data[1];
register unsigned t2 __asm__ ("t2") = msg->data[2];
register unsigned t3 __asm__ ("t3") = msg->data[3];
__asm__ volatile ("syscall" : "+r" (v0), "=r" (a0), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (t0), "=r" (t1), "=r" (t2), "=r" (t3));
return ret;
}
static int __call (__Capability target, __Message *msg)
{
register int ret __asm__ ("v0");
register unsigned v0 __asm__ ("v0") = target;
register unsigned a0 __asm__ ("a0") = msg->cap[0];
register unsigned a1 __asm__ ("a1") = msg->cap[1];
register unsigned a2 __asm__ ("a2") = msg->cap[2];
register unsigned a3 __asm__ ("a3") = msg->cap[3];
register unsigned t0 __asm__ ("t0") = msg->data[0];
register unsigned t1 __asm__ ("t1") = msg->data[1];
register unsigned t2 __asm__ ("t2") = msg->data[2];
register unsigned t3 __asm__ ("t3") = msg->data[3];
__asm__ volatile ("syscall" : "+r" (v0), "+r" (a0), "+r" (a1), "+r" (a2), "+r" (a3), "+r" (t0), "+r" (t1), "+r" (t2), "+r" (t3));
msg->cap[0] = a0;
msg->cap[1] = a1;
msg->cap[2] = a2;
msg->cap[3] = a3;
msg->data[0] = t0;
msg->data[1] = t1;
msg->data[2] = t2;
msg->data[3] = t3;
return ret;
}
static int __invoke_01 (__Capability t, unsigned d)
{
__Message msg;
int ret;
msg.data[0] = d;
return __invoke (t, &msg);
}
static int __invoke_02 (__Capability t, unsigned d0, unsigned d1)
{
__Message msg;
int ret;
msg.data[0] = d0;
msg.data[1] = d1;
return __invoke (t, &msg);
}
static int __invoke_11 (__Capability t, __Capability c, unsigned d)
{
__Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d;
return __invoke (t, &msg);
}
static int __invoke_12 (__Capability t, __Capability c, unsigned d0, unsigned d1)
{
__Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
return __invoke (t, &msg);
}
static __Capability __call_c01 (__Capability c, unsigned d)
{
__Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d;
ret = __call (__my_call, &msg);
return ret ? msg.cap[0] : 0;
}
static __Capability __call_c02 (__Capability c, unsigned d0, unsigned d1)
{
__Message msg;
int ret;
msg.cap[0] = c;
msg.data[0] = d0;
msg.data[1] = d1;
ret = __call (__my_call, &msg);
return ret ? msg.cap[0] : 0;
}
static __Capability __degrade (__Capability src, unsigned mask)
{
return __call_c02 (src, CAP_DEGRADE, mask);
}
static void __schedule ()
{
__invoke_01 (__my_admin, CAP_ADMIN_SCHEDULE);
}
static int __receiver_set_owner (__Capability receiver, __Capability owner)
{
return __invoke_11 (receiver, owner, CAP_RECEIVER_SET_OWNER);
}
static __Capability __receiver_create_capability (__Capability receiver, unsigned protected_data)
{
return __call_c02 (receiver, CAP_RECEIVER_CREATE_CAPABILITY, protected_data);
}
static __Capability __receiver_create_call_capability (__Capability receiver, unsigned protected_data)
{
return __call_c02 (receiver, CAP_RECEIVER_CREATE_CALL_CAPABILITY, protected_data);
}
static __Capability __memory_create (__Capability memory, unsigned type)
{
return __call_c02 (memory, CAP_MEMORY_CREATE, type);
}
static __Capability __memory_create_page (__Capability memory)
{
return __memory_create (memory, CAPTYPE_PAGE);
}
static __Capability __memory_create_thread (__Capability memory)
{
return __memory_create (memory, CAPTYPE_THREAD);
}
static __Capability __memory_create_receiver (__Capability memory)
{
return __memory_create (memory, CAPTYPE_RECEIVER);
}
static __Capability __memory_create_memory (__Capability memory)
{
return __memory_create (memory, CAPTYPE_MEMORY);
}
static __Capability __memory_create_cappage (__Capability memory)
{
return __memory_create (memory, CAPTYPE_CAPPAGE);
}
static int __memory_destroy (__Capability memory, __Capability target)
{
return __invoke_11 (memory, target, CAP_MEMORY_DESTROY);
}
/* TODO: #define CAP_MEMORY_LIST 3 */
static __Capability __memory_mapping (__Capability memory, unsigned address)
{
return __call_c02 (memory, CAP_MEMORY_MAPPING, address);
}
static void __drop (__Capability cap)
{
__invoke_11 (__my_memory, cap, CAP_MEMORY_DROP);
}
static int __thread_run (__Capability thread, int run)
{
return __invoke_02 (thread, CAP_THREAD_RUN, run);
}
/* TODO:
#define CAP_THREAD_GET_INFO 4
#define CAP_THREAD_SET_INFO 5
*/
/* TODO: all except map should also work for cappages.
#define CAP_PAGE_MAP 1
#define CAP_PAGE_SHARE 2
#define CAP_PAGE_SHARE_COW 3
#define CAP_PAGE_FORGET 4
*/
static __Capability __capability_get (__Capability cap)
{
return __call_c01 (cap, CAP_CAPABILITY_GET);
}
static int __capability_set_death_notify (__Capability source, __Capability target)
{
return __invoke_11 (source, target, CAP_CAPABILITY_SET_DEATH_NOTIFY);
}
static int __capability_cappage_set (__Capability page, __Capability cap, unsigned index)
{
return __invoke_12 (page, cap, CAP_CAPPAGE_SET, index);
}
#endif
#ifdef __cplusplus
}

51
entry.S
View File

@ -4,50 +4,9 @@
.globl run_idle
.set noat
#define Index 0
#define Random 1
#define EntryLo0 2
#define EntryLo1 3
#define BadVAddr 8
#define EntryHi 10
#define Status 12
#define EPC 14
// register save positions in Thread
#define SAVE_PC (5 * 4)
#define SAVE_SP (SAVE_PC + 4)
#define SAVE_AT (SAVE_SP + 4)
#define SAVE_V0 (SAVE_AT + 4)
#define SAVE_V1 (SAVE_V0 + 4)
#define SAVE_A0 (SAVE_V1 + 4)
#define SAVE_A1 (SAVE_A0 + 4)
#define SAVE_A2 (SAVE_A1 + 4)
#define SAVE_A3 (SAVE_A2 + 4)
#define SAVE_T0 (SAVE_A3 + 4)
#define SAVE_T1 (SAVE_T0 + 4)
#define SAVE_T2 (SAVE_T1 + 4)
#define SAVE_T3 (SAVE_T2 + 4)
#define SAVE_T4 (SAVE_T3 + 4)
#define SAVE_T5 (SAVE_T4 + 4)
#define SAVE_T6 (SAVE_T5 + 4)
#define SAVE_T7 (SAVE_T6 + 4)
#define SAVE_T8 (SAVE_T7 + 4)
#define SAVE_T9 (SAVE_T8 + 4)
#define SAVE_S0 (SAVE_T9 + 4)
#define SAVE_S1 (SAVE_S0 + 4)
#define SAVE_S2 (SAVE_S1 + 4)
#define SAVE_S3 (SAVE_S2 + 4)
#define SAVE_S4 (SAVE_S3 + 4)
#define SAVE_S5 (SAVE_S4 + 4)
#define SAVE_S6 (SAVE_S5 + 4)
#define SAVE_S7 (SAVE_S6 + 4)
#define SAVE_GP (SAVE_S7 + 4)
#define SAVE_FP (SAVE_GP + 4)
#define SAVE_RA (SAVE_FP + 4)
#define SAVE_HI (SAVE_RA + 4)
#define SAVE_LO (SAVE_HI + 4)
#define SAVE_K0 (SAVE_LO + 4)
#define SAVE_K1 (SAVE_K0 + 4)
#define ARCH
#define ASM
#include "arch.hh"
addr_000:
// TLB refill
@ -105,7 +64,7 @@ start_idle: // 288
// TODO: save only fragile registers now, the rest on task switch.
kernel_exit:
lw $k0, SAVE_PC($v0)
mtc0 $k0, $EPC
mtc0 $k0, $CP0_EPC
lw $k0, SAVE_LO($v0)
lw $k1, SAVE_HI($v0)
mtlo $k0
@ -190,7 +149,7 @@ save_regs:
mflo $v1
sw $v0, SAVE_HI($k0)
sw $v1, SAVE_LO($k0)
mfc0 $k1, $EPC
mfc0 $k1, $CP0_EPC
sw $k1, SAVE_PC($k0)
lw $gp, -0xd84($zero)

View File

@ -7,18 +7,17 @@
static void init_idle ():
// initialize idle task as if it is currently running.
idle.prev_obj = NULL
idle.next_obj = NULL
idle.prev = NULL
idle.next = NULL
idle.schedule_prev = NULL
idle.schedule_next = NULL
idle.address_space = &idle_memory
idle.refs = NULL
// initialize idle_memory.
idle_memory.prev_obj = NULL
idle_memory.next_obj = NULL
idle_memory.prev = NULL
idle_memory.next = NULL
idle_memory.address_space = NULL
idle_memory.refs = NULL
idle_memory.pages = &idle_page
idle_memory.threads = &idle
idle_memory.memories = NULL
@ -27,11 +26,11 @@ static void init_idle ():
idle_memory.arch.directory = (unsigned **)0x80000000
idle_memory.arch.asid = 0
// initialize idle_page
idle_page.prev_obj = NULL
idle_page.next_obj = NULL
idle_page.prev = NULL
idle_page.next = NULL
idle_page.physical = 0x80000000
idle_page.refs = NULL
idle_page.address_space = NULL
current = &idle
static void init_cp0 ():
@ -148,9 +147,10 @@ static void init_threads ():
thread->arch.a0 = (unsigned)mem->alloc_receiver ()
thread->arch.a1 = (unsigned)&top_memory
thread->arch.a2 = (unsigned)mem
Capability *admin = mem->alloc_capability ((Receiver *)(CAPTYPE_ADMIN | ~PAGE_MASK), &mem->capabilities, ~0)
Capability *admin = mem->alloc_capability ((Receiver *)(CAPTYPE_ADMIN | ~PAGE_MASK), NULL, &mem->capabilities, ~0)
thread->arch.a3 = (unsigned)admin
mem->pfree ((unsigned)pages)
thread->flags = THREAD_FLAG_RUNNING
thread->schedule_next = NULL
thread->schedule_prev = previous
if previous:
@ -169,10 +169,10 @@ void init ():
runners = NULL
zero_pages = NULL
// Fill junk pages with all memory not currently used.
junk_pages = (FreePage *)(((unsigned)&_end + (1 << 12) - 1) & ~((1 << 12) - 1))
junk_pages = (FreePage *)(((unsigned)&_end + ~PAGE_MASK) & PAGE_MASK)
FreePage *p, *next
unsigned count = 1
for p = junk_pages, next = p; (unsigned)next - 0x80000000 < (1 << 27); p = next, next = (FreePage *)((unsigned)p + (1 << 12)):
for p = junk_pages, next = p; (unsigned)next - 0x80000000 < (1 << 27); p = next, next = (FreePage *)((unsigned)p + ~PAGE_MASK + 1):
p->next = next
++count
p->next = NULL
@ -181,11 +181,10 @@ void init ():
// initialize everything about the idle task.
init_idle ()
// initialize top_memory.
top_memory.prev_obj = NULL
top_memory.next_obj = NULL
top_memory.prev = NULL
top_memory.next = NULL
top_memory.parent = NULL
top_memory.address_space = NULL
top_memory.refs = NULL
top_memory.pages = NULL
top_memory.threads = NULL
top_memory.memories = NULL

View File

@ -28,7 +28,7 @@ Thread *tlb_refill ():
/// An interrupt which is not an exception has occurred.
Thread *interrupt ():
panic (0x88877722)
panic (0x88877722, "Interrupt")
unsigned cause
cp0_get (CP0_CAUSE, cause)
for unsigned i = 0; i < 8; ++i:
@ -48,21 +48,15 @@ Thread *exception ():
cp0_get (CP0_CAUSE, cause)
switch (cause >> 2) & 0x1f:
case 0:
// Interrupt.
panic (0x11223344, "Interrupt.")
// Interrupt. This shouldn't happen, since CAUSE[IV] == 1.
panic (0x11223344, "Interrupt on exception vector.")
case 1:
// TLB modification.
panic (0x21223344, "TLB modification.")
case 2:
//unsigned a
//cp0_get (CP0_EPC, a)
//panic (a)
// TLB load or instruction fetch.
panic (0x31223344, "TLB load or instruction fetch.")
case 3:
unsigned a
cp0_get (CP0_EPC, a)
panic (a)
// TLB store.
panic (0x41223344, "TLB store.")
case 4:
@ -88,7 +82,6 @@ Thread *exception ():
panic (0x91223344, "Breakpoint.")
case 10:
// Reserved instruction.
panic ((*(unsigned *)0x004000b0) + 1)
panic (0xa1223344, "Reserved instruction.")
case 11:
// Coprocessor unusable.

View File

@ -1,14 +1,283 @@
#pypp 0
#include "kernel.hh"
Capability *Memory::find_capability (unsigned code):
for Capability *c = capabilities; c; c = c->next:
if c == (Capability *)code:
return c
Capability *Memory::find_capability (unsigned code, bool *copy):
*copy = code & 2 ? true : false
if code & 1:
// Cappage capability
unsigned num = (code & ~PAGE_MASK) >> 1
if num >= CAPPAGE_SIZE:
return NULL
Capability *page = (Capability *)(code & PAGE_MASK)
for Cappage *p = cappages; p; p = p->next:
if p->page == page:
return &page[num]
else:
// Normal capability
for Capability *c = capabilities; c; c = c->next:
if c == (Capability *)code:
return c
return NULL
void Capability::invoke (unsigned d0, unsigned d1, unsigned d2, unsigned d3, Capability *c0, Capability *c1, Capability *c2, Capability *c3):
if (unsigned)target & PAGE_MASK:
// TODO: Create message in receiver.
return
// TODO: Handle kernel request.
static Capability *reply
static void reply_cap (unsigned target, unsigned protected_data):
Capability r
Capability **ref
if target & ~KERNEL_MASK:
ref = &((Receiver *)target)->capabilities
else:
ref = &((Object_base *)protected_data)->refs
// alloc_capability needs a Memory, but it isn't used if return storage is given.
top_memory.alloc_capability ((Receiver *)target, NULL, ref, protected_data, &r)
unsigned d[4] = { 0, 0, 0, 0 }
Capability *caps[4] = { &r, NULL, NULL, NULL }
bool cops[4] = { true, false, false, false }
reply->invoke (d, caps, cops)
static void reply_cap (Capability *cap, bool copy):
unsigned d[4] = { 0, 0, 0, 0 }
Capability *caps[4] = { cap, NULL, NULL, NULL }
bool cops[4] = { copy, false, false, false }
reply->invoke (d, caps, cops)
static void reply_num (unsigned num):
unsigned d[4] = { num, 0, 0, 0 }
Capability *caps[4] = { NULL, NULL, NULL, NULL }
bool cops[4] = { false, false, false, false }
reply->invoke (d, caps, cops)
static void admin_invoke (unsigned target, Capability *cap, unsigned request, unsigned data):
switch request:
case CAP_ADMIN_SCHEDULE:
schedule ()
break
default:
break
static void receiver_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Receiver *receiver = (Receiver *)protected_data
switch request:
case CAP_RECEIVER_SET_OWNER:
if ((unsigned)cap->target & (CAPTYPE_MASK | ~KERNEL_MASK)) != CAPTYPE_THREAD:
// FIXME: This makes it impossible to use a fake thread capability.
return
receiver->own ((Thread *)cap->protected_data)
break
case CAP_RECEIVER_CREATE_CAPABILITY:
reply_cap ((unsigned)receiver, data)
break
case CAP_RECEIVER_CREATE_CALL_CAPABILITY:
reply_cap (CAPTYPE_RECEIVER | CAP_RECEIVER_CALL, protected_data)
break
default:
break
static void memory_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Memory *mem = (Memory *)protected_data
switch request:
case CAP_MEMORY_CREATE:
switch data:
case CAPTYPE_RECEIVER:
Receiver *ret = mem->alloc_receiver ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_MEMORY:
Memory *ret = mem->alloc_memory ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_THREAD:
Thread *ret = mem->alloc_thread ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_PAGE:
Page *ret = mem->alloc_page ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
case CAPTYPE_CAPPAGE:
Cappage *ret = mem->alloc_cappage ()
if ret:
reply_cap (data | REQUEST_MASK, (unsigned)ret)
else:
reply_num (0)
break
default:
return
break
case CAP_MEMORY_DESTROY:
// TODO
break
case CAP_MEMORY_LIST:
// TODO
break
case CAP_MEMORY_MAPPING:
bool write
Page *page = mem->get_mapping (data, &write)
unsigned t = CAPTYPE_PAGE | REQUEST_MASK
if !write:
t &= ~CAP_PAGE_WRITE
reply_cap (t, (unsigned)page)
break
case CAP_MEMORY_SET_LIMIT:
mem->limit = data
break
case CAP_MEMORY_GET_LIMIT:
reply_num (mem->limit)
break
case CAP_MEMORY_DROP:
if cap->address_space != mem:
break
mem->free_capability (cap)
break
default:
break
static void thread_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Thread *thread = (Thread *)protected_data
switch request:
case CAP_THREAD_RUN:
if data:
thread->run ()
else:
thread->unrun ()
break
case CAP_THREAD_GET_INFO:
// TODO
case CAP_THREAD_SET_INFO:
// TODO
default:
break
static void page_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Page *page
Cappage *cappage
if (target & CAPTYPE_MASK) == CAPTYPE_PAGE:
page = (Page *)protected_data
cappage = NULL
else:
page = NULL
cappage = (Cappage *)protected_data
switch request:
case CAP_PAGE_MAP:
if !page:
return
// TODO
case CAP_PAGE_SHARE:
// TODO
case CAP_PAGE_SHARE_COW:
// TODO
case CAP_PAGE_FORGET:
// TODO
case CAP_CAPPAGE_SET:
if !cappage:
return
// TODO
default:
break
static void capability_invoke (unsigned target, unsigned protected_data, Capability *cap, unsigned request, unsigned data):
Capability *capability = (Capability *)protected_data
switch request:
case CAP_CAPABILITY_GET:
reply_cap (capability, true)
break
case CAP_CAPABILITY_SET_DEATH_NOTIFY:
// TODO
default:
break
static bool kernel_invoke (unsigned target, unsigned protected_data, unsigned d[4], Capability *c[4], bool copy[4]):
// Kernel calling convention:
// data[0] is the request.
// cap[0] is the reply capability
// other parameters' meanings depend on the operation.
if !((1 << d[0]) & target & ~REQUEST_MASK):
// You are not allowed to perform this operation.
return false
reply = c[0]
if d[0] == CAP_DEGRADE:
reply_cap (target & d[1], protected_data)
return true
switch target & CAPTYPE_MASK:
case CAPTYPE_ADMIN:
admin_invoke (target, c[1], d[0], d[1])
break
case CAPTYPE_RECEIVER:
if target & CAP_RECEIVER_CALL:
// This is a call capability.
// TODO
return false
receiver_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_MEMORY:
memory_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_THREAD:
thread_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_PAGE:
page_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_CAPABILITY:
capability_invoke (target, protected_data, c[1], d[0], d[1])
break
case CAPTYPE_CAPPAGE:
page_invoke (target, protected_data, c[1], d[0], d[1])
break
default:
panic (0x99337744, "invalid capability type invoked")
return true
bool Capability::invoke (unsigned data[4], Capability *cap[4], bool copy[4]):
if (unsigned)target & ~KERNEL_MASK:
// This is not a kernel capability: send a message to the receiver.
bool tried_direct = false
if target->owner && target->owner->is_waiting ():
Capability *c[4]
for unsigned i = 0; i < 4; ++i:
if !cap[i]:
c[i] = NULL
else:
c[i] = target->owner->address_space->clone_capability (cap[i], copy[i])
if !c[i]:
for unsigned j = 0; j < i; ++j:
target->owner->address_space->free_capability (c[i])
tried_direct = true
break
if !tried_direct:
Thread_arch_receive (target->owner, data, c)
target->owner->unwait ()
return true
// The owner was not waiting, or it was not possible to deliver the message. Put it in the queue.
Message *msg = target->address_space->alloc_message (this)
if !msg:
return false
for unsigned i = 0; i < 4; ++i:
msg->data[i] = data[i]
if !cap[i]:
msg->capabilities[i] = NULL
else:
msg->capabilities[i] = target->address_space->clone_capability (cap[i], copy[i])
if !msg->capabilities[i]:
for unsigned j = 0; j < i; ++j:
target->address_space->free_capability (msg->capabilities[j])
target->address_space->free_message (msg)
return false
if tried_direct:
Thread_arch_receive_fail (target->owner)
target->owner->unwait ()
return true
// This is a kernel capability. Use a function to allow optimized call capabilities.
return kernel_invoke ((unsigned)target, protected_data, data, cap, copy)

View File

@ -2,6 +2,7 @@
#ifndef _KERNEL_HH
#define _KERNEL_HH
#define __KERNEL
#include "boot-programs/sos.h"
#ifndef EXTERN
@ -16,14 +17,14 @@ struct Thread
struct Message
struct Receiver
struct Capability
struct Cappage
struct Memory
#include "arch.hh"
struct Object_base:
// Next and previous object of any type in the same page.
Object_base *prev_obj, *next_obj
void free_obj (Memory *parent)
Capability *refs
Memory *address_space
inline bool is_free ()
template <typename _T> //
@ -43,11 +44,17 @@ struct Page : public Object <Page>:
unsigned physical
struct Thread : public Object <Thread>:
Memory *address_space
Receiver *receivers
unsigned pc, sp
Thread_arch arch
unsigned flags
Thread *schedule_prev, *schedule_next
Receiver *receivers
void run ()
void unrun ()
void wait ()
void unwait ()
bool is_waiting ():
return flags & THREAD_FLAG_WAITING
struct Message : public Object <Message>:
Capability *capabilities[4]
@ -64,22 +71,23 @@ struct Receiver : public Object <Receiver>:
struct Capability : public Object <Capability>:
Receiver *target
Capability *parent
Capability *children
Capability *sibling_prev, *sibling_next
unsigned protected_data
void invoke (unsigned d0, unsigned d1, unsigned d2, unsigned d3, Capability *c0, Capability *c1, Capability *c2, Capability *c3)
bool invoke (unsigned data[4], Capability *cap[4], bool copy[4])
void invalidate ()
struct Cappage : public Object <Cappage>:
Capability *page
struct Memory : public Object <Memory>:
Memory *parent
Free *frees
Page *pages
Thread *threads
Receiver *receivers
Capability *capabilities
Cappage *cappages
Memory *memories
unsigned limit, used
Memory_arch arch
@ -102,7 +110,9 @@ struct Memory : public Object <Memory>:
Thread *alloc_thread ()
Message *alloc_message (Capability *source)
Receiver *alloc_receiver ()
Capability *alloc_capability (Receiver *target, Capability **parent, unsigned protected_data)
Capability *alloc_capability (Receiver *target, Capability *parent, Capability **parent_ptr, unsigned protected_data, Capability *ret = NULL)
Capability *clone_capability (Capability *source, bool copy, Capability *ret = NULL)
Cappage *alloc_cappage ()
Memory *alloc_memory ()
void free_page (Page *page)
@ -110,17 +120,21 @@ struct Memory : public Object <Memory>:
void free_message (Message *message)
void free_receiver (Receiver *receiver)
void free_capability (Capability *capability)
void free_cappage (Cappage *page)
void free_memory (Memory *mem)
Capability *find_capability (unsigned code)
void free_obj (Object_base *obj)
Capability *find_capability (unsigned code, bool *copy)
// 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 (unsigned n, char const *message = "")
// Debug: switch caps led
void led (bool one, bool two, bool three)
void dbg_led (bool one, bool two, bool three)
void dbg_sleep (unsigned ms)
void dbg_send (unsigned code, unsigned bits = 32)
void schedule ()
@ -138,13 +152,14 @@ EXTERN Thread *current
// Defined in arch.cc
void Thread_arch_init (Thread *thread)
void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4])
void Thread_arch_receive_fail (Thread *thread)
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 arch_invoke ()
void arch_schedule (Thread *previous, Thread *target)
bool Memory::map (Page *page, unsigned address, bool write):
return Memory_arch_map (this, page, address, write)

View File

@ -28,6 +28,20 @@ void Thread_arch_init (Thread *thread):
thread->arch.k0 = 0
thread->arch.k1 = 0
void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4]):
thread->arch.a0 = (unsigned)c[0]
thread->arch.a1 = (unsigned)c[1]
thread->arch.a2 = (unsigned)c[2]
thread->arch.a3 = (unsigned)c[3]
thread->arch.t0 = d[0]
thread->arch.t1 = d[1]
thread->arch.t2 = d[2]
thread->arch.t3 = d[3]
thread->arch.v0 = 1
void Thread_arch_receive_fail (Thread *thread):
thread->arch.v0 = 0
void Memory_arch_init (Memory *mem):
mem->arch.asid = 1
mem->arch.directory = NULL
@ -94,32 +108,42 @@ Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable):
return (Page *)(v & ~1)
void arch_invoke ():
Capability *target, *c0, *c1, *c2, *c3
target = current->address_space->find_capability (current->arch.v0)
Capability *target, *c[4]
bool wait, copy[4]
Thread *caller = current
target = caller->address_space->find_capability (current->arch.v0, &wait)
if wait:
caller->wait ()
if !target:
// TODO: there must be no action here. This is just because the rest doesn't work yet.
led (current->arch.a0, current->arch.a1, current->arch.a2)
dbg_led (caller->arch.a0, caller->arch.a1, caller->arch.a2)
dbg_sleep (1000)
schedule ()
// Calling an invalid capability always fails.
caller->arch.v0 = 0
return
c0 = current->address_space->find_capability (current->arch.a0)
c1 = current->address_space->find_capability (current->arch.a1)
c2 = current->address_space->find_capability (current->arch.a2)
c3 = current->address_space->find_capability (current->arch.a3)
target->invoke (current->arch.t0, current->arch.t1, current->arch.t2, current->arch.t3, c0, c1, c2, c3)
void arch_schedule (Thread *previous, Thread *target):
if (Memory *)asids[target->address_space->arch.asid] != target->address_space:
if asids[0]:
target->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
target->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[target->address_space->arch.asid] = (unsigned)target
cp0_set (CP0_ENTRY_HI, target->address_space->arch.asid)
c[0] = caller->address_space->find_capability (caller->arch.a0, &copy[0])
c[1] = caller->address_space->find_capability (caller->arch.a1, &copy[1])
c[2] = caller->address_space->find_capability (caller->arch.a2, &copy[2])
c[3] = caller->address_space->find_capability (caller->arch.a3, &copy[3])
unsigned d[4]
d[0] = caller->arch.t0
d[1] = caller->arch.t1
d[2] = caller->arch.t2
d[3] = caller->arch.t3
caller->arch.v0 = target->invoke (d, c, copy) ? 1 : 0
if caller != current:
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
if asids[0]:
current->address_space->arch.asid = asids[0]
asids[0] = asids[asids[0]]
else:
static unsigned random = 1
current->address_space->arch.asid = random
// Overwrite used asid, so flush those values from tlb.
flush_tlb (random)
++random
if random >= 64:
random = 1
asids[current->address_space->arch.asid] = (unsigned)current
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)

View File

@ -48,6 +48,44 @@
#define PAGE_SIZE (1 << PAGE_BITS)
#define PAGE_MASK (~(PAGE_SIZE - 1))
// register save positions in Thread
#define SAVE_PC (5 * 4)
#define SAVE_SP (SAVE_PC + 4)
#define SAVE_AT (SAVE_SP + 4)
#define SAVE_V0 (SAVE_AT + 4)
#define SAVE_V1 (SAVE_V0 + 4)
#define SAVE_A0 (SAVE_V1 + 4)
#define SAVE_A1 (SAVE_A0 + 4)
#define SAVE_A2 (SAVE_A1 + 4)
#define SAVE_A3 (SAVE_A2 + 4)
#define SAVE_T0 (SAVE_A3 + 4)
#define SAVE_T1 (SAVE_T0 + 4)
#define SAVE_T2 (SAVE_T1 + 4)
#define SAVE_T3 (SAVE_T2 + 4)
#define SAVE_T4 (SAVE_T3 + 4)
#define SAVE_T5 (SAVE_T4 + 4)
#define SAVE_T6 (SAVE_T5 + 4)
#define SAVE_T7 (SAVE_T6 + 4)
#define SAVE_T8 (SAVE_T7 + 4)
#define SAVE_T9 (SAVE_T8 + 4)
#define SAVE_S0 (SAVE_T9 + 4)
#define SAVE_S1 (SAVE_S0 + 4)
#define SAVE_S2 (SAVE_S1 + 4)
#define SAVE_S3 (SAVE_S2 + 4)
#define SAVE_S4 (SAVE_S3 + 4)
#define SAVE_S5 (SAVE_S4 + 4)
#define SAVE_S6 (SAVE_S5 + 4)
#define SAVE_S7 (SAVE_S6 + 4)
#define SAVE_GP (SAVE_S7 + 4)
#define SAVE_FP (SAVE_GP + 4)
#define SAVE_RA (SAVE_FP + 4)
#define SAVE_HI (SAVE_RA + 4)
#define SAVE_LO (SAVE_HI + 4)
#define SAVE_K0 (SAVE_LO + 4)
#define SAVE_K1 (SAVE_K0 + 4)
#ifndef ASM
struct Thread_arch:
unsigned at, v0, v1, a0, a1, a2, a3
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
@ -82,4 +120,6 @@ extern "C":
extern unsigned thread_start[NUM_THREADS + 1]
#endif
#endif // defined ASM
#endif

View File

@ -3,8 +3,4 @@
void panic (unsigned n, char const *message):
while (1):
for unsigned bit = 0x80000000; bit; bit >>= 1:
for int i = 0; i < 600000; ++i:
led (n & bit, i > 200000 && i < 400000, false)
for int i = 0; i < 1000000; ++i:
led (false, false, true)
dbg_send (n)

View File

@ -1,12 +1,51 @@
#pypp 0
#include "kernel.hh"
void Thread::run ():
if flags & THREAD_FLAG_RUNNING:
return
flags |= THREAD_FLAG_RUNNING
if flags & THREAD_FLAG_WAITING:
return
schedule_next = first_scheduled
if schedule_next:
schedule_next->schedule_prev = this
first_scheduled = this
void Thread::unrun ():
if !(flags & THREAD_FLAG_RUNNING):
return
flags &= ~THREAD_FLAG_RUNNING
if !(flags & THREAD_FLAG_WAITING):
if current == this:
current = schedule_next
if schedule_prev:
schedule_prev->schedule_next = schedule_next
else:
first_scheduled = schedule_next
if schedule_next:
schedule_next->schedule_prev = schedule_prev
void Thread::wait ():
if flags & THREAD_FLAG_WAITING:
return
if flags & THREAD_FLAG_RUNNING:
unrun ()
flags |= THREAD_FLAG_WAITING
void Thread::unwait ():
if !(flags & THREAD_FLAG_WAITING):
return
flags &= ~THREAD_FLAG_WAITING
if flags & THREAD_FLAG_RUNNING:
flags &= ~THREAD_FLAG_RUNNING
run ()
void schedule ():
Thread *old = current
current = current->schedule_next
if current:
current = current->schedule_next
if !current:
current = first_scheduled
if !current:
current = &idle
if old != current:
arch_schedule (old, current)

View File

@ -58,7 +58,7 @@ static void __gpio_clear_pin (unsigned n):
#define NETWORK_IO 9
#define LIGHT 105
void led (bool one, bool two, bool three):
void dbg_led (bool one, bool two, bool three):
__gpio_as_output (CAPSLOCKLED_IO)
__gpio_as_output (NUMLOCKLED_IO)
__gpio_as_output (NETWORK_IO)
@ -76,5 +76,21 @@ void led (bool one, bool two, bool three):
__gpio_set_pin (NETWORK_IO)
void dbg_sleep (unsigned ms):
for unsigned i = 0; i < 10000 * ms; ++i:
for unsigned i = 0; i < 2673 * ms; ++i:
__gpio_as_output (CAPSLOCKLED_IO)
void dbg_send (unsigned code, unsigned bits):
for int i = bits; i >= 0; --i:
bool on = code & (1 << i)
dbg_led (false, false, false)
dbg_sleep (200)
if on:
dbg_led (true, false, false)
else:
dbg_led (false, true, false)
dbg_sleep (400)
dbg_led (false, false, false)
dbg_sleep (200)
dbg_led (true, true, false)
dbg_sleep (200)
dbg_led (false, false, false)