mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
new directory organization
This commit is contained in:
380
userspace/boot/bootinit.ccp
Normal file
380
userspace/boot/bootinit.ccp
Normal file
@@ -0,0 +1,380 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/bootinit.ccp: Bootstrapping code.
|
||||
// Copyright 2009-2010 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"
|
||||
|
||||
// These numbers are only used for elfrun.
|
||||
#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::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 unsigned *bss_mapping
|
||||
static Iris::Page bss_page
|
||||
|
||||
// Get the initial block device and filesystem.
|
||||
static Iris::Directory receive_devices ():
|
||||
Iris::Block device
|
||||
bool have_device = false
|
||||
Iris::Cap reply[2]
|
||||
bool have_reply[2]
|
||||
have_reply[0] = false
|
||||
have_reply[1] = false
|
||||
unsigned next = 2
|
||||
while true:
|
||||
Iris::wait ()
|
||||
kdebug_num (Iris::recv.protected_data.l, 1)
|
||||
kdebug (": ")
|
||||
if Iris::recv.protected_data.l == 0:
|
||||
kdebug ("sd detect event device request\n")
|
||||
// SD detection event device request.
|
||||
// Ignore all; that will result in the driver thinking there is a card.
|
||||
Iris::recv.reply.invoke ()
|
||||
continue
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Parent::PROVIDE_CAPABILITY:
|
||||
switch Iris::recv.data[1].l:
|
||||
case Iris::Block::ID:
|
||||
case Iris::WBlock::ID:
|
||||
// Ignore other partitions.
|
||||
Iris::Cap r = Iris::get_reply ()
|
||||
if Iris::recv.data[0].h != 0:
|
||||
kdebug ("ignoring non-0 partition\n")
|
||||
else:
|
||||
if have_device:
|
||||
Iris::panic (0, "double device provided")
|
||||
device = Iris::get_arg ()
|
||||
if have_reply[next - 2]:
|
||||
kdebug ("block provided (used)\n")
|
||||
reply[next++ - 2].invoke (0, 0, device.copy ())
|
||||
Iris::free_cap (device)
|
||||
else:
|
||||
kdebug ("block provided (stored)\n")
|
||||
have_device = true
|
||||
r.invoke ()
|
||||
Iris::free_cap (r)
|
||||
break
|
||||
case Iris::Directory::ID:
|
||||
kdebug ("directory provided\n")
|
||||
Iris::Directory ret = Iris::get_arg ()
|
||||
Iris::recv.reply.invoke ()
|
||||
return ret
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[1].l, "invalid capability type provided by boot thread")
|
||||
break
|
||||
case Iris::Parent::GET_CAPABILITY:
|
||||
if Iris::recv.data[1].l == Iris::Event::ID:
|
||||
kdebug ("event requested\n")
|
||||
// Detection of sd card.
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Cap event = Iris::my_receiver.create_capability (0)
|
||||
reply.invoke (0, 0, event.copy ())
|
||||
Iris::free_cap (event)
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
if Iris::recv.data[1].l != Iris::Block::ID && Iris::recv.data[1].l != Iris::WBlock::ID:
|
||||
Iris::panic (Iris::recv.data[1].l, "invalid capability type requested by boot thread")
|
||||
if next == Iris::recv.protected_data.l && have_device:
|
||||
kdebug ("block requested (sent)\n")
|
||||
Iris::recv.reply.invoke (0, 0, device.copy ())
|
||||
Iris::free_cap (device)
|
||||
have_device = false
|
||||
++next
|
||||
else:
|
||||
kdebug ("block requested (not sent)\n")
|
||||
reply[Iris::recv.protected_data.l - 2] = Iris::get_reply ()
|
||||
have_reply[Iris::recv.protected_data.l - 2] = true
|
||||
break
|
||||
case Iris::Parent::INIT_DONE:
|
||||
kdebug ("init done\n")
|
||||
// Ignore.
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Parent::EXIT:
|
||||
Iris::panic (Iris::recv.protected_data.l, "boot thread exits")
|
||||
default:
|
||||
Iris::panic (Iris::recv.protected_data.l, "invalid boot request")
|
||||
|
||||
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::Block 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::Block ret = root.get_file_ro (i)
|
||||
return ret
|
||||
Iris::panic (0, "bootfile not found")
|
||||
|
||||
static void run (Iris::Block 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)
|
||||
data.get_block (p << PAGE_BITS, PAGE_SIZE, 0, 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)
|
||||
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.
|
||||
page.share (bss_page, 0)
|
||||
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
|
||||
bss_mapping[(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::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)
|
||||
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 ()
|
||||
bss_mapping = (unsigned *)alloc_space (1)
|
||||
bss_page = Iris::my_memory.create_page ()
|
||||
Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
|
||||
|
||||
Iris::Memory top_memory = Iris::get_top_memory ()
|
||||
Iris::Directory root = receive_devices ()
|
||||
root.lock_ro ()
|
||||
Iris::Block run_block = find (root, ELFRUN_NAME)
|
||||
Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
|
||||
run (run_block, top_memory, parent_cap)
|
||||
Iris::wait ()
|
||||
if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY || Iris::recv.data[1].l != Iris::Elfrun::ID:
|
||||
Iris::panic (0, "elfrun doesn't provide correct capability")
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Elfrun elfrun = 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::Block init_block = find (root, INIT_NAME)
|
||||
Iris::Caps init_caps = elfrun.run_block (top_memory.copy (), init_block.copy (), parent_cap.copy (), 8, 63)
|
||||
|
||||
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_CAPABILITY:
|
||||
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.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 ()
|
||||
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")
|
||||
166
userspace/boot/crt0.ccp
Normal file
166
userspace/boot/crt0.ccp
Normal file
@@ -0,0 +1,166 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/init.S: Startup code for initial Threads.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "iris.hh"
|
||||
#include "devices.hh"
|
||||
|
||||
// For some unknown reason, gcc needs this to be defined.
|
||||
unsigned __gxx_personality_v0
|
||||
|
||||
struct list:
|
||||
list *prev, *next
|
||||
|
||||
static unsigned __slots, __caps
|
||||
static list *__slot_admin, *__cap_admin
|
||||
static list *__first_free_slot, *__first_free_cap
|
||||
|
||||
namespace Iris:
|
||||
bool enable_debug
|
||||
Caps my_caps
|
||||
Receiver my_receiver
|
||||
Thread my_thread
|
||||
Memory my_memory
|
||||
Cap my_call
|
||||
Parent my_parent
|
||||
__recv_data_t recv
|
||||
|
||||
void print_caps ():
|
||||
// __caps cannot be larger than 63.
|
||||
bool used[63]
|
||||
for unsigned i = 0; i < __caps; ++i:
|
||||
used[i] = true
|
||||
unsigned num = 0
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
if used[i - __cap_admin] == false:
|
||||
panic (0, "inconsistent userspace cap db")
|
||||
used[i - __cap_admin] = false
|
||||
++num
|
||||
kdebug_num (num, 2)
|
||||
kdebug (":")
|
||||
for unsigned i = 0; i < __caps; ++i:
|
||||
kdebug_char (used[i] ? '#' : '.')
|
||||
kdebug_char ('\n')
|
||||
|
||||
void free_slot (unsigned slot):
|
||||
//kdebug ("free slot\n")
|
||||
for list *i = __first_free_slot; i; i = i->next:
|
||||
if slot == i - __slot_admin:
|
||||
panic (0, "double free of userspace slot")
|
||||
__slot_admin[slot].prev = NULL
|
||||
__slot_admin[slot].next = __first_free_slot
|
||||
if __slot_admin[slot].next:
|
||||
__slot_admin[slot].next->prev = &__slot_admin[slot]
|
||||
__first_free_slot = &__slot_admin[slot]
|
||||
|
||||
void free_cap (Cap cap):
|
||||
if enable_debug:
|
||||
kdebug ("free cap ")
|
||||
kdebug_num (cap.idx (), 2)
|
||||
kdebug ("\n")
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
if cap.idx () == i - __cap_admin:
|
||||
panic (0, "double free of userspace cap")
|
||||
if cap.slot () != 0:
|
||||
kdebug ("trying to free capability from non-0 slot\n")
|
||||
Iris::panic (0)
|
||||
return
|
||||
list *l = &__cap_admin[cap.idx ()]
|
||||
l->prev = NULL
|
||||
l->next = __first_free_cap
|
||||
if l->next:
|
||||
l->next->prev = l
|
||||
__first_free_cap = l
|
||||
|
||||
unsigned alloc_slot ():
|
||||
//kdebug ("alloc slot\n")
|
||||
if !__first_free_slot:
|
||||
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
|
||||
kdebug ("out of slots!\n")
|
||||
Iris::panic (0)
|
||||
return ~0
|
||||
list *ret = __first_free_slot
|
||||
__first_free_slot = ret->next
|
||||
if ret->next:
|
||||
ret->next->prev = NULL
|
||||
return ret - __slot_admin
|
||||
|
||||
Cap alloc_cap ():
|
||||
if !__first_free_cap:
|
||||
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
|
||||
kdebug ("out of capabilities!\n")
|
||||
Iris::panic (0)
|
||||
return Cap (0, CAP_NONE)
|
||||
list *ret = __first_free_cap
|
||||
__first_free_cap = ret->next
|
||||
if ret->next:
|
||||
ret->next->prev = NULL
|
||||
if enable_debug:
|
||||
kdebug ("alloc cap ")
|
||||
kdebug_num (ret - __cap_admin, 2)
|
||||
kdebug ("\n")
|
||||
return Cap (0, ret - __cap_admin)
|
||||
|
||||
extern "C":
|
||||
void run__main (unsigned slots, unsigned caps, list *slot_admin, list *cap_admin):
|
||||
Iris::enable_debug = false
|
||||
__slots = slots
|
||||
__caps = caps
|
||||
__slot_admin = slot_admin
|
||||
__cap_admin = cap_admin
|
||||
__first_free_slot = NULL
|
||||
for unsigned i = 1; i < __slots; ++i:
|
||||
Iris::free_slot (i)
|
||||
__first_free_cap = NULL
|
||||
for unsigned i = 6; i < __caps; ++i:
|
||||
Iris::free_cap (Iris::Cap (0, i))
|
||||
Iris::my_caps = Iris::Cap (0, __caps_num)
|
||||
Iris::my_receiver = Iris::Cap (0, __receiver_num)
|
||||
Iris::my_thread = Iris::Cap (0, __thread_num)
|
||||
Iris::my_memory = Iris::Cap (0, __memory_num)
|
||||
Iris::my_call = Iris::Cap (0, __call_num)
|
||||
Iris::my_parent = Iris::Cap (0, __parent_num)
|
||||
Iris::recv.reply = Iris::alloc_cap ()
|
||||
Iris::recv.arg = Iris::alloc_cap ()
|
||||
Iris::Num ret = start ()
|
||||
Iris::my_parent.exit (ret)
|
||||
Iris::my_memory.destroy (Iris::my_thread)
|
||||
// The program no longer exists. If it somehow does, die again.
|
||||
while true:
|
||||
Iris::panic (0, "this program should no longer exist.")
|
||||
*(volatile unsigned *)~0
|
||||
|
||||
__asm__ volatile ("\t.text\n"
|
||||
"\t.globl __start\n"
|
||||
"\t.set noreorder\n"
|
||||
"__start:\n"
|
||||
"\tbal 1f\n"
|
||||
"__hack_label:\n"
|
||||
"\tnop\n"
|
||||
"\t.word _gp\n"
|
||||
"1:\n"
|
||||
"\tlw $gp, 0($ra)\n"
|
||||
"\tsll $v0, $a0, 3\n"
|
||||
"\tsll $v1, $a1, 3\n"
|
||||
"\tsubu $sp, $sp, $v0\n"
|
||||
"\tmove $a2, $sp\n"
|
||||
"\tsubu $sp, $sp, $v1\n"
|
||||
"\tmove $a3, $sp\n"
|
||||
"\tla $t9, run__main\n"
|
||||
"\tjr $t9\n"
|
||||
"\tnop\n"
|
||||
"\t.set reorder")
|
||||
628
userspace/boot/init.ccp
Normal file
628
userspace/boot/init.ccp
Normal file
@@ -0,0 +1,628 @@
|
||||
#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 INIT_CONFIG "init.config"
|
||||
#define INIT_CONFIG_SIZE 12
|
||||
|
||||
#define NUM_SLOTS 8
|
||||
#define NUM_CAPS 32
|
||||
|
||||
enum Captype:
|
||||
SYSREQ
|
||||
PROGRAM
|
||||
FILE
|
||||
|
||||
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::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 Devbase:
|
||||
char *name
|
||||
unsigned name_len
|
||||
unsigned type
|
||||
Program *client
|
||||
Iris::Cap cap
|
||||
|
||||
struct Serverdevice : public Devbase:
|
||||
unsigned index
|
||||
Program *server
|
||||
|
||||
struct Clientdevice:
|
||||
unsigned type, index
|
||||
Devbase *dev
|
||||
|
||||
static Iris::Memory top_memory
|
||||
static Iris::Directory root
|
||||
static Iris::Elfrun elfrun
|
||||
|
||||
struct Program:
|
||||
char *name
|
||||
unsigned name_len
|
||||
unsigned size
|
||||
Iris::Caps pages
|
||||
Iris::Memory memory
|
||||
Iris::Thread thread
|
||||
List <Serverdevice> server_devices
|
||||
List <Clientdevice> client_devices
|
||||
unsigned num_waiting
|
||||
bool priv
|
||||
void run ():
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (Iris::Num (PROGRAM, (unsigned)this))
|
||||
if priv:
|
||||
kdebug ("priv ")
|
||||
kdebug ("running ")
|
||||
for unsigned i = 0; i < name_len; ++i:
|
||||
kdebug_char (name[i])
|
||||
kdebug ("\n")
|
||||
Iris::Caps caps = elfrun.run_caps (top_memory, pages, cap.copy (), (size + PAGE_SIZE - 1) >> PAGE_BITS)
|
||||
Iris::free_cap (cap)
|
||||
thread = caps.get (__thread_num)
|
||||
memory = caps.get (__memory_num)
|
||||
Iris::free_cap (caps)
|
||||
if priv:
|
||||
thread.make_priv ()
|
||||
thread.run ()
|
||||
|
||||
struct File : public Devbase:
|
||||
unsigned size
|
||||
Iris::Caps pages
|
||||
|
||||
static List <Program> programs
|
||||
static List <File> files
|
||||
static Serverdevice *sysreq
|
||||
|
||||
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::Block 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_block (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]
|
||||
//kdebug ("name: ")
|
||||
for unsigned i = 0; i < name_len; ++i:
|
||||
name[i] = line[i]
|
||||
//kdebug_char (name[i])
|
||||
//kdebug_char ('\n')
|
||||
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 },
|
||||
{ "Block", 5, Iris::Block::ID },
|
||||
{ "WBlock", 6, Iris::WBlock::ID },
|
||||
{ "Boot", 4, Iris::Boot::ID },
|
||||
{ "Device", 6, Iris::Device::ID },
|
||||
{ "Event", 5, Iris::Event::ID },
|
||||
{ "Parent", 6, Iris::Parent::ID },
|
||||
{ "Keyboard", 8, Iris::Keyboard::ID },
|
||||
{ "Buzzer", 6, Iris::Buzzer::ID },
|
||||
{ "Display", 7, Iris::Display::ID },
|
||||
{ "Font", 4, Iris::Font::ID },
|
||||
{ "Setting", 7, Iris::Setting::ID },
|
||||
{ "Directory", 9, Iris::Directory::ID },
|
||||
{ "WDirectory", 10, Iris::WDirectory::ID },
|
||||
{ "Stream", 6, Iris::Stream::ID },
|
||||
{ "UI", 2, Iris::UI::ID },
|
||||
{ "RTC", 3, Iris::RTC::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 bool find_cap (char *&line, unsigned &len, Program **server, Devbase *&dev, bool &present):
|
||||
char *n
|
||||
unsigned l
|
||||
if !get_name (line, len, n, l):
|
||||
Iris::panic (0, "no capability name found in init.config")
|
||||
for List <Program>::Item *p = programs.begin (); p; p = p->next:
|
||||
List <Serverdevice>::Item *d
|
||||
for d = (*p)->server_devices.begin (); d; d = d->next:
|
||||
if string_match (n, l, (*d)->name, (*d)->name_len):
|
||||
if server:
|
||||
*server = &**p
|
||||
dev = &**d
|
||||
present = false
|
||||
return true
|
||||
if server:
|
||||
return false
|
||||
for List <File>::Item *f = files.begin (); f; f = f->next:
|
||||
if string_match (n, l, (*f)->name, (*f)->name_len):
|
||||
dev = &**f
|
||||
present = true
|
||||
return true
|
||||
return false
|
||||
|
||||
static void parse_line (char *&line, unsigned maxlen)
|
||||
static void include (char const *name, unsigned name_len):
|
||||
unsigned size
|
||||
Iris::Caps caps = load (name, name_len, size)
|
||||
unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
|
||||
char *config = alloc_space (pages)
|
||||
unsigned pages_slot = caps.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
|
||||
while ptr - config < size:
|
||||
parse_line (ptr, config + size - ptr)
|
||||
for unsigned p = 0; p < pages; ++p:
|
||||
Iris::my_memory.destroy (Iris::Cap (pages_slot, p))
|
||||
Iris::my_memory.destroy (caps)
|
||||
Iris::free_cap (caps)
|
||||
Iris::free_slot (pages_slot)
|
||||
|
||||
static char *get_filename (char *&line, unsigned &maxlen, unsigned &len):
|
||||
char q = *line++
|
||||
--maxlen
|
||||
len = 0
|
||||
while maxlen && *line != q:
|
||||
++line
|
||||
--maxlen
|
||||
++len
|
||||
if !maxlen:
|
||||
Iris::panic (0, "no closing quote in init.config")
|
||||
return line - len
|
||||
|
||||
static void do_load (char *&line, unsigned &maxlen, bool priv):
|
||||
Program *p = &**programs.insert ()
|
||||
if !get_name (line, maxlen, p->name, p->name_len) || !match (line, maxlen, "=") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (load)")
|
||||
unsigned l
|
||||
char *n = get_filename (line, maxlen, l)
|
||||
p->pages = load (n, l, p->size)
|
||||
p->priv = priv
|
||||
p->num_waiting = 0
|
||||
++line
|
||||
--maxlen
|
||||
|
||||
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, "program"):
|
||||
// program <name> = "<filename>"
|
||||
do_load (start, maxlen, false)
|
||||
else if match (start, maxlen, "driver"):
|
||||
// driver <name> = "<filename>"
|
||||
do_load (start, maxlen, true)
|
||||
else if match (start, maxlen, "file"):
|
||||
// file <name> = "<filename>"
|
||||
File *f = &**files.insert ()
|
||||
f->type = Iris::Block::ID
|
||||
if !get_name (start, maxlen, f->name, f->name_len) || !match (start, maxlen, "=") || !maxlen:
|
||||
Iris::panic (0, "syntax error in init.config (file name)")
|
||||
unsigned l
|
||||
char *n = get_filename (start, maxlen, l)
|
||||
f->pages = load (n, l, f->size)
|
||||
f->cap = Iris::my_receiver.create_capability (Iris::Num (FILE, (unsigned)f))
|
||||
++line
|
||||
--maxlen
|
||||
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 <Serverdevice>::Item *dev = (*p)->server_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)")
|
||||
(*dev)->server = &**p
|
||||
(*dev)->client = NULL
|
||||
(*dev)->cap = Iris::Cap ()
|
||||
else if match (start, maxlen, "sysreq"):
|
||||
Program *server
|
||||
if sysreq:
|
||||
Iris::panic (0, "double registration of sysreq")
|
||||
bool dummy
|
||||
if !find_cap (start, maxlen, &server, *(Devbase **)&sysreq, dummy):
|
||||
Iris::panic (0, "capability not found for sysreq")
|
||||
if sysreq->type != Iris::Keyboard::ID:
|
||||
kdebug ("capability for sysreq is not a keyboard\n")
|
||||
else if match (start, maxlen, "give"):
|
||||
// give <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 (give)")
|
||||
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 give")
|
||||
List <Clientdevice>::Item *d = (*p)->client_devices.insert ()
|
||||
find_type (start, maxlen, (*d)->type, (*d)->index)
|
||||
if !match (start, maxlen, "="):
|
||||
Iris::panic (1, "syntax error in init.config (give)")
|
||||
bool present
|
||||
if !find_cap (start, maxlen, NULL, (*d)->dev, present):
|
||||
Iris::panic (0, "capability not found for give")
|
||||
if (*d)->dev->type != (*d)->type:
|
||||
kdebug ("capability type mismatch for give\n")
|
||||
if (*d)->dev->client:
|
||||
Iris::panic (0, "capability given out twice")
|
||||
(*d)->dev->client = &**p
|
||||
if !present:
|
||||
++(*p)->num_waiting
|
||||
//kdebug ("registered give device: ")
|
||||
//kdebug_num ((*d)->type)
|
||||
//kdebug ("\n")
|
||||
else if match (start, maxlen, "include"):
|
||||
unsigned name_len
|
||||
char *name = get_filename (line, maxlen, name_len)
|
||||
include (name, name_len)
|
||||
else:
|
||||
for unsigned i = 0; i < maxlen; ++i:
|
||||
kdebug_char (start[i])
|
||||
kdebug_char ('\n')
|
||||
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 ()
|
||||
files.init ()
|
||||
root = Iris::my_parent.get_capability <Iris::Directory> ()
|
||||
elfrun = Iris::my_parent.get_capability <Iris::Elfrun> ()
|
||||
sysreq = NULL
|
||||
top_memory = Iris::get_top_memory ()
|
||||
include (INIT_CONFIG, INIT_CONFIG_SIZE)
|
||||
kdebug ("killing boot threads\n")
|
||||
Iris::my_parent.init_done ()
|
||||
for List <Program>::Item *p = programs.begin (); p; p = p->next:
|
||||
if !(*p)->num_waiting:
|
||||
(*p)->run ()
|
||||
if !sysreq:
|
||||
Iris::panic (0, "sysreq not registered")
|
||||
if sysreq->client:
|
||||
Iris::panic (0, "sysreq set to reserved capability")
|
||||
kdebug ("waiting for events.\n")
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case SYSREQ:
|
||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||
Iris::reboot ()
|
||||
continue
|
||||
kdebug ("sysreq event: rebooting device at release\n")
|
||||
continue
|
||||
case FILE:
|
||||
File *file = (File *)Iris::recv.protected_data.h
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Block::GET_SIZE:
|
||||
Iris::recv.reply.invoke (file->size)
|
||||
break
|
||||
case Iris::Block::GET_ALIGN_BITS:
|
||||
Iris::recv.reply.invoke (PAGE_BITS)
|
||||
break
|
||||
case Iris::Block::GET_BLOCK:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
Iris::Page target = Iris::get_arg ()
|
||||
Iris::Page source = file->pages.get (Iris::recv.data[1].l >> PAGE_BITS)
|
||||
source.share (target, Iris::Page::READONLY)
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
Iris::free_cap (source)
|
||||
Iris::free_cap (target)
|
||||
break
|
||||
default:
|
||||
Iris::panic (Iris::recv.data[0].l, "unknown request for init string")
|
||||
break
|
||||
case PROGRAM:
|
||||
Program *caller = (Program *)Iris::recv.protected_data.h
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Parent::GET_CAPABILITY:
|
||||
unsigned index = Iris::recv.data[0].h
|
||||
unsigned type = Iris::recv.data[1].l
|
||||
if Iris::recv.data[1].h:
|
||||
Iris::panic (Iris::recv.data[1].h, "high device requested")
|
||||
//kdebug ("requested device ")
|
||||
//kdebug_num (type)
|
||||
//kdebug (":")
|
||||
//kdebug_num (index)
|
||||
//kdebug ("\n")
|
||||
List <Clientdevice>::Item *d
|
||||
for d = caller->client_devices.begin (); d; d = d->next:
|
||||
//kdebug ("checking ")
|
||||
//kdebug_num ((*d)->type)
|
||||
//kdebug (":")
|
||||
//kdebug_num ((*d)->index)
|
||||
//kdebug ("\n")
|
||||
if (*d)->type == type && (*d)->index == index:
|
||||
break
|
||||
if !d:
|
||||
Iris::debug ("requested %x by %s\n", type, caller->name)
|
||||
Iris::panic (type, "unregistered device requested")
|
||||
Iris::recv.reply.invoke (0, 0, (*d)->dev->cap)
|
||||
//kdebug ("given device ")
|
||||
//kdebug_num (type)
|
||||
//kdebug (":")
|
||||
//kdebug_num (index)
|
||||
//kdebug ("\n")
|
||||
break
|
||||
case Iris::Parent::PROVIDE_CAPABILITY:
|
||||
if Iris::recv.data[1].h != 0:
|
||||
kdebug ("init: too high device provided\n")
|
||||
continue
|
||||
unsigned type = Iris::recv.data[1].l
|
||||
unsigned index = Iris::recv.data[0].h
|
||||
List <Serverdevice>::Item *d
|
||||
for d = caller->server_devices.begin (); d; d = d->next:
|
||||
if (*d)->type == type && (*d)->index == index:
|
||||
break
|
||||
if !d:
|
||||
Iris::debug ("caller: %s\n", caller->name)
|
||||
Iris::panic (type, "unregistered device provided")
|
||||
(*d)->cap = Iris::get_arg ()
|
||||
Iris::recv.reply.invoke ()
|
||||
if (*d)->client:
|
||||
if !--(*d)->client->num_waiting:
|
||||
(*d)->client->run ()
|
||||
//kdebug ("provided ")
|
||||
//kdebug_num ((*d)->type)
|
||||
//kdebug (":")
|
||||
//kdebug_num ((*d)->index)
|
||||
//kdebug ("\n")
|
||||
break
|
||||
case Iris::Parent::INIT_DONE:
|
||||
//kdebug ("init done\n")
|
||||
Iris::recv.reply.invoke ()
|
||||
if caller == sysreq->server:
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ)
|
||||
Iris::Keyboard (sysreq->cap).set_cb (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
kdebug ("registered sysreq\n")
|
||||
break
|
||||
case Iris::Parent::EXIT:
|
||||
kdebug ("child ")
|
||||
for unsigned i = 0; i < caller->name_len; ++i:
|
||||
kdebug_char (caller->name[i])
|
||||
kdebug (" exits with code ")
|
||||
kdebug_num (Iris::recv.data[1].h)
|
||||
kdebug (":")
|
||||
kdebug_num (Iris::recv.data[1].l)
|
||||
kdebug ("\n")
|
||||
top_memory.destroy (caller->memory)
|
||||
break
|
||||
default:
|
||||
// TODO.
|
||||
kdebug ("child request: ")
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug (" from ")
|
||||
for unsigned i = 0; i < caller->name_len; ++i:
|
||||
kdebug_char (caller->name[i])
|
||||
kdebug ("\n")
|
||||
32
userspace/boot/mkthreadlist
Executable file
32
userspace/boot/mkthreadlist
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
cat << EOF
|
||||
.globl init_start
|
||||
.globl thread_start
|
||||
.set noreorder
|
||||
.balign 0x1000
|
||||
EOF
|
||||
|
||||
for i in "$@" ; do
|
||||
cat << EOF
|
||||
${i##*/}:
|
||||
.incbin "fs/${i##*/}.elf"
|
||||
.balign 0x1000
|
||||
EOF
|
||||
done
|
||||
|
||||
cat << EOF
|
||||
end_threads:
|
||||
init_start:
|
||||
thread_start:
|
||||
EOF
|
||||
|
||||
for i in "$@" ; do
|
||||
cat << EOF
|
||||
.word ${i##*/}
|
||||
EOF
|
||||
done
|
||||
|
||||
cat << EOF
|
||||
.word end_threads
|
||||
.word 0
|
||||
EOF
|
||||
Reference in New Issue
Block a user