mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-04 23:08:26 +02:00
more
This commit is contained in:
parent
12320ef8df
commit
27d9e596ad
10
Makefile
10
Makefile
@ -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
119
alloc.ccp
@ -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)
|
||||
|
@ -26,3 +26,4 @@ __start:
|
||||
.comm __top_memory, 4
|
||||
.comm __my_memory, 4
|
||||
.comm __my_admin, 4
|
||||
.comm __my_call, 4
|
||||
|
@ -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
51
entry.S
@ -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)
|
||||
|
23
init.ccp
23
init.ccp
@ -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
|
||||
|
@ -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.
|
||||
|
287
invoke.ccp
287
invoke.ccp
@ -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)
|
||||
|
37
kernel.hhp
37
kernel.hhp
@ -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)
|
||||
|
72
mips.ccp
72
mips.ccp
@ -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, ©[0])
|
||||
c[1] = caller->address_space->find_capability (caller->arch.a1, ©[1])
|
||||
c[2] = caller->address_space->find_capability (caller->arch.a2, ©[2])
|
||||
c[3] = caller->address_space->find_capability (caller->arch.a3, ©[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)
|
||||
|
40
mips.hhp
40
mips.hhp
@ -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
|
||||
|
@ -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)
|
||||
|
45
schedule.ccp
45
schedule.ccp
@ -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)
|
||||
|
20
test.ccp
20
test.ccp
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user