1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-16 19:41:51 +02:00
iris/source/init.ccp
2010-10-07 09:52:04 +02:00

625 lines
18 KiB
COBOL

#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 },
{ "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 },
{ 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::poweroff ()
continue
kdebug ("sysreq event: powering device off 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::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::panic (0, "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")