#pypp 0 // Iris: micro-kernel for a capability-based operating system. // bootstrap/init.ccp: Bootstrapping code. // Copyright 2009 Bas Wijnen // // 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 . #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 // 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 devices Iris::Cap waiter static Iris::Memory top_memory static Iris::Directory root static Iris::Elfrun elfrun static List programs static Iris::Cap sysreq static unsigned to_receive, progs 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 do_run (char *&start, unsigned &maxlen, bool priv): char *n unsigned l if !get_name (start, maxlen, n, l): Iris::panic (0, "syntax error in init.config (driver)") List ::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) if priv: kdebug ("priv ") 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) if priv: (*p)->thread.make_priv () (*p)->thread.run () // TODO: pass arguments. start += maxlen maxlen = 0 static void parse_line (char *&line, unsigned maxlen) static void include_caps (Iris::Caps caps, unsigned 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 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) p->waiter = Iris::Cap () ++start --maxlen else if match (start, maxlen, "killbootthreads"): Iris::my_parent.init_done () else if match (start, maxlen, "receive"): // receive / [, ] = 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 ::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") if !(*p)->devices.begin (): ++progs List ::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)") (*dev)->server = &**p ++to_receive else if match (start, maxlen, "driver"): do_run (start, maxlen, true) else if match (start, maxlen, "run"): do_run (start, maxlen, false) else if match (start, maxlen, "wait"): kdebug ("waiting for device registration\n") while progs: Iris::wait () Program *caller = (Program *)Iris::recv.protected_data.l if !caller: Iris::panic (0, "bug in init: no caller") switch Iris::recv.data[0].l: case Iris::Parent::PROVIDE_DEVICE: 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 ::Item *d for d = caller->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 () --to_receive break case Iris::Parent::INIT_DONE: if caller->waiter.code != Iris::Cap ().code: Iris::panic (0, "caller was already waiting") caller->waiter = Iris::get_reply () --progs break default: Iris::panic (0, "unexpected request to init") if to_receive: Iris::panic (to_receive, "not all expected devices were registered") for List ::Item *p = programs.begin (); p; p = p->next: if (*p)->waiter.code != Iris::Cap ().code: (*p)->waiter.invoke () Iris::free_cap ((*p)->waiter) (*p)->waiter = Iris::Cap () kdebug ("got all devices\n") 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, "include"): char *n unsigned l if !get_name (start, maxlen, n, l): Iris::panic (0, "syntax error in init.config (include)") List ::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, "file not found for include") include_caps ((*p)->pages, (*p)->size) 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 () elfrun = Iris::my_parent.get_device () top_memory = Iris::get_top_memory () to_receive = 0 progs = 0 unsigned config_size Iris::Caps config_pages = load ("init.config", 12, config_size) include_caps (config_pages, config_size) 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: ") 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")