1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-28 12:49:54 +02:00

make things work with unfinished new startup procedure

This commit is contained in:
Bas Wijnen 2010-04-30 23:13:49 +02:00
parent 7c43204a7e
commit 12bfb320f7
37 changed files with 2374 additions and 1649 deletions

1
.gitignore vendored
View File

@ -21,3 +21,4 @@ mips/nanonote/server/depcomp
mips/nanonote/server/install-sh
mips/nanonote/server/missing
mips/nanonote/server/usb-server
fs/

View File

@ -51,6 +51,9 @@ fs/%.elf: source/crt0.o source/%.o
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
$(OBJCOPY) -S $(OBJCOPYFLAGS) $@
fs/%: %
ln -s ../$< $@
clean:
rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES)

View File

@ -171,6 +171,9 @@ void kMemory::free_obj (kObject *obj, kPointer *first):
((kFree *)self->prev)->next = self->next
else:
frees = (kFree *)self->next
//kdebug ("freeing page: ")
//kdebug_num ((unsigned)self - SIZE)
//kdebug ("\n")
pfree ((unsigned)self - SIZE)
kPage *kMemory::alloc_page ():
@ -292,7 +295,7 @@ kMemory *kMemory::alloc_memory ():
kMemory_arch_init (ret)
return ret
void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr):
void kCaps::set (unsigned index, kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr):
if index >= size:
kdebug ("size: ")
kdebug_num (size)
@ -300,11 +303,6 @@ void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef p
dpanic (index, "index too large for kCaps")
return
kCapability *c = &caps[index]
if (unsigned)target == 0x81fdc350:
kdebug ("setting cap ")
kdebug_num (index)
kdebug (" old target: ")
kdebug_num ((unsigned)c->target)
c->target = target
c->protected_data = pdata
c->parent = parent
@ -321,8 +319,6 @@ void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef p
c->sibling_next.reset ()
if c->sibling_next.valid ():
c->sibling_next->sibling_prev = kCapRef (this, index)
if (unsigned)target == 0x81fdc350:
kdebug (" done\n")
void kCaps::clone (unsigned index, kCapRef source, bool copy):
cap (index)->invalidate ()
@ -341,10 +337,9 @@ void kCaps::clone (unsigned index, kCapRef source, bool copy):
void kMemory::free_page (kPage *page):
if page->mapping != ~0:
page->address_space->unmap (page)
if page->flags & Kernel::Page::PAYING:
page->forget ()
if page->flags & Iris::Page::PAYING:
unuse ()
if page->frame:
pfree (page->frame)
free_obj (page, (kPointer *)&pages)
void kThread::unset_slot (unsigned s):
@ -367,6 +362,8 @@ void kMemory::free_thread (kThread *thread):
for unsigned i = 0; i < thread->slots; ++i:
thread->unset_slot (i)
free_obj (thread, (void **)&threads)
if old_current == thread:
old_current = NULL
void kMemory::free_message (kReceiver *owner, kMessage *message):
for unsigned i = 0; i < 2; ++i:
@ -382,11 +379,15 @@ void kMemory::free_receiver (kReceiver *receiver):
while receiver->messages:
free_message (receiver, receiver->messages)
free_obj (receiver, (void **)&receivers)
if receiver == reply_target:
reply_target = NULL
// Signal that it is correct to not reply here.
reply_protected.l = 1
void kReceiver::orphan ():
if prev_owned:
prev_owned->next_owned = next_owned
else:
else if owner:
owner->receivers = next_owned
if next_owned:
next_owned->prev_owned = prev_owned
@ -404,10 +405,14 @@ void kReceiver::own (kThread *o):
void kCapability::invalidate ():
if !target:
return
//kdebug_num ((unsigned)this)
//kdebug ("\n")
//kdebug_num ((unsigned)target)
//kdebug (":")
//kdebug_num ((unsigned)protected_data.l)
//kdebug ("\n")
if (unsigned)this == dbg_code.h:
dpanic (0, "invalidating watched capability")
if sibling_prev.valid ():
sibling_prev->sibling_next = sibling_next
else if parent.valid ():
@ -429,6 +434,8 @@ void kCapability::invalidate ():
if !next:
next = c->parent.deref ()
c->target = NULL
if c->parent.valid ():
c->parent->children = c->sibling_next
c->parent.reset ()
c->children.reset ()
c->sibling_prev.reset ()
@ -492,19 +499,24 @@ void kMemory::free_list (kList *l):
void kMemory::free_memory (kMemory *mem):
while mem->pages:
free_page (mem->pages)
//kdebug ("freeing page ")
//kdebug_num ((unsigned)mem->pages)
//kdebug (", next = ")
//kdebug_num ((unsigned)mem->pages->next)
//kdebug ("\n")
mem->free_page (mem->pages)
while mem->capses:
free_caps (mem->capses)
mem->free_caps (mem->capses)
while mem->threads:
free_thread (mem->threads)
mem->free_thread (mem->threads)
while mem->memories:
free_memory (mem->memories)
mem->free_memory (mem->memories)
while mem->receivers:
free_receiver (mem->receivers)
mem->free_receiver (mem->receivers)
while mem->lists:
free_list (mem->lists)
mem->free_list (mem->lists)
while mem->listitems:
free_listitem (mem->listitems)
mem->free_listitem (mem->listitems)
if mem->frees:
panic (0, "kernel memory leak: memory still in use")
free_obj (mem, (void **)&memories)
@ -519,10 +531,10 @@ void kPage::forget ():
share_next = NULL
else:
// If the page has a frame and should be freed, free it.
if !((flags ^ Kernel::Page::FRAME) & (Kernel::Page::PHYSICAL | Kernel::Page::FRAME)):
if !((flags ^ Iris::Page::FRAME) & (Iris::Page::PHYSICAL | Iris::Page::FRAME)):
raw_pfree (frame)
frame = 0
flags &= ~(Kernel::Page::FRAME | Kernel::Page::SHARED | Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
flags &= ~(Iris::Page::FRAME | Iris::Page::SHARED | Iris::Page::PHYSICAL | Iris::Page::UNCACHED)
kPage_arch_update_mapping (this)
static void check_receiver (kReceiver *r, kCapRef cap, unsigned line):
@ -546,6 +558,8 @@ static void check_receiver (kReceiver *r, kCapRef cap, unsigned line):
kdebug ("!= receiver\n")
dpanic (line, "consistency bug in kernel capabilities")
for kCapRef c = cap->children; c.valid (); c = c->sibling_next:
if c->protected_data.value () != cap->protected_data.value () || c->target != cap->target:
dpanic (line, "capability db bug")
check_receiver (r, c, line)
void kReceiver::check (unsigned line):
@ -556,7 +570,7 @@ void kMemory::check (unsigned line):
for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
r->check (line)
for kThread *t = threads; t; t = (kThread *)t->next:
if t->flags & Kernel::Thread::RUNNING && t->pc == 0:
if t->flags & Iris::Thread::RUNNING && t->pc == 0:
kdebug_num ((unsigned)t)
kdebug ("\n")
panic (line, "pc is 0")

344
boot-programs/bootinit.ccp Normal file
View File

@ -0,0 +1,344 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// boot-programs/bootinit.ccp: Bootstrapping code.
// 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 "devices.hh"
#include "iris.hh"
#include <elf.h>
#define ELFRUN_NAME "elfrun.elf"
#define INIT_NAME "init.elf"
#define NUM_SLOTS 8
#define NUM_CAPS 32
static unsigned _free
extern unsigned _end
void init_alloc ():
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
_free = ret + (pages << PAGE_BITS)
return (char *)ret
void *operator new[] (unsigned size):
//kdebug ("new ")
void *ret = (void *)_free
size = (size + 3) & ~3
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
if rest < size:
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < pages; ++p:
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
Iris::free_cap (page)
_free += size
//kdebug_num ((unsigned)ret)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("\n")
return ret
void *operator new (unsigned size):
return new char[size]
static bool have_data_mem, have_fs_mem
static Iris::Memory data_mem, fs_mem
// Get the initial block device and filesystem.
static Iris::Directory receive_devices ():
Iris::Caps data, fs
bool have_data = false, have_fs = false
Iris::Device fs_dev, data_dev
for unsigned i = 0; i < 2; ++i:
Iris::wait ()
if Iris::recv.data[0].l != Iris::Parent::PROVIDE_DEVICE:
Iris::panic (Iris::recv.data[0].l, "Invalid bootstrap request.")
switch Iris::recv.data[1].l:
case Iris::String::ID:
if have_data:
Iris::panic (0, "duplicate device.")
data_dev = Iris::get_arg ()
Iris::recv.reply.invoke ()
have_data = true
break
case Iris::Filesystem::ID:
if have_fs:
Iris::panic (0, "duplicate filesystem.")
fs_dev = Iris::get_arg ()
Iris::recv.reply.invoke ()
have_fs = true
break
default:
Iris::panic (Iris::recv.data[1].l, "unexpected device")
// Initialize the root file system.
data = data_dev.create_user (Iris::my_memory)
data_dev.use (data)
fs = fs_dev.create_user (Iris::my_memory)
fs_dev.use (fs)
Iris::Filesystem fs_cap = fs.get (0)
Iris::Directory root = fs_cap.use_device_ro (data.copy ())
have_data_mem = data_dev.call (0).l
if have_data_mem:
data_mem = Iris::get_arg ()
have_fs_mem = fs_dev.call (0).l
if have_fs_mem:
fs_mem = Iris::get_arg ()
Iris::free_cap (data)
Iris::free_cap (fs)
Iris::free_cap (fs_cap)
Iris::free_cap (data_dev)
Iris::free_cap (fs_dev)
return root
static bool stringcmp (char const *s1, char const *s2, unsigned size):
for unsigned t = 0; t < size; ++t:
if s1[t] != s2[t]:
return false
return true
static Iris::String find (Iris::Directory root, char const *name):
unsigned size = 0
while name[size]:
++size
Iris::Num num_files = root.get_size ()
for Iris::Num i = 0; i.value () < num_files.value (); i = i.value () + 1:
Iris::String n = root.get_name (i)
char current_name[16]
n.get_chars (0, current_name)
Iris::free_cap (n)
if !stringcmp (current_name, name, size):
continue
// Found elfrun.
Iris::String ret = root.get_file_ro (i)
return ret
Iris::panic (0, "bootfile not found")
static void run (Iris::String data, Iris::Memory parent_memory, Iris::Cap parent):
// Get the size.
Iris::Num size = data.get_size ()
if size.value () == 0:
Iris::panic (0, "elfrun is empty")
// Allocate a caps with all the pages.
unsigned pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
Iris::Caps pages_caps = Iris::my_memory.create_caps (pages)
unsigned slot = pages_caps.use ()
// Map them into the address space as well.
char *mapping = alloc_space (pages)
// Create a memory for the program.
Iris::Memory mem = parent_memory.create_memory ()
// Load the file into memory and map it.
for unsigned p = 0; p < pages; ++p:
//kdebug_num (p)
//kdebug ("/")
//kdebug_num (pages)
//kdebug ("\n")
Iris::set_recv_arg (Iris::Cap (slot, p))
Iris::my_memory.create_page ()
Iris::Page (slot, p).set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
data.get_page (p << PAGE_BITS, Iris::Cap (slot, p))
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
Iris::Thread thread = mem.create_thread (NUM_SLOTS)
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
Iris::panic (header->e_ident[j], "invalid ELF magic")
return
if header->e_ident[EI_CLASS] != ELFCLASS32:
kdebug ("invalid ELF class:")
kdebug_num (header->e_ident[EI_CLASS])
kdebug (" != ")
kdebug_num (ELFCLASS32)
kdebug ("\n")
Iris::panic (0)
return
if header->e_ident[EI_DATA] != ELFDATA2LSB:
Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
if header->e_ident[EI_VERSION] != EV_CURRENT:
Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
if header->e_type != ET_EXEC:
Iris::panic (header->e_type, "invalid ELF type")
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
Iris::panic (header->e_machine, "invalid ELF machine")
thread.set_pc (header->e_entry)
thread.set_sp (0x80000000)
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
continue
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
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
Iris::panic (shdr->sh_size, "thread too large")
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned idx = file_offset + section_offset
Iris::Page page = mem.mapping ((void *)p)
if Iris::recv.data[0].l == Iris::NO_ERROR:
// The address already has a mapping; assume that it is correct.
Iris::free_cap (page)
continue
Iris::free_cap (page)
page = mem.create_page ()
unsigned f
if readonly:
f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
else:
f = Iris::Page::PAYING
page.set_flags (f, f)
Iris::Page (slot, idx).share (page, 0)
//kdebug ("mapping at ")
//kdebug_num (p)
//if readonly:
// kdebug (" (readonly)")
//kdebug ("\n")
if !mem.map (page, p):
Iris::panic (0, "unable to map page")
return
Iris::free_cap (page)
else:
if readonly:
Iris::panic (0, "unwritable bss section")
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Iris::Page page = mem.mapping ((void *)p)
if Iris::recv.data[0].l == Iris::NO_ERROR:
// No error means there is a mapping.
Iris::free_cap (page)
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
else:
Iris::free_cap (page)
page = mem.create_page ()
if Iris::recv.data[0].l != Iris::NO_ERROR:
Iris::panic (Iris::recv.data[0].l, "out of memory")
if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME):
Iris::panic (0, "out of memory")
if !mem.map (page, p):
Iris::panic (0, "unable to map bss page")
Iris::free_cap (page)
for unsigned p = 0; p < pages; ++p:
Iris::my_memory.destroy (Iris::Page (slot, p))
Iris::my_memory.destroy (pages_caps)
Iris::free_slot (slot)
Iris::Page stackpage = mem.create_page ()
stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
Iris::free_cap (stackpage)
Iris::Caps caps = mem.create_caps (NUM_CAPS)
thread.use (caps, 0)
thread.set_info (Iris::Thread::A0, NUM_SLOTS)
thread.set_info (Iris::Thread::A1, NUM_CAPS)
Iris::Receiver receiver = mem.create_receiver ()
receiver.set_owner (thread.copy ())
Iris::Cap call = receiver.create_call_capability ()
caps.set (__caps_num, caps.copy ())
caps.set (__receiver_num, receiver.copy ())
caps.set (__thread_num, thread.copy ())
caps.set (__memory_num, mem.copy ())
caps.set (__call_num, call.copy ())
caps.set (__parent_num, parent)
thread.run ()
Iris::free_cap (receiver)
Iris::free_cap (thread)
Iris::free_cap (call)
Iris::free_cap (caps)
Iris::Num start ():
// Wait for the debugging device to be active, in case there is one.
Iris::schedule ()
kdebug ("Starting bootinit\n")
init_alloc ()
Iris::Memory top_memory = Iris::get_top_memory ()
Iris::Directory root = receive_devices ()
root.lock_ro ()
Iris::String run_string = find (root, ELFRUN_NAME)
Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
run (run_string, top_memory, parent_cap)
Iris::wait ()
if Iris::recv.data[0].l != Iris::Parent::PROVIDE_DEVICE || Iris::recv.data[1].l != Iris::Elfrun::ID:
Iris::panic (0, "elfrun doesn't provide correct capability")
Iris::Cap reply = Iris::get_reply ()
Iris::Device elfrun_dev = Iris::get_arg ()
Iris::my_caps.set (parent_cap.idx (), Iris::Cap (CAP_NONE))
Iris::free_cap (parent_cap)
reply.invoke ()
Iris::free_cap (reply)
parent_cap = Iris::my_receiver.create_capability (0)
Iris::Caps elfrun = elfrun_dev.create_user (Iris::my_memory)
elfrun_dev.use (elfrun)
Iris::Elfrun elfrun_cap = elfrun.get (0)
Iris::free_cap (elfrun)
Iris::String init_string = find (root, INIT_NAME)
Iris::Caps init_caps = elfrun_cap.run_string (top_memory.copy (), init_string.copy (), parent_cap.copy ())
Iris::Thread init = init_caps.get (__thread_num)
init.make_priv ()
init.run ()
Iris::free_cap (init)
Iris::free_cap (init_caps)
bool have_root = false
bool have_elfrun = false
while true:
Iris::wait ()
switch Iris::recv.data[0].l:
case Iris::Parent::GET_DEVICE:
switch Iris::recv.data[1].l:
case Iris::Directory::ID:
if have_root:
Iris::panic (0, "Init requests root directory twice")
Iris::recv.reply.invoke (0, 0, root.copy ())
have_root = true
break
case Iris::Elfrun::ID:
if have_elfrun:
Iris::panic (0, "Init requests elfrun twice")
Iris::recv.reply.invoke (0, 0, elfrun_cap.copy ())
have_elfrun = true
break
default:
Iris::panic (0, "Invalid device requested by init")
break
case Iris::Parent::INIT_DONE:
if Iris::recv.data[1].value () != 0:
Iris::recv.reply.invoke ()
break
// Special response: kill boot threads.
Iris::Cap reply = Iris::get_reply ()
root.unlock_ro ()
if have_data_mem:
top_memory.destroy (data_mem)
if have_fs_mem:
top_memory.destroy (fs_mem)
reply.invoke ()
Iris::free_cap (reply)
top_memory.destroy (Iris::my_memory)
Iris::panic (0, "bootinit should be destroyed")
default:
Iris::panic (Iris::recv.data[0].l, "invalid operation from init")

View File

@ -29,7 +29,8 @@ static unsigned __slots, __caps
static list *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap
namespace Kernel:
namespace Iris:
Caps my_caps
Receiver my_receiver
Thread my_thread
Memory my_memory
@ -77,7 +78,7 @@ namespace Kernel:
if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
kdebug ("out of slots!\n")
Kernel::panic (0)
Iris::panic (0)
return ~0
list *ret = __first_free_slot
__first_free_slot = ret->next
@ -90,7 +91,7 @@ namespace Kernel:
if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
kdebug ("out of capabilities!\n")
Kernel::panic (0)
Iris::panic (0)
return Cap (0, CAP_NONE)
list *ret = __first_free_cap
__first_free_cap = ret->next
@ -106,20 +107,21 @@ extern "C":
__cap_admin = cap_admin
__first_free_slot = NULL
for unsigned i = 1; i < __slots; ++i:
Kernel::free_slot (i)
Iris::free_slot (i)
__first_free_cap = NULL
for unsigned i = 7; i < __caps; ++i:
Kernel::free_cap (Kernel::Cap (0, i))
Kernel::my_receiver = Kernel::Cap (0, __receiver_num)
Kernel::my_thread = Kernel::Cap (0, __thread_num)
Kernel::my_memory = Kernel::Cap (0, __memory_num)
Kernel::my_call = Kernel::Cap (0, __call_num)
Kernel::my_parent = Kernel::Cap (0, __parent_num)
Kernel::recv.reply = Kernel::alloc_cap ()
Kernel::recv.arg = Kernel::alloc_cap ()
Kernel::Num ret = start ()
Kernel::my_parent.exit (ret)
Kernel::my_memory.destroy (Kernel::my_thread)
for unsigned i = 6; i < __caps; ++i:
Iris::free_cap (Iris::Cap (0, i))
Iris::my_caps = Iris::Cap (0, __caps_num)
Iris::my_receiver = Iris::Cap (0, __receiver_num)
Iris::my_thread = Iris::Cap (0, __thread_num)
Iris::my_memory = Iris::Cap (0, __memory_num)
Iris::my_call = Iris::Cap (0, __call_num)
Iris::my_parent = Iris::Cap (0, __parent_num)
Iris::recv.reply = Iris::alloc_cap ()
Iris::recv.arg = Iris::alloc_cap ()
Iris::Num ret = start ()
Iris::my_parent.exit (ret)
Iris::my_memory.destroy (Iris::my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
while true:
*(volatile unsigned *)~0

View File

@ -1,592 +0,0 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// bootstrap/init.ccp: Bootstrapping code.
// 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 "devices.hh"
#include "iris.hh"
#include "keys.hh"
#include <elf.h>
#define NUM_SLOTS 8
#define NUM_CAPS 32
enum Cap_codes:
SYSREQ = 1 << 16
THREAD
KEYBOARD
static unsigned _free
extern unsigned _end
void init_alloc ():
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
_free = ret + (pages << PAGE_BITS)
return (char *)ret
void *operator new[] (unsigned size):
//kdebug ("new ")
void *ret = (void *)_free
size = (size + 3) & ~3
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
if rest < size:
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < pages; ++p:
Kernel::Page page = Kernel::my_memory.create_page ()
page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
Kernel::my_memory.map (page, _free + rest + (p << PAGE_BITS))
Kernel::free_cap (page)
_free += size
//kdebug_num ((unsigned)ret)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("\n")
return ret
void *operator new (unsigned size):
return new char[size]
struct file:
unsigned size
// Only the first 16 characters of the name are used, because that's much easier.
// This means that file names must be different in the first 16 characters if sort order matters.
char name[16]
String string
static unsigned num_files
static file *files
static unsigned *index
static Kernel::Memory top_memory
static unsigned slot
static unsigned max_pages
static char *mapping
static unsigned current_thread
static Kernel::Caps terminals
static unsigned terminal_slot
static Kernel::Caps memories
static unsigned memory_slot
static unsigned *inuse
// Get the initial block device and filesystem.
static Directory receive_devices ():
Kernel::Caps data, fs
bool have_data = false, have_fs = false
Device fs_dev, data_dev
for unsigned i = 0; i < 2; ++i:
Kernel::wait ()
if Kernel::recv.data[0].l != Parent::PROVIDE_DEVICE:
Kernel::panic (Kernel::recv.data[0].l, "Invalid bootstrap request.")
switch Kernel::recv.data[1].l:
case String::ID:
if have_data:
Kernel::panic (0, "duplicate device.")
data_dev = Kernel::get_arg ()
Kernel::recv.reply.invoke ()
have_data = true
break
case Filesystem::ID:
if have_fs:
Kernel::panic (0, "duplicate filesystem.")
fs_dev = Kernel::get_arg ()
Kernel::recv.reply.invoke ()
have_fs = true
break
default:
Kernel::panic (Kernel::recv.data[1].l, "unexpected device")
// Initialize the root file system.
data = data_dev.create_user (Kernel::my_memory)
data_dev.use (data)
fs = fs_dev.create_user (Kernel::my_memory)
fs_dev.use (fs)
Filesystem fs_cap = fs.get (0)
Directory root = fs_cap.use_device_ro (data.copy ())
Kernel::free_cap (data)
Kernel::free_cap (fs)
Kernel::free_cap (fs_cap)
Kernel::free_cap (data_dev)
Kernel::free_cap (fs_dev)
return root
// Make a list of all files.
static void list_files (Directory root):
Kernel::Num fullsize = root.get_size ()
if fullsize.h != 0:
kdebug ("Too many files in bootstrap directory:")
kdebug_num (fullsize.h)
kdebug (":")
kdebug_num (fullsize.l)
kdebug ("\n")
Kernel::panic (0)
num_files = fullsize.l
files = new file[num_files]
Kernel::Caps caps = Kernel::my_memory.create_caps (num_files)
unsigned slot = Kernel::alloc_slot ()
caps.use (slot)
Kernel::free_cap (caps)
for unsigned i = 0; i < num_files; ++i:
String n = root.get_name (i)
n.get_chars (0, files[i].name)
Kernel::free_cap (n)
Kernel::set_recv_arg (Kernel::Cap (slot, i))
files[i].string = root.get_file_ro (i)
Kernel::Num fullsize = files[i].string.get_size ()
if fullsize.h != 0:
kdebug ("initial file size too large: ")
kdebug_num (fullsize.h)
kdebug (":")
kdebug_num (fullsize.l)
kdebug (".\n")
Kernel::panic (0)
files[i].size = fullsize.l
if max_pages < (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS:
max_pages = (fullsize.l + PAGE_SIZE - 1) >> PAGE_BITS
// Sort the list of files.
static bool is_less (file *f1, file *f2):
for unsigned i = 0; i < 16; ++i:
if f1->name[i] < f2->name[i]:
return true
if f1->name[i] > f2->name[i]:
return false
return false
// Bubble sort.
static void sort ():
index = new unsigned[num_files]
index[0] = 0
// Invariant: index[0...f-1] is sorted.
for unsigned f = 1; f < num_files; ++f:
// Bubble up until top. Test for less-than, because it wraps to maxunsigned.
unsigned i
// Invariant: index[0...f] \ index[i+1] is sorted and index[i+1...f] is sorted.
for i = f - 1; i < f; --i:
if is_less (&files[index[i]], &files[f]):
break
index[i + 1] = index[i]
index[i + 1] = f
static void run (file *f, bool priv, int id):
Kernel::Memory mem = Kernel::Cap (memory_slot, id)
Kernel::set_recv_arg (mem)
top_memory.create_memory ()
unsigned num_pages = (f->size + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < num_pages; ++p:
//kdebug_num (p)
//kdebug ("/")
//kdebug_num (num_pages)
//kdebug ("\n")
Kernel::set_recv_arg (Kernel::Cap (slot, p))
Kernel::my_memory.create_page ()
Kernel::Page (slot, p).set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING)
f->string.get_page (p << PAGE_BITS, Kernel::Cap (slot, p))
Kernel::my_memory.map (Kernel::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
Kernel::Thread thread = mem.create_thread (NUM_SLOTS)
if priv:
thread.make_priv ()
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
Kernel::panic (header->e_ident[j], "invalid ELF magic")
return
if header->e_ident[EI_CLASS] != ELFCLASS32:
kdebug ("invalid ELF class:")
kdebug_num (header->e_ident[EI_CLASS])
kdebug (" != ")
kdebug_num (ELFCLASS32)
kdebug ("\n")
Kernel::panic (0)
return
if header->e_ident[EI_DATA] != ELFDATA2LSB:
Kernel::panic (header->e_ident[EI_DATA], "invalid ELF data")
if header->e_ident[EI_VERSION] != EV_CURRENT:
Kernel::panic (header->e_ident[EI_VERSION], "invalid ELF version")
if header->e_type != ET_EXEC:
Kernel::panic (header->e_type, "invalid ELF type")
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
Kernel::panic (header->e_machine, "invalid ELF machine")
thread.set_pc (header->e_entry)
thread.set_sp (0x80000000)
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
continue
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
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
Kernel::panic (shdr->sh_size, "thread too large")
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned idx = file_offset + section_offset
Kernel::Page page = mem.mapping ((void *)p)
if Kernel::recv.data[0].l == Kernel::NO_ERROR:
// The address already has a mapping; assume that it is correct.
Kernel::free_cap (page)
continue
Kernel::free_cap (page)
page = mem.create_page ()
unsigned f
if readonly:
f = Kernel::Page::PAYING | Kernel::Page::MAPPED_READONLY
else:
f = Kernel::Page::PAYING
page.set_flags (f, f)
Kernel::Page (slot, idx).share (page, 0)
//kdebug ("mapping at ")
//kdebug_num (p)
//if readonly:
// kdebug (" (readonly)")
//kdebug ("\n")
if !mem.map (page, p):
Kernel::panic (0, "unable to map page")
return
Kernel::free_cap (page)
else:
if readonly:
Kernel::panic (0, "unwritable bss section")
return
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Kernel::Page page = mem.mapping ((void *)p)
if Kernel::recv.data[0].l == Kernel::NO_ERROR:
// No error means there is a mapping.
Kernel::free_cap (page)
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
else:
Kernel::free_cap (page)
page = mem.create_page ()
if Kernel::recv.data[0].l != Kernel::NO_ERROR:
Kernel::panic (Kernel::recv.data[0].l, "out of memory")
if !page.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME):
Kernel::panic (0, "out of memory")
if !mem.map (page, p):
Kernel::panic (0, "unable to map bss page")
Kernel::free_cap (page)
for unsigned p = 0; p < num_pages; ++p:
Kernel::my_memory.destroy (Kernel::Page (slot, p))
Kernel::Page stackpage = mem.create_page ()
stackpage.set_flags (Kernel::Page::PAYING | Kernel::Page::FRAME, Kernel::Page::PAYING | Kernel::Page::FRAME)
if Kernel::recv.data[0].l != Kernel::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
Kernel::panic (Kernel::recv.data[0].l, "unable to map initial stack page")
Kernel::free_cap (stackpage)
Kernel::Caps caps = mem.create_caps (NUM_CAPS)
thread.use (caps, 0)
thread.set_info (Kernel::Thread::A0, NUM_SLOTS)
thread.set_info (Kernel::Thread::A1, NUM_CAPS)
Kernel::Receiver receiver = mem.create_receiver ()
receiver.set_owner (thread.copy ())
Kernel::Cap call = receiver.create_call_capability ()
Kernel::Cap parent = Kernel::my_receiver.create_capability (Kernel::Num (current_thread++, THREAD))
caps.set (__receiver_num, receiver.copy ())
caps.set (__thread_num, thread.copy ())
caps.set (__memory_num, mem.copy ())
caps.set (__call_num, call.copy ())
caps.set (__parent_num, parent.copy ())
thread.run ()
Kernel::free_cap (receiver)
Kernel::free_cap (thread)
Kernel::free_cap (call)
Kernel::free_cap (parent)
Kernel::free_cap (caps)
static void kdebug_name (char const *t, file *f):
kdebug (t)
for unsigned j = 0; j < 16; ++j:
if f->name[j] != 0:
kdebug_char (f->name[j])
kdebug ("...")
static Device sysreq_dev
struct Dev:
static Dev *devs
static unsigned num_devs
Dev *next
unsigned code, idx, id
Device dev
static Dev *find (unsigned c, unsigned i):
for Dev *d = devs; d; d = d->next:
if d->code == c && d->idx == i:
return d
return NULL
static void add (unsigned c, unsigned i, Kernel::Cap cap):
if c == Keyboard::ID && i == 1:
sysreq_dev = cap
return
while find (c, i):
++i
Dev *d = new Dev ()
d->next = devs
d->code = c
d->idx = i
d->dev = cap
devs = d
d->id = num_devs++
static void kdebug_list ():
for Dev *d = devs; d; d = d->next:
kdebug (">")
kdebug_num (d->code)
kdebug (":")
kdebug_num (d->idx)
Dev *Dev::devs
unsigned Dev::num_devs
static void handle_init (unsigned id):
while true:
Kernel::wait ()
switch Kernel::recv.data[0].l:
case Parent::PROVIDE_DEVICE:
kdebug ("adding dev ")
kdebug_num (Kernel::recv.data[1].l)
kdebug (":")
kdebug_num (Kernel::recv.data[0].h)
kdebug (" as ")
kdebug_num (Dev::num_devs)
kdebug ("\n")
Kernel::Cap reply = Kernel::get_reply ()
Dev::add (Kernel::recv.data[1].l, Kernel::recv.data[0].h, Kernel::get_arg ())
reply.invoke ()
Kernel::free_cap (reply)
break
case Parent::INIT_DONE:
Kernel::Cap reply = Kernel::get_reply ()
memories.set (id + num_files, reply.copy ())
Kernel::free_cap (reply)
return
default:
kdebug ("unknown init request\n")
Kernel::panic (Kernel::recv.data[0].l)
static void get_device ():
Kernel::Cap reply = Kernel::get_reply ()
unsigned id = Kernel::recv.protected_data.l
Dev *d = Dev::find (Kernel::recv.data[1].l, Kernel::recv.data[0].h)
if d:
if inuse[id * Dev::num_devs + d->id] > 0:
Kernel::panic (id, "requesting device twice")
kdebug ("giving dev ")
kdebug_num (Kernel::recv.data[1].l)
kdebug (":")
kdebug_num (Kernel::recv.data[0].h)
kdebug (" = ")
kdebug_num (d->id)
kdebug (" to ")
kdebug_num (id)
kdebug ("\n")
Kernel::Caps cap = d->dev.create_user (Kernel::Memory (memory_slot, id), 0, 0x15000)
Kernel::Caps (terminal_slot, id).set (d->id, cap.copy ())
for unsigned i = 0; i < num_files; ++i:
if inuse[i * Dev::num_devs + d->id] == 2:
inuse[i * Dev::num_devs + d->id] = 1
inuse[id * Dev::num_devs + d->id] = 2
d->dev.use (cap)
Kernel::Cap ret = cap.get (0)
reply.invoke (0, 0, ret.copy ())
Kernel::free_cap (ret)
Kernel::free_cap (cap)
else:
kdebug ("device not found: ")
kdebug_num (Kernel::recv.data[1].l)
kdebug (":")
kdebug_num (Kernel::recv.data[0].h)
Dev::kdebug_list ()
kdebug ("\n")
reply.invoke (~0, ~0)
Kernel::panic (0)
Kernel::free_cap (reply)
static void draw_ball ():
int const r = 50
for int y = -r; y < r; ++y:
for int x = -r; x < r; ++x:
if x * x + y * y > r * r:
((unsigned *)0x15000)[(120 + y) * 320 + 160 + x] = 0x000000
else:
((unsigned *)0x15000)[(120 + y) * 320 + 160 + x] = 0x3f30ff
static void draw_square ():
int const r = 50
for int y = -r; y < r; ++y:
for int x = -r; x < r; ++x:
((unsigned *)0x15000)[(120 + y) * 320 + 160 + x] = 0xffff00
Kernel::Num start ():
// Wait for the debugging device to be active, in case there is one.
Kernel::schedule ()
Dev::devs = NULL
Dev::num_devs = 0
init_alloc ()
top_memory = Kernel::get_top_memory ()
Directory root = receive_devices ()
root.lock_ro ()
list_files (root)
sort ()
Kernel::Caps caps = Kernel::my_memory.create_caps (max_pages)
slot = caps.use ()
mapping = alloc_space (max_pages)
terminals = Kernel::my_memory.create_caps (num_files)
terminal_slot = terminals.use ()
// Two times, because it holds the memory and the init_done reply for each task.
memories = Kernel::my_memory.create_caps (num_files * 2)
memory_slot = memories.use ()
for unsigned i = 0; i < num_files; ++i:
kdebug_name ("loading ", &files[index[i]])
run (&files[index[i]], files[index[i]].name[0] == '#', i)
kdebug ("running\n")
handle_init (i)
inuse = new unsigned[num_files * Dev::num_devs]
for unsigned f = 0; f < num_files; ++f:
for unsigned d = 0; d < Dev::num_devs; ++d:
inuse[f * Dev::num_devs + d] = 0
// Notify all programs that they may start.
for unsigned i = 0; i < num_files; ++i:
Kernel::Cap (memory_slot, i + num_files).invoke ()
// create terminals.
for unsigned i = 0; i < num_files; ++i:
Kernel::Caps term (terminal_slot, i)
Kernel::Memory mem (memory_slot, i)
Kernel::set_recv_arg (term)
mem.create_caps (Dev::num_devs)
// set up system request.
Kernel::Caps sysreq_caps = sysreq_dev.create_user (Kernel::my_memory)
sysreq_dev.use (sysreq_caps)
Keyboard sysreq = sysreq_caps.get (0)
Kernel::free_cap (sysreq_dev)
Kernel::free_cap (sysreq_caps)
Kernel::Cap cap = Kernel::my_receiver.create_capability (Kernel::Num (0, SYSREQ))
sysreq.set_cb (cap.copy ())
Kernel::free_cap (sysreq)
Kernel::free_cap (cap)
// set up own capabilities.
Dev *display_dev = Dev::find (Display::ID, 0)
if !display_dev:
Kernel::panic (0, "no display")
Kernel::Caps display_caps = display_dev->dev.create_user (Kernel::my_memory, 0, 0x15000)
Display display = display_caps.get (0)
draw_ball ()
Dev *keyboard_dev = Dev::find (Keyboard::ID, 0)
if !keyboard_dev:
Kernel::panic (0, "no keyboard")
Kernel::Caps keyboard_caps = keyboard_dev->dev.create_user (Kernel::my_memory, 0, 0x15000)
Keyboard keyboard = keyboard_caps.get (0)
kdebug ("init done\n")
root.unlock_ro ()
Kernel::free_slot (slot)
Kernel::my_memory.destroy (caps)
Dev **waiter = new Dev *[num_files]
Kernel::Cap keyboard_cb = Kernel::my_receiver.create_capability (Kernel::Num (0, KEYBOARD))
bool in_system = false
while true:
Kernel::wait ()
switch Kernel::recv.protected_data.h:
case SYSREQ:
// System request.
if Kernel::recv.data[0].l & Keyboard::RELEASE:
continue
keyboard_dev->dev.use (keyboard_caps)
display_dev->dev.use (display_caps)
keyboard.set_cb (keyboard_cb)
in_system = true
continue
case THREAD:
// Request for something from a child thread.
switch Kernel::recv.data[0].l:
case Parent::INIT_DONE:
Kernel::panic (Kernel::recv.protected_data.l, "double init_done")
case Parent::PROVIDE_DEVICE:
Kernel::panic (Kernel::recv.protected_data.l, "too late now for provide")
case Parent::GET_DEVICE:
get_device ()
break
case Parent::WAIT:
unsigned id = Kernel::recv.protected_data.l
Dev *dev = Dev::find (Kernel::recv.data[1].l, 0)
if id >= num_files:
Kernel::panic (0, "invalid id")
if !dev:
Kernel::panic (0, "invalid dev")
switch inuse[id * Dev::num_devs + dev->id]:
case 0:
Kernel::panic (0, "waiting for non-owned device")
case 2:
if !in_system:
Kernel::recv.reply.invoke ()
break
// fall through.
case 1:
Kernel::Cap reply = Kernel::get_reply ()
memories.set (id + num_files, reply.copy ())
Kernel::free_cap (reply)
waiter[id] = dev
break
break
case Parent::EXIT:
Kernel::panic (Kernel::recv.protected_data.l, "exit is not supported")
default:
Kernel::panic (Kernel::recv.data[0].l, "invalid operation from child")
break
case KEYBOARD:
if !in_system:
break
if Kernel::recv.data[0].l == (Key::ENTER | Keyboard::RELEASE):
for Dev *d = Dev::devs; d; d = d->next:
if d->idx != 0:
continue
for unsigned i = 0; i < num_files; ++i:
if inuse[i * Dev::num_devs + d->id] == 2:
Kernel::Cap c = Kernel::Caps (terminal_slot, i).get (d->id)
d->dev.use (c)
Kernel::free_cap (c)
if waiter[i] == d:
Kernel::Cap (memory_slot, i + num_files).invoke ()
waiter[i] = NULL
in_system = false
break
if Kernel::recv.data[0].l & Keyboard::RELEASE:
continue
unsigned which = 0
switch Kernel::recv.data[0].l:
case Key::VOLUME_DOWN:
// Set ball.
draw_ball ()
which = 2
break
case Key::VOLUME_UP:
// Set square.
draw_square ()
which = 1
break
if which != 0:
for Dev *d = Dev::devs; d; d = d->next:
if d->code != Display::ID || d->idx != 0:
continue
for unsigned f = 0; f < num_files; ++f:
if inuse[f * Dev::num_devs + d->id] == 0:
continue
inuse[f * Dev::num_devs + d->id] = (--which ? 2 : 1)
break
default:
Kernel::panic (Kernel::recv.protected_data.h, "unknown source of request")

View File

@ -162,16 +162,16 @@ class Udc:
char log_buffer[1000]
unsigned log_buffer_size
unsigned log_buffer_start
Kernel::Cap caller, caller_arg
Iris::Cap caller, caller_arg
bool have_caller
unsigned *page
unsigned *p
Kernel::Page buffer_page
Iris::Page buffer_page
public:
void init ()
void log (unsigned c)
void interrupt (unsigned cmd)
void send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::Cap arg)
void send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg)
Udc::Device Udc::device_descriptor = { sizeof (Device), Device::Type, 0x200, 0, 0, 0, max_packet_size0, 0xfffe, 0x0002, 0x100, 1, 2, 0, 1 }
Udc::my_config Udc::config_descriptor = {
@ -217,9 +217,9 @@ void Udc::init ():
// Normally a normal new page should be allocated here, but new isn't implemented at this point.
page = (unsigned *)LCD_FRAMEBUFFER_BASE
p = page
buffer_page = Kernel::my_memory.create_page ()
buffer_page.set_flags (Kernel::Page::FRAME | Kernel::Page::PAYING, Kernel::Page::FRAME | Kernel::Page::PAYING)
Kernel::my_memory.map (buffer_page, (unsigned)page)
buffer_page = Iris::my_memory.create_page ()
buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING, Iris::Page::FRAME | Iris::Page::PAYING)
Iris::my_memory.map (buffer_page, (unsigned)page)
// Disconnect from the bus and don't try to get high-speed.
UDC_POWER = 0
@ -242,14 +242,14 @@ void Udc::init ():
UDC_INTROUTE = 1 << 1
// Wait a while.
for unsigned w = 0; w < 10000; ++w:
Kernel::schedule ()
Iris::schedule ()
// Connect to the host.
UDC_POWER = UDC_POWER_SOFTCONN
bool Udc::vendor (Setup *s, unsigned cmd):
if !(s->request_type & 0x80):
kdebug ("data to device without size\n")
Kernel::panic (0)
Iris::panic (0)
return true
if s->request == 10:
static unsigned b[2]
@ -258,10 +258,10 @@ bool Udc::vendor (Setup *s, unsigned cmd):
if cmd_code != ~0:
b[0] = cmd_code
b[1] = cmd_arg
if cmd_code == Directory::LOCK_RO || cmd_code == Directory::UNLOCK_RO:
if cmd_code == Iris::Directory::LOCK_RO || cmd_code == Iris::Directory::UNLOCK_RO:
caller.invoke ()
Kernel::free_cap (caller)
Kernel::free_cap (caller_arg)
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("(un)lock response\n")
cmd_code = ~0
@ -283,10 +283,10 @@ bool Udc::vendor (Setup *s, unsigned cmd):
state = TX
return true
void Udc::send (unsigned code, unsigned narg, Kernel::Cap reply, Kernel::Cap arg):
void Udc::send (unsigned code, unsigned narg, Iris::Cap reply, Iris::Cap arg):
if cmd_code != ~0:
kdebug ("new code sent while old one wasn't finished.\n")
Kernel::panic (0)
Iris::panic (0)
cmd_code = code
cmd_arg = narg
caller = reply
@ -404,7 +404,7 @@ void Udc::irq_in (unsigned cmd):
switch state:
case IDLE:
if rebooting:
Kernel::reboot ()
Iris::reboot ()
if !(csr & UDC_CSR0_OUTPKTRDY):
return
union { unsigned d[2]; Setup s; } packet
@ -439,53 +439,53 @@ void Udc::irq_in (unsigned cmd):
case RX:
// The protocol that is used doesn't allow large packets, so being here always means the entire packet is received.
switch rx_request & 0xff:
case Directory::GET_SIZE & 0xff:
case Iris::Directory::GET_SIZE & 0xff:
if !have_caller:
kdebug ("received dir size from server without a caller waiting\n")
Kernel::panic (0)
Iris::panic (0)
unsigned size_l = UDC_FIFO (0)
unsigned size_h = UDC_FIFO (0)
caller.invoke (Kernel::Num (size_l, size_h))
Kernel::free_cap (caller)
Kernel::free_cap (caller_arg)
caller.invoke (Iris::Num (size_l, size_h))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("get_size response\n")
break
case Directory::GET_NAME & 0xff:
case Iris::Directory::GET_NAME & 0xff:
if !have_caller:
kdebug ("received filename from server without a caller waiting\n")
Kernel::panic (0)
Iris::panic (0)
unsigned n[4]
for unsigned i = 0; i < 4; ++i:
n[i] = UDC_FIFO (0)
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3]))
Kernel::free_cap (caller)
Kernel::free_cap (caller_arg)
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
//kdebug ("get_name response\n")
have_caller = false
break
case ::String::GET_SIZE & 0xff:
case Iris::String::GET_SIZE & 0xff:
if !have_caller:
kdebug ("received string size from server without a caller waiting\n")
Kernel::panic (0)
Iris::panic (0)
unsigned size_l = UDC_FIFO (0)
unsigned size_h = UDC_FIFO (0)
caller.invoke (Kernel::Num (size_l, size_h))
Kernel::free_cap (caller)
Kernel::free_cap (caller_arg)
caller.invoke (Iris::Num (size_l, size_h))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("get_filesize response\n")
break
case ::String::GET_CHARS & 0xff:
case Iris::String::GET_CHARS & 0xff:
if !have_caller:
kdebug ("received string char data from server without a caller waiting\n")
Kernel::panic (0)
Iris::panic (0)
unsigned n[4]
for unsigned i = 0; i < 4; ++i:
n[i] = UDC_FIFO (0)
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3]))
Kernel::free_cap (caller)
Kernel::free_cap (caller_arg)
caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("get_chars response\n")
break
@ -493,7 +493,7 @@ void Udc::irq_in (unsigned cmd):
kdebug ("invalid vendor request: ")
kdebug_num (rx_request)
kdebug ("\n")
Kernel::panic (0)
Iris::panic (0)
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
state = IDLE
break
@ -504,7 +504,7 @@ void Udc::irq_out (unsigned cmd):
UDC_INDEX = 1
if !have_caller:
kdebug ("received bulk data from server without a caller waiting\n")
Kernel::panic (0)
Iris::panic (0)
unsigned size = UDC_OUTCOUNT
unsigned csr = UDC_OUTCSR
//kdebug ("handling bulk interrupt for ")
@ -516,11 +516,11 @@ void Udc::irq_out (unsigned cmd):
for unsigned i = 0; i < size; i += 4:
*p++ = UDC_FIFO (1)
if p - page == PAGE_SIZE >> 2:
buffer_page.share (caller_arg, Kernel::Page::FORGET)
buffer_page.set_flags (Kernel::Page::FRAME, Kernel::Page::FRAME)
buffer_page.share (caller_arg, Iris::Page::FORGET)
buffer_page.set_flags (Iris::Page::FRAME, Iris::Page::FRAME)
caller.invoke ()
Kernel::free_cap (caller)
Kernel::free_cap (caller_arg)
Iris::free_cap (caller)
Iris::free_cap (caller_arg)
have_caller = false
//kdebug ("bulk response\n")
p = page
@ -561,153 +561,153 @@ enum pdata:
FILE
NAME
Kernel::Num start ():
Iris::Num start ():
map_udc ()
map_gpio ()
map_cpm ()
Udc udc
Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
udc.init ()
Kernel::register_interrupt (IRQ_UDC)
Device fs_dev = Kernel::my_receiver.create_capability (FS)
Device data_dev = Kernel::my_receiver.create_capability (DATA)
Kernel::my_parent.provide_device <Filesystem> (fs_dev.copy ())
Kernel::my_parent.provide_device <String> (data_dev.copy ())
Kernel::free_cap (fs_dev)
Kernel::free_cap (data_dev)
Iris::register_interrupt (IRQ_UDC)
Iris::Device fs_dev = Iris::my_receiver.create_capability (FS)
Iris::Device data_dev = Iris::my_receiver.create_capability (DATA)
Iris::my_parent.provide_device <Iris::Filesystem> (fs_dev.copy ())
Iris::my_parent.provide_device <Iris::String> (data_dev.copy ())
Iris::free_cap (fs_dev)
Iris::free_cap (data_dev)
unsigned data_current_user = 0, fs_current_user = 0
unsigned next_user
unsigned state = 0
while true:
Kernel::wait ()
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
switch Kernel::recv.protected_data.h:
Iris::wait ()
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
switch Iris::recv.protected_data.h:
case 0:
switch Kernel::recv.protected_data.l:
switch Iris::recv.protected_data.l:
case IRQ_UDC:
udc.interrupt (state)
Kernel::register_interrupt (IRQ_UDC)
Iris::register_interrupt (IRQ_UDC)
break
case LOG:
udc.log (Kernel::recv.data[0].l)
udc.log (Iris::recv.data[0].l)
break
case FS:
Device::host (FS, fs_current_user, reply, arg)
Iris::Device::host (FS, fs_current_user, reply, arg)
continue
case DATA:
Device::host (DATA, data_current_user, reply, arg)
Iris::Device::host (DATA, data_current_user, reply, arg)
continue
default:
udc.log ('~')
char digit[] = "0123456789abcdef"
for unsigned i = 0; i < 8; ++i:
udc.log (digit[(Kernel::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
udc.log (digit[(Iris::recv.protected_data.l >> (4 * (7 - i))) & 0xf])
udc.log ('\n')
break
break
case DATA:
if data_current_user != Kernel::recv.protected_data.l:
if data_current_user != Iris::recv.protected_data.l:
break
switch Kernel::recv.data[0].l:
case ::String::GET_SIZE:
case ::String::GET_CHARS:
switch Iris::recv.data[0].l:
case Iris::String::GET_SIZE:
case Iris::String::GET_CHARS:
reply.invoke (0)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case ::String::GET_PAGE:
case Iris::String::GET_PAGE:
default:
reply.invoke (Kernel::ERR_INVALID_OPERATION)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
break
case FS:
if fs_current_user != Kernel::recv.protected_data.l:
if fs_current_user != Iris::recv.protected_data.l:
break
switch Kernel::recv.data[0].l:
case Filesystem::USE_DEVICE:
case Filesystem::USE_DEVICE_RO:
Directory dir = Kernel::my_receiver.create_capability (Kernel::Num (0, DIRECTORY))
switch Iris::recv.data[0].l:
case Iris::Filesystem::USE_DEVICE:
case Iris::Filesystem::USE_DEVICE_RO:
Iris::Directory dir = Iris::my_receiver.create_capability (Iris::Num (0, DIRECTORY))
reply.invoke (0, 0, dir.copy ())
Kernel::free_cap (dir)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
Iris::free_cap (dir)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
default:
reply.invoke (Kernel::ERR_INVALID_OPERATION)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
break
case DIRECTORY:
switch Kernel::recv.data[0].l:
case Directory::GET_NAME:
Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, NAME))
switch Iris::recv.data[0].l:
case Iris::Directory::GET_NAME:
Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, NAME))
reply.invoke (0, 0, name.copy ())
Kernel::free_cap (name)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
Iris::free_cap (name)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case Directory::GET_SIZE:
case Directory::LOCK_RO:
case Directory::UNLOCK_RO:
state = Kernel::recv.data[0].l
if Kernel::recv.data[1].h != 0:
case Iris::Directory::GET_SIZE:
case Iris::Directory::LOCK_RO:
case Iris::Directory::UNLOCK_RO:
state = Iris::recv.data[0].l
if Iris::recv.data[1].h != 0:
kdebug ("index out of supported range\n")
Kernel::panic (0)
udc.send (Kernel::recv.data[0].l, Kernel::recv.data[1].l, reply, arg)
Iris::panic (0)
udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
continue
case Directory::GET_FILE_RO:
if Kernel::recv.data[1].h != 0:
case Iris::Directory::GET_FILE_RO:
if Iris::recv.data[1].h != 0:
kdebug ("index out of supported range\n")
Kernel::panic (0)
Iris::panic (0)
//kdebug ("sending file\n")
Kernel::Cap file = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, FILE))
Iris::Cap file = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, FILE))
reply.invoke (0, 0, file.copy ())
Kernel::free_cap (file)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
Iris::free_cap (file)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case Directory::GET_FILE_INFO:
case Iris::Directory::GET_FILE_INFO:
default:
reply.invoke (Kernel::ERR_INVALID_OPERATION)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
break
case FILE:
switch Kernel::recv.data[0].l:
case ::String::GET_SIZE:
case ::String::GET_CHARS:
case ::String::GET_PAGE:
udc.send (Kernel::recv.data[0].l | ((Kernel::recv.data[1].l >> PAGE_BITS) << 16), Kernel::recv.protected_data.l, reply, arg)
switch Iris::recv.data[0].l:
case Iris::String::GET_SIZE:
case Iris::String::GET_CHARS:
case Iris::String::GET_PAGE:
udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.l, reply, arg)
continue
default:
reply.invoke (Kernel::ERR_INVALID_OPERATION)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
break
case NAME:
switch Kernel::recv.data[0].l:
case ::String::GET_SIZE:
switch Iris::recv.data[0].l:
case Iris::String::GET_SIZE:
reply.invoke (16)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
case ::String::GET_CHARS:
state = Kernel::recv.data[0].l
udc.send (Directory::GET_NAME, Kernel::recv.protected_data.l, reply, arg)
case Iris::String::GET_CHARS:
state = Iris::recv.data[0].l
udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.l, reply, arg)
continue
default:
reply.invoke (Kernel::ERR_INVALID_OPERATION)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
reply.invoke (Iris::ERR_INVALID_OPERATION)
Iris::free_cap (reply)
Iris::free_cap (arg)
continue
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
Iris::free_cap (reply)
Iris::free_cap (arg)

View File

@ -21,363 +21,405 @@
#include "iris.hh"
// List interface.
template <typename _T> //
struct List : public Kernel::Caps:
List (Kernel::Caps c = Kernel::Cap ()) : Kernel::Caps (c):
List <_T> create (unsigned size, Kernel::Memory mem = Kernel::my_memory):
return List <_T> (mem.create_caps (size))
void set (unsigned idx, _T value):
return Kernel::Caps::set (idx, value)
_T get (unsigned idx):
return _T (Kernel::Caps::get (idx))
namespace Iris:
// Caplist interface.
template <typename _T> //
struct Caplist : public Iris::Caps:
Caplist (Iris::Caps c = Iris::Cap ()) : Iris::Caps (c):
Caplist <_T> create (unsigned size, Iris::Memory mem = Iris::my_memory):
return Caplist <_T> (mem.create_caps (size))
void set (unsigned idx, _T value):
return Iris::Caps::set (idx, value)
_T get (unsigned idx):
return _T (Iris::Caps::get (idx))
/// A block of data with a size and content. Any character can be stored in it (including '\0').
struct String : public Kernel::Cap:
String (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
GET_SIZE = 0x2001
GET_CHARS
GET_PAGE
ID
/// Get the size of the string.
Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
/// Get exactly 16 characters. The index must be word-aligned.
char *get_chars (Kernel::Num idx, char buffer[16]):
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
unsigned *b = (unsigned *)buffer
b[0] = Kernel::recv.data[0].l
b[1] = Kernel::recv.data[0].h
b[2] = Kernel::recv.data[1].l
b[3] = Kernel::recv.data[1].h
return buffer
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
Cap get_page (Kernel::Num idx, Kernel::Page ret = Kernel::my_memory.create_page ()):
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
return ret
/// A block of data with a size and content. Any character can be stored in it (including '\0').
struct String : public Iris::Cap:
String (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
GET_SIZE = 0x2001
GET_CHARS
GET_PAGE
ID
/// Get the size of the string.
Iris::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
/// Get exactly 16 characters. The index must be word-aligned.
char *get_chars (Iris::Num idx, char buffer[16]):
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
unsigned *b = (unsigned *)buffer
b[0] = Iris::recv.data[0].l
b[1] = Iris::recv.data[0].h
b[2] = Iris::recv.data[1].l
b[3] = Iris::recv.data[1].h
return buffer
/// Helper function for get_page.
static Iris::Page _create_paying_page ():
Iris::Page ret = Iris::my_memory.create_page ()
ret.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
return ret
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
Cap get_page (Iris::Num idx, Iris::Page ret = _create_paying_page ()):
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
return ret
/// A writable String.
struct WString : public String:
WString (Kernel::Cap c = Kernel::Cap ()) : String (c):
enum request:
TRUNCATE = String::ID
SET_CHARS
SET_PAGE
ID
/// Set the size of the string. Strings may have a limit to this setting.
void truncate (Kernel::Num size):
call (CAP_MASTER_DIRECT | TRUNCATE, size)
/// Set exactly 4 characters. The index must be word-aligned.
void set_chars (Kernel::Num idx, char buffer[4]):
call (Kernel::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
void set_page (Kernel::Num idx, Kernel::Page page):
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
/// A writable String.
struct WString : public String:
WString (Iris::Cap c = Iris::Cap ()) : String (c):
enum request:
TRUNCATE = String::ID
SET_CHARS
SET_PAGE
ID
/// Set the size of the string. Strings may have a limit to this setting.
void truncate (Iris::Num size):
call (CAP_MASTER_DIRECT | TRUNCATE, size)
/// Set exactly 4 characters. The index must be word-aligned.
void set_chars (Iris::Num idx, char buffer[4]):
call (Iris::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
void set_page (Iris::Num idx, Iris::Page page):
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
// Every process which wants to be switchable through a terminal must implement this interface.
struct Device : public Kernel::Cap:
Device (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
CREATE_USER = WString::ID
DESTROY_USER
UNUSE
USE
ID
// Create a new user for this device. It will not be the active user.
// The provided storage must allow object creation; no other actions may be used by the terminal.
Kernel::Cap create_user (Kernel::Memory storage, unsigned arg1 = 0, Kernel::Num arg2 = 0):
iocall (storage, Kernel::Num (CAP_MASTER_DIRECT | CREATE_USER, arg1), arg2)
return Kernel::get_arg ()
// Destroy a user. It is made inactive if it was active.
void destroy_user (Kernel::Cap user):
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
// Make user inactive.
void unuse (Kernel::Cap user):
ocall (user, CAP_MASTER_DIRECT | UNUSE)
// Make user active. It makes the previous active user inactive.
void use (Kernel::Cap user):
ocall (user, CAP_MASTER_DIRECT | USE)
// Convenience function for threads implementing a device.
static void host (unsigned id, unsigned &current_user, Kernel::Cap &reply, Kernel::Cap &arg, unsigned capssize = 3, unsigned (*create)(Kernel::Memory mem, Kernel::Caps caps) = NULL, void (*destroy)(unsigned id, Kernel::Caps caps) = NULL, void (*use)(unsigned id, Kernel::Caps caps) = NULL, void (*unuse)(unsigned id, Kernel::Caps caps) = NULL):
static unsigned last_user
switch Kernel::recv.data[0].l:
case Device::CREATE_USER:
Kernel::Memory mem (arg)
Kernel::Caps caps = mem.create_caps (capssize)
unsigned user
if create:
user = create (mem, caps)
else:
// Increment last_user; skip 0.
// FIXME: if this really wraps, it is possible that two users share their id.
if !++last_user:
++last_user
user = last_user
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (user, id))
caps.set (0, c.copy ())
caps.set (1, mem.copy ())
reply.invoke (0, 0, caps.copy ())
Kernel::free_cap (c)
Kernel::free_cap (caps)
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
case Device::DESTROY_USER:
Kernel::Caps caps (arg)
Kernel::Cap c = caps.get (0)
Kernel::Num user = Kernel::my_receiver.get_protected (c)
Kernel::free_cap (c)
if user.h != id:
Kernel::panic (user.h, "invalid id for destroy")
// TODO: unuse.
if destroy:
destroy (user.l, caps)
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
case Device::USE:
Kernel::Caps caps (arg)
Kernel::Cap c = caps.get (0)
Kernel::Num user = Kernel::my_receiver.get_protected (c)
Kernel::free_cap (c)
if user.h != id:
Kernel::panic (user.h, "invalid id for use")
// TODO: send unuse signal.
current_user = user.l
if use:
use (user.l, caps)
c = caps.get (2)
c.invoke (1)
Kernel::free_cap (c)
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
case Device::UNUSE:
Kernel::Caps caps (arg)
Kernel::Cap c = caps.get (0)
Kernel::Num user = Kernel::my_receiver.get_protected (c)
Kernel::free_cap (c)
if user.h != id:
Kernel::panic (user.h, "invalid id for unuse")
if unuse:
unuse (user.l, caps)
if user.l == current_user:
// Every process which wants to be switchable through a terminal must implement this interface.
struct Device : public Iris::Cap:
Device (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
CREATE_USER = WString::ID
DESTROY_USER
UNUSE
USE
ID
// Create a new user for this device. It will not be the active user.
// The provided storage must allow object creation; no other actions may be used by the terminal.
Iris::Cap create_user (Iris::Memory storage, unsigned arg1 = 0, Iris::Num arg2 = 0):
iocall (storage, Iris::Num (CAP_MASTER_DIRECT | CREATE_USER, arg1), arg2)
return Iris::get_arg ()
// Destroy a user. It is made inactive if it was active.
void destroy_user (Iris::Cap user):
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
// Make user inactive.
void unuse (Iris::Cap user):
ocall (user, CAP_MASTER_DIRECT | UNUSE)
// Make user active. It makes the previous active user inactive.
void use (Iris::Cap user):
ocall (user, CAP_MASTER_DIRECT | USE)
// Convenience function for threads implementing a device.
static void host (unsigned id, unsigned &current_user, Iris::Cap &reply, Iris::Cap &arg, unsigned capssize = 3, unsigned (*create)(Iris::Memory mem, Iris::Caps caps) = NULL, void (*destroy)(unsigned id, Iris::Caps caps) = NULL, void (*use)(unsigned id, Iris::Caps caps) = NULL, void (*unuse)(unsigned id, Iris::Caps caps) = NULL):
static unsigned last_user
switch Iris::recv.data[0].l:
case Device::CREATE_USER:
Iris::Memory mem (arg)
Iris::Caps caps = mem.create_caps (capssize)
unsigned user
if create:
user = create (mem, caps)
else:
// Increment last_user; skip 0.
// FIXME: if this really wraps, it is possible that two users share their id.
if !++last_user:
++last_user
user = last_user
Iris::Cap c = Iris::my_receiver.create_capability (Iris::Num (user, id))
caps.set (0, c.copy ())
caps.set (1, mem.copy ())
reply.invoke (0, 0, caps.copy ())
Iris::free_cap (c)
Iris::free_cap (caps)
Iris::free_cap (reply)
Iris::free_cap (arg)
break
case Device::DESTROY_USER:
Iris::Caps caps (arg)
Iris::Cap c = caps.get (0)
Iris::Num user = Iris::my_receiver.get_protected (c)
Iris::free_cap (c)
if user.h != id:
Iris::panic (user.h, "invalid id for destroy")
// TODO: unuse.
if destroy:
destroy (user.l, caps)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (arg)
break
case Device::USE:
Iris::Caps caps (arg)
Iris::Cap c = caps.get (0)
Iris::Num user = Iris::my_receiver.get_protected (c)
Iris::free_cap (c)
if user.h != id:
Iris::panic (user.h, "invalid id for use")
// TODO: send unuse signal.
current_user = user.l
if use:
use (user.l, caps)
c = caps.get (2)
c.invoke (0)
Kernel::free_cap (c)
current_user = 0
reply.invoke ()
Kernel::free_cap (reply)
Kernel::free_cap (arg)
break
c.invoke (1)
Iris::free_cap (c)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (arg)
break
case Device::UNUSE:
Iris::Caps caps (arg)
Iris::Cap c = caps.get (0)
Iris::Num user = Iris::my_receiver.get_protected (c)
Iris::free_cap (c)
if user.h != id:
Iris::panic (user.h, "invalid id for unuse")
if unuse:
unuse (user.l, caps)
if user.l == current_user:
c = caps.get (2)
c.invoke (0)
Iris::free_cap (c)
current_user = 0
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (arg)
break
default:
kdebug ("invalid request\n")
reply.invoke (~0)
Iris::free_cap (reply)
Iris::free_cap (arg)
break
// Interface for talking to the parent process.
struct Parent : public Kernel::Cap:
Parent (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
GET_DEVICE = Device::ID
PROVIDE_DEVICE
WAIT
GET_MEMORY
PROVIDE_MEMORY
INIT_DONE
EXIT
ID
// Get a device handle.
template <typename _T> _T get_device (unsigned num = 0):
icall (Kernel::Num (CAP_MASTER_DIRECT | GET_DEVICE, num), _T::ID)
return Kernel::get_arg ()
// Provide a device handle.
template <typename _T> void provide_device (Device dev, unsigned num = 0):
ocall (dev, Kernel::Num (CAP_MASTER_DIRECT | PROVIDE_DEVICE, num), _T::ID)
// Wait until a device is used by the caller again.
template <typename _T> void wait (unsigned num = 0):
call (Kernel::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
Kernel::Memory get_memory (Kernel::Cap target):
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
return Kernel::get_arg ()
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
Kernel::Cap provide_memory (unsigned limit):
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
return Kernel::get_arg ()
// Signal the parent that the initialisation phase is over.
void init_done ():
call (CAP_MASTER_DIRECT | INIT_DONE)
// Exit the program. The parent does not reply, but kills the process.
void exit (Kernel::Num code):
call (CAP_MASTER_DIRECT | EXIT, code)
struct Elfrun : public Iris::Cap:
Elfrun (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
RUN_STRING = Device::ID
RUN_CAPS
ID
enum arg_pos:
PARENT_MEMORY
DATA
PARENT
Iris::Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
Iris::Caps caps = Iris::my_memory.create_caps (3)
caps.set (PARENT_MEMORY, parent_memory)
caps.set (DATA, data)
caps.set (PARENT, parent)
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Iris::Num (num_slots, num_caps))
Iris::Caps ret = Iris::get_arg ()
Iris::my_memory.destroy (caps)
Iris::free_cap (caps)
return ret
Iris::Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
Iris::Caps caps = Iris::my_memory.create_caps (3)
caps.set (PARENT_MEMORY, parent_memory)
caps.set (DATA, data)
caps.set (PARENT, parent)
iocall (caps.copy (), Iris::Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Iris::Num (num_slots, num_caps))
Iris::Caps ret = Iris::get_arg ()
Iris::my_memory.destroy (caps)
Iris::free_cap (caps)
return ret
// Keyboard interface.
struct Keyboard : public Kernel::Cap:
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
SET_CB = Parent::ID
GET_NUM_KEYS
GET_KEYS
ID
// 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.
void set_cb (Kernel::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
// Get the number of keys on the keyboard.
unsigned get_num_keys ():
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
// Get the keycodes for the keys. The reply sends 4 key codes (32 bit each).
void get_keys (unsigned first):
call (CAP_MASTER_DIRECT | GET_KEYS, first)
// Interface for talking to the parent process.
struct Parent : public Iris::Cap:
Parent (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
GET_DEVICE = Elfrun::ID
PROVIDE_DEVICE
WAIT
GET_MEMORY
PROVIDE_MEMORY
INIT_DONE
EXIT
ID
// Get a device handle.
template <typename _T> _T get_device (unsigned num = 0):
icall (Iris::Num (CAP_MASTER_DIRECT | GET_DEVICE, num), _T::ID)
return Iris::get_arg ()
// Provide a device handle.
template <typename _T> void provide_device (Device dev, unsigned num = 0):
ocall (dev, Iris::Num (CAP_MASTER_DIRECT | PROVIDE_DEVICE, num), _T::ID)
// Wait until a device is used by the caller again.
template <typename _T> void wait (unsigned num = 0):
call (Iris::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
Iris::Memory get_memory (Iris::Cap target):
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
return Iris::get_arg ()
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
Iris::Cap provide_memory (unsigned limit):
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
return Iris::get_arg ()
// Signal the parent that the initialisation phase is over.
void init_done (Iris::Num stage = 0):
call (CAP_MASTER_DIRECT | INIT_DONE, stage)
// Exit the program. The parent does not reply, but kills the process.
void exit (Iris::Num code):
call (CAP_MASTER_DIRECT | EXIT, code)
// Buzzer interface.
struct Buzzer : public Kernel::Cap:
Buzzer (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
BEEP = Keyboard::ID
STOP
ID
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
void beep (unsigned freq, unsigned ms, unsigned volume, Kernel::Cap cb = Kernel::Cap ()):
ocall (cb, Kernel::Num (CAP_MASTER_DIRECT | BEEP, volume), Kernel::Num (freq, ms))
// Abort current beep, if any.
void stop ():
call (CAP_MASTER_DIRECT | STOP)
// Keyboard interface.
struct Keyboard : public Iris::Cap:
Keyboard (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
SET_CB = Parent::ID
GET_NUM_KEYS
GET_KEYS
ID
// 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.
void set_cb (Iris::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
// Get the number of keys on the keyboard.
unsigned get_num_keys ():
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
// Get the keycodes for the keys. The reply sends 4 key codes (32 bit each).
void get_keys (unsigned first):
call (CAP_MASTER_DIRECT | GET_KEYS, first)
// Display interface.
struct Display : public Kernel::Cap:
Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
SET_EOF_CB = Buzzer::ID
MAP_FB
GET_INFO
ID
// 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 (Kernel::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
// Map the framebuffer into memory.
void map_fb (unsigned address):
call (CAP_MASTER_DIRECT | MAP_FB, address)
// Get information about the display.
void get_info ():
// TODO: Interface is to be designed.
kdebug ("using undefined interface Display::get_info ()\n")
Kernel::panic (0)
// Buzzer interface.
struct Buzzer : public Iris::Cap:
Buzzer (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
BEEP = Keyboard::ID
STOP
ID
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
void beep (unsigned freq, unsigned ms, unsigned volume, Iris::Cap cb = Iris::Cap ()):
ocall (cb, Iris::Num (CAP_MASTER_DIRECT | BEEP, volume), Iris::Num (freq, ms))
// Abort current beep, if any.
void stop ():
call (CAP_MASTER_DIRECT | STOP)
// Numerical setting, such as a display backlight.
struct Setting : public Kernel::Cap:
Setting (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
SET = Display::ID
GET_RANGE
ID
// Set a new value.
void set (unsigned value):
call (CAP_MASTER_DIRECT | SET, value)
// Get the maximum value for this setting. Using a higher value with SET gives undefined results.
unsigned get_range ():
return call (CAP_MASTER_DIRECT | GET_RANGE).l
// Display interface.
struct Display : public Iris::Cap:
Display (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
SET_EOF_CB = Buzzer::ID
MAP_FB
GET_INFO
ID
// 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 (Iris::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
// Map the framebuffer into memory.
void map_fb (unsigned address):
call (CAP_MASTER_DIRECT | MAP_FB, address)
// Get information about the display.
void get_info ():
// TODO: Interface is to be designed.
Iris::panic (0, "using undefined interface Display::get_info ()")
// File system interface.
// filesystem-related interfaces: directory, stream, seekable.
// Normal files implement stream and/or seekable. Directories implement directory.
// Seekable is not a class, it is identical to [W]String.
// Numerical setting, such as a display backlight.
struct Setting : public Iris::Cap:
Setting (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
SET = Display::ID
GET_RANGE
ID
// Set a new value.
void set (unsigned value):
call (CAP_MASTER_DIRECT | SET, value)
// Get the maximum value for this setting. Using a higher value with SET gives undefined results.
unsigned get_range ():
return call (CAP_MASTER_DIRECT | GET_RANGE).l
// Directory interface.
struct Directory : public Kernel::Cap:
Directory (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
GET_SIZE = Setting::ID
GET_NAME
GET_FILE_RO
GET_FILE_INFO
LOCK_RO
UNLOCK_RO
ID
// Get the number of entries in this directory.
Kernel::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename.
String get_name (Kernel::Num idx):
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
return Kernel::get_arg ()
// Get the file.
Kernel::Cap get_file_ro (Kernel::Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
return Kernel::get_arg ()
// Get file info. TODO: define possible types.
Kernel::Num get_file_info (Kernel::Num idx, unsigned type):
return icall (Kernel::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
void lock_ro ():
call (CAP_MASTER_DIRECT | LOCK_RO)
// Release a read-only lock. Write operations can only be done when the directory is locked.
void unlock_ro ():
call (CAP_MASTER_DIRECT | UNLOCK_RO)
struct WDirectory : public Directory:
WDirectory (Kernel::Cap c = Kernel::Cap ()) : Directory (c):
enum request:
GET_FILE = Directory::ID
CREATE_FILE
DELETE_FILE
LOCK
UNLOCK
ID
// Get the file.
Kernel::Cap get_file (Kernel::Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
return Kernel::get_arg ()
// Create a new file. After this, any index may map to a different file.
Kernel::Cap create_file (String name):
icall (CAP_MASTER_DIRECT | CREATE_FILE)
return Kernel::get_arg ()
// Delete a file. After this, any index may map to a different file.
void delete_file (Kernel::Num idx):
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Lock the directory. Write operations can only be done when the directory is locked.
void lock ():
call (CAP_MASTER_DIRECT | LOCK)
// Unlock the directory. Write operations can only be done when the directory is locked.
void unlock ():
call (CAP_MASTER_DIRECT | UNLOCK)
// File system interface.
// filesystem-related interfaces: directory, stream, seekable.
// Normal files implement stream and/or seekable. Directories implement directory.
// Seekable is not a class, it is identical to [W]String.
// A filesystem turns a String into a Directory.
struct Filesystem : public Device:
Filesystem (Kernel::Cap c = Kernel::Cap ()) : Device (c):
enum request:
USE_DEVICE = WDirectory::ID
USE_DEVICE_RO
ID
WDirectory use_device (WString dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
return Kernel::get_arg ()
Directory use_device_ro (String dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
return Kernel::get_arg ()
// Directory interface.
struct Directory : public Iris::Cap:
Directory (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
GET_SIZE = Setting::ID
GET_NAME
GET_FILE_RO
GET_FILE_INFO
LOCK_RO
UNLOCK_RO
ID
// Get the number of entries in this directory.
Iris::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename.
String get_name (Iris::Num idx):
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
return Iris::get_arg ()
// Get the file.
Iris::Cap get_file_ro (Iris::Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
return Iris::get_arg ()
// Get file info. TODO: define possible types.
Iris::Num get_file_info (Iris::Num idx, unsigned type):
return icall (Iris::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
void lock_ro ():
call (CAP_MASTER_DIRECT | LOCK_RO)
// Release a read-only lock. Write operations can only be done when the directory is locked.
void unlock_ro ():
call (CAP_MASTER_DIRECT | UNLOCK_RO)
struct WDirectory : public Directory:
WDirectory (Iris::Cap c = Iris::Cap ()) : Directory (c):
enum request:
GET_FILE = Directory::ID
CREATE_FILE
DELETE_FILE
LOCK
UNLOCK
ID
// Get the file.
Iris::Cap get_file (Iris::Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
return Iris::get_arg ()
// Create a new file. After this, any index may map to a different file.
Iris::Cap create_file (String name):
icall (CAP_MASTER_DIRECT | CREATE_FILE)
return Iris::get_arg ()
// Delete a file. After this, any index may map to a different file.
void delete_file (Iris::Num idx):
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Lock the directory. Write operations can only be done when the directory is locked.
void lock ():
call (CAP_MASTER_DIRECT | LOCK)
// Unlock the directory. Write operations can only be done when the directory is locked.
void unlock ():
call (CAP_MASTER_DIRECT | UNLOCK)
// Stream interface.
struct Stream : public Kernel::Cap:
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
enum request:
READ = Filesystem::ID
WRITE
ID
// Try to read size bytes. Returns the number of bytes successfully read.
Kernel::Num read (Kernel::Num size, bool block):
return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, block), size)
// Try to write size bytes. Returns the number of bytes successfully written.
Kernel::Num write (String s, Kernel::Num size):
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
// A filesystem turns a String into a Directory.
struct Filesystem : public Device:
Filesystem (Iris::Cap c = Iris::Cap ()) : Device (c):
enum request:
USE_DEVICE = WDirectory::ID
USE_DEVICE_RO
ID
WDirectory use_device (WString dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
return Iris::get_arg ()
Directory use_device_ro (String dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
return Iris::get_arg ()
// Stream interface.
struct Stream : public Iris::Cap:
Stream (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request:
READ = Filesystem::ID
WRITE
ID
// Try to read size bytes. Returns the number of bytes successfully read.
Iris::Num read (Iris::Num size, bool block):
return icall (Iris::Num (CAP_MASTER_DIRECT | READ, block), size)
// Try to write size bytes. Returns the number of bytes successfully written.
Iris::Num write (String s, Iris::Num size):
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
// Block device interface.
struct Block_device : public WString:
Block_device (Kernel::Cap c = Kernel::Cap ()) : WString (c):
// TODO: to be designed.
// Block device interface.
struct Block_device : public WString:
Block_device (Iris::Cap c = Iris::Cap ()) : WString (c):
// TODO: to be designed.
// TODO.

59
init.config Normal file
View File

@ -0,0 +1,59 @@
# load <name> = '<filename>' load a file into memory. Don't use this after killbootthreads.
load session = "session.config"
load driver_lcd = "lcd.elf"
load driver_buzzer = "buzzer.elf"
load driver_gpio = "gpio.elf"
# load driver_audio = "audio.elf"
# load driver_udc = "udc.elf"
# load driver_nand = "nand.elf"
# load emu_lcd = "emu_display.elf"
# load emu_buzzer = "emu_buzzer.elf"
# load emu_keyboard = "emu_keyboard.elf"
# load emu_audio = "emu_audio.elf"
# load emu_udc = "emu_udc.elf"
# killbootthreads destroy bootinit, bootfs and bootstore.
killbootthreads
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
receive driver_lcd / Display = display
receive driver_lcd / Setting = display_bright
receive driver_buzzer / Buzzer = buzzer
receive driver_gpio / Keyboard , 0 = keyboard
receive driver_gpio / Keyboard , 1 = sysreq
# receive driver_audio / Audio = audio
# receive driver_udc / Udc = udc
# receive driver_nand / WString = nand
# driver <name> run a previously loaded program priviledged.
driver driver_lcd
driver driver_buzzer
driver driver_gpio
# driver driver_audio
# driver driver_udc
# driver driver_nand
# wait wait until all expected capabilities are received.
wait
# sysreq <cap> use a capability as the system request keyboard.
sysreq sysreq
# give <name> (<type> [, <index>]) = <cap> give this capability to this program when it requests it.
# give emu_display (display) = display
# give emu_display_bright (setting) = display_bright
# give emu_buzzer (buzzer) = buzzer
# give emu_keyboard (keyboard, 0) = keyboard
# give emu_audio (audio) = audio
# give emu_udc (udc) = udc
# run <name> run a previously loaded program (normally).
# run emu_lcd
# run emu_buzzer
# run emu_keyboard
# run emu_audio
# run emu_udc
# include <name> include a loaded file as another config file.
include session

View File

@ -60,8 +60,8 @@ void kThread::raise (unsigned code, unsigned data):
kdebug (':')
kdebug_num ((unsigned)old_current)
kdebug ('/')
if code < Kernel::NUM_EXCEPTION_CODES:
kdebug (Kernel::exception_name[code])
if code < Iris::NUM_EXCEPTION_CODES:
kdebug (Iris::exception_name[code])
else:
kdebug ("invalid code:")
kdebug_num (code)
@ -73,7 +73,7 @@ void kThread::raise (unsigned code, unsigned data):
if slots < 1 || !slot[0].caps || !slot[0].caps->cap (0)->target:
return
kCapability::Context c
c.data[0] = Kernel::Num (code, data)
c.data[0] = Iris::Num (code, data)
slot[0].caps->cap (0)->invoke (&c)
// From user-provided, thus untrusted, data, find a capability.
@ -128,7 +128,7 @@ bool kReceiver::try_deliver ():
return true
// Send a message to a receiver; try to deliver it immediately.
bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *c):
bool kReceiver::send_message (Iris::Num protected_data, kCapability::Context *c):
//log_message ("send_message", (unsigned)this, protected_data.l, c)
if owner && owner->is_waiting () && (!protected_only || protected_data.value () == reply_protected_data.value ()):
if protected_only:
@ -161,59 +161,64 @@ bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *
return true
static kCapability::Context *context
static kReceiver *reply_target
static Kernel::Num reply_protected
static void reply_num (Kernel::Num num):
static void reply_num (Iris::Num num):
kCapability::Context c
c.data[0] = num
c.data[1] = 0
if reply_target:
reply_target->send_message (reply_protected, &c)
else:
else if reply_protected.l == 0:
dpanic (0, "nothing to reply to")
else:
kdebug ("not replying, because receiver was destroyed in the operation\n")
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
kCapability::Context c
c.data[0] = Kernel::Num (num1, num2)
c.data[0] = Iris::Num (num1, num2)
c.data[1] = num3
if reply_target:
reply_target->send_message (reply_protected, &c)
else if reply_protected.l == 0:
dpanic (0, "nothing to reply to")
else:
dpanic (0, "nothing to reply to")
kdebug ("not replying, because receiver was destroyed in the operation\n")
static void reply_cap (unsigned target, Kernel::Num protected_data, kCapRef *ref, unsigned num = 0):
static void reply_cap (unsigned target, Iris::Num protected_data, kCapRef *ref, unsigned num = 0):
if !reply_target:
dpanic (0, "nothing to reply to")
if reply_protected.l == 0:
dpanic (0, "nothing to reply to")
else:
kdebug ("not replying, because receiver was destroyed in the operation\n")
return
replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref)
kCapability::Context c
c.arg = kCapRef (&replied_caps, 0)
c.copy[1] = true
c.data[0] = Kernel::Num (num, 0)
c.data[0] = Iris::Num (num, 0)
reply_target->send_message (reply_protected, &c)
c.arg->invalidate ()
static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void receiver_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
kReceiver *receiver = (kReceiver *)protected_data.l
switch cmd:
case Kernel::Receiver::SET_OWNER & REQUEST_MASK:
case Iris::Receiver::SET_OWNER & REQUEST_MASK:
if !c->arg.valid ():
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
unsigned cap = (unsigned)c->arg->target
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Kernel::Thread::SET_OWNER):
if cap != (CAPTYPE_THREAD | CAP_MASTER) && cap != (CAPTYPE_THREAD | Iris::Thread::SET_OWNER):
// FIXME: This makes it impossible to use a fake kThread capability.
return
receiver->own ((kThread *)c->arg->protected_data.l)
break
case Kernel::Receiver::CREATE_CAPABILITY & REQUEST_MASK:
case Iris::Receiver::CREATE_CAPABILITY & REQUEST_MASK:
reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities)
return
case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
case Iris::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Iris::Receiver::CALL_ASYNC : Iris::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
return
case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK:
case Iris::Receiver::GET_PROTECTED & REQUEST_MASK:
if !c->arg.valid () || c->arg->target != receiver:
if !c->arg.valid ():
kdebug ("invalid arg\n")
@ -226,23 +231,23 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
kdebug_num ((unsigned)c->arg->protected_data.l)
kdebug ("\n")
dpanic (0, "wrong argument for get_protected")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
reply_num (c->arg->protected_data)
return
case Kernel::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK:
case Iris::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK:
reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
return
case Kernel::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
case Iris::Receiver::SET_REPLY_PROTECTED_DATA & REQUEST_MASK:
receiver->reply_protected_data = c->data[1]
break
case Kernel::Receiver::GET_ALARM & REQUEST_MASK:
case Iris::Receiver::GET_ALARM & REQUEST_MASK:
reply_num (receiver->alarm_count)
return
case Kernel::Receiver::SET_ALARM & REQUEST_MASK:
case Kernel::Receiver::ADD_ALARM & REQUEST_MASK:
case Iris::Receiver::SET_ALARM & REQUEST_MASK:
case Iris::Receiver::ADD_ALARM & REQUEST_MASK:
unsigned old = receiver->alarm_count
if cmd == (Kernel::Receiver::SET_ALARM & REQUEST_MASK):
if cmd == (Iris::Receiver::SET_ALARM & REQUEST_MASK):
receiver->alarm_count = c->data[1].l
else:
receiver->alarm_count += c->data[1].l
@ -267,14 +272,14 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
return
default:
dpanic (cmd, "invalid receiver operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
reply_num (0)
static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void memory_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
kMemory *mem = (kMemory *)protected_data.l
switch cmd:
case Kernel::Memory::CREATE & REQUEST_MASK:
case Iris::Memory::CREATE & REQUEST_MASK:
switch c->data[0].h:
case CAPTYPE_RECEIVER:
kReceiver *ret = mem->alloc_receiver ()
@ -282,7 +287,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
else:
dpanic (0x03311992, "out of memory creating receiver")
reply_num (Kernel::ERR_OUT_OF_MEMORY)
reply_num (Iris::ERR_OUT_OF_MEMORY)
return
case CAPTYPE_MEMORY:
kMemory *ret = mem->alloc_memory ()
@ -290,7 +295,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
else:
dpanic (0x13311992, "out of memory creating memory")
reply_num (Kernel::ERR_OUT_OF_MEMORY)
reply_num (Iris::ERR_OUT_OF_MEMORY)
return
case CAPTYPE_THREAD:
kThread *ret = mem->alloc_thread (c->data[1].l)
@ -301,7 +306,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
kdebug (")")
else:
dpanic (0x23311992, "out of memory creating thread")
reply_num (Kernel::ERR_OUT_OF_MEMORY)
reply_num (Iris::ERR_OUT_OF_MEMORY)
return
case CAPTYPE_PAGE:
kPage *ret = mem->alloc_page ()
@ -309,7 +314,7 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
else:
dpanic (0x33311992, "out of memory creating page")
reply_num (Kernel::ERR_OUT_OF_MEMORY)
reply_num (Iris::ERR_OUT_OF_MEMORY)
return
case CAPTYPE_CAPS:
kCaps *ret = mem->alloc_caps (c->data[1].l)
@ -317,16 +322,16 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
else:
dpanic (0x43311992, "out of memory creating caps")
reply_num (Kernel::ERR_OUT_OF_MEMORY)
reply_num (Iris::ERR_OUT_OF_MEMORY)
return
default:
dpanic (0, "invalid create type")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
break
case Kernel::Memory::DESTROY & REQUEST_MASK:
case Iris::Memory::DESTROY & REQUEST_MASK:
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || !c->arg->target || ((kObject *)c->arg->protected_data.l)->address_space != mem:
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
switch (unsigned)c->arg->target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER:
@ -348,87 +353,88 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
panic (0x55228930, "invalid case")
return
break
case Kernel::Memory::LIST & REQUEST_MASK:
case Iris::Memory::LIST & REQUEST_MASK:
// TODO
break
case Kernel::Memory::MAP & REQUEST_MASK:
case Iris::Memory::MAP & REQUEST_MASK:
// FIXME: this should work for fake pages as well.
if !c->arg.valid () || (unsigned)c->arg->target & ~KERNEL_MASK || ((unsigned)c->arg->target & CAPTYPE_MASK) != CAPTYPE_PAGE:
dpanic (0x22993341, "Trying to map non-page")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
kPage *page = (kPage *)c->arg->protected_data.l
if page->address_space != mem:
dpanic (0x52993341, "Trying to map foreign page")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
if c->data[1].l & (unsigned)c->arg->target & Kernel::Page::READONLY:
if c->data[1].l & (unsigned)c->arg->target & Iris::Page::READONLY:
kdebug ("Mapping readonly because capability is readonly\n")
page->flags |= Kernel::Page::MAPPED_READONLY
page->flags |= Iris::Page::MAPPED_READONLY
mem->map (page, c->data[1].l & PAGE_MASK)
break
case Kernel::Memory::MAPPING & REQUEST_MASK:
case Iris::Memory::MAPPING & REQUEST_MASK:
kPage *page = mem->get_mapping (c->data[1].l)
if !page:
reply_num (Kernel::ERR_UNMAPPED_READ)
reply_num (Iris::ERR_UNMAPPED_READ)
return
unsigned t = CAPTYPE_PAGE | CAP_MASTER
if page->flags & Kernel::Page::MAPPED_READONLY:
t |= Kernel::Page::READONLY
if page->flags & Iris::Page::MAPPED_READONLY:
t |= Iris::Page::READONLY
reply_cap (t, (unsigned)page, &page->refs)
return
case Kernel::Memory::GET_LIMIT & REQUEST_MASK:
case Iris::Memory::GET_LIMIT & REQUEST_MASK:
reply_num (mem->limit)
return
case Kernel::Memory::SET_LIMIT & REQUEST_MASK:
case Iris::Memory::SET_LIMIT & REQUEST_MASK:
mem->limit = c->data[1].l
break
default:
dpanic (0, "invalid memory operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
reply_num (0)
static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void thread_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
dbg_push (__LINE__)
kThread *thread = (kThread *)protected_data.l
switch cmd:
case Kernel::Thread::GET_INFO & REQUEST_MASK:
case Iris::Thread::GET_INFO & REQUEST_MASK:
switch c->data[0].h:
case Kernel::Thread::PC:
case Iris::Thread::PC:
reply_num (thread->pc)
return
case Kernel::Thread::SP:
case Iris::Thread::SP:
reply_num (thread->sp)
return
case Kernel::Thread::FLAGS:
case Iris::Thread::FLAGS:
reply_num (thread->flags)
return
default:
reply_num (*kThread_arch_info (thread, c->data[0].h))
return
case Kernel::Thread::SET_INFO & REQUEST_MASK:
case Iris::Thread::SET_INFO & REQUEST_MASK:
unsigned *value
switch c->data[0].h:
case Kernel::Thread::PC:
case Iris::Thread::PC:
value = &thread->pc
break
case Kernel::Thread::SP:
case Iris::Thread::SP:
value = &thread->sp
break
case Kernel::Thread::FLAGS:
case Iris::Thread::FLAGS:
// It is not possible to set the PRIV flag (but it can be reset).
if c->data[1].l & Kernel::Thread::PRIV:
c->data[1].h &= ~Kernel::Thread::PRIV
if c->data[1].l & Iris::Thread::PRIV:
c->data[1].h &= ~Iris::Thread::PRIV
value = &thread->flags
if c->data[1].h & ~Kernel::Thread::USER_FLAGS:
if c->data[1].h & ~Iris::Thread::USER_FLAGS:
unsigned v = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
if (v & Kernel::Thread::WAITING) != (*value & Kernel::Thread::WAITING):
if v & Kernel::Thread::WAITING:
if (v & Iris::Thread::WAITING) != (*value & Iris::Thread::WAITING):
if v & Iris::Thread::WAITING:
thread->wait ()
else
thread->unwait ()
if (v & Kernel::Thread::RUNNING) != (*value & Kernel::Thread::RUNNING):
if v & Kernel::Thread::RUNNING:
if (v & Iris::Thread::RUNNING) != (*value & Iris::Thread::RUNNING):
if v & Iris::Thread::RUNNING:
thread->run ()
else:
thread->unrun ()
@ -439,140 +445,155 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
if value:
*value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
break
case Kernel::Thread::USE_SLOT & REQUEST_MASK:
case Iris::Thread::USE_SLOT & REQUEST_MASK:
dbg_push (__LINE__)
if c->data[1].l >= thread->slots || !c->arg.valid ():
if c->data[1].l == 0xdeadbeef:
bool dummy
dbg_code.h = (unsigned)c->arg.deref ()
break
dbg_send (5, 3)
dpanic (c->data[1].l, "no argument given for USE_SLOT")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
// FIXME: This doesn't allow using a fake caps.
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Kernel::Caps::USE):
dpanic (0, "argument for USE_SLOT is not a caps")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Iris::Caps::USE):
dpanic ((unsigned)c->arg->target, "argument for USE_SLOT is not a caps")
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
dbg_push (__LINE__)
unsigned slot = c->data[1].l
dbg_push (__LINE__)
kCaps *new_caps = (kCaps *)c->arg->protected_data.l
dbg_push (__LINE__)
if slot >= thread->slots:
dpanic (0, "using invalid slot")
return
dbg_push (__LINE__)
thread->unset_slot (slot)
dbg_push (__LINE__)
thread->slot[slot].caps = new_caps
dbg_push (__LINE__)
if new_caps:
dbg_push (__LINE__)
thread->slot[slot].next = new_caps->first_slot
thread->slot[slot].caps = new_caps
new_caps->first_slot.thread = thread
new_caps->first_slot.index = slot
dbg_push (__LINE__)
break
case Kernel::Thread::GET_CAPS & REQUEST_MASK:
case Iris::Thread::GET_CAPS & REQUEST_MASK:
unsigned slot = c->data[1].l
if slot < thread->slots:
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->slot[slot].caps, &thread->slot[slot].caps->refs, thread->slots)
else:
reply_num (thread->slots)
return
case Kernel::Thread::SCHEDULE & REQUEST_MASK:
case Iris::Thread::SCHEDULE & REQUEST_MASK:
do_schedule = true
return
default:
if !(thread->flags & Kernel::Thread::PRIV):
if !(thread->flags & Iris::Thread::PRIV):
dpanic (0, "invalid thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
switch cmd:
case Kernel::Thread::PRIV_REGISTER_INTERRUPT & REQUEST_MASK:
case Iris::Thread::PRIV_REGISTER_INTERRUPT & REQUEST_MASK:
arch_register_interrupt (c->data[1].l, c->arg.valid () && (((unsigned)c->arg->target) & ~REQUEST_MASK) == CAPTYPE_RECEIVER ? (kReceiver *)c->arg->protected_data.l : NULL)
break
case Kernel::Thread::PRIV_GET_TOP_MEMORY & REQUEST_MASK:
case Iris::Thread::PRIV_GET_TOP_MEMORY & REQUEST_MASK:
reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs)
return
case Kernel::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
case Iris::Thread::PRIV_MAKE_PRIV & REQUEST_MASK:
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
dpanic (0, "not a thread argument for make priv")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV
((kThread *)c->arg->protected_data.l)->flags |= Iris::Thread::PRIV
break
case Kernel::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
case Iris::Thread::PRIV_ALLOC_RANGE & REQUEST_MASK:
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
panic (0x54365435, "non-memory argument to alloc_range")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
kMemory *mem = (kMemory *)c->arg->protected_data.l
if !mem->use (c->data[1].l):
dpanic (0x34365435, "out of memory during alloc_range")
reply_num (Kernel::ERR_OUT_OF_MEMORY)
reply_num (Iris::ERR_OUT_OF_MEMORY)
return
unsigned data = phys_alloc (c->data[1].l)
if !data:
mem->unuse (c->data[1].l)
dpanic (0x14365435, "out of memory during alloc_range")
reply_num (Kernel::ERR_OUT_OF_MEMORY)
reply_num (Iris::ERR_OUT_OF_MEMORY)
return
reply_num (data & ~0xc0000000)
return
case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
case Iris::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
if !c->arg.valid ():
panic (0x71342134, "no argument provided for alloc physical")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
panic (0x21342134, "no page provided for alloc physical")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
kPage *page = (kPage *)c->arg->protected_data.l
page->forget ()
if !(c->data[1].l & 2):
if page->flags & Kernel::Page::PAYING:
page->flags &= ~Kernel::Page::PAYING
if page->flags & Iris::Page::PAYING:
page->flags &= ~Iris::Page::PAYING
page->address_space->unuse ()
else:
// This is for mapping allocated ranges. They are already paid for. Record that.
if page->flags & Kernel::Page::PAYING:
if page->flags & Iris::Page::PAYING:
page->address_space->unuse ()
else:
page->flags |= Kernel::Page::PAYING
page->flags |= Iris::Page::PAYING
page->frame = (c->data[1].l & PAGE_MASK) | 0x80000000
page->flags |= Kernel::Page::FRAME
page->flags |= Iris::Page::FRAME
if !(c->data[1].l & 1):
page->flags |= Kernel::Page::UNCACHED
page->flags |= Iris::Page::UNCACHED
if !(c->data[1].l & 2):
page->flags |= Kernel::Page::PHYSICAL
page->flags |= Iris::Page::PHYSICAL
kPage_arch_update_mapping (page)
break
case Kernel::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
case Iris::Thread::PRIV_PHYSICAL_ADDRESS & REQUEST_MASK:
if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
dpanic (0x99049380, "invalid page for physical address")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
kPage *page = (kPage *)c->arg->protected_data.l
reply_num (page->frame & ~0xc0000000)
return
case Kernel::Thread::PRIV_REBOOT & REQUEST_MASK:
case Iris::Thread::PRIV_REBOOT & REQUEST_MASK:
arch_reboot ()
case Kernel::Thread::PRIV_PANIC & REQUEST_MASK:
case Iris::Thread::PRIV_PANIC & REQUEST_MASK:
if c->data[1].l == 0xdeaddead:
dbg_code.l = 1
break
panic (c->data[1].l, "panic requested by thread")
reply_num (~0)
return
case Kernel::Thread::DBG_SEND & REQUEST_MASK:
case Iris::Thread::DBG_SEND & REQUEST_MASK:
dbg_send (c->data[1].l, c->data[1].h)
break
default:
dpanic (0, "invalid priv thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
dbg_push (__LINE__)
reply_num (0)
dbg_push (__LINE__)
return
static void page_check_payment (kPage *page):
kPage *p
for p = page; p; p = p->share_prev:
if p->flags & Kernel::Page::PAYING:
if p->flags & Iris::Page::PAYING:
return
for p = page->share_next; p; p = p->share_next:
if p->flags & Kernel::Page::PAYING:
if p->flags & Iris::Page::PAYING:
return
// No kPage is paying for this frame anymore.
raw_pfree (page->frame)
@ -581,46 +602,55 @@ static void page_check_payment (kPage *page):
p->frame = NULL
p->share_prev = NULL
p->share_next = NULL
p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
kPage_arch_update_mapping (p)
for p = page, next = p->share_next; p; p = next, next = p->share_next:
p->frame = NULL
p->share_prev = NULL
p->share_next = NULL
p->flags &= ~(Kernel::Page::SHARED | Kernel::Page::FRAME)
p->flags &= ~(Iris::Page::SHARED | Iris::Page::FRAME)
kPage_arch_update_mapping (p)
static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void page_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
kPage *page = (kPage *)protected_data.l
switch cmd & ~Kernel::Page::READONLY:
case Kernel::Page::SHARE & REQUEST_MASK:
switch cmd & ~Iris::Page::READONLY:
case Iris::Page::SHARE & REQUEST_MASK:
if !c->arg.valid ():
// Cannot share without a target page.
dpanic (0, "no target page for share")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
// FIXME: This makes it impossible to use a fake kPage capability.
dpanic (0, "share target is no page")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
kPage *t = (kPage *)c->arg->protected_data.l
//kdebug ("sharing from ")
//kdebug_num ((unsigned)page)
//kdebug (" (frame ")
//kdebug_num (page->frame)
//kdebug (") to ")
//kdebug_num ((unsigned)t)
//kdebug (" (frame ")
//kdebug_num (t->frame)
//kdebug (")\n")
if t != page:
t->forget ()
if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY:
t->flags |= Kernel::Page::READONLY
if !(page->flags & Kernel::Page::FRAME):
if c->data[0].h & Iris::Page::READONLY || cmd & Iris::Page::READONLY:
t->flags |= Iris::Page::READONLY
if !(page->flags & Iris::Page::FRAME):
kdebug ("share problem: ")
kdebug_num (page->flags)
kdebug ("\n")
dpanic (0, "sharing nothing results in lost page")
kPage_arch_update_mapping (t)
break
if c->data[0].h & Kernel::Page::COPY:
if ~t->flags & Kernel::Page::PAYING:
if c->data[0].h & Iris::Page::COPY:
if ~t->flags & Iris::Page::PAYING:
kPage_arch_update_mapping (t)
break
if !(c->data[0].h & Kernel::Page::FORGET) || page->flags & Kernel::Page::SHARED:
if !(c->data[0].h & Iris::Page::FORGET) || page->flags & Iris::Page::SHARED:
unsigned *d = (unsigned *)page->frame
if t == page:
kPage *other = page->share_next ? page->share_next : page->share_prev
@ -635,20 +665,20 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
page->share_prev = NULL
page_check_payment (other)
else:
t->flags |= Kernel::Page::FRAME
t->flags |= Iris::Page::FRAME
t->frame = raw_zalloc ()
for unsigned i = 0; i < PAGE_SIZE; i += 4:
((unsigned *)t->frame)[i >> 2] = d[i >> 2]
if c->data[0].h & Kernel::Page::FORGET:
if c->data[0].h & Iris::Page::FORGET:
page->frame = NULL
page->flags &= ~Kernel::Page::FRAME
page->flags &= ~Iris::Page::FRAME
kPage_arch_update_mapping (page)
else:
if t != page:
t->frame = page->frame
t->flags |= Kernel::Page::FRAME
t->flags |= Iris::Page::FRAME
page->frame = NULL
page->flags &= ~Kernel::Page::FRAME
page->flags &= ~Iris::Page::FRAME
kPage_arch_update_mapping (page)
else:
dpanic (0, "sharing page with itself...")
@ -657,15 +687,15 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
dpanic (0, "sharing page with itself")
kPage_arch_update_mapping (t)
break
if c->data[0].h & Kernel::Page::FORGET:
if ~page->flags & Kernel::Page::SHARED:
if t->flags & Kernel::Page::PAYING:
if c->data[0].h & Iris::Page::FORGET:
if ~page->flags & Iris::Page::SHARED:
if t->flags & Iris::Page::PAYING:
t->frame = page->frame
t->flags |= Kernel::Page::FRAME
t->flags |= Iris::Page::FRAME
else:
dpanic (0, "move page failed because target is not paying")
page->frame = NULL
page->flags &= ~Kernel::Page::FRAME
page->flags &= ~Iris::Page::FRAME
kPage_arch_update_mapping (page)
else:
t->share_prev = page->share_prev
@ -685,49 +715,49 @@ static void page_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
if t->share_prev:
t->share_prev->share_next = t
t->frame = page->frame
t->flags |= Kernel::Page::FRAME
t->flags |= Iris::Page::FRAME
kPage_arch_update_mapping (t)
break
case Kernel::Page::SET_FLAGS & REQUEST_MASK:
if cmd & Kernel::Page::READONLY:
case Iris::Page::SET_FLAGS & REQUEST_MASK:
if cmd & Iris::Page::READONLY:
dpanic (0, "setting page flags denied")
reply_num (Kernel::ERR_WRITE_DENIED)
reply_num (Iris::ERR_WRITE_DENIED)
return
// Always refuse to set reserved flags.
c->data[1].h &= ~(Kernel::Page::PHYSICAL | Kernel::Page::UNCACHED)
c->data[1].h &= ~(Iris::Page::PHYSICAL | Iris::Page::UNCACHED)
// Remember the old flags.
unsigned old = page->flags
// Compute the new flags.
page->flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
// If we stop paying, see if the frame is still paid for. If not, free it.
if ~page->flags & old & Kernel::Page::PAYING:
if ~page->flags & old & Iris::Page::PAYING:
// Decrease the use counter in any case.
page->address_space->unuse ()
page_check_payment (page)
// If we start paying, increase the use counter.
if page->flags & ~old & Kernel::Page::PAYING:
if page->flags & ~old & Iris::Page::PAYING:
if !page->address_space->use():
dpanic (0, "cannot pay for frame")
// If it doesn't work, refuse to set the flag, and refuse to allocate a frame.
page->flags &= ~(Kernel::Page::PAYING | Kernel::Page::FRAME)
page->flags &= ~(Iris::Page::PAYING | Iris::Page::FRAME)
// However, if there already was a frame, keep it.
if old & Kernel::Page::FRAME:
page->flags |= Kernel::Page::FRAME
if old & Iris::Page::FRAME:
page->flags |= Iris::Page::FRAME
// If we want a frame, see if we can get it.
if ~old & page->flags & Kernel::Page::FRAME:
if ~page->flags & Kernel::Page::PAYING:
if ~old & page->flags & Iris::Page::FRAME:
if ~page->flags & Iris::Page::PAYING:
dpanic (0, "cannot have frame without paying")
page->flags &= ~Kernel::Page::FRAME
page->flags &= ~Iris::Page::FRAME
else:
page->frame = page->address_space->zalloc ()
kPage_arch_update_mapping (page)
break
default:
dpanic (0, "invalid page operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
if page->flags > 0x7f:
dpanic (page->flags, "weird output from page operation")
@ -755,12 +785,12 @@ static void print_cap (kCapRef cap, kCapRef self):
else:
kdebug (']')
static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void caps_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
kCaps *caps = (kCapsP)protected_data.l
switch cmd:
case Kernel::Caps::GET & REQUEST_MASK:
case Iris::Caps::GET & REQUEST_MASK:
if c->data[1].l >= caps->size:
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
kdebug_num ((unsigned)caps)
kdebug (" size: ")
kdebug_num (caps->size)
@ -782,10 +812,10 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
#endif
reply_cap ((unsigned)ret->target, ret->protected_data, ((unsigned)ret->target & ~KERNEL_MASK) == 0 ? &((kObject *)ret->protected_data.l)->refs : &ret->target->capabilities)
return
case Kernel::Caps::GET_SIZE & REQUEST_MASK:
case Iris::Caps::GET_SIZE & REQUEST_MASK:
reply_num (caps->size)
return
case Kernel::Caps::SET & REQUEST_MASK:
case Iris::Caps::SET & REQUEST_MASK:
if c->data[1].l >= caps->size:
dpanic (0, "invalid index for set caps")
return
@ -802,10 +832,10 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
//kdebug_num (caps->caps[c->data[1].l].protected_data.l)
//kdebug ("\n")
return
case Kernel::Caps::TRUNCATE & REQUEST_MASK:
case Iris::Caps::TRUNCATE & REQUEST_MASK:
dpanic (0, "truncate caps is not implemented yet.")
return
case Kernel::Caps::PRINT & REQUEST_MASK:
case Iris::Caps::PRINT & REQUEST_MASK:
if c->data[1].l >= caps->size:
dpanic (0, "invalid caps for print")
return
@ -839,12 +869,12 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
return
default:
dpanic (cmd, "invalid caps operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void list_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
kList *list = (kListP)protected_data.l
if cmd == Kernel::List::SET_CB & REQUEST_MASK:
if cmd == Iris::List::SET_CB & REQUEST_MASK:
list->owner.clone (0, c->arg, c->copy[1])
return
kListitem *item
@ -853,81 +883,81 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
else:
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM:
dpanic (0, "invalid request for list: arg is no listitem")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
item = (kListitem *)c->arg->protected_data.l
if item->list != list:
dpanic (0, "item list is not equal to called object")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
switch cmd:
case Kernel::List::GET_NEXT & REQUEST_MASK:
case Iris::List::GET_NEXT & REQUEST_MASK:
if !item:
item = list->first_listitem
else:
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::LIST:
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Iris::Listitem::LIST:
dpanic (0, "trying to get next listitem with insufficient rights")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
item = item->next_item
if !item:
reply_num (0)
return
reply_cap (CAPTYPE_LISTITEM | Kernel::Listitem::LIST, (unsigned)item, &item->refs)
reply_cap (CAPTYPE_LISTITEM | Iris::Listitem::LIST, (unsigned)item, &item->refs)
return
case Kernel::List::ADD_ITEM & REQUEST_MASK:
case Iris::List::ADD_ITEM & REQUEST_MASK:
if !item:
dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Kernel::Listitem::ADD:
if ((unsigned)c->arg->target & REQUEST_MASK) != CAP_MASTER && ((unsigned)c->arg->target & REQUEST_MASK) != Iris::Listitem::ADD:
dpanic (0, "trying to add listitem with insufficient rights")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
((kListitem *)c->arg->protected_data.l)->add (list)
break
case Kernel::List::GET_INFO & REQUEST_MASK:
case Iris::List::GET_INFO & REQUEST_MASK:
if !item:
dpanic (0, "no item for List::GET_INFO")
reply_num (Kernel::ERR_INVALID_ARGUMENT, ~0, ~0)
reply_num (Iris::ERR_INVALID_ARGUMENT, ~0, ~0)
return
reply_num (item->info)
return
case Kernel::List::SET_INFO & REQUEST_MASK:
case Iris::List::SET_INFO & REQUEST_MASK:
if !item:
dpanic (0, "no item for List::SET_INFO")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
item->info = c->data[1]
break
case Kernel::List::GET_CAP & REQUEST_MASK:
case Iris::List::GET_CAP & REQUEST_MASK:
if !item:
dpanic (0, "no item for List::GET_CAP")
reply_num (Kernel::ERR_INVALID_ARGUMENT)
reply_num (Iris::ERR_INVALID_ARGUMENT)
return
kCapability *cap = item->target.cap (0)
reply_cap ((unsigned)cap->target, cap->protected_data, ((unsigned)cap->target & ~KERNEL_MASK) == 0 ? &((kObject *)cap->target)->refs : &cap->target->capabilities)
return
default:
dpanic (0, "invalid list operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
reply_num (0)
static void listitem_invoke (unsigned cmd, unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void listitem_invoke (unsigned cmd, unsigned target, Iris::Num protected_data, kCapability::Context *c):
kListitem *item = (kListitemP)protected_data.l
switch cmd:
case Kernel::Listitem::CLEAR & REQUEST_MASK:
case Iris::Listitem::CLEAR & REQUEST_MASK:
// Disable linked capability.
item->add (NULL)
break
case Kernel::Listitem::SET_CAP & REQUEST_MASK:
case Iris::Listitem::SET_CAP & REQUEST_MASK:
// Set linked capability.
item->target.clone (0, c->arg, c->copy[1])
break
default:
dpanic (0, "invalid listitem operation")
reply_num (Kernel::ERR_INVALID_OPERATION)
reply_num (Iris::ERR_INVALID_OPERATION)
return
reply_num (0)
@ -936,18 +966,18 @@ static void kill_reply (kReceiver *r):
while cap.valid ():
kCapability *c = cap.deref ()
cap = c->sibling_next
if (unsigned)c->target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
if (unsigned)c->target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
c->invalidate ()
static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapability::Context *c):
static void kernel_invoke (unsigned target, Iris::Num protected_data, kCapability::Context *c):
// Kernel calling convention:
// data[0].l is the request.
// reply is the reply capability, or (for call capabilities) the target to call.
// other parameters' meanings depend on the operation.
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL_ASYNC):
if target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL) || target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL_ASYNC):
// This is a call capability. reply is the capability to call.
kReceiver *owner = (kReceiver *)protected_data.l
owner->protected_only = target == (CAPTYPE_RECEIVER | Kernel::Receiver::CALL)
owner->protected_only = target == (CAPTYPE_RECEIVER | Iris::Receiver::CALL)
if must_wait:
old_current->wait ()
if !reply_target:
@ -961,11 +991,11 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
// This is a user-implemented object. Create a real reply capability.
kReceiver *call_target = reply_target
c->reply = kCapRef (&reply_caps, 0)
c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Kernel::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs)
c->reply.set ((kReceiver *)(CAPTYPE_RECEIVER | Iris::Receiver::REPLY), protected_data, kCapRef (), &((kReceiver *)protected_data.l)->refs)
c->copy[0] = true
call_target->send_message (reply_protected, c)
c->reply->invalidate ()
else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
else if (unsigned)reply_target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
// Reply capability: destroy all before invoke.
kReceiver *r = (kReceiver *)reply_protected.l
kill_reply (r)
@ -981,7 +1011,7 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
return
if must_wait:
old_current->wait ()
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY):
if target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
// This is a reply capability.
kReceiver *r = (kReceiver *)protected_data.l
kill_reply (r)
@ -1026,7 +1056,7 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
return
return
void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c):
void invoke (kReceiverP target, Iris::Num protected_data, kCapability::Context *c):
if dbg_code.l && old_current->id != 1:
log_message ("invoke", (unsigned)target, protected_data.l, c)
if (unsigned)target & ~KERNEL_MASK:
@ -1046,4 +1076,5 @@ void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context
reply_protected = c->reply->protected_data
else:
reply_target = NULL
reply_protected.l = 0
kernel_invoke ((unsigned)target, protected_data, c)

View File

@ -53,11 +53,12 @@
// Master capabilities can create others.
#define CAP_MASTER_CREATE (1 << 31)
#define __receiver_num 0
#define __thread_num 1
#define __memory_num 2
#define __call_num 3
#define __parent_num 4
#define __caps_num 0
#define __receiver_num 1
#define __thread_num 2
#define __memory_num 3
#define __call_num 4
#define __parent_num 5
// 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.
@ -65,9 +66,8 @@
// This constant signifies that no capability is passed.
#define CAP_NONE (~CAP_COPY)
struct Parent
namespace Kernel:
namespace Iris:
struct Parent
enum Exception_code:
NO_ERROR
ERR_WRITE_DENIED
@ -138,6 +138,7 @@ namespace Kernel:
Cap alloc_cap ()
void free_slot (unsigned slot)
void free_cap (Cap cap)
extern bool enable_debug
struct Cap:
unsigned code
@ -161,6 +162,7 @@ namespace Kernel:
Num protected_data
Cap reply, arg
extern Caps my_caps
extern Receiver my_receiver
extern Thread my_thread
extern Memory my_memory
@ -280,7 +282,7 @@ namespace Kernel:
Cap create_capability (Num protected_data):
icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
return get_arg ()
Num get_protected (Kernel::Cap target):
Num get_protected (Cap target):
return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED)
Num get_reply_protected_data ():
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
@ -455,8 +457,8 @@ namespace Kernel:
PHYSICAL = 0x20
// This is a read-only flag, saying if this is uncachable memory.
UNCACHED = 0x40
void share (Cap target, unsigned flags):
ocall (target, Kernel::Num (CAP_MASTER_DIRECT | SHARE, flags))
void share (Cap target, unsigned flags = 0):
ocall (target, Num (CAP_MASTER_DIRECT | SHARE, flags))
unsigned get_flags ():
return call (CAP_MASTER_DIRECT | GET_FLAGS).l
bool set_flags (unsigned new_flags, unsigned mask):
@ -576,7 +578,7 @@ namespace Kernel:
Cap ().call ()
// The start function has this prototype (there is no main function).
Kernel::Num start ()
Iris::Num start ()
#ifndef __KERNEL__
#if 1
@ -596,7 +598,7 @@ static void kdebug_num (unsigned n, unsigned digits = 8):
for i = 0; i < digits; ++i:
kdebug_char (encode[(n >> (4 * ((digits - 1) - i))) & 0xf])
namespace Kernel:
namespace Iris:
inline void panic (unsigned code, char const *message = NULL):
if message:
kdebug (message)

View File

@ -75,7 +75,7 @@ struct kCapRef:
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, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
inline void set (kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
struct kObject:
kCapRef refs
@ -97,7 +97,7 @@ bool kObject::is_free ():
struct kCapability : public kObject:
struct Context:
Kernel::Num data[2]
Iris::Num data[2]
kCapRef reply
kCapRef arg
bool copy[2]
@ -105,7 +105,7 @@ struct kCapability : public kObject:
kCapRef parent
kCapRef children
kCapRef sibling_prev, sibling_next
Kernel::Num protected_data
Iris::Num protected_data
inline void invoke (kCapability::Context *c)
void invalidate ()
@ -138,7 +138,7 @@ struct kThread : public kObject:
void wait ()
void unwait ()
bool is_waiting ():
return flags & Kernel::Thread::WAITING
return flags & Iris::Thread::WAITING
kCapRef find_capability (unsigned code, bool *copy)
struct kReceiver : public kObject:
@ -154,14 +154,14 @@ struct kReceiver : public kObject:
// The message queue. kMessages are added at the tail, and removed at the front.
kMessageP messages
kMessageP last_message
Kernel::Num reply_protected_data
Iris::Num reply_protected_data
bool protected_only
// This limit is for messages stored in its address space. There is unlimited space if senders provide it.
unsigned queue_limit, queue_use
void own (kThreadP o)
void orphan ()
bool try_deliver ()
bool send_message (Kernel::Num protected_data, kCapability::Context *c)
bool send_message (Iris::Num protected_data, kCapability::Context *c)
void check (unsigned line)
struct kPage : public kObject:
@ -177,7 +177,7 @@ struct kCaps : public kObject:
unsigned size
kCapability caps[1]
inline kCapability *cap (unsigned idx)
void set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
void set (unsigned index, kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr = NULL)
void clone (unsigned index, kCapRef source, bool copy)
void init (unsigned size)
@ -185,8 +185,8 @@ struct kCaps : public kObject:
#define MAX_NUM_CAPS ((PAGE_SIZE - 8 - sizeof (kCaps)) / sizeof (kCapability) + 1)
struct kMessage : public kObject:
Kernel::Num protected_data
Kernel::Num data[2]
Iris::Num protected_data
Iris::Num data[2]
// This is a real Caps of two elements, not a link.
kCaps caps
@ -198,7 +198,7 @@ struct kList : public kObject:
struct kListitem : public kObject:
kListP list
kListitemP prev_item, next_item
Kernel::Num info
Iris::Num info
// This is a real Caps of one element, not a link.
kCaps target
void add (kList *l)
@ -257,7 +257,7 @@ extern "C":
#define panic(n, m) panic_impl ((n), __stringify (__LINE__), __PRETTY_FUNCTION__, (m))
void panic_impl (unsigned n, char const *line, char const *name, char const *message = "")
#ifndef NDEBUG
EXTERN Kernel::Num dbg_code
EXTERN Iris::Num dbg_code
EXTERN unsigned dbg_buffer[32]
EXTERN unsigned dbg_buffer_head
static void dbg_push (unsigned n):
@ -293,7 +293,11 @@ EXTERN kThreadP current, old_current
EXTERN bool do_schedule, must_wait
// reply_caps is the source of a receiver-generated reply capability.
// replied_caps is the source of kernel-generated capabilities which are used as arguments in a reply.
// reply_target is the target receiver for kernel replies.
// reply_protected is the protected data for the kernel reply.
EXTERN kCaps reply_caps, replied_caps
EXTERN kReceiver *reply_target
EXTERN Iris::Num reply_protected
// Defined in memory.ccp
unsigned init_memory (unsigned mem)
@ -303,11 +307,11 @@ unsigned phys_alloc (unsigned num)
void phys_free (unsigned page, unsigned num)
// Defind in invoke.ccp
void invoke (kReceiverP target, Kernel::Num protected_data, kCapability::Context *c)
void invoke (kReceiverP target, Iris::Num protected_data, kCapability::Context *c)
// Defined by architecture-specific files.
void kThread_arch_init (kThread *thread)
void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel::Num *data)
void kThread_arch_receive (kThread *thread, Iris::Num protected_data, Iris::Num *data)
unsigned *kThread_arch_info (kThread *thread, unsigned num)
void kMemory_arch_init (kMemory *mem)
void kMemory_arch_free (kMemory *mem)
@ -336,7 +340,7 @@ kCapability *kCapRef::deref ():
return caps ? caps->cap (index) : NULL
void kCapRef::clone (kCapRef source, bool copy):
caps->clone (index, source, copy)
void kCapRef::set (kReceiver *target, Kernel::Num pdata, kCapRef parent, kCapRef *parent_ptr):
void kCapRef::set (kReceiver *target, Iris::Num pdata, kCapRef parent, kCapRef *parent_ptr):
if valid ():
deref ()->invalidate ()
caps->set (index, target, pdata, parent, parent_ptr)

View File

@ -172,6 +172,8 @@ void phys_free (unsigned page, unsigned num):
kFreePages *p
for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
// Do nothing.
if p == p->next:
dpanic (0, "page is its own next")
// 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.

View File

@ -38,7 +38,7 @@ void kPage_arch_init (kPage *page):
page->arch.prev_mapped = NULL
page->arch.next_mapped = NULL
void kThread_arch_receive (kThread *thread, Kernel::Num protected_data, Kernel::Num *data):
void kThread_arch_receive (kThread *thread, Iris::Num protected_data, Iris::Num *data):
thread->arch.a[0] = data[0].l
thread->arch.a[1] = data[0].h
thread->arch.a[2] = data[1].l
@ -161,12 +161,12 @@ static unsigned make_entry_lo (kPage *page):
//kdebug ("not mapping because there is no frame\n")
return 0
unsigned flags
if page->flags & Kernel::Page::UNCACHED:
if page->flags & Iris::Page::UNCACHED:
flags = 0x10 | 0x2
else:
// 18 is write-back cache; 00 is write-through cache.
flags = 0x18 | 0x2
if ~page->flags & Kernel::Page::MAPPED_READONLY:
if ~page->flags & Iris::Page::MAPPED_READONLY:
flags |= 0x4
return ((page->frame & ~0x80000000) >> 6) | flags

View File

@ -33,7 +33,7 @@ static void init_idle ():
idle.schedule_next = NULL
idle.address_space = &idle_memory
idle.refs.reset ()
idle.flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV
idle.flags = Iris::Thread::RUNNING | Iris::Thread::PRIV
// initialize idle_memory.
idle_memory.prev = NULL
idle_memory.next = NULL
@ -52,7 +52,7 @@ static void init_idle ():
idle_page.prev = NULL
idle_page.next = NULL
idle_page.frame = 0x80000000
idle_page.flags = Kernel::Page::PAYING | Kernel::Page::FRAME
idle_page.flags = Iris::Page::PAYING | Iris::Page::FRAME
idle_page.refs.reset ()
idle_page.address_space = NULL
current = &idle
@ -147,7 +147,7 @@ static void init_threads ():
return
thread->pc = header->e_entry
thread->sp = 0x80000000
unsigned *used = (unsigned *)mem->zalloc ()
kPage **used = (kPage **)mem->zalloc ()
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
@ -168,12 +168,19 @@ static void init_threads ():
panic (0, "different pages mapped to one address in intitial file")
return
continue
used[idx] = 1
page = mem->alloc_page ()
page->frame = thread_start[i] + (idx << PAGE_BITS)
page->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
page->flags = Iris::Page::PAYING | Iris::Page::FRAME
if used[idx]:
page->share_next = used[idx]
used[idx]->share_prev = page
used[idx]->flags |= Iris::Page::SHARED
used[idx] = page
page->flags |= Iris::Page::SHARED
else:
used[idx] = page
if readonly:
page->flags |= Kernel::Page::MAPPED_READONLY
page->flags |= Iris::Page::MAPPED_READONLY
if !mem->map (page, p):
panic (0x22446688, "unable to map initial page")
return
@ -200,7 +207,7 @@ static void init_threads ():
if !page->frame:
panic (0x02220022, "out of memory");
return
page->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
page->flags = Iris::Page::PAYING | Iris::Page::FRAME
if !mem->map (page, p):
panic (0x33557799, "unable to map initial bss page")
return
@ -210,7 +217,7 @@ static void init_threads ():
kdebug_num (i, 1)
kdebug ('\n')
else:
if page->flags & Kernel::Page::MAPPED_READONLY:
if page->flags & Iris::Page::MAPPED_READONLY:
panic (0x20203030, "bss section starts on read-only page")
return
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
@ -230,7 +237,7 @@ static void init_threads ():
mem->pfree ((unsigned)used)
kPage *stackpage = mem->alloc_page ()
stackpage->frame = mem->zalloc ()
stackpage->flags = Kernel::Page::PAYING | Kernel::Page::FRAME
stackpage->flags = Iris::Page::PAYING | Iris::Page::FRAME
if !stackpage || !mem->map (stackpage, 0x7ffff000):
panic (0x13151719, "unable to map initial stack page")
return
@ -242,11 +249,12 @@ static void init_threads ():
kReceiver *recv = mem->alloc_receiver ()
recv->owner = thread
thread->receivers = recv
thread->slot[0].caps->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->slot[0].caps->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Kernel::Num ((unsigned)thread), kCapRef (), &thread->refs)
thread->slot[0].caps->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Kernel::Num ((unsigned)mem), kCapRef (), &mem->refs)
thread->slot[0].caps->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Kernel::Receiver::CALL), Kernel::Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->flags = Kernel::Thread::RUNNING | Kernel::Thread::PRIV
thread->slot[0].caps->set (__caps_num, (kReceiverP)(CAPTYPE_CAPS | CAP_MASTER), Iris::Num ((unsigned)thread->slot[0].caps), kCapRef (), &thread->slot[0].caps->refs)
thread->slot[0].caps->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Iris::Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->slot[0].caps->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Iris::Num ((unsigned)thread), kCapRef (), &thread->refs)
thread->slot[0].caps->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Iris::Num ((unsigned)mem), kCapRef (), &mem->refs)
thread->slot[0].caps->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Iris::Receiver::CALL), Iris::Num ((unsigned)recv), kCapRef (), &recv->refs)
thread->flags = Iris::Thread::RUNNING | Iris::Thread::PRIV
if !i:
first_scheduled = thread
init_receiver = recv

View File

@ -33,7 +33,7 @@ static kThread *handle_exit ():
schedule ()
if !current:
current = &idle
if (current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) != Kernel::Thread::RUNNING:
if (current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) != Iris::Thread::RUNNING:
panic (current->flags, "non-scheduled thread running")
if old_current == current:
return current
@ -54,7 +54,7 @@ static kThread *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 & Kernel::Thread::PRIV:
if current->flags & Iris::Thread::PRIV:
cp0_set (CP0_STATUS, 0x1000ff13)
else:
cp0_set (CP0_STATUS, 0x0000ff13)
@ -69,7 +69,7 @@ kThread *tlb_refill ():
if !directory:
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Kernel::ERR_NO_PAGE_DIRECTORY, addr)
current->raise (Iris::ERR_NO_PAGE_DIRECTORY, addr)
return handle_exit ()
unsigned EntryHi
cp0_get (CP0_ENTRY_HI, EntryHi)
@ -77,7 +77,7 @@ kThread *tlb_refill ():
if !t:
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Kernel::ERR_NO_PAGE_TABLE, addr)
current->raise (Iris::ERR_NO_PAGE_TABLE, addr)
else:
// - 2 instead of - 1 means reset bit 0
unsigned idx = (EntryHi >> 12) & ((1 << 9) - 2)
@ -161,13 +161,22 @@ static void arch_invoke ():
return
msg.reply = old_current->find_capability (old_current->arch.t[0], &msg.copy[0])
msg.arg = old_current->find_capability (old_current->arch.t[1], &msg.copy[1])
msg.data[0] = Kernel::Num (old_current->arch.a[0], old_current->arch.a[1])
msg.data[1] = Kernel::Num (old_current->arch.a[2], old_current->arch.a[3])
msg.data[0] = Iris::Num (old_current->arch.a[0], old_current->arch.a[1])
msg.data[1] = Iris::Num (old_current->arch.a[2], old_current->arch.a[3])
dbg_push (old_current->arch.v[0])
dbg_push (old_current->arch.t[0])
dbg_push (old_current->arch.t[1])
dbg_push (old_current->arch.a[0])
dbg_push (old_current->arch.a[1])
dbg_push (old_current->arch.a[2])
dbg_push (old_current->arch.a[3])
dbg_push (0xdeadbeef)
target->invoke (&msg)
dbg_push (0xfacebeef)
if do_schedule && !must_wait:
// If the call was to schedule without wait, it isn't done yet.
schedule ()
else if old_current != current && (old_current->flags & (Kernel::Thread::RUNNING | Kernel::Thread::WAITING)) == Kernel::Thread::RUNNING:
else if old_current != current && old_current && (old_current->flags & (Iris::Thread::RUNNING | Iris::Thread::WAITING)) == Iris::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
@ -186,31 +195,31 @@ kThread *exception ():
// TLB modification.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Kernel::ERR_WRITE_DENIED, addr)
current->raise (Iris::ERR_WRITE_DENIED, addr)
break
case 2:
// TLB load or instruction fetch.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Kernel::ERR_UNMAPPED_READ, addr)
current->raise (Iris::ERR_UNMAPPED_READ, addr)
break
case 3:
// TLB store.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Kernel::ERR_UNMAPPED_WRITE, addr)
current->raise (Iris::ERR_UNMAPPED_WRITE, addr)
break
case 4:
// Address error load or instruction fetch.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Kernel::ERR_INVALID_ADDRESS_READ, addr)
current->raise (Iris::ERR_INVALID_ADDRESS_READ, addr)
break
case 5:
// Address error store.
unsigned addr
cp0_get (CP0_BAD_V_ADDR, addr)
current->raise (Kernel::ERR_INVALID_ADDRESS_WRITE, addr)
current->raise (Iris::ERR_INVALID_ADDRESS_WRITE, addr)
break
case 6:
// Bus error instruction fetch.
@ -229,7 +238,7 @@ kThread *exception ():
case 9:
// Breakpoint.
#if 0 || defined (NDEBUG)
//current->raise (Kernel::ERR_BREAKPOINT, 0)
//current->raise (Iris::ERR_BREAKPOINT, 0)
#ifndef NDEBUG
current->pc += 4
#endif
@ -251,19 +260,19 @@ kThread *exception ():
break
case 10:
// Reserved instruction.
current->raise (Kernel::ERR_RESERVED_INSTRUCTION, 0)
current->raise (Iris::ERR_RESERVED_INSTRUCTION, 0)
break
case 11:
// Coprocessor unusable.
current->raise (Kernel::ERR_COPROCESSOR_UNUSABLE, 0)
current->raise (Iris::ERR_COPROCESSOR_UNUSABLE, 0)
break
case 12:
// Arithmetic overflow.
current->raise (Kernel::ERR_OVERFLOW, 0)
current->raise (Iris::ERR_OVERFLOW, 0)
break
case 13:
// Trap.
current->raise (Kernel::ERR_TRAP, 0)
current->raise (Iris::ERR_TRAP, 0)
break
case 15:
// Floating point exception.
@ -272,7 +281,7 @@ kThread *exception ():
case 23:
// Reference to WatchHi/WatchLo address.
cp0_set0 (CP0_WATCH_LO)
current->raise (Kernel::ERR_WATCHPOINT, 0)
current->raise (Iris::ERR_WATCHPOINT, 0)
break
case 24:
// Machine check.

View File

@ -28,12 +28,12 @@ LDFLAGS = --omagic -Ttext $(load)
arch_iris_sources = mips/interrupts.cc mips/arch.cc
boot_sources = mips/init.cc mips/nanonote/board.cc
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh devices.hh
boot_threads = init udc
programs = \#nanonote-gpio \#lcd display-emu bsquare display-emu2 ball \#buzzer metronome
boot_threads = bootinit udc
programs = init gpio lcd display-emu bsquare ball buzzer metronome elfrun
all: test
test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw $(addsuffix .elf,$(addprefix fs/,$(programs)))
test: iris.raw mips/nanonote/server/usb-server mips/nanonote/sdram-setup.raw $(addsuffix .elf,$(addprefix fs/,$(programs))) fs/init.config
echo "reboot 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')" | nc localhost 5050
mips/nanonote/server/usb-server: mips/nanonote/server/usb-server.ccp mips/nanonote/server/Makefile.am mips/nanonote/server/configure.ac devices.hh
@ -55,12 +55,15 @@ mips/nanonote/sdram-setup.elf: LDFLAGS = --omagic -T mips/nanonote/sdram-setup.l
mips/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads))
mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
mips/init.o: TARGET_FLAGS = -I/usr/include
boot-programs/init.o: TARGET_FLAGS = -I/usr/include
boot-programs/bootinit.o: TARGET_FLAGS = -I/usr/include
source/elfrun.o: TARGET_FLAGS = -I/usr/include
source/gpio.ccp: source/nanonote-gpio.ccp
ln -s $(subst source/,,$<) $@
$(addsuffix .elf,$(boot_threads)): TARGET_FLAGS = -I.
$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
$(addprefix fs/,$(addsuffix .elf,$(programs))): LDFLAGS = -EL
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh
source/\#lcd.o: source/charset.data
source/lcd.o: source/charset.data
source/charset.data: source/charset
$< > $@

View File

@ -104,14 +104,14 @@
// Default lcd framebuffer mapping space.
#define LCD_FRAMEBUFFER_BASE ((unsigned *)0x00015000)
// Map IO memory (requires a priviledged Kernel::my_thread capability).
// Map IO memory (requires a priviledged Iris::my_thread capability).
#include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping):
Kernel::Page p = Kernel::my_memory.create_page ()
Iris::Page p = Iris::my_memory.create_page ()
// false means not cachable; false means don't free when done.
p.alloc_physical (physical, false, false)
Kernel::my_memory.map (p, mapping)
Kernel::free_cap (p)
Iris::my_memory.map (p, mapping)
Iris::free_cap (p)
#define map_cpm() do { __map_io (CPM_PHYSICAL, CPM_BASE); } while (0)
#define map_intc() do { __map_io (INTC_PHYSICAL, INTC_BASE); } while (0)
@ -135,8 +135,8 @@ static void __map_io (unsigned physical, unsigned mapping):
// udelay implementation
void cdelay (unsigned cs):
Kernel::my_receiver.set_alarm (cs + 1)
Kernel::Cap ().call ()
Iris::my_receiver.set_alarm (cs + 1)
Iris::Cap ().call ()
#endif

View File

@ -105,37 +105,37 @@ void data::poll ():
case ~1 & 0xffff:
// No event.
break
case Directory::GET_SIZE:
case Iris::Directory::GET_SIZE:
unsigned long long size = dir.size ()
std::cerr << "sending dir size\n"
std::cerr << Directory::GET_SIZE << '\n'
std::cerr << Iris::Directory::GET_SIZE << '\n'
char *str = (char *)&size
for unsigned i = 0; i < 8; ++i:
std::cerr << " " << (unsigned)(str[i] & 0xff)
std::cerr << '\n'
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Iris::Directory::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
std::cerr << "unable to send size to device: " << usb_strerror () << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
continue
case Directory::GET_NAME:
case Iris::Directory::GET_NAME:
if buffer[1] >= dir.size ():
std::cerr << "invalid file name requested" << std::endl;
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
std::cerr << "sending filename\n"
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Directory::GET_NAME, 0, 0, dir[buffer[1]].name, 16, timeout) != 16:
std::cerr << "sending filename " << dir[buffer[1]].full << "\n"
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Iris::Directory::GET_NAME, 0, 0, dir[buffer[1]].name, 16, timeout) != 16:
std::cerr << "unable to send name to device: " << usb_strerror () << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
continue
case Directory::LOCK_RO:
case Iris::Directory::LOCK_RO:
std::cerr << "lock\n"
lock++
std::cerr << "freezing file list\n"
@ -145,7 +145,7 @@ void data::poll ():
if !i->name.empty () && i->name[0] != '.':
dir.push_back (Name (i->name))
continue
case Directory::UNLOCK_RO:
case Iris::Directory::UNLOCK_RO:
std::cerr << "unlock\n"
if !lock:
std::cerr << "unlocking without lock" << std::endl
@ -156,7 +156,7 @@ void data::poll ():
if !--lock:
dir.clear ()
continue
case String::GET_PAGE:
case Iris::String::GET_PAGE:
if buffer[1] >= dir.size ():
std::cerr << "reading invalid file" << std::endl
usb_release_interface (handle, 0)
@ -178,16 +178,16 @@ void data::poll ():
handle = NULL
return
continue
case String::GET_SIZE:
case Iris::String::GET_SIZE:
if buffer[1] >= dir.size ():
std::cerr << "reading invalid file size" << std::endl
std::cerr << "reading invalid file size " << buffer[1] << " >= " << dir.size () << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
handle = NULL
return
unsigned long long size = dir[buffer[1]].content.size ()
std::cerr << "sending file size " << size << "\n"
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, String::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, Iris::String::GET_SIZE, 0, 0, (char *)&size, 8, timeout) != 8:
std::cerr << "unable to send size to device: " << usb_strerror () << std::endl
usb_release_interface (handle, 0)
usb_close (handle)
@ -312,18 +312,18 @@ void data::boot (unsigned entry):
std::cerr << "(re)booted NanoNote\n"
static void dump_devices ():
std::cerr << std::hex << "String: " << String::ID
std::cerr << "\nWString: " << WString::ID
std::cerr << "\nDevice: " << Device::ID
std::cerr << "\nParent: " << Parent::ID
std::cerr << "\nKeyboard: " << Keyboard::ID
std::cerr << "\nBuzzer: " << Buzzer::ID
std::cerr << "\nDisplay: " << Display::ID
std::cerr << "\nSetting: " << Setting::ID
std::cerr << "\nDirectory: " << Directory::ID
std::cerr << "\nWDirectory: " << WDirectory::ID
std::cerr << "\nFilesystem: " << Filesystem::ID
std::cerr << "\nStream: " << Stream::ID
std::cerr << std::hex << "String: " << Iris::String::ID
std::cerr << "\nWString: " << Iris::WString::ID
std::cerr << "\nDevice: " << Iris::Device::ID
std::cerr << "\nParent: " << Iris::Parent::ID
std::cerr << "\nKeyboard: " << Iris::Keyboard::ID
std::cerr << "\nBuzzer: " << Iris::Buzzer::ID
std::cerr << "\nDisplay: " << Iris::Display::ID
std::cerr << "\nSetting: " << Iris::Setting::ID
std::cerr << "\nDirectory: " << Iris::Directory::ID
std::cerr << "\nWDirectory: " << Iris::WDirectory::ID
std::cerr << "\nFilesystem: " << Iris::Filesystem::ID
std::cerr << "\nStream: " << Iris::Stream::ID
std::cerr << "\n"
int main (int argc, char **argv):

View File

@ -21,7 +21,7 @@
.balign 0x1000
thread0:
.incbin "init.elf"
.incbin "bootinit.elf"
.balign 0x1000
thread1:

View File

@ -137,14 +137,14 @@
// Default lcd framebuffer mapping space.
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000)
// Map IO memory (requires a priviledged Kernel::my_thread capability).
// Map IO memory (requires a priviledged Iris::my_thread capability).
#include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping):
Kernel::Page p = Kernel::my_memory.create_page ()
Iris::Page p = Iris::my_memory.create_page ()
// false means not cachable; false means don't free when done.
p.alloc_physical (physical, false, false)
Kernel::my_memory.map (p, mapping)
Kernel::free_cap (p)
Iris::my_memory.map (p, mapping)
Iris::free_cap (p)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_BASE); } while (0)
@ -2326,8 +2326,8 @@ static __inline__ void udelay (unsigned us):
#ifndef __KERNEL__
static __inline__ void cdelay (unsigned ds):
Kernel::my_receiver.set_alarm (ds * (HZ / 100))
Kernel::Cap ().call (~0)
Iris::my_receiver.set_alarm (ds * (HZ / 100))
Iris::Cap ().call (~0)
#endif
/***************************************************************************

View File

@ -48,7 +48,7 @@ void kdebug_num (unsigned num, unsigned digits):
static void print_addr (char const *t, unsigned addr, bool last = false):
kdebug (t)
kdebug_num (addr)
#if 1
#if 0
unsigned de = addr >> 21
unsigned te = (addr >> 12) & ((1 << 9) - 1)
if de < 0x400 && old_current && old_current->address_space->arch.directory && old_current->address_space->arch.directory[de]:
@ -83,7 +83,7 @@ static void print_addr (char const *t, unsigned addr, bool last = false):
kdebug_num (((unsigned *)addr)[i])
kdebug ("\n")
#else
kdebug (last ? '\n' : ';')
kdebug (last ? "\n" : "; ")
#endif
static void panic_message (unsigned n, const char *line, char const *name, char const *message):
@ -118,11 +118,11 @@ static void panic_message (unsigned n, const char *line, char const *name, char
kdebug (':')
kdebug_num (dbg_code.l)
kdebug ('\n')
kdebug ("debug buffer:")
kdebug ("debug buffer (most recently pushed at end):")
unsigned b = dbg_buffer_head
for unsigned i = 0; i < 16; ++i:
for unsigned i = 0; i < 8; ++i:
kdebug ('\n')
for unsigned j = 0; j < 2; ++j:
for unsigned j = 0; j < 4; ++j:
kdebug (' ')
kdebug_num (dbg_buffer[b])
++b

81
plan
View File

@ -42,3 +42,84 @@ te doen:
- start programma van filesystem
- nand driver
- filesystems met backing store
Boot process:
- bootinit and filesystem (and backing store) are started.
- bootinit starts run.elf and loads init.elf.
- run starts init.
- init loads init.config and executes it.
- during that process, the initial programs are killed.
Order:
run.elf
init.elf
init.config
load.elf
drivers
emulations
programs
init.config is a script:
# load <name> = <filename> load a file into memory. Don't use this after killbootthreads.
load session = session.config
load driver_lcd = lcd.elf
load driver_buzzer = buzzer.elf
load driver_gpio = gpio.elf
load driver_audio = audio.elf
load driver_udc = udc.elf
load driver_nand = nand.elf
load emu_lcd = emu_display.elf
load emu_buzzer = emu_buzzer.elf
load emu_keyboard = emu_keyboard.elf
load emu_audio = emu_audio.elf
load emu_udc = emu_udc.elf
# killbootthreads destroy bootinit, bootfs and bootstore.
killbootthreads
# receive <cap> = <name> (<type> [, <index>]) prepare to accept a capability from a named program.
receive display = driver_lcd (display)
receive display_bright = driver_lcd (setting)
receive buzzer = driver_buzzer (buzzer)
receive keyboard = driver_gpio (keyboard, 0)
receive sysreq = driver_gpio (keyboard, 1)
receive audio = driver_audio (audio)
receive udc = driver_udc (udc)
receive nand = driver_nand (wstring)
# driver <name> run a previously loaded program priviledged.
driver driver_lcd
driver driver_buzzer
driver driver_gpio
driver driver_audio
driver driver_udc
driver driver_nand
# wait wait until all expected capabilities are received.
wait
# sysreq <cap> use a capability as the system request keyboard.
sysreq sysreq
# give <name> (<type> [, <index>]) = <cap> give this capability to this program when it requests it.
give emu_display (display) = display
give emu_display_bright (setting) = display_bright
give emu_buzzer (buzzer) = buzzer
give emu_keyboard (keyboard, 0) = keyboard
give emu_audio (audio) = audio
give emu_udc (udc) = udc
# run <name> run a previously loaded program (normally).
run emu_lcd
run emu_buzzer
run emu_keyboard
run emu_audio
run emu_udc
# include <name> include a loaded file as another config file.
include session
# loop sit and do nothing (respond to system request).
loop

View File

@ -36,24 +36,24 @@ static void unrun_thread (kThread *thread):
thread->schedule_next->schedule_prev = thread->schedule_prev
void kThread::run ():
if flags & Kernel::Thread::RUNNING:
if flags & Iris::Thread::RUNNING:
return
flags |= Kernel::Thread::RUNNING
flags |= Iris::Thread::RUNNING
if is_waiting ():
return
run_thread (this)
void kThread::unrun ():
if !(flags & Kernel::Thread::RUNNING):
if !(flags & Iris::Thread::RUNNING):
return
flags &= ~Kernel::Thread::RUNNING
flags &= ~Iris::Thread::RUNNING
if is_waiting ():
return
unrun_thread (this)
void kThread::unwait ():
flags &= ~Kernel::Thread::WAITING
if flags & Kernel::Thread::RUNNING:
flags &= ~Iris::Thread::WAITING
if flags & Iris::Thread::RUNNING:
run_thread (this)
static void alarm_tick (kReceiver *recv):
@ -73,9 +73,9 @@ static void alarm_tick (kReceiver *recv):
--recv->alarm_count
void kThread::wait ():
if flags & Kernel::Thread::RUNNING:
if flags & Iris::Thread::RUNNING:
unrun_thread (this)
flags |= Kernel::Thread::WAITING
flags |= Iris::Thread::WAITING
// Try to receive a message from a kReceiver immediately.
for kReceiver *r = receivers; r; r = r->next_owned:
if r->try_deliver ():

View File

@ -33,16 +33,16 @@ void ball (int x, int y, unsigned colour):
continue
framebuffer[ty * 320 + tx] = (colour)
Kernel::Num start ():
Kernel::my_parent.init_done ()
Iris::Num start ():
Iris::my_parent.init_done ()
int colour = 0x3f30ff
framebuffer = (unsigned *)0x15000
Display display = Kernel::my_parent.get_device <Display> (0x10000)
Iris::Display display = Iris::my_parent.get_device <Iris::Display> (0x10000)
int x = r, y = r, dx = 3, dy = 0
Kernel::Cap eof = Kernel::my_receiver.create_capability (0)
Iris::Cap eof = Iris::my_receiver.create_capability (0)
while true:
display.set_eof_cb (eof)
Kernel::wait ()
Iris::wait ()
ball (x, y, 0)
x += dx
y += dy

View File

@ -32,16 +32,16 @@ void square (int x, int y, bool print):
continue
framebuffer[ty * 320 + tx] = (print ? colour : 0)
Kernel::Num start ():
Kernel::my_parent.init_done ()
Iris::Num start ():
Iris::my_parent.init_done ()
colour = 0xffff00
framebuffer = (unsigned *)0x15000
Display display = Kernel::my_parent.get_device <Display> (0x10001)
Iris::Display display = Iris::my_parent.get_device <Iris::Display> (0x10001)
int x = r, y = r, dx = 3, dy = 3
Kernel::Cap eof = Kernel::my_receiver.create_capability (0)
Iris::Cap eof = Iris::my_receiver.create_capability (0)
while true:
display.set_eof_cb (eof)
Kernel::wait ()
Iris::wait ()
square (x, y, false)
x += dx
y += dy

View File

@ -22,7 +22,7 @@
class DevBuzzer:
static unsigned const pwm = 4
Kernel::Cap event
Iris::Cap event
bool is_beeping
public:
DevBuzzer ():
@ -36,9 +36,9 @@ class DevBuzzer:
return
tcu_stop_counter (pwm)
event.invoke ()
Kernel::free_cap (event)
Iris::free_cap (event)
is_beeping = false
void beep (unsigned freq, unsigned ms, Kernel::Cap cb):
void beep (unsigned freq, unsigned ms, Iris::Cap cb):
stop ()
event = cb
unsigned full = JZ_EXTAL / 64 / freq
@ -46,37 +46,37 @@ class DevBuzzer:
tcu_set_half_data (pwm, full / 2)
tcu_set_count (pwm, 0)
tcu_start_counter (pwm)
Kernel::my_receiver.set_alarm (ms * HZ / 1000)
Iris::my_receiver.set_alarm (ms * HZ / 1000)
is_beeping = true
enum codes:
BUZZER = 32
Kernel::Num start ():
Iris::Num start ():
map_tcu ()
DevBuzzer buzzer
Device dev = Kernel::my_receiver.create_capability (BUZZER)
Kernel::my_parent.provide_device <Buzzer> (dev.copy ())
Kernel::free_cap (dev)
Kernel::my_parent.init_done ()
Iris::Device dev = Iris::my_receiver.create_capability (BUZZER)
Iris::my_parent.provide_device <Iris::Buzzer> (dev.copy ())
Iris::free_cap (dev)
Iris::my_parent.init_done ()
unsigned user (~0)
unsigned next_user (0)
while true:
Kernel::wait ()
switch Kernel::recv.protected_data.h:
Iris::wait ()
switch Iris::recv.protected_data.h:
case ~0:
// Alarm.
buzzer.stop ()
break
case 0:
switch Kernel::recv.protected_data.l:
switch Iris::recv.protected_data.l:
case BUZZER:
// Buzzer device control request.
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
Device::host (BUZZER, user, reply, arg)
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Device::host (BUZZER, user, reply, arg)
break
default:
kdebug ("invalid buzzer request\n")
@ -84,22 +84,22 @@ Kernel::Num start ():
break
case BUZZER:
// Buzzer device user request.
if Kernel::recv.protected_data.l != user:
if Iris::recv.protected_data.l != user:
kdebug ("invalid user requesting buzzer\n")
Kernel::recv.reply.invoke ()
Iris::recv.reply.invoke ()
break
switch Kernel::recv.data[0].l:
case Buzzer::BEEP:
switch Iris::recv.data[0].l:
case Iris::Buzzer::BEEP:
// Volume is not used by this buzzer.
Kernel::Cap arg = Kernel::get_arg ()
Kernel::Cap reply = Kernel::get_reply ()
buzzer.beep (Kernel::recv.data[1].l, Kernel::recv.data[1].h, arg)
Iris::Cap arg = Iris::get_arg ()
Iris::Cap reply = Iris::get_reply ()
buzzer.beep (Iris::recv.data[1].l, Iris::recv.data[1].h, arg)
reply.invoke ()
Kernel::free_cap (reply)
Iris::free_cap (reply)
break
case Buzzer::STOP:
case Iris::Buzzer::STOP:
buzzer.stop ()
Kernel::recv.reply.invoke ()
Iris::recv.reply.invoke ()
break
default:
kdebug ("Buzzer: other\n")
@ -107,5 +107,5 @@ Kernel::Num start ():
break
default:
kdebug ("Buzzer: unknown num: ")
kdebug_num (Kernel::recv.protected_data.h)
kdebug_num (Iris::recv.protected_data.h)
kdebug ("\n")

View File

@ -29,7 +29,9 @@ static unsigned __slots, __caps
static list *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap
namespace Kernel:
namespace Iris:
bool enable_debug
Caps my_caps
Receiver my_receiver
Thread my_thread
Memory my_memory
@ -44,6 +46,8 @@ namespace Kernel:
used[i] = true
unsigned num = 0
for list *i = __first_free_cap; i; i = i->next:
if used[i - __cap_admin] == false:
panic (0, "inconsistent userspace cap db")
used[i - __cap_admin] = false
++num
kdebug_num (num, 2)
@ -54,6 +58,9 @@ namespace Kernel:
void free_slot (unsigned slot):
//kdebug ("free slot\n")
for list *i = __first_free_slot; i; i = i->next:
if slot == i - __slot_admin:
panic (0, "double free of userspace slot")
__slot_admin[slot].prev = NULL
__slot_admin[slot].next = __first_free_slot
if __slot_admin[slot].next:
@ -61,12 +68,16 @@ namespace Kernel:
__first_free_slot = &__slot_admin[slot]
void free_cap (Cap cap):
//kdebug ("free cap ")
//kdebug_num (cap.idx (), 2)
//kdebug ("\n")
if enable_debug:
kdebug ("free cap ")
kdebug_num (cap.idx (), 2)
kdebug ("\n")
for list *i = __first_free_cap; i; i = i->next:
if cap.idx () == i - __cap_admin:
panic (0, "double free of userspace cap")
if cap.slot () != 0:
kdebug ("trying to free capability from non-0 slot\n")
Kernel::panic (0)
Iris::panic (0)
return
list *l = &__cap_admin[cap.idx ()]
l->prev = NULL
@ -80,7 +91,7 @@ namespace Kernel:
if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
kdebug ("out of slots!\n")
Kernel::panic (0)
Iris::panic (0)
return ~0
list *ret = __first_free_slot
__first_free_slot = ret->next
@ -89,42 +100,45 @@ namespace Kernel:
return ret - __slot_admin
Cap alloc_cap ():
//kdebug ("alloc cap ")
if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
kdebug ("out of capabilities!\n")
Kernel::panic (0)
Iris::panic (0)
return Cap (0, CAP_NONE)
list *ret = __first_free_cap
__first_free_cap = ret->next
if ret->next:
ret->next->prev = NULL
//kdebug_num (ret - __cap_admin, 2)
//kdebug ("\n")
if enable_debug:
kdebug ("alloc cap ")
kdebug_num (ret - __cap_admin, 2)
kdebug ("\n")
return Cap (0, ret - __cap_admin)
extern "C":
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
Iris::enable_debug = false
__slots = slots
__caps = caps
__slot_admin = slot_admin
__cap_admin = cap_admin
__first_free_slot = NULL
for unsigned i = 1; i < __slots; ++i:
Kernel::free_slot (i)
Iris::free_slot (i)
__first_free_cap = NULL
for unsigned i = 7; i < __caps; ++i:
Kernel::free_cap (Kernel::Cap (0, i))
Kernel::my_receiver = Kernel::Cap (0, __receiver_num)
Kernel::my_thread = Kernel::Cap (0, __thread_num)
Kernel::my_memory = Kernel::Cap (0, __memory_num)
Kernel::my_call = Kernel::Cap (0, __call_num)
Kernel::my_parent = Kernel::Cap (0, __parent_num)
Kernel::recv.reply = Kernel::alloc_cap ()
Kernel::recv.arg = Kernel::alloc_cap ()
Kernel::Num ret = start ()
Kernel::my_parent.invoke (~0, ret)
Kernel::my_memory.destroy (Kernel::my_thread)
for unsigned i = 6; i < __caps; ++i:
Iris::free_cap (Iris::Cap (0, i))
Iris::my_caps = Iris::Cap (0, __caps_num)
Iris::my_receiver = Iris::Cap (0, __receiver_num)
Iris::my_thread = Iris::Cap (0, __thread_num)
Iris::my_memory = Iris::Cap (0, __memory_num)
Iris::my_call = Iris::Cap (0, __call_num)
Iris::my_parent = Iris::Cap (0, __parent_num)
Iris::recv.reply = Iris::alloc_cap ()
Iris::recv.arg = Iris::alloc_cap ()
Iris::Num ret = start ()
Iris::my_parent.invoke (~0, ret)
Iris::my_memory.destroy (Iris::my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
while true:
*(volatile unsigned *)~0

View File

@ -19,64 +19,64 @@
#include <devices.hh>
#include <iris.hh>
Kernel::Num start ():
Device d = Kernel::my_receiver.create_capability (0)
Kernel::my_parent.provide_device <Display> (d.copy (), 0x10000)
Kernel::free_cap (d)
Kernel::my_parent.init_done ()
Display real = Kernel::my_parent.get_device <Display> (0)
Iris::Num start ():
Iris::Device d = Iris::my_receiver.create_capability (0)
Iris::my_parent.provide_device <Iris::Display> (d.copy (), 0x10000)
Iris::free_cap (d)
Iris::my_parent.init_done ()
Iris::Display real = Iris::my_parent.get_device <Iris::Display> (0)
while true:
Kernel::wait ()
Kernel::Cap arg = Kernel::get_arg ()
Kernel::Cap reply = Kernel::get_reply ()
switch Kernel::recv.protected_data.h:
Iris::wait ()
Iris::Cap arg = Iris::get_arg ()
Iris::Cap reply = Iris::get_reply ()
switch Iris::recv.protected_data.h:
case 0:
switch Kernel::recv.data[0].l:
case Device::CREATE_USER:
Kernel::Memory mem (arg)
Kernel::Caps ret = mem.create_caps (3)
Kernel::Cap target = Kernel::my_receiver.create_capability (Kernel::Num (0, 1))
switch Iris::recv.data[0].l:
case Iris::Device::CREATE_USER:
Iris::Memory mem (arg)
Iris::Caps ret = mem.create_caps (3)
Iris::Cap target = Iris::my_receiver.create_capability (Iris::Num (0, 1))
ret.set (0, target.copy ())
ret.set (1, mem)
Kernel::free_cap (target)
Iris::free_cap (target)
for unsigned i = 0; i < 320 * 240 * 4; i += PAGE_SIZE:
Kernel::Page p = Kernel::my_memory.mapping ((void *)(0x15000 + i))
Kernel::Page t = mem.create_page ()
t.set_flags (Kernel::Page::PAYING, Kernel::Page::PAYING)
p.share (t, Kernel::Page::FORGET)
Iris::Page p = Iris::my_memory.mapping ((void *)(0x15000 + i))
Iris::Page t = mem.create_page ()
t.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
p.share (t, Iris::Page::FORGET)
mem.map (t, 0x15000 + i)
Kernel::my_memory.destroy (t)
Kernel::free_cap (t)
Kernel::free_cap (p)
Iris::my_memory.destroy (t)
Iris::free_cap (t)
Iris::free_cap (p)
reply.invoke (0, 0, ret.copy ())
Kernel::free_cap (ret)
Iris::free_cap (ret)
break
case Device::DESTROY_USER:
Kernel::panic (0, "destroying emulation user")
case Device::USE:
case Device::UNUSE:
case Iris::Device::DESTROY_USER:
Iris::panic (0, "destroying emulation user")
case Iris::Device::USE:
case Iris::Device::UNUSE:
reply.invoke ()
break
default:
kdebug_num (Kernel::recv.data[0].l)
kdebug_num (Iris::recv.data[0].l)
kdebug ("\n")
Kernel::panic (0, "invalid emulation command")
Iris::panic (0, "invalid emulation command")
break
case 1:
switch Kernel::recv.data[0].l:
case Display::SET_EOF_CB:
switch Iris::recv.data[0].l:
case Iris::Display::SET_EOF_CB:
real.set_eof_cb (arg.copy ())
while Kernel::recv.data[0].l != 0:
Kernel::my_parent.wait <Display> (0)
while Iris::recv.data[0].l != 0:
Iris::my_parent.wait <Iris::Display> (0)
real.set_eof_cb (arg.copy ())
reply.invoke ()
break
default:
kdebug_num (Kernel::recv.data[0].l)
kdebug_num (Iris::recv.data[0].l)
kdebug_char ('\n')
Kernel::panic (Kernel::recv.data[0].l, "invalid operation on display emulation")
Iris::panic (Iris::recv.data[0].l, "invalid operation on display emulation")
break
default:
Kernel::panic (0, "bug in display emulation")
Kernel::free_cap (arg)
Kernel::free_cap (reply)
Iris::panic (0, "bug in display emulation")
Iris::free_cap (arg)
Iris::free_cap (reply)

View File

@ -1 +0,0 @@
display-emu.ccp

286
source/elfrun.ccp Normal file
View File

@ -0,0 +1,286 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/elfrun.ccp: Process creation server.
// 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 "devices.hh"
#include "iris.hh"
#include <elf.h>
static unsigned _free
extern unsigned _end
void init_alloc ():
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
_free = ret + (pages << PAGE_BITS)
return (char *)ret
void *operator new[] (unsigned size):
//kdebug ("new ")
void *ret = (void *)_free
size = (size + 3) & ~3
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
if rest < size:
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < pages; ++p:
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
Iris::free_cap (page)
_free += size
//kdebug_num ((unsigned)ret)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("\n")
return ret
void *operator new (unsigned size):
return new char[size]
static Iris::Memory parent_memory
static Iris::Cap parent
static unsigned slot
static char *mapping
static unsigned pages
static Iris::Caps pages_caps
static Iris::Memory mem
static Iris::Caps map_string (Iris::String data):
// Get the size.
Iris::Num size = data.get_size ()
if size.value () == 0:
Iris::panic (0, "data string is empty")
// Allocate a caps with all the pages.
pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
pages_caps = Iris::my_memory.create_caps (pages)
slot = pages_caps.use ()
// Map them into the address space as well.
mapping = alloc_space (pages)
// Create a memory for the program.
mem = parent_memory.create_memory ()
// Load the file into memory and map it.
for unsigned p = 0; p < pages; ++p:
//kdebug_num (p)
//kdebug ("/")
//kdebug_num (pages)
//kdebug ("\n")
Iris::set_recv_arg (Iris::Cap (slot, p))
data.get_page (p << PAGE_BITS)
Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
static Iris::Caps map_caps (Iris::Caps data, unsigned p):
// Get the size.
if p == 0:
Iris::panic (0, "data caps is empty")
// Allocate a new caps with all the pages for mapping locally.
pages = p
pages_caps = Iris::my_memory.create_caps (pages)
slot = pages_caps.use ()
unsigned src_slot = data.use ()
// Map them into the address space as well.
mapping = alloc_space (pages)
// Create a memory for the program.
mem = parent_memory.create_memory ()
// Load the file into memory and map it.
for unsigned p = 0; p < pages; ++p:
//kdebug_num (p)
//kdebug ("/")
//kdebug_num (pages)
//kdebug ("\n")
Iris::Page page = Iris::Cap (slot, p)
Iris::set_recv_arg (page)
Iris::my_memory.create_page ()
Iris::Page (Iris::Cap (src_slot, p)).share (page)
Iris::my_memory.map (page, (unsigned)&mapping[p << PAGE_BITS])
Iris::free_slot (src_slot)
static Iris::Caps run (Iris::Caps data, Iris::Memory parent_memory, Iris::Cap parent, unsigned num_slots, unsigned num_caps):
Iris::Thread thread = mem.create_thread (num_slots)
Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
Iris::panic (header->e_ident[j], "invalid ELF magic")
return Iris::Caps ()
if header->e_ident[EI_CLASS] != ELFCLASS32:
kdebug ("invalid ELF class:")
kdebug_num (header->e_ident[EI_CLASS])
kdebug (" != ")
kdebug_num (ELFCLASS32)
kdebug ("\n")
Iris::panic (0)
return Iris::Caps ()
if header->e_ident[EI_DATA] != ELFDATA2LSB:
Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
if header->e_ident[EI_VERSION] != EV_CURRENT:
Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
if header->e_type != ET_EXEC:
Iris::panic (header->e_type, "invalid ELF type")
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
Iris::panic (header->e_machine, "invalid ELF machine")
thread.set_pc (header->e_entry)
thread.set_sp (0x80000000)
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
if ~shdr->sh_flags & SHF_ALLOC:
continue
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
if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
kdebug ("thread size: ")
kdebug_num (file_offset)
kdebug (",")
kdebug_num (shdr->sh_size)
kdebug ("\n")
Iris::panic (shdr->sh_size, "thread too large")
return Iris::Caps ()
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
unsigned idx = file_offset + section_offset
Iris::Page page = mem.mapping ((void *)p)
if Iris::recv.data[0].l == Iris::NO_ERROR:
// The address already has a mapping; assume that it is correct.
Iris::free_cap (page)
continue
Iris::free_cap (page)
page = mem.create_page ()
unsigned f
if readonly:
f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
else:
f = Iris::Page::PAYING
page.set_flags (f, f)
Iris::Page (slot, idx).share (page, 0)
//kdebug ("mapping at ")
//kdebug_num (p)
//if readonly:
// kdebug (" (readonly)")
//kdebug ("\n")
if !mem.map (page, p):
Iris::panic (0, "unable to map page")
return Iris::Caps ()
Iris::free_cap (page)
else:
if readonly:
Iris::panic (0, "unwritable bss section")
return Iris::Caps ()
for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
Iris::Page page = mem.mapping ((void *)p)
if Iris::recv.data[0].l == Iris::NO_ERROR:
// No error means there is a mapping.
Iris::free_cap (page)
for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
((unsigned *)&mapping[p - shdr->sh_addr])[(a & ~PAGE_MASK) >> 2] = 0
else:
Iris::free_cap (page)
page = mem.create_page ()
if Iris::recv.data[0].l != Iris::NO_ERROR:
Iris::panic (Iris::recv.data[0].l, "out of memory")
if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME):
Iris::panic (0, "out of memory")
if !mem.map (page, p):
Iris::panic (0, "unable to map bss page")
Iris::free_cap (page)
for unsigned p = 0; p < pages; ++p:
Iris::my_memory.destroy (Iris::Page (slot, p))
Iris::my_memory.destroy (pages_caps)
Iris::free_slot (slot)
Iris::free_cap (pages_caps)
Iris::Page stackpage = mem.create_page ()
stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
Iris::free_cap (stackpage)
Iris::Caps caps = mem.create_caps (num_caps)
thread.use (caps, 0)
thread.set_info (Iris::Thread::A0, num_slots)
thread.set_info (Iris::Thread::A1, num_caps)
Iris::Receiver receiver = mem.create_receiver ()
receiver.set_owner (thread.copy ())
Iris::Cap call = receiver.create_call_capability ()
caps.set (__caps_num, caps.copy ())
caps.set (__receiver_num, receiver.copy ())
caps.set (__thread_num, thread.copy ())
caps.set (__memory_num, mem.copy ())
caps.set (__call_num, call.copy ())
caps.set (__parent_num, parent.copy ())
Iris::free_cap (receiver)
Iris::free_cap (thread)
Iris::free_cap (mem)
Iris::free_cap (call)
return caps
Iris::Num start ():
kdebug ("elfrun started.\n")
init_alloc ()
Iris::Device dev = Iris::my_receiver.create_capability (0)
Iris::my_parent.provide_device <Iris::Elfrun> (dev.copy ())
unsigned user = ~0
while true:
Iris::wait ()
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::print_caps ()
switch Iris::recv.protected_data.h:
case 0:
Iris::Device::host (1, user, reply, arg)
break
case 1:
switch Iris::recv.data[0].l:
case Iris::Elfrun::RUN_STRING:
unsigned num_slots = Iris::recv.data[1].l
unsigned num_caps = Iris::recv.data[1].h
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
Iris::String data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
map_string (data)
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
reply.invoke (0, 0, ret.copy ())
free_cap (ret)
free_cap (parent_memory)
free_cap (parent)
free_cap (data)
break
case Iris::Elfrun::RUN_CAPS:
unsigned num_slots = Iris::recv.data[1].l
unsigned num_caps = Iris::recv.data[1].h
unsigned p = Iris::recv.data[0].h
parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
Iris::Caps data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
map_caps (data, p)
Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
reply.invoke (0, 0, ret.copy ())
free_cap (ret)
free_cap (parent_memory)
free_cap (parent)
free_cap (data)
break
default:
Iris::panic (0, "invalid operation for elfrun")
reply.invoke (~0)
break
Iris::free_cap (arg)
Iris::free_cap (reply)

1
source/gpio.ccp Symbolic link
View File

@ -0,0 +1 @@
nanonote-gpio.ccp

412
source/init.ccp Normal file
View File

@ -0,0 +1,412 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// bootstrap/init.ccp: Bootstrapping code.
// 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 "devices.hh"
#include "iris.hh"
#include "keys.hh"
#define NUM_SLOTS 8
#define NUM_CAPS 32
static unsigned _free
extern unsigned _end
void init_alloc ():
_free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
char *alloc_space (unsigned pages):
unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
_free = ret + (pages << PAGE_BITS)
return (char *)ret
void *operator new[] (unsigned size):
//kdebug ("new ")
void *ret = (void *)_free
size = (size + 3) & ~3
unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
if rest < size:
unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
for unsigned p = 0; p < pages; ++p:
Iris::Page page = Iris::my_memory.create_page ()
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME, Iris::Page::PAYING | Iris::Page::FRAME)
Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
Iris::free_cap (page)
_free += size
//kdebug_num ((unsigned)ret)
//kdebug ("+")
//kdebug_num (size)
//kdebug ("\n")
return ret
void *operator new (unsigned size):
return new char[size]
template <typename _T> //
struct List:
struct Item:
Item *prev, *next
_T value
_T &operator* ():
return value
_T *operator-> ():
return &value
Item *first
Item *begin ():
return first
void erase (Item *i):
if i->prev:
i->prev->next = i->next
else:
first = i->next
if i->next:
i->next->prev = i->prev
delete i
Item *insert (Item *after = NULL):
Item *ret = new Item
if after:
ret->prev = after->prev
ret->next = after
if ret->prev:
ret->prev->next = ret
else:
first = ret
after->prev = ret
else:
ret->prev = NULL
ret->next = first
first = ret
if ret->next:
ret->next->prev = ret
return ret
void init ():
first = NULL
List () : first (NULL):
struct Program
struct Device:
char *name
unsigned name_len
unsigned type, index
Iris::Cap cap
Program *server
Program *client
struct Program:
char *name
unsigned name_len
unsigned size
Iris::Caps pages
Iris::Memory memory
Iris::Thread thread
List <Device> devices
static Iris::Memory top_memory
static Iris::Directory root
static Iris::Elfrun elfrun
static List <Program> programs
static bool name_match (char const *name, unsigned name_len, Iris::String n):
char nm[16]
n.get_chars (0, nm)
for unsigned t = 0; t < 16 && t < name_len; ++t:
if nm[t] != name[t]:
return false
return true
static Iris::Caps load (char const *name, unsigned name_len, unsigned &size, Iris::Caps target = Iris::alloc_cap ()):
kdebug ("loading ")
for unsigned i = 0; i < name_len; ++i:
kdebug_char (name[i])
kdebug ("\n")
root.lock_ro ()
Iris::Num sz = root.get_size ()
if sz.h:
Iris::panic (sz.h, "too many files")
for unsigned i = 0; i < sz.l; ++i:
Iris::String n = root.get_name (i)
if !name_match (name, name_len, n):
Iris::free_cap (n)
continue
Iris::free_cap (n)
Iris::String file = root.get_file_ro (i)
Iris::Num s = file.get_size ()
if s.h:
Iris::panic (s.h, "file is too large to load")
size = s.l
unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
if pages > 0:
Iris::set_recv_arg (target)
Iris::my_memory.create_caps (pages)
unsigned slot = target.use ()
for unsigned p = 0; p < pages; ++p:
Iris::set_recv_arg (Iris::Cap (slot, p))
file.get_page (p << PAGE_BITS)
Iris::free_slot (slot)
Iris::free_cap (file)
root.unlock_ro ()
return target
Iris::panic (0, "file not found for init")
return target
static void delspace (char *&line, unsigned &maxlen):
while maxlen && (*line == ' ' || *line == '\t'):
++line
--maxlen
if maxlen && *line == '#':
line += maxlen
maxlen = 0
static bool match (char *&line, unsigned &maxlen, char const *word):
delspace (line, maxlen)
char const *w = word
char *l = line
unsigned len = 0
while *word:
if *l++ != *word++:
return false
++len
line = l
maxlen -= len
delspace (line, maxlen)
//kdebug ("match: ")
//kdebug (w)
//kdebug ("\n")
return true
static bool isnamechar (char c):
if c >= 'a' && c <= 'z':
return true
if c >= 'A' && c <= 'Z':
return true
if c >= '0' && c <= '9':
return true
if c == '_':
return true
return false
static bool get_name (char *&line, unsigned &len, char *&name, unsigned &name_len):
delspace (line, len)
if !len:
return false
name_len = 0
while name_len < len && isnamechar (line[name_len]):
++name_len
name = new char[name_len]
for unsigned i = 0; i < name_len; ++i:
name[i] = line[i]
line += name_len
len -= name_len
delspace (line, len)
return true
static bool string_match (char const *s1, unsigned l1, char const *s2, unsigned l2):
if l1 != l2:
return false
for unsigned i = 0; i < l1; ++i:
if s1[i] != s2[i]:
return false
return true
struct Type:
char const *name
unsigned len
unsigned type
static unsigned read_num (char *&line, unsigned &len):
delspace (line, len)
unsigned num = 0
while len && *line >= '0' && *line <= '9':
num *= 10
num += *line - '0'
++line
--len
delspace (line, len)
return num
static Type types[] = {
{ "String", 6, Iris::String::ID },
{ "WString", 7, Iris::WString::ID },
{ "Device", 6, Iris::Device::ID },
{ "Parent", 6, Iris::Parent::ID },
{ "Keyboard", 8, Iris::Keyboard::ID },
{ "Buzzer", 6, Iris::Buzzer::ID },
{ "Display", 7, Iris::Display::ID },
{ "Setting", 7, Iris::Setting::ID },
{ "Directory", 9, Iris::Directory::ID },
{ "WDirectory", 10, Iris::WDirectory::ID },
{ "Filesystem", 10, Iris::Filesystem::ID },
{ "Stream", 6, Iris::Stream::ID },
{ NULL, 0, 0 }
}
static void find_type (char *&line, unsigned &len, unsigned &type, unsigned &index):
char *n
unsigned l
if !get_name (line, len, n, l) || !len:
Iris::panic (0, "no name for type")
for unsigned t = 0; types[t].len != 0; ++t:
if string_match (types[t].name, types[t].len, n, l):
type = types[t].type
if len && *line == ',':
++line
--len
index = read_num (line, len)
else:
index = 0
return
Iris::panic (0, "no valid type found")
static void parse_line (char *&line, unsigned maxlen):
char *start = line
while maxlen && *line != '\n':
++line
--maxlen
// The line to execute is from start to line.
maxlen = line - start
if *line == '\n':
++line
delspace (start, maxlen)
if !maxlen:
return
if match (start, maxlen, "load"):
Program *p = &**programs.insert ()
if !get_name (start, maxlen, p->name, p->name_len) || !match (start, maxlen, "=") || !maxlen:
Iris::panic (0, "syntax error in init.config (load)")
char q = *start++
--maxlen
unsigned len = 0
while maxlen && *start != q:
++start
--maxlen
++len
if !maxlen:
Iris::panic (0, "no closing quote in init.config")
p->pages = load (start - len, len, p->size)
++start
--maxlen
else if match (start, maxlen, "killbootthreads"):
Iris::my_parent.init_done ()
else if match (start, maxlen, "receive"):
// receive <name> / <type> [, <index>] = <cap>
char *n
unsigned l
if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
Iris::panic (0, "syntax error in init.config (receive)")
List <Program>::Item *p
for p = programs.begin (); p; p = p->next:
if string_match ((*p)->name, (*p)->name_len, n, l):
break
if !p:
Iris::panic (0, "program not found for receive")
List <Device>::Item *dev = (*p)->devices.insert ()
find_type (start, maxlen, (*dev)->type, (*dev)->index)
if !match (start, maxlen, "=") || !get_name (start, maxlen, (*dev)->name, (*dev)->name_len):
Iris::panic (1, "syntax error in init.config (receive)")
else if match (start, maxlen, "driver"):
char *n
unsigned l
if !get_name (start, maxlen, n, l):
Iris::panic (0, "syntax error in init.config (driver)")
List <Program>::Item *p
for p = programs.begin (); p; p = p->next:
if string_match ((*p)->name, (*p)->name_len, n, l):
break
if !p:
Iris::panic (0, "program not found for driver")
Iris::Cap cap = Iris::my_receiver.create_capability ((unsigned)&**p)
kdebug ("running ")
for unsigned i = 0; i < (*p)->name_len; ++i:
kdebug_char ((*p)->name[i])
kdebug ("\n")
Iris::Caps caps = elfrun.run_caps (top_memory, (*p)->pages, cap.copy (), ((*p)->size + PAGE_SIZE - 1) >> PAGE_BITS)
Iris::free_cap (cap)
(*p)->thread = caps.get (__thread_num)
(*p)->memory = caps.get (__memory_num)
(*p)->thread.make_priv ()
(*p)->thread.run ()
// TODO: pass arguments.
start += maxlen
maxlen = 0
else if match (start, maxlen, "wait"):
// TODO
start += maxlen
maxlen = 0
else if match (start, maxlen, "sysreq"):
// TODO
start += maxlen
maxlen = 0
else if match (start, maxlen, "give"):
// TODO
start += maxlen
maxlen = 0
else if match (start, maxlen, "run"):
// TODO
start += maxlen
maxlen = 0
else if match (start, maxlen, "include"):
// TODO
start += maxlen
maxlen = 0
else:
Iris::panic (0, "invalid line in init.config")
delspace (start, maxlen)
if maxlen:
kdebug ("Junk: ")
for unsigned i = 0; i < maxlen; ++i:
kdebug_char (start[i])
kdebug_char ('\n')
Iris::panic (0, "junk at end of line in init.config")
Iris::Num start ():
init_alloc ()
programs.init ()
root = Iris::my_parent.get_device <Iris::Directory> ()
elfrun = Iris::my_parent.get_device <Iris::Elfrun> ()
top_memory = Iris::get_top_memory ()
unsigned config_size
Iris::Caps config_pages = load ("init.config", 12, config_size)
unsigned pages = (config_size + PAGE_SIZE - 1) >> PAGE_BITS
char *config = alloc_space (pages)
unsigned pages_slot = config_pages.use ()
for unsigned p = 0; p < pages; ++p:
Iris::Page page (pages_slot, p)
Iris::my_memory.map (page, (unsigned)&config[p << PAGE_BITS])
char *ptr = config
kdebug ("parsing config\n")
while ptr - config < config_size:
parse_line (ptr, config + config_size - ptr)
kdebug ("destroying pages\n")
for unsigned p = 0; p < pages; ++p:
Iris::my_memory.destroy (Iris::Cap (pages_slot, p))
Iris::my_memory.destroy (config_pages)
Iris::free_cap (config_pages)
Iris::free_slot (pages_slot)
kdebug ("waiting for events.\n")
while true:
Iris::wait ()
Program *caller = (Program *)Iris::recv.protected_data.l
if !caller:
// System request.
// TODO.
kdebug ("system request\n")
continue
switch Iris::recv.data[0].l:
default:
// TODO.
kdebug ("child request\n")

View File

@ -225,7 +225,7 @@ static void log_str (char const *str):
while *str:
log_char (*str++)
static void log_num (Kernel::Num n):
static void log_num (Iris::Num n):
char const *encode = "0123456789abcdef"
log_char ('[')
for unsigned i = 0; i < 8; ++i:
@ -237,10 +237,10 @@ static void log_num (Kernel::Num n):
static void log_msg ():
log_str ("prot:")
log_num (Kernel::recv.protected_data)
log_num (Iris::recv.protected_data)
log_str ("data:")
for unsigned i = 0; i < 2; ++i:
log_num (Kernel::recv.data[i])
log_num (Iris::recv.data[i])
log_char ('\n')
enum captype:
@ -261,25 +261,25 @@ static unsigned pages
static Descriptor descriptor __attribute__ ((aligned (16)))
static bool is_on
static unsigned create (Kernel::Memory mem, Kernel::Caps caps):
static unsigned create (Iris::Memory mem, Iris::Caps caps):
unsigned physical = mem.alloc_range (pages)
unsigned address = 0x15000
if physical & ~PAGE_MASK:
Kernel::panic (0, "can't allocate framebuffer")
Iris::panic (0, "can't allocate framebuffer")
assert (physical & PAGE_MASK && ~physical)
for unsigned i = 0; i < pages; ++i:
Kernel::Page p = mem.create_page ()
Iris::Page p = mem.create_page ()
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
if address != ~0:
mem.map (p, address + (i << PAGE_BITS))
Kernel::free_cap (p)
Iris::free_cap (p)
return physical
static void destroy (unsigned physical, Kernel::Caps caps):
static void destroy (unsigned physical, Iris::Caps caps):
unsigned address = 0x15000
Kernel::Memory mem = caps.get (1)
Iris::Memory mem = caps.get (1)
if physical == ~0:
Kernel::panic (0, "unable to destroy framebuffer with wrong cap0")
Iris::panic (0, "unable to destroy framebuffer with wrong cap0")
if descriptor.frame == physical && is_on:
lcd_clr_ena ()
#ifdef NANONOTE
@ -287,13 +287,13 @@ static void destroy (unsigned physical, Kernel::Caps caps):
#endif
if address != ~0:
for unsigned i = 0; i < pages; ++i:
Kernel::Page p = mem.mapping ((void *)(address + (i << PAGE_BITS)))
Iris::Page p = mem.mapping ((void *)(address + (i << PAGE_BITS)))
mem.destroy (p)
Kernel::free_cap (p)
Iris::free_cap (p)
static void use (unsigned physical, Kernel::Caps caps):
static void use (unsigned physical, Iris::Caps caps):
if physical == ~0:
Kernel::panic (0, "unable to use framebuffer with wrong cap0")
Iris::panic (0, "unable to use framebuffer with wrong cap0")
bool was_unused = descriptor.frame == 0
descriptor.frame = physical
unsigned dptr = (unsigned)&descriptor
@ -304,9 +304,9 @@ static void use (unsigned physical, Kernel::Caps caps):
write_reg (BACKLIGHT1, 0x5f)
#endif
static void unuse (unsigned physical, Kernel::Caps caps):
static void unuse (unsigned physical, Iris::Caps caps):
if physical == ~0:
Kernel::panic (0, "unable to unuse framebuffer with wrong cap0")
Iris::panic (0, "unable to unuse framebuffer with wrong cap0")
if descriptor.frame == physical:
lcd_clr_ena ()
#ifdef NANONOTE
@ -314,8 +314,8 @@ static void unuse (unsigned physical, Kernel::Caps caps):
#endif
descriptor.frame = 0
Kernel::Num start ():
Kernel::schedule ()
Iris::Num start ():
Iris::schedule ()
map_lcd ()
map_cpm ()
#ifdef NANONOTE
@ -324,13 +324,13 @@ Kernel::Num start ():
pages = (frame_size + ~PAGE_MASK) >> PAGE_BITS
#if 0
unsigned physical = Kernel::my_memory.alloc_range (pages)
unsigned physical = Iris::my_memory.alloc_range (pages)
assert (physical & PAGE_MASK && ~physical)
for unsigned i = 0; i < pages; ++i:
Kernel::Page p = Kernel::my_memory.create_page ()
Iris::Page p = Iris::my_memory.create_page ()
p.alloc_physical (physical + (i << PAGE_BITS), false, true)
Kernel::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + (i << PAGE_BITS))
Kernel::free_cap (p)
Iris::my_memory.map (p, (unsigned)LCD_FRAMEBUFFER_BASE + (i << PAGE_BITS))
Iris::free_cap (p)
for unsigned y = 0; y < v; ++y:
for unsigned x = 0; x < h; ++x:
unsigned r = spot (x, y, 100, 160)
@ -346,10 +346,10 @@ Kernel::Num start ():
#else
unsigned physical = 0
#endif
Kernel::Page p = Kernel::my_memory.mapping (&descriptor)
Iris::Page p = Iris::my_memory.mapping (&descriptor)
unsigned paddr = p.physical_address ()
physical_descriptor = paddr + ((unsigned)&descriptor & ~PAGE_MASK)
Kernel::free_cap (p)
Iris::free_cap (p)
descriptor.next = physical_descriptor
descriptor.frame = physical
descriptor.id = 0xdeadbeef
@ -359,67 +359,67 @@ Kernel::Num start ():
reset ()
#if defined (TRENDTAC)
Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
Iris::Cap logcap = Iris::my_receiver.create_capability (LOG)
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
#endif
// Register the backlight device.
Kernel::Cap backlight = Kernel::my_receiver.create_capability (BACKLIGHT)
Kernel::my_parent.provide_device <Setting> (backlight.copy ())
Kernel::free_cap (backlight)
Iris::Cap backlight = Iris::my_receiver.create_capability (BACKLIGHT)
Iris::my_parent.provide_device <Iris::Setting> (backlight.copy ())
Iris::free_cap (backlight)
// Register the display device.
Kernel::Cap display = Kernel::my_receiver.create_capability (LCD)
Kernel::my_parent.provide_device <Display> (display.copy ())
Kernel::free_cap (display)
Kernel::my_parent.init_done ()
Iris::Cap display = Iris::my_receiver.create_capability (LCD)
Iris::my_parent.provide_device <Iris::Display> (display.copy ())
Iris::free_cap (display)
Iris::my_parent.init_done ()
Kernel::Cap eof_cb
Iris::Cap eof_cb
bool have_eof = false
is_on = true
unsigned lcd_user = 0
unsigned current_backlight = 0
while true:
Kernel::wait ()
Iris::wait ()
//log_msg ()
switch Kernel::recv.protected_data.h:
switch Iris::recv.protected_data.h:
case 0:
switch Kernel::recv.protected_data.l:
switch Iris::recv.protected_data.l:
case IRQ_LCD:
have_eof = false
eof_cb.invoke ()
Kernel::free_cap (eof_cb)
Iris::free_cap (eof_cb)
break
#if defined (TRENDTAC)
case LOG:
log_char (Kernel::recv.data[0].l)
log_char (Iris::recv.data[0].l)
break
#endif
case BACKLIGHT:
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
Device::host (BACKLIGHT, current_backlight, reply, arg)
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Device::host (BACKLIGHT, current_backlight, reply, arg)
break
case LCD:
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
Device::host (LCD, lcd_user, reply, arg, 3, create, destroy, use, unuse)
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Device::host (LCD, lcd_user, reply, arg, 3, create, destroy, use, unuse)
break
default:
Kernel::panic (Kernel::recv.protected_data.l, "invalid operation for master lcd")
Iris::panic (Iris::recv.protected_data.l, "invalid operation for master lcd")
break
break
case BACKLIGHT:
if current_backlight != Kernel::recv.protected_data.l:
if current_backlight != Iris::recv.protected_data.l:
log_char ('&')
log_num (current_backlight)
log_num (Kernel::recv.protected_data)
log_num (Iris::recv.protected_data)
log_char ('\n')
break
switch Kernel::recv.data[0].l:
case Setting::SET:
switch Iris::recv.data[0].l:
case Iris::Setting::SET:
// TODO
unsigned state = Kernel::recv.data[1].l
unsigned state = Iris::recv.data[1].l
if !state:
#if defined (NANONOTE)
if is_on:
@ -434,40 +434,40 @@ Kernel::Num start ():
is_on = true
#else
#endif
Kernel::recv.reply.invoke ()
Iris::recv.reply.invoke ()
break
case Setting::GET_RANGE:
Kernel::recv.reply.invoke (~0)
case Iris::Setting::GET_RANGE:
Iris::recv.reply.invoke (~0)
break
default:
Kernel::panic (0, "invalid operation for backlight")
Iris::panic (0, "invalid operation for backlight")
break
break
case LCD:
if descriptor.frame != Kernel::recv.protected_data.l:
//Kernel::panic (0, "invalid user requesting lcd")
Kernel::recv.reply.invoke (~0)
if descriptor.frame != Iris::recv.protected_data.l:
//Iris::panic (0, "invalid user requesting lcd")
Iris::recv.reply.invoke (~0)
break
switch Kernel::recv.data[0].l:
case Display::SET_EOF_CB:
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
switch Iris::recv.data[0].l:
case Iris::Display::SET_EOF_CB:
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
if have_eof:
Kernel::free_cap (eof_cb)
Kernel::panic (0, "replacing eof_cb")
Iris::free_cap (eof_cb)
Iris::panic (0, "replacing eof_cb")
else:
lcd_clr_eof ()
Kernel::register_interrupt (IRQ_LCD)
Iris::register_interrupt (IRQ_LCD)
have_eof = true
eof_cb = arg
reply.invoke ()
Kernel::free_cap (reply)
Iris::free_cap (reply)
break
case Display::GET_INFO:
Kernel::panic (0, "get_info isn't defined yet.")
case Iris::Display::GET_INFO:
Iris::panic (0, "get_info isn't defined yet.")
default:
Kernel::panic (Kernel::recv.data[0].l, "invalid operation for lcd")
Iris::panic (Iris::recv.data[0].l, "invalid operation for lcd")
break
default:
Kernel::panic (0, "invalid master operation type for lcd")
Iris::panic (0, "invalid master operation type for lcd")
break

View File

@ -19,11 +19,11 @@
#include "devices.hh"
#include "keys.hh"
Kernel::Num start ():
Kernel::my_parent.init_done ()
Buzzer buzzer = Kernel::my_parent.get_device <Buzzer> ()
Keyboard kbd = Kernel::my_parent.get_device <Keyboard> ()
Kernel::Cap key = Kernel::my_receiver.create_capability (0)
Iris::Num start ():
Iris::my_parent.init_done ()
Iris::Buzzer buzzer = Iris::my_parent.get_device <Iris::Buzzer> ()
Iris::Keyboard kbd = Iris::my_parent.get_device <Iris::Keyboard> ()
Iris::Cap key = Iris::my_receiver.create_capability (0)
kbd.set_cb (key)
// Frequency of the pulse train in millihertz.
unsigned mHz = 1000
@ -31,17 +31,17 @@ Kernel::Num start ():
unsigned freq = 1000
bool running (false)
while true:
Kernel::wait ()
switch Kernel::recv.protected_data.l:
Iris::wait ()
switch Iris::recv.protected_data.l:
case ~0:
if running:
buzzer.beep (freq, 10, ~0)
Kernel::my_receiver.set_alarm (HZ * 1000 / mHz)
Iris::my_receiver.set_alarm (HZ * 1000 / mHz)
break
case 0:
if Kernel::recv.data[0].l & Keyboard::RELEASE:
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
break
switch Kernel::recv.data[0].l:
switch Iris::recv.data[0].l:
case Key::VOLUME_UP:
freq = freq * 11 / 10
break
@ -63,7 +63,7 @@ Kernel::Num start ():
case Key::P:
running = !running
if running:
Kernel::my_receiver.set_alarm (0)
Iris::my_receiver.set_alarm (0)
break
break
default:

View File

@ -37,25 +37,25 @@ class DevKbd:
static unsigned const NUM_KEYS = 58
static unsigned const keys[NUM_KEYS]
unsigned state[NUM_COLS]
Kernel::Cap event
Iris::Cap event
bool is_active
bool is_scanning
public:
unsigned size ():
return NUM_KEYS
void send_keys (unsigned first, Kernel::Cap target):
void send_keys (unsigned first, Iris::Cap target):
unsigned d[4]
unsigned i
for i = 0; first + i < NUM_KEYS && i < 4; ++i:
d[i] = keys[first + i]
for ; i < 4; ++i:
d[i] = ~0
target.invoke (Kernel::Num (d[0], d[1]), Kernel::Num (d[2], d[3]))
target.invoke (Iris::Num (d[0], d[1]), Iris::Num (d[2], d[3]))
bool scanning ():
return is_scanning
void inactive ():
if is_active:
Kernel::free_cap (event)
Iris::free_cap (event)
is_active = false
void check (unsigned col, unsigned rowdata):
for unsigned r = 0; r < NUM_ROWS; ++r:
@ -63,7 +63,7 @@ class DevKbd:
continue
unsigned code = encode[r][col]
if rowdata & (1 << ROWS[r]):
code |= Keyboard::RELEASE
code |= Iris::Keyboard::RELEASE
if is_active:
event.invoke (code)
state[col] = rowdata
@ -101,7 +101,7 @@ class DevKbd:
gpio_as_interrupt (ROWS_PORT, high, true, true)
gpio_as_interrupt (ROWS_PORT, low, false, true)
gpio_unmask_irq (ROWS_PORT, ALL_ROWS)
void active (Kernel::Cap cb):
void active (Iris::Cap cb):
inactive ()
event = cb
is_active = true
@ -167,7 +167,7 @@ unsigned const DevKbd::keys[NUM_KEYS] = {
class PowerButton:
bool state, started
Kernel::Cap cb
Iris::Cap cb
public:
void scan ():
if !started:
@ -176,16 +176,16 @@ class PowerButton:
bool s = gpio_get_port (3) & (1 << 29)
if s != state:
state = s
cb.invoke (state ? Keyboard::RELEASE : 0)
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
gpio_as_interrupt (3, 1 << 29, !state, true)
gpio_unmask_irq (3, 1 << 29)
PowerButton ():
gpio_as_gpio (3, 29)
state = true
started = false
void set_cb (Kernel::Cap c):
void set_cb (Iris::Cap c):
if started:
Kernel::free_cap (cb)
Iris::free_cap (cb)
else:
started = true
cb = c
@ -196,100 +196,100 @@ enum codes:
KBD_DEV = 32
PWR
Kernel::Num start ():
Iris::Num start ():
map_gpio ()
DevKbd kbd
PowerButton pwr
Device dev = Kernel::my_receiver.create_capability (KBD_DEV)
Keyboard pw = Kernel::my_receiver.create_capability (PWR)
Kernel::my_parent.provide_device <Keyboard> (dev.copy (), 0)
Kernel::my_parent.provide_device <Keyboard> (pw.copy (), 1)
Kernel::free_cap (dev)
Kernel::free_cap (pw)
Kernel::my_parent.init_done ()
Iris::Device dev = Iris::my_receiver.create_capability (KBD_DEV)
Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR)
Iris::my_parent.provide_device <Iris::Keyboard> (dev.copy (), 0)
Iris::my_parent.provide_device <Iris::Keyboard> (pw.copy (), 1)
Iris::free_cap (dev)
Iris::free_cap (pw)
Iris::my_parent.init_done ()
if kbd.scanning ():
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
unsigned user (0), power_user (0)
unsigned next_user (0)
Kernel::register_interrupt (IRQ_GPIO3)
Iris::register_interrupt (IRQ_GPIO3)
while true:
Kernel::wait ()
switch Kernel::recv.protected_data.h:
Iris::wait ()
switch Iris::recv.protected_data.h:
case ~0:
// Alarm.
kbd.scan ()
if kbd.scanning ():
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
break
case 0:
switch Kernel::recv.protected_data.l:
switch Iris::recv.protected_data.l:
case IRQ_GPIO3:
// Interrupt.
pwr.scan ()
kbd.scan ()
if kbd.scanning ():
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
Kernel::register_interrupt (IRQ_GPIO3)
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
Iris::register_interrupt (IRQ_GPIO3)
break
case PWR:
// Power button request.
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
Device::host (PWR, power_user, reply, arg)
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Device::host (PWR, power_user, reply, arg)
break
case KBD_DEV:
// Keyboard device control request.
Kernel::Cap reply = Kernel::get_reply ()
Kernel::Cap arg = Kernel::get_arg ()
Device::host (KBD_DEV, user, reply, arg)
Iris::Cap reply = Iris::get_reply ()
Iris::Cap arg = Iris::get_arg ()
Iris::Device::host (KBD_DEV, user, reply, arg)
break
default:
break
break
case KBD_DEV:
// Keyboard device user request.
if Kernel::recv.protected_data.l != user:
if Iris::recv.protected_data.l != user:
kdebug ("invalid user requesting keyboard\n")
Kernel::recv.reply.invoke ()
Iris::recv.reply.invoke ()
break
switch Kernel::recv.data[0].l:
case Keyboard::SET_CB:
Kernel::Cap reply = Kernel::get_reply ()
kbd.active (Kernel::get_arg ())
switch Iris::recv.data[0].l:
case Iris::Keyboard::SET_CB:
Iris::Cap reply = Iris::get_reply ()
kbd.active (Iris::get_arg ())
reply.invoke ()
Kernel::free_cap (reply)
Iris::free_cap (reply)
break
case Keyboard::GET_NUM_KEYS:
Kernel::recv.reply.invoke (kbd.size ())
case Iris::Keyboard::GET_NUM_KEYS:
Iris::recv.reply.invoke (kbd.size ())
break
case Keyboard::GET_KEYS:
kbd.send_keys (Kernel::recv.data[0].l, Kernel::recv.reply)
case Iris::Keyboard::GET_KEYS:
kbd.send_keys (Iris::recv.data[0].l, Iris::recv.reply)
break
default:
kdebug ("keyboard other\n")
break
break
case PWR:
if Kernel::recv.protected_data.l != power_user:
if Iris::recv.protected_data.l != power_user:
kdebug ("invalid user requesting power\n")
Kernel::recv.reply.invoke ()
Iris::recv.reply.invoke ()
break
switch Kernel::recv.data[0].l:
case Keyboard::SET_CB:
Kernel::Cap reply = Kernel::get_reply ()
pwr.set_cb (Kernel::get_arg ())
switch Iris::recv.data[0].l:
case Iris::Keyboard::SET_CB:
Iris::Cap reply = Iris::get_reply ()
pwr.set_cb (Iris::get_arg ())
reply.invoke ()
Kernel::free_cap (reply)
Iris::free_cap (reply)
break
default:
kdebug ("Power button invalid request\n")
kdebug_num (Kernel::recv.data[0].l)
kdebug_num (Iris::recv.data[0].l)
kdebug ("\n")
break
break
default:
kdebug ("keyboard unknown num: ")
kdebug_num (Kernel::recv.protected_data.h)
kdebug_num (Iris::recv.protected_data.h)
kdebug ("\n")

View File

@ -53,14 +53,14 @@ enum event_type:
TOUCHPAD_EVENT
NUM_EVENTS
static Kernel::Cap events[NUM_EVENTS]
static Iris::Cap events[NUM_EVENTS]
static void event (event_type type, unsigned data):
events[type].invoke (data)
static void set_cb (event_type type):
Kernel::free_cap (events[type])
events[type] = Kernel::get_arg ()
Iris::free_cap (events[type])
events[type] = Iris::get_arg ()
class DevKeyboard:
static unsigned const encode[GPIO_KBD_NUM_COLS][GPIO_KBD_NUM_ROWS]
@ -252,72 +252,72 @@ enum codes:
LOCKLEDS
PWM
Kernel::Num start ():
Iris::Num start ():
map_gpio ()
map_pwm0 ()
for unsigned i = 0; i < NUM_EVENTS; ++i:
events[i] = Kernel::alloc_cap ()
events[i] = Iris::alloc_cap ()
DevKeyboard kbd
Touchpad tp
Lockleds leds
Pwm pwm
Kernel::Cap c = Kernel::my_receiver.create_capability (KEYBOARD)
Kernel::my_parent.provide_device <Keyboard> (c.copy (), 0)
Kernel::free_cap (c)
c = Kernel::my_receiver.create_capability (TOUCHPAD)
Kernel::my_parent.provide_device <Keyboard> (c.copy (), 1)
Kernel::free_cap (c)
Kernel::my_parent.init_done ()
Iris::Cap c = Iris::my_receiver.create_capability (KEYBOARD)
Iris::my_parent.provide_device <Keyboard> (c.copy (), 0)
Iris::free_cap (c)
c = Iris::my_receiver.create_capability (TOUCHPAD)
Iris::my_parent.provide_device <Keyboard> (c.copy (), 1)
Iris::free_cap (c)
Iris::my_parent.init_done ()
if kbd.is_scanning ():
Kernel::my_receiver.set_alarm (ALARM_INTERVAL)
Iris::my_receiver.set_alarm (ALARM_INTERVAL)
// 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
Kernel::register_interrupt (IRQ_GPIO0)
Iris::register_interrupt (IRQ_GPIO0)
while true:
Kernel::schedule ()
Kernel::wait ()
switch Kernel::recv.protected_data.l:
Iris::schedule ()
Iris::wait ()
switch Iris::recv.protected_data.l:
case ~0:
// Alarm.
kbd.scan ()
if kbd.is_scanning ():
Kernel::my_receiver.set_alarm (ALARM_INTERVAL)
Iris::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.
Kernel::register_interrupt (IRQ_GPIO0)
Iris::register_interrupt (IRQ_GPIO0)
break
case KEYBOARD:
set_cb (KEYBOARD_EVENT)
Kernel::recv.reply.invoke ()
Iris::recv.reply.invoke ()
kbd.send_initial ()
event (KEYBOARD_EVENT, ~0)
break
case TOUCHPAD:
set_cb (TOUCHPAD_EVENT)
Kernel::recv.reply.invoke ()
Iris::recv.reply.invoke ()
tp.send_initial ()
event (TOUCHPAD_EVENT, ~0)
break
case LOCKLEDS:
leds.set (Kernel::recv.data[0].l)
Kernel::recv.reply.invoke ()
leds.set (Iris::recv.data[0].l)
Iris::recv.reply.invoke ()
break
case PWM:
pwm.set_backlight (Kernel::recv.data[0].l)
Kernel::recv.reply.invoke ()
pwm.set_backlight (Iris::recv.data[0].l)
Iris::recv.reply.invoke ()
break
default:
kdebug ("invalid gpio operation ")
kdebug_num (Kernel::recv.protected_data.l)
kdebug_num (Iris::recv.protected_data.l)
kdebug ("\n")
break