1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-06-28 23:29:50 +03: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/install-sh
mips/nanonote/server/missing mips/nanonote/server/missing
mips/nanonote/server/usb-server mips/nanonote/server/usb-server
fs/

View File

@ -51,6 +51,9 @@ fs/%.elf: source/crt0.o source/%.o
$(LD) $(LDFLAGS) $(filter %.o,$^) -o $@ $(LD) $(LDFLAGS) $(filter %.o,$^) -o $@
$(OBJCOPY) -S $(OBJCOPYFLAGS) $@ $(OBJCOPY) -S $(OBJCOPYFLAGS) $@
fs/%: %
ln -s ../$< $@
clean: clean:
rm -f *.o boot-programs/*.o $(BUILT_SOURCES) $(ARCH_CLEAN_FILES) 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 ((kFree *)self->prev)->next = self->next
else: else:
frees = (kFree *)self->next frees = (kFree *)self->next
//kdebug ("freeing page: ")
//kdebug_num ((unsigned)self - SIZE)
//kdebug ("\n")
pfree ((unsigned)self - SIZE) pfree ((unsigned)self - SIZE)
kPage *kMemory::alloc_page (): kPage *kMemory::alloc_page ():
@ -292,7 +295,7 @@ kMemory *kMemory::alloc_memory ():
kMemory_arch_init (ret) kMemory_arch_init (ret)
return 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: if index >= size:
kdebug ("size: ") kdebug ("size: ")
kdebug_num (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") dpanic (index, "index too large for kCaps")
return return
kCapability *c = &caps[index] 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->target = target
c->protected_data = pdata c->protected_data = pdata
c->parent = parent c->parent = parent
@ -321,8 +319,6 @@ void kCaps::set (unsigned index, kReceiver *target, Kernel::Num pdata, kCapRef p
c->sibling_next.reset () c->sibling_next.reset ()
if c->sibling_next.valid (): if c->sibling_next.valid ():
c->sibling_next->sibling_prev = kCapRef (this, index) c->sibling_next->sibling_prev = kCapRef (this, index)
if (unsigned)target == 0x81fdc350:
kdebug (" done\n")
void kCaps::clone (unsigned index, kCapRef source, bool copy): void kCaps::clone (unsigned index, kCapRef source, bool copy):
cap (index)->invalidate () cap (index)->invalidate ()
@ -341,10 +337,9 @@ void kCaps::clone (unsigned index, kCapRef source, bool copy):
void kMemory::free_page (kPage *page): void kMemory::free_page (kPage *page):
if page->mapping != ~0: if page->mapping != ~0:
page->address_space->unmap (page) page->address_space->unmap (page)
if page->flags & Kernel::Page::PAYING: page->forget ()
if page->flags & Iris::Page::PAYING:
unuse () unuse ()
if page->frame:
pfree (page->frame)
free_obj (page, (kPointer *)&pages) free_obj (page, (kPointer *)&pages)
void kThread::unset_slot (unsigned s): void kThread::unset_slot (unsigned s):
@ -367,6 +362,8 @@ void kMemory::free_thread (kThread *thread):
for unsigned i = 0; i < thread->slots; ++i: for unsigned i = 0; i < thread->slots; ++i:
thread->unset_slot (i) thread->unset_slot (i)
free_obj (thread, (void **)&threads) free_obj (thread, (void **)&threads)
if old_current == thread:
old_current = NULL
void kMemory::free_message (kReceiver *owner, kMessage *message): void kMemory::free_message (kReceiver *owner, kMessage *message):
for unsigned i = 0; i < 2; ++i: for unsigned i = 0; i < 2; ++i:
@ -382,11 +379,15 @@ void kMemory::free_receiver (kReceiver *receiver):
while receiver->messages: while receiver->messages:
free_message (receiver, receiver->messages) free_message (receiver, receiver->messages)
free_obj (receiver, (void **)&receivers) 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 (): void kReceiver::orphan ():
if prev_owned: if prev_owned:
prev_owned->next_owned = next_owned prev_owned->next_owned = next_owned
else: else if owner:
owner->receivers = next_owned owner->receivers = next_owned
if next_owned: if next_owned:
next_owned->prev_owned = prev_owned next_owned->prev_owned = prev_owned
@ -404,10 +405,14 @@ void kReceiver::own (kThread *o):
void kCapability::invalidate (): void kCapability::invalidate ():
if !target: if !target:
return return
//kdebug_num ((unsigned)this)
//kdebug ("\n")
//kdebug_num ((unsigned)target) //kdebug_num ((unsigned)target)
//kdebug (":") //kdebug (":")
//kdebug_num ((unsigned)protected_data.l) //kdebug_num ((unsigned)protected_data.l)
//kdebug ("\n") //kdebug ("\n")
if (unsigned)this == dbg_code.h:
dpanic (0, "invalidating watched capability")
if sibling_prev.valid (): if sibling_prev.valid ():
sibling_prev->sibling_next = sibling_next sibling_prev->sibling_next = sibling_next
else if parent.valid (): else if parent.valid ():
@ -429,6 +434,8 @@ void kCapability::invalidate ():
if !next: if !next:
next = c->parent.deref () next = c->parent.deref ()
c->target = NULL c->target = NULL
if c->parent.valid ():
c->parent->children = c->sibling_next
c->parent.reset () c->parent.reset ()
c->children.reset () c->children.reset ()
c->sibling_prev.reset () c->sibling_prev.reset ()
@ -492,19 +499,24 @@ void kMemory::free_list (kList *l):
void kMemory::free_memory (kMemory *mem): void kMemory::free_memory (kMemory *mem):
while mem->pages: 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: while mem->capses:
free_caps (mem->capses) mem->free_caps (mem->capses)
while mem->threads: while mem->threads:
free_thread (mem->threads) mem->free_thread (mem->threads)
while mem->memories: while mem->memories:
free_memory (mem->memories) mem->free_memory (mem->memories)
while mem->receivers: while mem->receivers:
free_receiver (mem->receivers) mem->free_receiver (mem->receivers)
while mem->lists: while mem->lists:
free_list (mem->lists) mem->free_list (mem->lists)
while mem->listitems: while mem->listitems:
free_listitem (mem->listitems) mem->free_listitem (mem->listitems)
if mem->frees: if mem->frees:
panic (0, "kernel memory leak: memory still in use") panic (0, "kernel memory leak: memory still in use")
free_obj (mem, (void **)&memories) free_obj (mem, (void **)&memories)
@ -519,10 +531,10 @@ void kPage::forget ():
share_next = NULL share_next = NULL
else: else:
// If the page has a frame and should be freed, free it. // 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) raw_pfree (frame)
frame = 0 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) kPage_arch_update_mapping (this)
static void check_receiver (kReceiver *r, kCapRef cap, unsigned line): 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") kdebug ("!= receiver\n")
dpanic (line, "consistency bug in kernel capabilities") dpanic (line, "consistency bug in kernel capabilities")
for kCapRef c = cap->children; c.valid (); c = c->sibling_next: 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) check_receiver (r, c, line)
void kReceiver::check (unsigned line): void kReceiver::check (unsigned line):
@ -556,7 +570,7 @@ void kMemory::check (unsigned line):
for kReceiver *r = receivers; r; r = (kReceiver *)r->next: for kReceiver *r = receivers; r; r = (kReceiver *)r->next:
r->check (line) r->check (line)
for kThread *t = threads; t; t = (kThread *)t->next: 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_num ((unsigned)t)
kdebug ("\n") kdebug ("\n")
panic (line, "pc is 0") 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 *__slot_admin, *__cap_admin
static list *__first_free_slot, *__first_free_cap static list *__first_free_slot, *__first_free_cap
namespace Kernel: namespace Iris:
Caps my_caps
Receiver my_receiver Receiver my_receiver
Thread my_thread Thread my_thread
Memory my_memory Memory my_memory
@ -77,7 +78,7 @@ namespace Kernel:
if !__first_free_slot: if !__first_free_slot:
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT. // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
kdebug ("out of slots!\n") kdebug ("out of slots!\n")
Kernel::panic (0) Iris::panic (0)
return ~0 return ~0
list *ret = __first_free_slot list *ret = __first_free_slot
__first_free_slot = ret->next __first_free_slot = ret->next
@ -90,7 +91,7 @@ namespace Kernel:
if !__first_free_cap: if !__first_free_cap:
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE // Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
kdebug ("out of capabilities!\n") kdebug ("out of capabilities!\n")
Kernel::panic (0) Iris::panic (0)
return Cap (0, CAP_NONE) return Cap (0, CAP_NONE)
list *ret = __first_free_cap list *ret = __first_free_cap
__first_free_cap = ret->next __first_free_cap = ret->next
@ -106,20 +107,21 @@ extern "C":
__cap_admin = cap_admin __cap_admin = cap_admin
__first_free_slot = NULL __first_free_slot = NULL
for unsigned i = 1; i < __slots; ++i: for unsigned i = 1; i < __slots; ++i:
Kernel::free_slot (i) Iris::free_slot (i)
__first_free_cap = NULL __first_free_cap = NULL
for unsigned i = 7; i < __caps; ++i: for unsigned i = 6; i < __caps; ++i:
Kernel::free_cap (Kernel::Cap (0, i)) Iris::free_cap (Iris::Cap (0, i))
Kernel::my_receiver = Kernel::Cap (0, __receiver_num) Iris::my_caps = Iris::Cap (0, __caps_num)
Kernel::my_thread = Kernel::Cap (0, __thread_num) Iris::my_receiver = Iris::Cap (0, __receiver_num)
Kernel::my_memory = Kernel::Cap (0, __memory_num) Iris::my_thread = Iris::Cap (0, __thread_num)
Kernel::my_call = Kernel::Cap (0, __call_num) Iris::my_memory = Iris::Cap (0, __memory_num)
Kernel::my_parent = Kernel::Cap (0, __parent_num) Iris::my_call = Iris::Cap (0, __call_num)
Kernel::recv.reply = Kernel::alloc_cap () Iris::my_parent = Iris::Cap (0, __parent_num)
Kernel::recv.arg = Kernel::alloc_cap () Iris::recv.reply = Iris::alloc_cap ()
Kernel::Num ret = start () Iris::recv.arg = Iris::alloc_cap ()
Kernel::my_parent.exit (ret) Iris::Num ret = start ()
Kernel::my_memory.destroy (Kernel::my_thread) 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. // The program no longer exists. If it somehow does, generate an address fault.
while true: while true:
*(volatile unsigned *)~0 *(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] char log_buffer[1000]
unsigned log_buffer_size unsigned log_buffer_size
unsigned log_buffer_start unsigned log_buffer_start
Kernel::Cap caller, caller_arg Iris::Cap caller, caller_arg
bool have_caller bool have_caller
unsigned *page unsigned *page
unsigned *p unsigned *p
Kernel::Page buffer_page Iris::Page buffer_page
public: public:
void init () void init ()
void log (unsigned c) void log (unsigned c)
void interrupt (unsigned cmd) 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::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 = { 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. // Normally a normal new page should be allocated here, but new isn't implemented at this point.
page = (unsigned *)LCD_FRAMEBUFFER_BASE page = (unsigned *)LCD_FRAMEBUFFER_BASE
p = page p = page
buffer_page = Kernel::my_memory.create_page () buffer_page = Iris::my_memory.create_page ()
buffer_page.set_flags (Kernel::Page::FRAME | Kernel::Page::PAYING, Kernel::Page::FRAME | Kernel::Page::PAYING) buffer_page.set_flags (Iris::Page::FRAME | Iris::Page::PAYING, Iris::Page::FRAME | Iris::Page::PAYING)
Kernel::my_memory.map (buffer_page, (unsigned)page) Iris::my_memory.map (buffer_page, (unsigned)page)
// Disconnect from the bus and don't try to get high-speed. // Disconnect from the bus and don't try to get high-speed.
UDC_POWER = 0 UDC_POWER = 0
@ -242,14 +242,14 @@ void Udc::init ():
UDC_INTROUTE = 1 << 1 UDC_INTROUTE = 1 << 1
// Wait a while. // Wait a while.
for unsigned w = 0; w < 10000; ++w: for unsigned w = 0; w < 10000; ++w:
Kernel::schedule () Iris::schedule ()
// Connect to the host. // Connect to the host.
UDC_POWER = UDC_POWER_SOFTCONN UDC_POWER = UDC_POWER_SOFTCONN
bool Udc::vendor (Setup *s, unsigned cmd): bool Udc::vendor (Setup *s, unsigned cmd):
if !(s->request_type & 0x80): if !(s->request_type & 0x80):
kdebug ("data to device without size\n") kdebug ("data to device without size\n")
Kernel::panic (0) Iris::panic (0)
return true return true
if s->request == 10: if s->request == 10:
static unsigned b[2] static unsigned b[2]
@ -258,10 +258,10 @@ bool Udc::vendor (Setup *s, unsigned cmd):
if cmd_code != ~0: if cmd_code != ~0:
b[0] = cmd_code b[0] = cmd_code
b[1] = cmd_arg 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 () caller.invoke ()
Kernel::free_cap (caller) Iris::free_cap (caller)
Kernel::free_cap (caller_arg) Iris::free_cap (caller_arg)
have_caller = false have_caller = false
//kdebug ("(un)lock response\n") //kdebug ("(un)lock response\n")
cmd_code = ~0 cmd_code = ~0
@ -283,10 +283,10 @@ bool Udc::vendor (Setup *s, unsigned cmd):
state = TX state = TX
return true 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: if cmd_code != ~0:
kdebug ("new code sent while old one wasn't finished.\n") kdebug ("new code sent while old one wasn't finished.\n")
Kernel::panic (0) Iris::panic (0)
cmd_code = code cmd_code = code
cmd_arg = narg cmd_arg = narg
caller = reply caller = reply
@ -404,7 +404,7 @@ void Udc::irq_in (unsigned cmd):
switch state: switch state:
case IDLE: case IDLE:
if rebooting: if rebooting:
Kernel::reboot () Iris::reboot ()
if !(csr & UDC_CSR0_OUTPKTRDY): if !(csr & UDC_CSR0_OUTPKTRDY):
return return
union { unsigned d[2]; Setup s; } packet union { unsigned d[2]; Setup s; } packet
@ -439,53 +439,53 @@ void Udc::irq_in (unsigned cmd):
case RX: case RX:
// The protocol that is used doesn't allow large packets, so being here always means the entire packet is received. // The protocol that is used doesn't allow large packets, so being here always means the entire packet is received.
switch rx_request & 0xff: switch rx_request & 0xff:
case Directory::GET_SIZE & 0xff: case Iris::Directory::GET_SIZE & 0xff:
if !have_caller: if !have_caller:
kdebug ("received dir size from server without a caller waiting\n") 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_l = UDC_FIFO (0)
unsigned size_h = UDC_FIFO (0) unsigned size_h = UDC_FIFO (0)
caller.invoke (Kernel::Num (size_l, size_h)) caller.invoke (Iris::Num (size_l, size_h))
Kernel::free_cap (caller) Iris::free_cap (caller)
Kernel::free_cap (caller_arg) Iris::free_cap (caller_arg)
have_caller = false have_caller = false
//kdebug ("get_size response\n") //kdebug ("get_size response\n")
break break
case Directory::GET_NAME & 0xff: case Iris::Directory::GET_NAME & 0xff:
if !have_caller: if !have_caller:
kdebug ("received filename from server without a caller waiting\n") kdebug ("received filename from server without a caller waiting\n")
Kernel::panic (0) Iris::panic (0)
unsigned n[4] unsigned n[4]
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
n[i] = UDC_FIFO (0) n[i] = UDC_FIFO (0)
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3])) caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
Kernel::free_cap (caller) Iris::free_cap (caller)
Kernel::free_cap (caller_arg) Iris::free_cap (caller_arg)
//kdebug ("get_name response\n") //kdebug ("get_name response\n")
have_caller = false have_caller = false
break break
case ::String::GET_SIZE & 0xff: case Iris::String::GET_SIZE & 0xff:
if !have_caller: if !have_caller:
kdebug ("received string size from server without a caller waiting\n") 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_l = UDC_FIFO (0)
unsigned size_h = UDC_FIFO (0) unsigned size_h = UDC_FIFO (0)
caller.invoke (Kernel::Num (size_l, size_h)) caller.invoke (Iris::Num (size_l, size_h))
Kernel::free_cap (caller) Iris::free_cap (caller)
Kernel::free_cap (caller_arg) Iris::free_cap (caller_arg)
have_caller = false have_caller = false
//kdebug ("get_filesize response\n") //kdebug ("get_filesize response\n")
break break
case ::String::GET_CHARS & 0xff: case Iris::String::GET_CHARS & 0xff:
if !have_caller: if !have_caller:
kdebug ("received string char data from server without a caller waiting\n") kdebug ("received string char data from server without a caller waiting\n")
Kernel::panic (0) Iris::panic (0)
unsigned n[4] unsigned n[4]
for unsigned i = 0; i < 4; ++i: for unsigned i = 0; i < 4; ++i:
n[i] = UDC_FIFO (0) n[i] = UDC_FIFO (0)
caller.invoke (Kernel::Num (n[0], n[1]), Kernel::Num (n[2], n[3])) caller.invoke (Iris::Num (n[0], n[1]), Iris::Num (n[2], n[3]))
Kernel::free_cap (caller) Iris::free_cap (caller)
Kernel::free_cap (caller_arg) Iris::free_cap (caller_arg)
have_caller = false have_caller = false
//kdebug ("get_chars response\n") //kdebug ("get_chars response\n")
break break
@ -493,7 +493,7 @@ void Udc::irq_in (unsigned cmd):
kdebug ("invalid vendor request: ") kdebug ("invalid vendor request: ")
kdebug_num (rx_request) kdebug_num (rx_request)
kdebug ("\n") kdebug ("\n")
Kernel::panic (0) Iris::panic (0)
UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY UDC_CSR0 = csr | UDC_CSR0_DATAEND | UDC_CSR0_SVDOUTPKTRDY
state = IDLE state = IDLE
break break
@ -504,7 +504,7 @@ void Udc::irq_out (unsigned cmd):
UDC_INDEX = 1 UDC_INDEX = 1
if !have_caller: if !have_caller:
kdebug ("received bulk data from server without a caller waiting\n") kdebug ("received bulk data from server without a caller waiting\n")
Kernel::panic (0) Iris::panic (0)
unsigned size = UDC_OUTCOUNT unsigned size = UDC_OUTCOUNT
unsigned csr = UDC_OUTCSR unsigned csr = UDC_OUTCSR
//kdebug ("handling bulk interrupt for ") //kdebug ("handling bulk interrupt for ")
@ -516,11 +516,11 @@ void Udc::irq_out (unsigned cmd):
for unsigned i = 0; i < size; i += 4: for unsigned i = 0; i < size; i += 4:
*p++ = UDC_FIFO (1) *p++ = UDC_FIFO (1)
if p - page == PAGE_SIZE >> 2: if p - page == PAGE_SIZE >> 2:
buffer_page.share (caller_arg, Kernel::Page::FORGET) buffer_page.share (caller_arg, Iris::Page::FORGET)
buffer_page.set_flags (Kernel::Page::FRAME, Kernel::Page::FRAME) buffer_page.set_flags (Iris::Page::FRAME, Iris::Page::FRAME)
caller.invoke () caller.invoke ()
Kernel::free_cap (caller) Iris::free_cap (caller)
Kernel::free_cap (caller_arg) Iris::free_cap (caller_arg)
have_caller = false have_caller = false
//kdebug ("bulk response\n") //kdebug ("bulk response\n")
p = page p = page
@ -561,153 +561,153 @@ enum pdata:
FILE FILE
NAME NAME
Kernel::Num start (): Iris::Num start ():
map_udc () map_udc ()
map_gpio () map_gpio ()
map_cpm () map_cpm ()
Udc udc 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") __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
udc.init () udc.init ()
Kernel::register_interrupt (IRQ_UDC) Iris::register_interrupt (IRQ_UDC)
Device fs_dev = Kernel::my_receiver.create_capability (FS) Iris::Device fs_dev = Iris::my_receiver.create_capability (FS)
Device data_dev = Kernel::my_receiver.create_capability (DATA) Iris::Device data_dev = Iris::my_receiver.create_capability (DATA)
Kernel::my_parent.provide_device <Filesystem> (fs_dev.copy ()) Iris::my_parent.provide_device <Iris::Filesystem> (fs_dev.copy ())
Kernel::my_parent.provide_device <String> (data_dev.copy ()) Iris::my_parent.provide_device <Iris::String> (data_dev.copy ())
Kernel::free_cap (fs_dev) Iris::free_cap (fs_dev)
Kernel::free_cap (data_dev) Iris::free_cap (data_dev)
unsigned data_current_user = 0, fs_current_user = 0 unsigned data_current_user = 0, fs_current_user = 0
unsigned next_user unsigned next_user
unsigned state = 0 unsigned state = 0
while true: while true:
Kernel::wait () Iris::wait ()
Kernel::Cap reply = Kernel::get_reply () Iris::Cap reply = Iris::get_reply ()
Kernel::Cap arg = Kernel::get_arg () Iris::Cap arg = Iris::get_arg ()
switch Kernel::recv.protected_data.h: switch Iris::recv.protected_data.h:
case 0: case 0:
switch Kernel::recv.protected_data.l: switch Iris::recv.protected_data.l:
case IRQ_UDC: case IRQ_UDC:
udc.interrupt (state) udc.interrupt (state)
Kernel::register_interrupt (IRQ_UDC) Iris::register_interrupt (IRQ_UDC)
break break
case LOG: case LOG:
udc.log (Kernel::recv.data[0].l) udc.log (Iris::recv.data[0].l)
break break
case FS: case FS:
Device::host (FS, fs_current_user, reply, arg) Iris::Device::host (FS, fs_current_user, reply, arg)
continue continue
case DATA: case DATA:
Device::host (DATA, data_current_user, reply, arg) Iris::Device::host (DATA, data_current_user, reply, arg)
continue continue
default: default:
udc.log ('~') udc.log ('~')
char digit[] = "0123456789abcdef" char digit[] = "0123456789abcdef"
for unsigned i = 0; i < 8; ++i: 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') udc.log ('\n')
break break
break break
case DATA: case DATA:
if data_current_user != Kernel::recv.protected_data.l: if data_current_user != Iris::recv.protected_data.l:
break break
switch Kernel::recv.data[0].l: switch Iris::recv.data[0].l:
case ::String::GET_SIZE: case Iris::String::GET_SIZE:
case ::String::GET_CHARS: case Iris::String::GET_CHARS:
reply.invoke (0) reply.invoke (0)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
case ::String::GET_PAGE: case Iris::String::GET_PAGE:
default: default:
reply.invoke (Kernel::ERR_INVALID_OPERATION) reply.invoke (Iris::ERR_INVALID_OPERATION)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
break break
case FS: case FS:
if fs_current_user != Kernel::recv.protected_data.l: if fs_current_user != Iris::recv.protected_data.l:
break break
switch Kernel::recv.data[0].l: switch Iris::recv.data[0].l:
case Filesystem::USE_DEVICE: case Iris::Filesystem::USE_DEVICE:
case Filesystem::USE_DEVICE_RO: case Iris::Filesystem::USE_DEVICE_RO:
Directory dir = Kernel::my_receiver.create_capability (Kernel::Num (0, DIRECTORY)) Iris::Directory dir = Iris::my_receiver.create_capability (Iris::Num (0, DIRECTORY))
reply.invoke (0, 0, dir.copy ()) reply.invoke (0, 0, dir.copy ())
Kernel::free_cap (dir) Iris::free_cap (dir)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
default: default:
reply.invoke (Kernel::ERR_INVALID_OPERATION) reply.invoke (Iris::ERR_INVALID_OPERATION)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
break break
case DIRECTORY: case DIRECTORY:
switch Kernel::recv.data[0].l: switch Iris::recv.data[0].l:
case Directory::GET_NAME: case Iris::Directory::GET_NAME:
Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (Kernel::recv.data[1].l, NAME)) Iris::Cap name = Iris::my_receiver.create_capability (Iris::Num (Iris::recv.data[1].l, NAME))
reply.invoke (0, 0, name.copy ()) reply.invoke (0, 0, name.copy ())
Kernel::free_cap (name) Iris::free_cap (name)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
case Directory::GET_SIZE: case Iris::Directory::GET_SIZE:
case Directory::LOCK_RO: case Iris::Directory::LOCK_RO:
case Directory::UNLOCK_RO: case Iris::Directory::UNLOCK_RO:
state = Kernel::recv.data[0].l state = Iris::recv.data[0].l
if Kernel::recv.data[1].h != 0: if Iris::recv.data[1].h != 0:
kdebug ("index out of supported range\n") kdebug ("index out of supported range\n")
Kernel::panic (0) Iris::panic (0)
udc.send (Kernel::recv.data[0].l, Kernel::recv.data[1].l, reply, arg) udc.send (Iris::recv.data[0].l, Iris::recv.data[1].l, reply, arg)
continue continue
case Directory::GET_FILE_RO: case Iris::Directory::GET_FILE_RO:
if Kernel::recv.data[1].h != 0: if Iris::recv.data[1].h != 0:
kdebug ("index out of supported range\n") kdebug ("index out of supported range\n")
Kernel::panic (0) Iris::panic (0)
//kdebug ("sending file\n") //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 ()) reply.invoke (0, 0, file.copy ())
Kernel::free_cap (file) Iris::free_cap (file)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
case Directory::GET_FILE_INFO: case Iris::Directory::GET_FILE_INFO:
default: default:
reply.invoke (Kernel::ERR_INVALID_OPERATION) reply.invoke (Iris::ERR_INVALID_OPERATION)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
break break
case FILE: case FILE:
switch Kernel::recv.data[0].l: switch Iris::recv.data[0].l:
case ::String::GET_SIZE: case Iris::String::GET_SIZE:
case ::String::GET_CHARS: case Iris::String::GET_CHARS:
case ::String::GET_PAGE: case Iris::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) udc.send (Iris::recv.data[0].l | ((Iris::recv.data[1].l >> PAGE_BITS) << 16), Iris::recv.protected_data.l, reply, arg)
continue continue
default: default:
reply.invoke (Kernel::ERR_INVALID_OPERATION) reply.invoke (Iris::ERR_INVALID_OPERATION)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
break break
case NAME: case NAME:
switch Kernel::recv.data[0].l: switch Iris::recv.data[0].l:
case ::String::GET_SIZE: case Iris::String::GET_SIZE:
reply.invoke (16) reply.invoke (16)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
case ::String::GET_CHARS: case Iris::String::GET_CHARS:
state = Kernel::recv.data[0].l state = Iris::recv.data[0].l
udc.send (Directory::GET_NAME, Kernel::recv.protected_data.l, reply, arg) udc.send (Iris::Directory::GET_NAME, Iris::recv.protected_data.l, reply, arg)
continue continue
default: default:
reply.invoke (Kernel::ERR_INVALID_OPERATION) reply.invoke (Iris::ERR_INVALID_OPERATION)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
continue continue
reply.invoke () reply.invoke ()
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)

View File

@ -21,363 +21,405 @@
#include "iris.hh" #include "iris.hh"
// List interface. namespace Iris:
template <typename _T> // // Caplist interface.
struct List : public Kernel::Caps: template <typename _T> //
List (Kernel::Caps c = Kernel::Cap ()) : Kernel::Caps (c): struct Caplist : public Iris::Caps:
List <_T> create (unsigned size, Kernel::Memory mem = Kernel::my_memory): Caplist (Iris::Caps c = Iris::Cap ()) : Iris::Caps (c):
return List <_T> (mem.create_caps (size)) Caplist <_T> create (unsigned size, Iris::Memory mem = Iris::my_memory):
void set (unsigned idx, _T value): return Caplist <_T> (mem.create_caps (size))
return Kernel::Caps::set (idx, value) void set (unsigned idx, _T value):
_T get (unsigned idx): return Iris::Caps::set (idx, value)
return _T (Kernel::Caps::get (idx)) _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'). /// A block of data with a size and content. Any character can be stored in it (including '\0').
struct String : public Kernel::Cap: struct String : public Iris::Cap:
String (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): String (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request: enum request:
GET_SIZE = 0x2001 GET_SIZE = 0x2001
GET_CHARS GET_CHARS
GET_PAGE GET_PAGE
ID ID
/// Get the size of the string. /// Get the size of the string.
Kernel::Num get_size (): Iris::Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE) return call (CAP_MASTER_DIRECT | GET_SIZE)
/// Get exactly 16 characters. The index must be word-aligned. /// Get exactly 16 characters. The index must be word-aligned.
char *get_chars (Kernel::Num idx, char buffer[16]): char *get_chars (Iris::Num idx, char buffer[16]):
call (CAP_MASTER_DIRECT | GET_CHARS, idx) call (CAP_MASTER_DIRECT | GET_CHARS, idx)
unsigned *b = (unsigned *)buffer unsigned *b = (unsigned *)buffer
b[0] = Kernel::recv.data[0].l b[0] = Iris::recv.data[0].l
b[1] = Kernel::recv.data[0].h b[1] = Iris::recv.data[0].h
b[2] = Kernel::recv.data[1].l b[2] = Iris::recv.data[1].l
b[3] = Kernel::recv.data[1].h b[3] = Iris::recv.data[1].h
return buffer 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. /// Helper function for get_page.
Cap get_page (Kernel::Num idx, Kernel::Page ret = Kernel::my_memory.create_page ()): static Iris::Page _create_paying_page ():
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx) Iris::Page ret = Iris::my_memory.create_page ()
return ret 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. /// A writable String.
struct WString : public String: struct WString : public String:
WString (Kernel::Cap c = Kernel::Cap ()) : String (c): WString (Iris::Cap c = Iris::Cap ()) : String (c):
enum request: enum request:
TRUNCATE = String::ID TRUNCATE = String::ID
SET_CHARS SET_CHARS
SET_PAGE SET_PAGE
ID ID
/// Set the size of the string. Strings may have a limit to this setting. /// Set the size of the string. Strings may have a limit to this setting.
void truncate (Kernel::Num size): void truncate (Iris::Num size):
call (CAP_MASTER_DIRECT | TRUNCATE, size) call (CAP_MASTER_DIRECT | TRUNCATE, size)
/// Set exactly 4 characters. The index must be word-aligned. /// Set exactly 4 characters. The index must be word-aligned.
void set_chars (Kernel::Num idx, char buffer[4]): void set_chars (Iris::Num idx, char buffer[4]):
call (Kernel::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx) 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. /// 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): void set_page (Iris::Num idx, Iris::Page page):
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx) ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
// Every process which wants to be switchable through a terminal must implement this interface. // Every process which wants to be switchable through a terminal must implement this interface.
struct Device : public Kernel::Cap: struct Device : public Iris::Cap:
Device (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Device (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request: enum request:
CREATE_USER = WString::ID CREATE_USER = WString::ID
DESTROY_USER DESTROY_USER
UNUSE UNUSE
USE USE
ID ID
// Create a new user for this device. It will not be the active user. // 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. // 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): Iris::Cap create_user (Iris::Memory storage, unsigned arg1 = 0, Iris::Num arg2 = 0):
iocall (storage, Kernel::Num (CAP_MASTER_DIRECT | CREATE_USER, arg1), arg2) iocall (storage, Iris::Num (CAP_MASTER_DIRECT | CREATE_USER, arg1), arg2)
return Kernel::get_arg () return Iris::get_arg ()
// Destroy a user. It is made inactive if it was active. // Destroy a user. It is made inactive if it was active.
void destroy_user (Kernel::Cap user): void destroy_user (Iris::Cap user):
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER) ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
// Make user inactive. // Make user inactive.
void unuse (Kernel::Cap user): void unuse (Iris::Cap user):
ocall (user, CAP_MASTER_DIRECT | UNUSE) ocall (user, CAP_MASTER_DIRECT | UNUSE)
// Make user active. It makes the previous active user inactive. // Make user active. It makes the previous active user inactive.
void use (Kernel::Cap user): void use (Iris::Cap user):
ocall (user, CAP_MASTER_DIRECT | USE) ocall (user, CAP_MASTER_DIRECT | USE)
// Convenience function for threads implementing a device. // 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 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 static unsigned last_user
switch Kernel::recv.data[0].l: switch Iris::recv.data[0].l:
case Device::CREATE_USER: case Device::CREATE_USER:
Kernel::Memory mem (arg) Iris::Memory mem (arg)
Kernel::Caps caps = mem.create_caps (capssize) Iris::Caps caps = mem.create_caps (capssize)
unsigned user unsigned user
if create: if create:
user = create (mem, caps) user = create (mem, caps)
else: else:
// Increment last_user; skip 0. // Increment last_user; skip 0.
// FIXME: if this really wraps, it is possible that two users share their id. // FIXME: if this really wraps, it is possible that two users share their id.
if !++last_user: if !++last_user:
++last_user ++last_user
user = last_user user = last_user
Kernel::Cap c = Kernel::my_receiver.create_capability (Kernel::Num (user, id)) Iris::Cap c = Iris::my_receiver.create_capability (Iris::Num (user, id))
caps.set (0, c.copy ()) caps.set (0, c.copy ())
caps.set (1, mem.copy ()) caps.set (1, mem.copy ())
reply.invoke (0, 0, caps.copy ()) reply.invoke (0, 0, caps.copy ())
Kernel::free_cap (c) Iris::free_cap (c)
Kernel::free_cap (caps) Iris::free_cap (caps)
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
break break
case Device::DESTROY_USER: case Device::DESTROY_USER:
Kernel::Caps caps (arg) Iris::Caps caps (arg)
Kernel::Cap c = caps.get (0) Iris::Cap c = caps.get (0)
Kernel::Num user = Kernel::my_receiver.get_protected (c) Iris::Num user = Iris::my_receiver.get_protected (c)
Kernel::free_cap (c) Iris::free_cap (c)
if user.h != id: if user.h != id:
Kernel::panic (user.h, "invalid id for destroy") Iris::panic (user.h, "invalid id for destroy")
// TODO: unuse. // TODO: unuse.
if destroy: if destroy:
destroy (user.l, caps) destroy (user.l, caps)
reply.invoke () reply.invoke ()
Kernel::free_cap (reply) Iris::free_cap (reply)
Kernel::free_cap (arg) Iris::free_cap (arg)
break break
case Device::USE: case Device::USE:
Kernel::Caps caps (arg) Iris::Caps caps (arg)
Kernel::Cap c = caps.get (0) Iris::Cap c = caps.get (0)
Kernel::Num user = Kernel::my_receiver.get_protected (c) Iris::Num user = Iris::my_receiver.get_protected (c)
Kernel::free_cap (c) Iris::free_cap (c)
if user.h != id: if user.h != id:
Kernel::panic (user.h, "invalid id for use") Iris::panic (user.h, "invalid id for use")
// TODO: send unuse signal. // TODO: send unuse signal.
current_user = user.l current_user = user.l
if use: if use:
use (user.l, caps) 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:
c = caps.get (2) c = caps.get (2)
c.invoke (0) c.invoke (1)
Kernel::free_cap (c) Iris::free_cap (c)
current_user = 0 reply.invoke ()
reply.invoke () Iris::free_cap (reply)
Kernel::free_cap (reply) Iris::free_cap (arg)
Kernel::free_cap (arg) break
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 Elfrun : public Iris::Cap:
struct Parent : public Kernel::Cap: Elfrun (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
Parent (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request:
enum request: RUN_STRING = Device::ID
GET_DEVICE = Device::ID RUN_CAPS
PROVIDE_DEVICE ID
WAIT enum arg_pos:
GET_MEMORY PARENT_MEMORY
PROVIDE_MEMORY DATA
INIT_DONE PARENT
EXIT Iris::Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
ID Iris::Caps caps = Iris::my_memory.create_caps (3)
// Get a device handle. caps.set (PARENT_MEMORY, parent_memory)
template <typename _T> _T get_device (unsigned num = 0): caps.set (DATA, data)
icall (Kernel::Num (CAP_MASTER_DIRECT | GET_DEVICE, num), _T::ID) caps.set (PARENT, parent)
return Kernel::get_arg () iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Iris::Num (num_slots, num_caps))
// Provide a device handle. Iris::Caps ret = Iris::get_arg ()
template <typename _T> void provide_device (Device dev, unsigned num = 0): Iris::my_memory.destroy (caps)
ocall (dev, Kernel::Num (CAP_MASTER_DIRECT | PROVIDE_DEVICE, num), _T::ID) Iris::free_cap (caps)
// Wait until a device is used by the caller again. return ret
template <typename _T> void wait (unsigned num = 0): Iris::Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
call (Kernel::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID) Iris::Caps caps = Iris::my_memory.create_caps (3)
// 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. caps.set (PARENT_MEMORY, parent_memory)
Kernel::Memory get_memory (Kernel::Cap target): caps.set (DATA, data)
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY) caps.set (PARENT, parent)
return Kernel::get_arg () iocall (caps.copy (), Iris::Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Iris::Num (num_slots, num_caps))
// 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::Caps ret = Iris::get_arg ()
Kernel::Cap provide_memory (unsigned limit): Iris::my_memory.destroy (caps)
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit) Iris::free_cap (caps)
return Kernel::get_arg () return ret
// 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)
// Keyboard interface. // Interface for talking to the parent process.
struct Keyboard : public Kernel::Cap: struct Parent : public Iris::Cap:
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Parent (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request: enum request:
SET_CB = Parent::ID GET_DEVICE = Elfrun::ID
GET_NUM_KEYS PROVIDE_DEVICE
GET_KEYS WAIT
ID GET_MEMORY
// At event: the callback is called with a keycode. One bit defines if it's a press or release event. PROVIDE_MEMORY
enum constant: INIT_DONE
RELEASE = 1 << 31 EXIT
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately. ID
void set_cb (Kernel::Cap cb): // Get a device handle.
ocall (cb, CAP_MASTER_DIRECT | SET_CB) template <typename _T> _T get_device (unsigned num = 0):
// Get the number of keys on the keyboard. icall (Iris::Num (CAP_MASTER_DIRECT | GET_DEVICE, num), _T::ID)
unsigned get_num_keys (): return Iris::get_arg ()
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l // Provide a device handle.
// Get the keycodes for the keys. The reply sends 4 key codes (32 bit each). template <typename _T> void provide_device (Device dev, unsigned num = 0):
void get_keys (unsigned first): ocall (dev, Iris::Num (CAP_MASTER_DIRECT | PROVIDE_DEVICE, num), _T::ID)
call (CAP_MASTER_DIRECT | GET_KEYS, first) // 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. // Keyboard interface.
struct Buzzer : public Kernel::Cap: struct Keyboard : public Iris::Cap:
Buzzer (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Keyboard (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request: enum request:
BEEP = Keyboard::ID SET_CB = Parent::ID
STOP GET_NUM_KEYS
ID GET_KEYS
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted. ID
void beep (unsigned freq, unsigned ms, unsigned volume, Kernel::Cap cb = Kernel::Cap ()): // At event: the callback is called with a keycode. One bit defines if it's a press or release event.
ocall (cb, Kernel::Num (CAP_MASTER_DIRECT | BEEP, volume), Kernel::Num (freq, ms)) enum constant:
// Abort current beep, if any. RELEASE = 1 << 31
void stop (): // Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
call (CAP_MASTER_DIRECT | STOP) 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. // Buzzer interface.
struct Display : public Kernel::Cap: struct Buzzer : public Iris::Cap:
Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Buzzer (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request: enum request:
SET_EOF_CB = Buzzer::ID BEEP = Keyboard::ID
MAP_FB STOP
GET_INFO ID
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.
// Register an end-of-frame callback. void beep (unsigned freq, unsigned ms, unsigned volume, Iris::Cap cb = Iris::Cap ()):
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events. ocall (cb, Iris::Num (CAP_MASTER_DIRECT | BEEP, volume), Iris::Num (freq, ms))
void set_eof_cb (Kernel::Cap cb): // Abort current beep, if any.
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB) void stop ():
// Map the framebuffer into memory. call (CAP_MASTER_DIRECT | STOP)
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)
// Numerical setting, such as a display backlight. // Display interface.
struct Setting : public Kernel::Cap: struct Display : public Iris::Cap:
Setting (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Display (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request: enum request:
SET = Display::ID SET_EOF_CB = Buzzer::ID
GET_RANGE MAP_FB
ID GET_INFO
// Set a new value. ID
void set (unsigned value): // Register an end-of-frame callback.
call (CAP_MASTER_DIRECT | SET, value) // At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
// Get the maximum value for this setting. Using a higher value with SET gives undefined results. void set_eof_cb (Iris::Cap cb):
unsigned get_range (): ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
return call (CAP_MASTER_DIRECT | GET_RANGE).l // 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. // Numerical setting, such as a display backlight.
// filesystem-related interfaces: directory, stream, seekable. struct Setting : public Iris::Cap:
// Normal files implement stream and/or seekable. Directories implement directory. Setting (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
// Seekable is not a class, it is identical to [W]String. 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. // File system interface.
struct Directory : public Kernel::Cap: // filesystem-related interfaces: directory, stream, seekable.
Directory (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): // Normal files implement stream and/or seekable. Directories implement directory.
enum request: // Seekable is not a class, it is identical to [W]String.
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)
// A filesystem turns a String into a Directory. // Directory interface.
struct Filesystem : public Device: struct Directory : public Iris::Cap:
Filesystem (Kernel::Cap c = Kernel::Cap ()) : Device (c): Directory (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
enum request: enum request:
USE_DEVICE = WDirectory::ID GET_SIZE = Setting::ID
USE_DEVICE_RO GET_NAME
ID GET_FILE_RO
WDirectory use_device (WString dev): GET_FILE_INFO
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE) LOCK_RO
return Kernel::get_arg () UNLOCK_RO
Directory use_device_ro (String dev): ID
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO) // Get the number of entries in this directory.
return Kernel::get_arg () 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. // A filesystem turns a String into a Directory.
struct Stream : public Kernel::Cap: struct Filesystem : public Device:
Stream (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): Filesystem (Iris::Cap c = Iris::Cap ()) : Device (c):
enum request: enum request:
READ = Filesystem::ID USE_DEVICE = WDirectory::ID
WRITE USE_DEVICE_RO
ID ID
// Try to read size bytes. Returns the number of bytes successfully read. WDirectory use_device (WString dev):
Kernel::Num read (Kernel::Num size, bool block): ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, block), size) return Iris::get_arg ()
// Try to write size bytes. Returns the number of bytes successfully written. Directory use_device_ro (String dev):
Kernel::Num write (String s, Kernel::Num size): ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
return ocall (s, CAP_MASTER_DIRECT | WRITE, size) 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. // Block device interface.
struct Block_device : public WString: struct Block_device : public WString:
Block_device (Kernel::Cap c = Kernel::Cap ()) : WString (c): Block_device (Iris::Cap c = Iris::Cap ()) : WString (c):
// TODO: to be designed. // TODO: to be designed.
// TODO. // 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 (':')
kdebug_num ((unsigned)old_current) kdebug_num ((unsigned)old_current)
kdebug ('/') kdebug ('/')
if code < Kernel::NUM_EXCEPTION_CODES: if code < Iris::NUM_EXCEPTION_CODES:
kdebug (Kernel::exception_name[code]) kdebug (Iris::exception_name[code])
else: else:
kdebug ("invalid code:") kdebug ("invalid code:")
kdebug_num (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: if slots < 1 || !slot[0].caps || !slot[0].caps->cap (0)->target:
return return
kCapability::Context c kCapability::Context c
c.data[0] = Kernel::Num (code, data) c.data[0] = Iris::Num (code, data)
slot[0].caps->cap (0)->invoke (&c) slot[0].caps->cap (0)->invoke (&c)
// From user-provided, thus untrusted, data, find a capability. // From user-provided, thus untrusted, data, find a capability.
@ -128,7 +128,7 @@ bool kReceiver::try_deliver ():
return true return true
// Send a message to a receiver; try to deliver it immediately. // 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) //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 owner && owner->is_waiting () && (!protected_only || protected_data.value () == reply_protected_data.value ()):
if protected_only: if protected_only:
@ -161,59 +161,64 @@ bool kReceiver::send_message (Kernel::Num protected_data, kCapability::Context *
return true return true
static kCapability::Context *context 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 kCapability::Context c
c.data[0] = num c.data[0] = num
c.data[1] = 0 c.data[1] = 0
if reply_target: if reply_target:
reply_target->send_message (reply_protected, &c) reply_target->send_message (reply_protected, &c)
else: else if reply_protected.l == 0:
dpanic (0, "nothing to reply to") 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): static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
kCapability::Context c kCapability::Context c
c.data[0] = Kernel::Num (num1, num2) c.data[0] = Iris::Num (num1, num2)
c.data[1] = num3 c.data[1] = num3
if reply_target: if reply_target:
reply_target->send_message (reply_protected, &c) reply_target->send_message (reply_protected, &c)
else if reply_protected.l == 0:
dpanic (0, "nothing to reply to")
else: 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: 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 return
replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref) replied_caps.set (0, (kReceiver *)target, protected_data, kCapRef (), ref)
kCapability::Context c kCapability::Context c
c.arg = kCapRef (&replied_caps, 0) c.arg = kCapRef (&replied_caps, 0)
c.copy[1] = true 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) reply_target->send_message (reply_protected, &c)
c.arg->invalidate () 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 kReceiver *receiver = (kReceiver *)protected_data.l
switch cmd: switch cmd:
case Kernel::Receiver::SET_OWNER & REQUEST_MASK: case Iris::Receiver::SET_OWNER & REQUEST_MASK:
if !c->arg.valid (): if !c->arg.valid ():
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
unsigned cap = (unsigned)c->arg->target 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. // FIXME: This makes it impossible to use a fake kThread capability.
return return
receiver->own ((kThread *)c->arg->protected_data.l) receiver->own ((kThread *)c->arg->protected_data.l)
break break
case Kernel::Receiver::CREATE_CAPABILITY & REQUEST_MASK: case Iris::Receiver::CREATE_CAPABILITY & REQUEST_MASK:
reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities) reply_cap ((unsigned)receiver, c->data[1], &receiver->capabilities)
return return
case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK: case Iris::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) reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Iris::Receiver::CALL_ASYNC : Iris::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
return 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 () || c->arg->target != receiver:
if !c->arg.valid (): if !c->arg.valid ():
kdebug ("invalid arg\n") 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_num ((unsigned)c->arg->protected_data.l)
kdebug ("\n") kdebug ("\n")
dpanic (0, "wrong argument for get_protected") dpanic (0, "wrong argument for get_protected")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
reply_num (c->arg->protected_data) reply_num (c->arg->protected_data)
return 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) reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
return 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] receiver->reply_protected_data = c->data[1]
break break
case Kernel::Receiver::GET_ALARM & REQUEST_MASK: case Iris::Receiver::GET_ALARM & REQUEST_MASK:
reply_num (receiver->alarm_count) reply_num (receiver->alarm_count)
return return
case Kernel::Receiver::SET_ALARM & REQUEST_MASK: case Iris::Receiver::SET_ALARM & REQUEST_MASK:
case Kernel::Receiver::ADD_ALARM & REQUEST_MASK: case Iris::Receiver::ADD_ALARM & REQUEST_MASK:
unsigned old = receiver->alarm_count 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 receiver->alarm_count = c->data[1].l
else: else:
receiver->alarm_count += c->data[1].l receiver->alarm_count += c->data[1].l
@ -267,14 +272,14 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
return return
default: default:
dpanic (cmd, "invalid receiver operation") dpanic (cmd, "invalid receiver operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return return
reply_num (0) 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 kMemory *mem = (kMemory *)protected_data.l
switch cmd: switch cmd:
case Kernel::Memory::CREATE & REQUEST_MASK: case Iris::Memory::CREATE & REQUEST_MASK:
switch c->data[0].h: switch c->data[0].h:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
kReceiver *ret = mem->alloc_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) reply_cap (CAPTYPE_RECEIVER | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x03311992, "out of memory creating receiver") dpanic (0x03311992, "out of memory creating receiver")
reply_num (Kernel::ERR_OUT_OF_MEMORY) reply_num (Iris::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_MEMORY: case CAPTYPE_MEMORY:
kMemory *ret = mem->alloc_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) reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x13311992, "out of memory creating memory") dpanic (0x13311992, "out of memory creating memory")
reply_num (Kernel::ERR_OUT_OF_MEMORY) reply_num (Iris::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_THREAD: case CAPTYPE_THREAD:
kThread *ret = mem->alloc_thread (c->data[1].l) 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 (")") kdebug (")")
else: else:
dpanic (0x23311992, "out of memory creating thread") dpanic (0x23311992, "out of memory creating thread")
reply_num (Kernel::ERR_OUT_OF_MEMORY) reply_num (Iris::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_PAGE: case CAPTYPE_PAGE:
kPage *ret = mem->alloc_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) reply_cap (CAPTYPE_PAGE | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x33311992, "out of memory creating page") dpanic (0x33311992, "out of memory creating page")
reply_num (Kernel::ERR_OUT_OF_MEMORY) reply_num (Iris::ERR_OUT_OF_MEMORY)
return return
case CAPTYPE_CAPS: case CAPTYPE_CAPS:
kCaps *ret = mem->alloc_caps (c->data[1].l) 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) reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)ret, &ret->refs)
else: else:
dpanic (0x43311992, "out of memory creating caps") dpanic (0x43311992, "out of memory creating caps")
reply_num (Kernel::ERR_OUT_OF_MEMORY) reply_num (Iris::ERR_OUT_OF_MEMORY)
return return
default: default:
dpanic (0, "invalid create type") dpanic (0, "invalid create type")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
break 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: 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 return
switch (unsigned)c->arg->target & CAPTYPE_MASK: switch (unsigned)c->arg->target & CAPTYPE_MASK:
case CAPTYPE_RECEIVER: case CAPTYPE_RECEIVER:
@ -348,87 +353,88 @@ static void memory_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
panic (0x55228930, "invalid case") panic (0x55228930, "invalid case")
return return
break break
case Kernel::Memory::LIST & REQUEST_MASK: case Iris::Memory::LIST & REQUEST_MASK:
// TODO // TODO
break break
case Kernel::Memory::MAP & REQUEST_MASK: case Iris::Memory::MAP & REQUEST_MASK:
// FIXME: this should work for fake pages as well. // 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: 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") dpanic (0x22993341, "Trying to map non-page")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
kPage *page = (kPage *)c->arg->protected_data.l kPage *page = (kPage *)c->arg->protected_data.l
if page->address_space != mem: if page->address_space != mem:
dpanic (0x52993341, "Trying to map foreign page") dpanic (0x52993341, "Trying to map foreign page")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return 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") 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) mem->map (page, c->data[1].l & PAGE_MASK)
break break
case Kernel::Memory::MAPPING & REQUEST_MASK: case Iris::Memory::MAPPING & REQUEST_MASK:
kPage *page = mem->get_mapping (c->data[1].l) kPage *page = mem->get_mapping (c->data[1].l)
if !page: if !page:
reply_num (Kernel::ERR_UNMAPPED_READ) reply_num (Iris::ERR_UNMAPPED_READ)
return return
unsigned t = CAPTYPE_PAGE | CAP_MASTER unsigned t = CAPTYPE_PAGE | CAP_MASTER
if page->flags & Kernel::Page::MAPPED_READONLY: if page->flags & Iris::Page::MAPPED_READONLY:
t |= Kernel::Page::READONLY t |= Iris::Page::READONLY
reply_cap (t, (unsigned)page, &page->refs) reply_cap (t, (unsigned)page, &page->refs)
return return
case Kernel::Memory::GET_LIMIT & REQUEST_MASK: case Iris::Memory::GET_LIMIT & REQUEST_MASK:
reply_num (mem->limit) reply_num (mem->limit)
return return
case Kernel::Memory::SET_LIMIT & REQUEST_MASK: case Iris::Memory::SET_LIMIT & REQUEST_MASK:
mem->limit = c->data[1].l mem->limit = c->data[1].l
break break
default: default:
dpanic (0, "invalid memory operation") dpanic (0, "invalid memory operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return return
reply_num (0) 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 kThread *thread = (kThread *)protected_data.l
switch cmd: switch cmd:
case Kernel::Thread::GET_INFO & REQUEST_MASK: case Iris::Thread::GET_INFO & REQUEST_MASK:
switch c->data[0].h: switch c->data[0].h:
case Kernel::Thread::PC: case Iris::Thread::PC:
reply_num (thread->pc) reply_num (thread->pc)
return return
case Kernel::Thread::SP: case Iris::Thread::SP:
reply_num (thread->sp) reply_num (thread->sp)
return return
case Kernel::Thread::FLAGS: case Iris::Thread::FLAGS:
reply_num (thread->flags) reply_num (thread->flags)
return return
default: default:
reply_num (*kThread_arch_info (thread, c->data[0].h)) reply_num (*kThread_arch_info (thread, c->data[0].h))
return return
case Kernel::Thread::SET_INFO & REQUEST_MASK: case Iris::Thread::SET_INFO & REQUEST_MASK:
unsigned *value unsigned *value
switch c->data[0].h: switch c->data[0].h:
case Kernel::Thread::PC: case Iris::Thread::PC:
value = &thread->pc value = &thread->pc
break break
case Kernel::Thread::SP: case Iris::Thread::SP:
value = &thread->sp value = &thread->sp
break break
case Kernel::Thread::FLAGS: case Iris::Thread::FLAGS:
// It is not possible to set the PRIV flag (but it can be reset). // It is not possible to set the PRIV flag (but it can be reset).
if c->data[1].l & Kernel::Thread::PRIV: if c->data[1].l & Iris::Thread::PRIV:
c->data[1].h &= ~Kernel::Thread::PRIV c->data[1].h &= ~Iris::Thread::PRIV
value = &thread->flags 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) 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 & Iris::Thread::WAITING) != (*value & Iris::Thread::WAITING):
if v & Kernel::Thread::WAITING: if v & Iris::Thread::WAITING:
thread->wait () thread->wait ()
else else
thread->unwait () thread->unwait ()
if (v & Kernel::Thread::RUNNING) != (*value & Kernel::Thread::RUNNING): if (v & Iris::Thread::RUNNING) != (*value & Iris::Thread::RUNNING):
if v & Kernel::Thread::RUNNING: if v & Iris::Thread::RUNNING:
thread->run () thread->run ()
else: else:
thread->unrun () thread->unrun ()
@ -439,140 +445,155 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
if value: if value:
*value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h) *value = (*value & ~c->data[1].h) | (c->data[1].l & c->data[1].h)
break 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 >= 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) dbg_send (5, 3)
dpanic (c->data[1].l, "no argument given for USE_SLOT") dpanic (c->data[1].l, "no argument given for USE_SLOT")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
// FIXME: This doesn't allow using a fake caps. // 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): if (unsigned)c->arg->target != (CAPTYPE_CAPS | CAP_MASTER) && (unsigned)c->arg->target != (CAPTYPE_CAPS | Iris::Caps::USE):
dpanic (0, "argument for USE_SLOT is not a caps") dpanic ((unsigned)c->arg->target, "argument for USE_SLOT is not a caps")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
dbg_push (__LINE__)
unsigned slot = c->data[1].l unsigned slot = c->data[1].l
dbg_push (__LINE__)
kCaps *new_caps = (kCaps *)c->arg->protected_data.l kCaps *new_caps = (kCaps *)c->arg->protected_data.l
dbg_push (__LINE__)
if slot >= thread->slots: if slot >= thread->slots:
dpanic (0, "using invalid slot") dpanic (0, "using invalid slot")
return return
dbg_push (__LINE__)
thread->unset_slot (slot) thread->unset_slot (slot)
dbg_push (__LINE__)
thread->slot[slot].caps = new_caps thread->slot[slot].caps = new_caps
dbg_push (__LINE__)
if new_caps: if new_caps:
dbg_push (__LINE__)
thread->slot[slot].next = new_caps->first_slot thread->slot[slot].next = new_caps->first_slot
thread->slot[slot].caps = new_caps thread->slot[slot].caps = new_caps
new_caps->first_slot.thread = thread new_caps->first_slot.thread = thread
new_caps->first_slot.index = slot new_caps->first_slot.index = slot
dbg_push (__LINE__)
break break
case Kernel::Thread::GET_CAPS & REQUEST_MASK: case Iris::Thread::GET_CAPS & REQUEST_MASK:
unsigned slot = c->data[1].l unsigned slot = c->data[1].l
if slot < thread->slots: if slot < thread->slots:
reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->slot[slot].caps, &thread->slot[slot].caps->refs, thread->slots) reply_cap (CAPTYPE_CAPS | CAP_MASTER, (unsigned)thread->slot[slot].caps, &thread->slot[slot].caps->refs, thread->slots)
else: else:
reply_num (thread->slots) reply_num (thread->slots)
return return
case Kernel::Thread::SCHEDULE & REQUEST_MASK: case Iris::Thread::SCHEDULE & REQUEST_MASK:
do_schedule = true do_schedule = true
return return
default: default:
if !(thread->flags & Kernel::Thread::PRIV): if !(thread->flags & Iris::Thread::PRIV):
dpanic (0, "invalid thread operation") dpanic (0, "invalid thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return return
switch cmd: 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) 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 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) reply_cap (CAPTYPE_MEMORY | CAP_MASTER, (unsigned)&top_memory, &top_memory.refs)
return 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: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_THREAD:
dpanic (0, "not a thread argument for make priv") dpanic (0, "not a thread argument for make priv")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
((kThread *)c->arg->protected_data.l)->flags |= Kernel::Thread::PRIV ((kThread *)c->arg->protected_data.l)->flags |= Iris::Thread::PRIV
break 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: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_MEMORY:
panic (0x54365435, "non-memory argument to alloc_range") panic (0x54365435, "non-memory argument to alloc_range")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
kMemory *mem = (kMemory *)c->arg->protected_data.l kMemory *mem = (kMemory *)c->arg->protected_data.l
if !mem->use (c->data[1].l): if !mem->use (c->data[1].l):
dpanic (0x34365435, "out of memory during alloc_range") dpanic (0x34365435, "out of memory during alloc_range")
reply_num (Kernel::ERR_OUT_OF_MEMORY) reply_num (Iris::ERR_OUT_OF_MEMORY)
return return
unsigned data = phys_alloc (c->data[1].l) unsigned data = phys_alloc (c->data[1].l)
if !data: if !data:
mem->unuse (c->data[1].l) mem->unuse (c->data[1].l)
dpanic (0x14365435, "out of memory during alloc_range") dpanic (0x14365435, "out of memory during alloc_range")
reply_num (Kernel::ERR_OUT_OF_MEMORY) reply_num (Iris::ERR_OUT_OF_MEMORY)
return return
reply_num (data & ~0xc0000000) reply_num (data & ~0xc0000000)
return return
case Kernel::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK: case Iris::Thread::PRIV_ALLOC_PHYSICAL & REQUEST_MASK:
if !c->arg.valid (): if !c->arg.valid ():
panic (0x71342134, "no argument provided for alloc physical") panic (0x71342134, "no argument provided for alloc physical")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
panic (0x21342134, "no page provided for alloc physical") panic (0x21342134, "no page provided for alloc physical")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
kPage *page = (kPage *)c->arg->protected_data.l kPage *page = (kPage *)c->arg->protected_data.l
page->forget () page->forget ()
if !(c->data[1].l & 2): if !(c->data[1].l & 2):
if page->flags & Kernel::Page::PAYING: if page->flags & Iris::Page::PAYING:
page->flags &= ~Kernel::Page::PAYING page->flags &= ~Iris::Page::PAYING
page->address_space->unuse () page->address_space->unuse ()
else: else:
// This is for mapping allocated ranges. They are already paid for. Record that. // 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 () page->address_space->unuse ()
else: else:
page->flags |= Kernel::Page::PAYING page->flags |= Iris::Page::PAYING
page->frame = (c->data[1].l & PAGE_MASK) | 0x80000000 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): if !(c->data[1].l & 1):
page->flags |= Kernel::Page::UNCACHED page->flags |= Iris::Page::UNCACHED
if !(c->data[1].l & 2): if !(c->data[1].l & 2):
page->flags |= Kernel::Page::PHYSICAL page->flags |= Iris::Page::PHYSICAL
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
break 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: if !c->arg.valid () || ((unsigned)c->arg->target) & ~REQUEST_MASK != CAPTYPE_PAGE:
dpanic (0x99049380, "invalid page for physical address") dpanic (0x99049380, "invalid page for physical address")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
kPage *page = (kPage *)c->arg->protected_data.l kPage *page = (kPage *)c->arg->protected_data.l
reply_num (page->frame & ~0xc0000000) reply_num (page->frame & ~0xc0000000)
return return
case Kernel::Thread::PRIV_REBOOT & REQUEST_MASK: case Iris::Thread::PRIV_REBOOT & REQUEST_MASK:
arch_reboot () arch_reboot ()
case Kernel::Thread::PRIV_PANIC & REQUEST_MASK: case Iris::Thread::PRIV_PANIC & REQUEST_MASK:
if c->data[1].l == 0xdeaddead: if c->data[1].l == 0xdeaddead:
dbg_code.l = 1 dbg_code.l = 1
break break
panic (c->data[1].l, "panic requested by thread") panic (c->data[1].l, "panic requested by thread")
reply_num (~0) reply_num (~0)
return 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) dbg_send (c->data[1].l, c->data[1].h)
break break
default: default:
dpanic (0, "invalid priv thread operation") dpanic (0, "invalid priv thread operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return return
dbg_push (__LINE__)
reply_num (0) reply_num (0)
dbg_push (__LINE__)
return return
static void page_check_payment (kPage *page): static void page_check_payment (kPage *page):
kPage *p kPage *p
for p = page; p; p = p->share_prev: for p = page; p; p = p->share_prev:
if p->flags & Kernel::Page::PAYING: if p->flags & Iris::Page::PAYING:
return return
for p = page->share_next; p; p = p->share_next: for p = page->share_next; p; p = p->share_next:
if p->flags & Kernel::Page::PAYING: if p->flags & Iris::Page::PAYING:
return return
// No kPage is paying for this frame anymore. // No kPage is paying for this frame anymore.
raw_pfree (page->frame) raw_pfree (page->frame)
@ -581,46 +602,55 @@ static void page_check_payment (kPage *page):
p->frame = NULL p->frame = NULL
p->share_prev = NULL p->share_prev = NULL
p->share_next = 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) kPage_arch_update_mapping (p)
for p = page, next = p->share_next; p; p = next, next = p->share_next: for p = page, next = p->share_next; p; p = next, next = p->share_next:
p->frame = NULL p->frame = NULL
p->share_prev = NULL p->share_prev = NULL
p->share_next = 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) 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 kPage *page = (kPage *)protected_data.l
switch cmd & ~Kernel::Page::READONLY: switch cmd & ~Iris::Page::READONLY:
case Kernel::Page::SHARE & REQUEST_MASK: case Iris::Page::SHARE & REQUEST_MASK:
if !c->arg.valid (): if !c->arg.valid ():
// Cannot share without a target page. // Cannot share without a target page.
dpanic (0, "no target page for share") dpanic (0, "no target page for share")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE: if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_PAGE:
// FIXME: This makes it impossible to use a fake kPage capability. // FIXME: This makes it impossible to use a fake kPage capability.
dpanic (0, "share target is no page") dpanic (0, "share target is no page")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
kPage *t = (kPage *)c->arg->protected_data.l 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: if t != page:
t->forget () t->forget ()
if c->data[0].h & Kernel::Page::READONLY || cmd & Kernel::Page::READONLY: if c->data[0].h & Iris::Page::READONLY || cmd & Iris::Page::READONLY:
t->flags |= Kernel::Page::READONLY t->flags |= Iris::Page::READONLY
if !(page->flags & Kernel::Page::FRAME): if !(page->flags & Iris::Page::FRAME):
kdebug ("share problem: ") kdebug ("share problem: ")
kdebug_num (page->flags) kdebug_num (page->flags)
kdebug ("\n") kdebug ("\n")
dpanic (0, "sharing nothing results in lost page") dpanic (0, "sharing nothing results in lost page")
kPage_arch_update_mapping (t) kPage_arch_update_mapping (t)
break break
if c->data[0].h & Kernel::Page::COPY: if c->data[0].h & Iris::Page::COPY:
if ~t->flags & Kernel::Page::PAYING: if ~t->flags & Iris::Page::PAYING:
kPage_arch_update_mapping (t) kPage_arch_update_mapping (t)
break 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 unsigned *d = (unsigned *)page->frame
if t == page: if t == page:
kPage *other = page->share_next ? page->share_next : page->share_prev 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->share_prev = NULL
page_check_payment (other) page_check_payment (other)
else: else:
t->flags |= Kernel::Page::FRAME t->flags |= Iris::Page::FRAME
t->frame = raw_zalloc () t->frame = raw_zalloc ()
for unsigned i = 0; i < PAGE_SIZE; i += 4: for unsigned i = 0; i < PAGE_SIZE; i += 4:
((unsigned *)t->frame)[i >> 2] = d[i >> 2] ((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->frame = NULL
page->flags &= ~Kernel::Page::FRAME page->flags &= ~Iris::Page::FRAME
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
else: else:
if t != page: if t != page:
t->frame = page->frame t->frame = page->frame
t->flags |= Kernel::Page::FRAME t->flags |= Iris::Page::FRAME
page->frame = NULL page->frame = NULL
page->flags &= ~Kernel::Page::FRAME page->flags &= ~Iris::Page::FRAME
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
else: else:
dpanic (0, "sharing page with itself...") 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") dpanic (0, "sharing page with itself")
kPage_arch_update_mapping (t) kPage_arch_update_mapping (t)
break break
if c->data[0].h & Kernel::Page::FORGET: if c->data[0].h & Iris::Page::FORGET:
if ~page->flags & Kernel::Page::SHARED: if ~page->flags & Iris::Page::SHARED:
if t->flags & Kernel::Page::PAYING: if t->flags & Iris::Page::PAYING:
t->frame = page->frame t->frame = page->frame
t->flags |= Kernel::Page::FRAME t->flags |= Iris::Page::FRAME
else: else:
dpanic (0, "move page failed because target is not paying") dpanic (0, "move page failed because target is not paying")
page->frame = NULL page->frame = NULL
page->flags &= ~Kernel::Page::FRAME page->flags &= ~Iris::Page::FRAME
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
else: else:
t->share_prev = page->share_prev 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: if t->share_prev:
t->share_prev->share_next = t t->share_prev->share_next = t
t->frame = page->frame t->frame = page->frame
t->flags |= Kernel::Page::FRAME t->flags |= Iris::Page::FRAME
kPage_arch_update_mapping (t) kPage_arch_update_mapping (t)
break break
case Kernel::Page::SET_FLAGS & REQUEST_MASK: case Iris::Page::SET_FLAGS & REQUEST_MASK:
if cmd & Kernel::Page::READONLY: if cmd & Iris::Page::READONLY:
dpanic (0, "setting page flags denied") dpanic (0, "setting page flags denied")
reply_num (Kernel::ERR_WRITE_DENIED) reply_num (Iris::ERR_WRITE_DENIED)
return return
// Always refuse to set reserved flags. // 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. // Remember the old flags.
unsigned old = page->flags unsigned old = page->flags
// Compute the new flags. // Compute the new flags.
page->flags = (page->flags & ~c->data[1].h) | (c->data[1].l & c->data[1].h) 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 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. // Decrease the use counter in any case.
page->address_space->unuse () page->address_space->unuse ()
page_check_payment (page) page_check_payment (page)
// If we start paying, increase the use counter. // 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(): if !page->address_space->use():
dpanic (0, "cannot pay for frame") dpanic (0, "cannot pay for frame")
// If it doesn't work, refuse to set the flag, and refuse to allocate a 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. // However, if there already was a frame, keep it.
if old & Kernel::Page::FRAME: if old & Iris::Page::FRAME:
page->flags |= Kernel::Page::FRAME page->flags |= Iris::Page::FRAME
// If we want a frame, see if we can get it. // If we want a frame, see if we can get it.
if ~old & page->flags & Kernel::Page::FRAME: if ~old & page->flags & Iris::Page::FRAME:
if ~page->flags & Kernel::Page::PAYING: if ~page->flags & Iris::Page::PAYING:
dpanic (0, "cannot have frame without paying") dpanic (0, "cannot have frame without paying")
page->flags &= ~Kernel::Page::FRAME page->flags &= ~Iris::Page::FRAME
else: else:
page->frame = page->address_space->zalloc () page->frame = page->address_space->zalloc ()
kPage_arch_update_mapping (page) kPage_arch_update_mapping (page)
break break
default: default:
dpanic (0, "invalid page operation") dpanic (0, "invalid page operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return return
if page->flags > 0x7f: if page->flags > 0x7f:
dpanic (page->flags, "weird output from page operation") dpanic (page->flags, "weird output from page operation")
@ -755,12 +785,12 @@ static void print_cap (kCapRef cap, kCapRef self):
else: else:
kdebug (']') 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 kCaps *caps = (kCapsP)protected_data.l
switch cmd: switch cmd:
case Kernel::Caps::GET & REQUEST_MASK: case Iris::Caps::GET & REQUEST_MASK:
if c->data[1].l >= caps->size: if c->data[1].l >= caps->size:
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
kdebug_num ((unsigned)caps) kdebug_num ((unsigned)caps)
kdebug (" size: ") kdebug (" size: ")
kdebug_num (caps->size) kdebug_num (caps->size)
@ -782,10 +812,10 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
#endif #endif
reply_cap ((unsigned)ret->target, ret->protected_data, ((unsigned)ret->target & ~KERNEL_MASK) == 0 ? &((kObject *)ret->protected_data.l)->refs : &ret->target->capabilities) reply_cap ((unsigned)ret->target, ret->protected_data, ((unsigned)ret->target & ~KERNEL_MASK) == 0 ? &((kObject *)ret->protected_data.l)->refs : &ret->target->capabilities)
return return
case Kernel::Caps::GET_SIZE & REQUEST_MASK: case Iris::Caps::GET_SIZE & REQUEST_MASK:
reply_num (caps->size) reply_num (caps->size)
return return
case Kernel::Caps::SET & REQUEST_MASK: case Iris::Caps::SET & REQUEST_MASK:
if c->data[1].l >= caps->size: if c->data[1].l >= caps->size:
dpanic (0, "invalid index for set caps") dpanic (0, "invalid index for set caps")
return 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_num (caps->caps[c->data[1].l].protected_data.l)
//kdebug ("\n") //kdebug ("\n")
return return
case Kernel::Caps::TRUNCATE & REQUEST_MASK: case Iris::Caps::TRUNCATE & REQUEST_MASK:
dpanic (0, "truncate caps is not implemented yet.") dpanic (0, "truncate caps is not implemented yet.")
return return
case Kernel::Caps::PRINT & REQUEST_MASK: case Iris::Caps::PRINT & REQUEST_MASK:
if c->data[1].l >= caps->size: if c->data[1].l >= caps->size:
dpanic (0, "invalid caps for print") dpanic (0, "invalid caps for print")
return return
@ -839,12 +869,12 @@ static void caps_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
return return
default: default:
dpanic (cmd, "invalid caps operation") dpanic (cmd, "invalid caps operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return 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 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]) list->owner.clone (0, c->arg, c->copy[1])
return return
kListitem *item kListitem *item
@ -853,81 +883,81 @@ static void list_invoke (unsigned cmd, unsigned target, Kernel::Num protected_da
else: else:
if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM: if ((unsigned)c->arg->target & ~REQUEST_MASK) != CAPTYPE_LISTITEM:
dpanic (0, "invalid request for list: arg is no listitem") dpanic (0, "invalid request for list: arg is no listitem")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
item = (kListitem *)c->arg->protected_data.l item = (kListitem *)c->arg->protected_data.l
if item->list != list: if item->list != list:
dpanic (0, "item list is not equal to called object") dpanic (0, "item list is not equal to called object")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
switch cmd: switch cmd:
case Kernel::List::GET_NEXT & REQUEST_MASK: case Iris::List::GET_NEXT & REQUEST_MASK:
if !item: if !item:
item = list->first_listitem item = list->first_listitem
else: 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") dpanic (0, "trying to get next listitem with insufficient rights")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
item = item->next_item item = item->next_item
if !item: if !item:
reply_num (0) reply_num (0)
return return
reply_cap (CAPTYPE_LISTITEM | Kernel::Listitem::LIST, (unsigned)item, &item->refs) reply_cap (CAPTYPE_LISTITEM | Iris::Listitem::LIST, (unsigned)item, &item->refs)
return return
case Kernel::List::ADD_ITEM & REQUEST_MASK: case Iris::List::ADD_ITEM & REQUEST_MASK:
if !item: if !item:
dpanic (0, "invalid request: no listitem for List::ADD_ITEM") dpanic (0, "invalid request: no listitem for List::ADD_ITEM")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return 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") dpanic (0, "trying to add listitem with insufficient rights")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
((kListitem *)c->arg->protected_data.l)->add (list) ((kListitem *)c->arg->protected_data.l)->add (list)
break break
case Kernel::List::GET_INFO & REQUEST_MASK: case Iris::List::GET_INFO & REQUEST_MASK:
if !item: if !item:
dpanic (0, "no item for List::GET_INFO") 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 return
reply_num (item->info) reply_num (item->info)
return return
case Kernel::List::SET_INFO & REQUEST_MASK: case Iris::List::SET_INFO & REQUEST_MASK:
if !item: if !item:
dpanic (0, "no item for List::SET_INFO") dpanic (0, "no item for List::SET_INFO")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
item->info = c->data[1] item->info = c->data[1]
break break
case Kernel::List::GET_CAP & REQUEST_MASK: case Iris::List::GET_CAP & REQUEST_MASK:
if !item: if !item:
dpanic (0, "no item for List::GET_CAP") dpanic (0, "no item for List::GET_CAP")
reply_num (Kernel::ERR_INVALID_ARGUMENT) reply_num (Iris::ERR_INVALID_ARGUMENT)
return return
kCapability *cap = item->target.cap (0) 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) reply_cap ((unsigned)cap->target, cap->protected_data, ((unsigned)cap->target & ~KERNEL_MASK) == 0 ? &((kObject *)cap->target)->refs : &cap->target->capabilities)
return return
default: default:
dpanic (0, "invalid list operation") dpanic (0, "invalid list operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return return
reply_num (0) 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 kListitem *item = (kListitemP)protected_data.l
switch cmd: switch cmd:
case Kernel::Listitem::CLEAR & REQUEST_MASK: case Iris::Listitem::CLEAR & REQUEST_MASK:
// Disable linked capability. // Disable linked capability.
item->add (NULL) item->add (NULL)
break break
case Kernel::Listitem::SET_CAP & REQUEST_MASK: case Iris::Listitem::SET_CAP & REQUEST_MASK:
// Set linked capability. // Set linked capability.
item->target.clone (0, c->arg, c->copy[1]) item->target.clone (0, c->arg, c->copy[1])
break break
default: default:
dpanic (0, "invalid listitem operation") dpanic (0, "invalid listitem operation")
reply_num (Kernel::ERR_INVALID_OPERATION) reply_num (Iris::ERR_INVALID_OPERATION)
return return
reply_num (0) reply_num (0)
@ -936,18 +966,18 @@ static void kill_reply (kReceiver *r):
while cap.valid (): while cap.valid ():
kCapability *c = cap.deref () kCapability *c = cap.deref ()
cap = c->sibling_next cap = c->sibling_next
if (unsigned)c->target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY): if (unsigned)c->target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
c->invalidate () 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: // Kernel calling convention:
// data[0].l is the request. // data[0].l is the request.
// reply is the reply capability, or (for call capabilities) the target to call. // reply is the reply capability, or (for call capabilities) the target to call.
// other parameters' meanings depend on the operation. // 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. // This is a call capability. reply is the capability to call.
kReceiver *owner = (kReceiver *)protected_data.l 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: if must_wait:
old_current->wait () old_current->wait ()
if !reply_target: 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. // This is a user-implemented object. Create a real reply capability.
kReceiver *call_target = reply_target kReceiver *call_target = reply_target
c->reply = kCapRef (&reply_caps, 0) 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 c->copy[0] = true
call_target->send_message (reply_protected, c) call_target->send_message (reply_protected, c)
c->reply->invalidate () 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. // Reply capability: destroy all before invoke.
kReceiver *r = (kReceiver *)reply_protected.l kReceiver *r = (kReceiver *)reply_protected.l
kill_reply (r) kill_reply (r)
@ -981,7 +1011,7 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
return return
if must_wait: if must_wait:
old_current->wait () old_current->wait ()
if target == (CAPTYPE_RECEIVER | Kernel::Receiver::REPLY): if target == (CAPTYPE_RECEIVER | Iris::Receiver::REPLY):
// This is a reply capability. // This is a reply capability.
kReceiver *r = (kReceiver *)protected_data.l kReceiver *r = (kReceiver *)protected_data.l
kill_reply (r) kill_reply (r)
@ -1026,7 +1056,7 @@ static void kernel_invoke (unsigned target, Kernel::Num protected_data, kCapabil
return return
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: if dbg_code.l && old_current->id != 1:
log_message ("invoke", (unsigned)target, protected_data.l, c) log_message ("invoke", (unsigned)target, protected_data.l, c)
if (unsigned)target & ~KERNEL_MASK: 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 reply_protected = c->reply->protected_data
else: else:
reply_target = NULL reply_target = NULL
reply_protected.l = 0
kernel_invoke ((unsigned)target, protected_data, c) kernel_invoke ((unsigned)target, protected_data, c)

View File

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

View File

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

View File

@ -172,6 +172,8 @@ void phys_free (unsigned page, unsigned num):
kFreePages *p kFreePages *p
for p = first_free; p->next && (unsigned)p->next < page; p = p->next: for p = first_free; p->next && (unsigned)p->next < page; p = p->next:
// Do nothing. // Do nothing.
if p == p->next:
dpanic (0, "page is its own next")
// The new block should be inserted directly after p. // The new block should be inserted directly after p.
if (unsigned)p->next == page + size: if (unsigned)p->next == page + size:
// It can be merged with the block after it: do that. // 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.prev_mapped = NULL
page->arch.next_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[0] = data[0].l
thread->arch.a[1] = data[0].h thread->arch.a[1] = data[0].h
thread->arch.a[2] = data[1].l 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") //kdebug ("not mapping because there is no frame\n")
return 0 return 0
unsigned flags unsigned flags
if page->flags & Kernel::Page::UNCACHED: if page->flags & Iris::Page::UNCACHED:
flags = 0x10 | 0x2 flags = 0x10 | 0x2
else: else:
// 18 is write-back cache; 00 is write-through cache. // 18 is write-back cache; 00 is write-through cache.
flags = 0x18 | 0x2 flags = 0x18 | 0x2
if ~page->flags & Kernel::Page::MAPPED_READONLY: if ~page->flags & Iris::Page::MAPPED_READONLY:
flags |= 0x4 flags |= 0x4
return ((page->frame & ~0x80000000) >> 6) | flags return ((page->frame & ~0x80000000) >> 6) | flags

View File

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

View File

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

View File

@ -28,12 +28,12 @@ LDFLAGS = --omagic -Ttext $(load)
arch_iris_sources = mips/interrupts.cc mips/arch.cc arch_iris_sources = mips/interrupts.cc mips/arch.cc
boot_sources = mips/init.cc mips/nanonote/board.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 arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh devices.hh
boot_threads = init udc boot_threads = bootinit udc
programs = \#nanonote-gpio \#lcd display-emu bsquare display-emu2 ball \#buzzer metronome programs = init gpio lcd display-emu bsquare ball buzzer metronome elfrun
all: test 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 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 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/nanonote/threadlist.o: $(addsuffix .elf,$(boot_threads))
mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20" mips/boot.o: TARGET_FLAGS = -DMEMORY_SIZE="32 << 20"
mips/init.o: TARGET_FLAGS = -I/usr/include 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)): TARGET_FLAGS = -I.
$(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL $(addsuffix .elf,$(boot_threads)): LDFLAGS = -EL
$(addprefix fs/,$(addsuffix .elf,$(programs))): LDFLAGS = -EL $(addprefix fs/,$(addsuffix .elf,$(programs))): LDFLAGS = -EL
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): devices.hh keys.hh $(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 source/charset.data: source/charset
$< > $@ $< > $@

View File

@ -104,14 +104,14 @@
// Default lcd framebuffer mapping space. // Default lcd framebuffer mapping space.
#define LCD_FRAMEBUFFER_BASE ((unsigned *)0x00015000) #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> #include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping): 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. // false means not cachable; false means don't free when done.
p.alloc_physical (physical, false, false) p.alloc_physical (physical, false, false)
Kernel::my_memory.map (p, mapping) Iris::my_memory.map (p, mapping)
Kernel::free_cap (p) Iris::free_cap (p)
#define map_cpm() do { __map_io (CPM_PHYSICAL, CPM_BASE); } while (0) #define map_cpm() do { __map_io (CPM_PHYSICAL, CPM_BASE); } while (0)
#define map_intc() do { __map_io (INTC_PHYSICAL, INTC_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 // udelay implementation
void cdelay (unsigned cs): void cdelay (unsigned cs):
Kernel::my_receiver.set_alarm (cs + 1) Iris::my_receiver.set_alarm (cs + 1)
Kernel::Cap ().call () Iris::Cap ().call ()
#endif #endif

View File

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

View File

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

View File

@ -137,14 +137,14 @@
// Default lcd framebuffer mapping space. // Default lcd framebuffer mapping space.
#define LCD_FRAMEBUFFER_BASE ((unsigned short *)0x00021000) #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> #include <iris.hh>
static void __map_io (unsigned physical, unsigned mapping): 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. // false means not cachable; false means don't free when done.
p.alloc_physical (physical, false, false) p.alloc_physical (physical, false, false)
Kernel::my_memory.map (p, mapping) Iris::my_memory.map (p, mapping)
Kernel::free_cap (p) Iris::free_cap (p)
#define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0) #define map_harb() do { __map_io (HARB_PHYSICAL, HARB_BASE); } while (0)
#define map_emc() do { __map_io (EMC_PHYSICAL, EMC_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__ #ifndef __KERNEL__
static __inline__ void cdelay (unsigned ds): static __inline__ void cdelay (unsigned ds):
Kernel::my_receiver.set_alarm (ds * (HZ / 100)) Iris::my_receiver.set_alarm (ds * (HZ / 100))
Kernel::Cap ().call (~0) Iris::Cap ().call (~0)
#endif #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): static void print_addr (char const *t, unsigned addr, bool last = false):
kdebug (t) kdebug (t)
kdebug_num (addr) kdebug_num (addr)
#if 1 #if 0
unsigned de = addr >> 21 unsigned de = addr >> 21
unsigned te = (addr >> 12) & ((1 << 9) - 1) 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]: 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_num (((unsigned *)addr)[i])
kdebug ("\n") kdebug ("\n")
#else #else
kdebug (last ? '\n' : ';') kdebug (last ? "\n" : "; ")
#endif #endif
static void panic_message (unsigned n, const char *line, char const *name, char const *message): 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 (':')
kdebug_num (dbg_code.l) kdebug_num (dbg_code.l)
kdebug ('\n') kdebug ('\n')
kdebug ("debug buffer:") kdebug ("debug buffer (most recently pushed at end):")
unsigned b = dbg_buffer_head unsigned b = dbg_buffer_head
for unsigned i = 0; i < 16; ++i: for unsigned i = 0; i < 8; ++i:
kdebug ('\n') kdebug ('\n')
for unsigned j = 0; j < 2; ++j: for unsigned j = 0; j < 4; ++j:
kdebug (' ') kdebug (' ')
kdebug_num (dbg_buffer[b]) kdebug_num (dbg_buffer[b])
++b ++b

81
plan
View File

@ -42,3 +42,84 @@ te doen:
- start programma van filesystem - start programma van filesystem
- nand driver - nand driver
- filesystems met backing store - 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 thread->schedule_next->schedule_prev = thread->schedule_prev
void kThread::run (): void kThread::run ():
if flags & Kernel::Thread::RUNNING: if flags & Iris::Thread::RUNNING:
return return
flags |= Kernel::Thread::RUNNING flags |= Iris::Thread::RUNNING
if is_waiting (): if is_waiting ():
return return
run_thread (this) run_thread (this)
void kThread::unrun (): void kThread::unrun ():
if !(flags & Kernel::Thread::RUNNING): if !(flags & Iris::Thread::RUNNING):
return return
flags &= ~Kernel::Thread::RUNNING flags &= ~Iris::Thread::RUNNING
if is_waiting (): if is_waiting ():
return return
unrun_thread (this) unrun_thread (this)
void kThread::unwait (): void kThread::unwait ():
flags &= ~Kernel::Thread::WAITING flags &= ~Iris::Thread::WAITING
if flags & Kernel::Thread::RUNNING: if flags & Iris::Thread::RUNNING:
run_thread (this) run_thread (this)
static void alarm_tick (kReceiver *recv): static void alarm_tick (kReceiver *recv):
@ -73,9 +73,9 @@ static void alarm_tick (kReceiver *recv):
--recv->alarm_count --recv->alarm_count
void kThread::wait (): void kThread::wait ():
if flags & Kernel::Thread::RUNNING: if flags & Iris::Thread::RUNNING:
unrun_thread (this) unrun_thread (this)
flags |= Kernel::Thread::WAITING flags |= Iris::Thread::WAITING
// Try to receive a message from a kReceiver immediately. // Try to receive a message from a kReceiver immediately.
for kReceiver *r = receivers; r; r = r->next_owned: for kReceiver *r = receivers; r; r = r->next_owned:
if r->try_deliver (): if r->try_deliver ():

View File

@ -33,16 +33,16 @@ void ball (int x, int y, unsigned colour):
continue continue
framebuffer[ty * 320 + tx] = (colour) framebuffer[ty * 320 + tx] = (colour)
Kernel::Num start (): Iris::Num start ():
Kernel::my_parent.init_done () Iris::my_parent.init_done ()
int colour = 0x3f30ff int colour = 0x3f30ff
framebuffer = (unsigned *)0x15000 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 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: while true:
display.set_eof_cb (eof) display.set_eof_cb (eof)
Kernel::wait () Iris::wait ()
ball (x, y, 0) ball (x, y, 0)
x += dx x += dx
y += dy y += dy

View File

@ -32,16 +32,16 @@ void square (int x, int y, bool print):
continue continue
framebuffer[ty * 320 + tx] = (print ? colour : 0) framebuffer[ty * 320 + tx] = (print ? colour : 0)
Kernel::Num start (): Iris::Num start ():
Kernel::my_parent.init_done () Iris::my_parent.init_done ()
colour = 0xffff00 colour = 0xffff00
framebuffer = (unsigned *)0x15000 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 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: while true:
display.set_eof_cb (eof) display.set_eof_cb (eof)
Kernel::wait () Iris::wait ()
square (x, y, false) square (x, y, false)
x += dx x += dx
y += dy y += dy

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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