Root/userspace/boot/init.ccp

1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// bootstrap/init.ccp: Bootstrapping code.
4// Copyright 2009 Bas Wijnen <wijnen@debian.org>
5//
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#include "devices.hh"
20#include "iris.hh"
21#include "keys.hh"
22
23#define INIT_CONFIG "init.config"
24#define INIT_CONFIG_SIZE 12
25
26#define NUM_SLOTS 8
27#define NUM_CAPS 32
28
29enum Captype:
30    SYSREQ
31    PROGRAM
32    FILE
33
34static unsigned _free
35extern unsigned _end
36
37void init_alloc ():
38    _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
39
40char *alloc_space (unsigned pages):
41    unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
42    _free = ret + (pages << PAGE_BITS)
43    return (char *)ret
44
45void *operator new[] (unsigned size):
46    //kdebug ("new ")
47    void *ret = (void *)_free
48    size = (size + 3) & ~3
49    unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
50    if rest < size:
51        unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
52        for unsigned p = 0; p < pages; ++p:
53            Iris::Page page = Iris::my_memory.create_page ()
54            page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
55            Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
56            Iris::free_cap (page)
57    _free += size
58    //kdebug_num ((unsigned)ret)
59    //kdebug ("+")
60    //kdebug_num (size)
61    //kdebug ("\n")
62    return ret
63
64void *operator new (unsigned size):
65    return new char[size]
66
67template <typename _T> //
68struct List:
69    struct Item:
70        Item *prev, *next
71        _T value
72        _T &operator* ():
73            return value
74        _T *operator-> ():
75            return &value
76    Item *first
77    Item *begin ():
78        return first
79    void erase (Item *i):
80        if i->prev:
81            i->prev->next = i->next
82        else:
83            first = i->next
84        if i->next:
85            i->next->prev = i->prev
86        delete i
87    Item *insert (Item *after = NULL):
88        Item *ret = new Item
89        if after:
90            ret->prev = after->prev
91            ret->next = after
92            if ret->prev:
93                ret->prev->next = ret
94            else:
95                first = ret
96            after->prev = ret
97        else:
98            ret->prev = NULL
99            ret->next = first
100            first = ret
101            if ret->next:
102                ret->next->prev = ret
103        return ret
104    void init ():
105        first = NULL
106    List () : first (NULL):
107
108struct Program
109
110struct Devbase:
111    char *name
112    unsigned name_len
113    unsigned type
114    Program *client
115    Iris::Cap cap
116
117struct Serverdevice : public Devbase:
118    unsigned index
119    Program *server
120
121struct Clientdevice:
122    unsigned type, index
123    Devbase *dev
124
125static Iris::Memory top_memory
126static Iris::Directory root
127static Iris::Elfrun elfrun
128
129struct Program:
130    char *name
131    unsigned name_len
132    unsigned size
133    Iris::Caps pages
134    Iris::Memory memory
135    Iris::Thread thread
136    List <Serverdevice> server_devices
137    List <Clientdevice> client_devices
138    unsigned num_waiting
139    bool priv
140    void run ():
141        Iris::Cap cap = Iris::my_receiver.create_capability (Iris::Num (PROGRAM, (unsigned)this))
142        if priv:
143            kdebug ("priv ")
144        kdebug ("running ")
145        for unsigned i = 0; i < name_len; ++i:
146            kdebug_char (name[i])
147        kdebug ("\n")
148        Iris::Caps caps = elfrun.run_caps (top_memory, pages, cap.copy (), (size + PAGE_SIZE - 1) >> PAGE_BITS)
149        Iris::free_cap (cap)
150        thread = caps.get (__thread_num)
151        memory = caps.get (__memory_num)
152        Iris::free_cap (caps)
153        if priv:
154            thread.make_priv ()
155        thread.run ()
156
157struct File : public Devbase:
158    unsigned size
159    Iris::Caps pages
160
161static List <Program> programs
162static List <File> files
163static Serverdevice *sysreq
164
165static bool name_match (char const *name, unsigned name_len, Iris::String n):
166    char nm[16]
167    n.get_chars (0, nm)
168    for unsigned t = 0; t < 16 && t < name_len; ++t:
169        if nm[t] != name[t]:
170            return false
171    return true
172
173static Iris::Caps load (char const *name, unsigned name_len, unsigned &size, Iris::Caps target = Iris::alloc_cap ()):
174    kdebug ("loading ")
175    for unsigned i = 0; i < name_len; ++i:
176        kdebug_char (name[i])
177    kdebug ("\n")
178    root.lock_ro ()
179    Iris::Num sz = root.get_size ()
180    if sz.h:
181        Iris::panic (sz.h, "too many files")
182    for unsigned i = 0; i < sz.l; ++i:
183        Iris::String n = root.get_name (i)
184        if !name_match (name, name_len, n):
185            Iris::free_cap (n)
186            continue
187        Iris::free_cap (n)
188        Iris::Block file = root.get_file_ro (i)
189        Iris::Num s = file.get_size ()
190        if s.h:
191            Iris::panic (s.h, "file is too large to load")
192        size = s.l
193        unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
194        if pages > 0:
195            Iris::set_recv_arg (target)
196            Iris::my_memory.create_caps (pages)
197            unsigned slot = target.use ()
198            for unsigned p = 0; p < pages; ++p:
199                Iris::set_recv_arg (Iris::Cap (slot, p))
200                file.get_block (p << PAGE_BITS)
201            Iris::free_slot (slot)
202        Iris::free_cap (file)
203        root.unlock_ro ()
204        return target
205    Iris::panic (0, "file not found for init")
206    return target
207
208static void delspace (char *&line, unsigned &maxlen):
209    while maxlen && (*line == ' ' || *line == '\t'):
210        ++line
211        --maxlen
212    if maxlen && *line == '#':
213        line += maxlen
214        maxlen = 0
215
216static bool match (char *&line, unsigned &maxlen, char const *word):
217    delspace (line, maxlen)
218    char const *w = word
219    char *l = line
220    unsigned len = 0
221    while *word:
222        if *l++ != *word++:
223            return false
224        ++len
225    line = l
226    maxlen -= len
227    delspace (line, maxlen)
228    //kdebug ("match: ")
229    //kdebug (w)
230    //kdebug ("\n")
231    return true
232
233static bool isnamechar (char c):
234    if c >= 'a' && c <= 'z':
235        return true
236    if c >= 'A' && c <= 'Z':
237        return true
238    if c >= '0' && c <= '9':
239        return true
240    if c == '_':
241        return true
242    return false
243
244static bool get_name (char *&line, unsigned &len, char *&name, unsigned &name_len):
245    delspace (line, len)
246    if !len:
247        return false
248    name_len = 0
249    while name_len < len && isnamechar (line[name_len]):
250        ++name_len
251    name = new char[name_len]
252    //kdebug ("name: ")
253    for unsigned i = 0; i < name_len; ++i:
254        name[i] = line[i]
255        //kdebug_char (name[i])
256    //kdebug_char ('\n')
257    line += name_len
258    len -= name_len
259    delspace (line, len)
260    return true
261
262static bool string_match (char const *s1, unsigned l1, char const *s2, unsigned l2):
263    if l1 != l2:
264        return false
265    for unsigned i = 0; i < l1; ++i:
266        if s1[i] != s2[i]:
267            return false
268    return true
269
270struct Type:
271    char const *name
272    unsigned len
273    unsigned type
274
275static unsigned read_num (char *&line, unsigned &len):
276    delspace (line, len)
277    unsigned num = 0
278    while len && *line >= '0' && *line <= '9':
279        num *= 10
280        num += *line - '0'
281        ++line
282        --len
283    delspace (line, len)
284    return num
285
286static Type types[] = {
287    { "String", 6, Iris::String::ID },
288    { "WString", 7, Iris::WString::ID },
289    { "Block", 5, Iris::Block::ID },
290    { "WBlock", 6, Iris::WBlock::ID },
291    { "Boot", 4, Iris::Boot::ID },
292    { "Device", 6, Iris::Device::ID },
293    { "Event", 5, Iris::Event::ID },
294    { "Parent", 6, Iris::Parent::ID },
295    { "Keyboard", 8, Iris::Keyboard::ID },
296    { "Buzzer", 6, Iris::Buzzer::ID },
297    { "Display", 7, Iris::Display::ID },
298    { "Font", 4, Iris::Font::ID },
299    { "Setting", 7, Iris::Setting::ID },
300    { "Directory", 9, Iris::Directory::ID },
301    { "WDirectory", 10, Iris::WDirectory::ID },
302    { "Stream", 6, Iris::Stream::ID },
303    { "UI", 2, Iris::UI::ID },
304    { "RTC", 3, Iris::RTC::ID },
305    { NULL, 0, 0 }
306    }
307
308static void find_type (char *&line, unsigned &len, unsigned &type, unsigned &index):
309    char *n
310    unsigned l
311    if !get_name (line, len, n, l) || !len:
312        Iris::panic (0, "no name for type")
313    for unsigned t = 0; types[t].len != 0; ++t:
314        if string_match (types[t].name, types[t].len, n, l):
315            type = types[t].type
316            if len && *line == ',':
317                ++line
318                --len
319                index = read_num (line, len)
320            else:
321                index = 0
322            return
323    Iris::panic (0, "no valid type found")
324
325static bool find_cap (char *&line, unsigned &len, Program **server, Devbase *&dev, bool &present):
326    char *n
327    unsigned l
328    if !get_name (line, len, n, l):
329        Iris::panic (0, "no capability name found in init.config")
330    for List <Program>::Item *p = programs.begin (); p; p = p->next:
331        List <Serverdevice>::Item *d
332        for d = (*p)->server_devices.begin (); d; d = d->next:
333            if string_match (n, l, (*d)->name, (*d)->name_len):
334                if server:
335                    *server = &**p
336                dev = &**d
337                present = false
338                return true
339    if server:
340        return false
341    for List <File>::Item *f = files.begin (); f; f = f->next:
342        if string_match (n, l, (*f)->name, (*f)->name_len):
343            dev = &**f
344            present = true
345            return true
346    return false
347
348static void parse_line (char *&line, unsigned maxlen)
349static void include (char const *name, unsigned name_len):
350    unsigned size
351    Iris::Caps caps = load (name, name_len, size)
352    unsigned pages = (size + PAGE_SIZE - 1) >> PAGE_BITS
353    char *config = alloc_space (pages)
354    unsigned pages_slot = caps.use ()
355    for unsigned p = 0; p < pages; ++p:
356        Iris::Page page (pages_slot, p)
357        Iris::my_memory.map (page, (unsigned)&config[p << PAGE_BITS])
358    char *ptr = config
359    while ptr - config < size:
360        parse_line (ptr, config + size - ptr)
361    for unsigned p = 0; p < pages; ++p:
362        Iris::my_memory.destroy (Iris::Cap (pages_slot, p))
363    Iris::my_memory.destroy (caps)
364    Iris::free_cap (caps)
365    Iris::free_slot (pages_slot)
366
367static char *get_filename (char *&line, unsigned &maxlen, unsigned &len):
368    char q = *line++
369    --maxlen
370    len = 0
371    while maxlen && *line != q:
372        ++line
373        --maxlen
374        ++len
375    if !maxlen:
376        Iris::panic (0, "no closing quote in init.config")
377    return line - len
378
379static void do_load (char *&line, unsigned &maxlen, bool priv):
380    Program *p = &**programs.insert ()
381    if !get_name (line, maxlen, p->name, p->name_len) || !match (line, maxlen, "=") || !maxlen:
382        Iris::panic (0, "syntax error in init.config (load)")
383    unsigned l
384    char *n = get_filename (line, maxlen, l)
385    p->pages = load (n, l, p->size)
386    p->priv = priv
387    p->num_waiting = 0
388    ++line
389    --maxlen
390
391static void parse_line (char *&line, unsigned maxlen):
392    char *start = line
393    while maxlen && *line != '\n':
394        ++line
395        --maxlen
396    // The line to execute is from start to line.
397    maxlen = line - start
398    if *line == '\n':
399        ++line
400    delspace (start, maxlen)
401    if !maxlen:
402        return
403    if match (start, maxlen, "program"):
404        // program <name> = "<filename>"
405        do_load (start, maxlen, false)
406    else if match (start, maxlen, "driver"):
407        // driver <name> = "<filename>"
408        do_load (start, maxlen, true)
409    else if match (start, maxlen, "file"):
410        // file <name> = "<filename>"
411        File *f = &**files.insert ()
412        f->type = Iris::Block::ID
413        if !get_name (start, maxlen, f->name, f->name_len) || !match (start, maxlen, "=") || !maxlen:
414            Iris::panic (0, "syntax error in init.config (file name)")
415        unsigned l
416        char *n = get_filename (start, maxlen, l)
417        f->pages = load (n, l, f->size)
418        f->cap = Iris::my_receiver.create_capability (Iris::Num (FILE, (unsigned)f))
419        ++line
420        --maxlen
421    else if match (start, maxlen, "receive"):
422        // receive <name> / <type> [, <index>] = <cap>
423        char *n
424        unsigned l
425        if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
426            Iris::panic (0, "syntax error in init.config (receive)")
427        List <Program>::Item *p
428        for p = programs.begin (); p; p = p->next:
429            if string_match ((*p)->name, (*p)->name_len, n, l):
430                break
431        if !p:
432            Iris::panic (0, "program not found for receive")
433        List <Serverdevice>::Item *dev = (*p)->server_devices.insert ()
434        find_type (start, maxlen, (*dev)->type, (*dev)->index)
435        if !match (start, maxlen, "=") || !get_name (start, maxlen, (*dev)->name, (*dev)->name_len):
436            Iris::panic (1, "syntax error in init.config (receive)")
437        (*dev)->server = &**p
438        (*dev)->client = NULL
439        (*dev)->cap = Iris::Cap ()
440    else if match (start, maxlen, "sysreq"):
441        Program *server
442        if sysreq:
443            Iris::panic (0, "double registration of sysreq")
444        bool dummy
445        if !find_cap (start, maxlen, &server, *(Devbase **)&sysreq, dummy):
446            Iris::panic (0, "capability not found for sysreq")
447        if sysreq->type != Iris::Keyboard::ID:
448            kdebug ("capability for sysreq is not a keyboard\n")
449    else if match (start, maxlen, "give"):
450        // give <name> / <type> [, <index>] = <cap>
451        char *n
452        unsigned l
453        if !get_name (start, maxlen, n, l) || !match (start, maxlen, "/") || !maxlen:
454            Iris::panic (0, "syntax error in init.config (give)")
455        List <Program>::Item *p
456        for p = programs.begin (); p; p = p->next:
457            if string_match ((*p)->name, (*p)->name_len, n, l):
458                break
459        if !p:
460            Iris::panic (0, "program not found for give")
461        List <Clientdevice>::Item *d = (*p)->client_devices.insert ()
462        find_type (start, maxlen, (*d)->type, (*d)->index)
463        if !match (start, maxlen, "="):
464            Iris::panic (1, "syntax error in init.config (give)")
465        bool present
466        if !find_cap (start, maxlen, NULL, (*d)->dev, present):
467            Iris::panic (0, "capability not found for give")
468        if (*d)->dev->type != (*d)->type:
469            kdebug ("capability type mismatch for give\n")
470        if (*d)->dev->client:
471            Iris::panic (0, "capability given out twice")
472        (*d)->dev->client = &**p
473        if !present:
474            ++(*p)->num_waiting
475        //kdebug ("registered give device: ")
476        //kdebug_num ((*d)->type)
477        //kdebug ("\n")
478    else if match (start, maxlen, "include"):
479        unsigned name_len
480        char *name = get_filename (line, maxlen, name_len)
481        include (name, name_len)
482    else:
483        for unsigned i = 0; i < maxlen; ++i:
484            kdebug_char (start[i])
485        kdebug_char ('\n')
486        Iris::panic (0, "invalid line in init.config")
487    delspace (start, maxlen)
488    if maxlen:
489        kdebug ("Junk: ")
490        for unsigned i = 0; i < maxlen; ++i:
491            kdebug_char (start[i])
492        kdebug_char ('\n')
493        Iris::panic (0, "junk at end of line in init.config")
494
495Iris::Num start ():
496    init_alloc ()
497    programs.init ()
498    files.init ()
499    root = Iris::my_parent.get_capability <Iris::Directory> ()
500    elfrun = Iris::my_parent.get_capability <Iris::Elfrun> ()
501    sysreq = NULL
502    top_memory = Iris::get_top_memory ()
503    include (INIT_CONFIG, INIT_CONFIG_SIZE)
504    kdebug ("killing boot threads\n")
505    Iris::my_parent.init_done ()
506    for List <Program>::Item *p = programs.begin (); p; p = p->next:
507        if !(*p)->num_waiting:
508            (*p)->run ()
509    if !sysreq:
510        Iris::panic (0, "sysreq not registered")
511    if sysreq->client:
512        Iris::panic (0, "sysreq set to reserved capability")
513    kdebug ("waiting for events.\n")
514    while true:
515        Iris::wait ()
516        switch Iris::recv.protected_data.l:
517            case SYSREQ:
518                if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
519                    Iris::reboot ()
520                    continue
521                kdebug ("sysreq event: rebooting device at release\n")
522                continue
523            case FILE:
524                File *file = (File *)Iris::recv.protected_data.h
525                switch Iris::recv.data[0].l:
526                    case Iris::Block::GET_SIZE:
527                        Iris::recv.reply.invoke (file->size)
528                        break
529                    case Iris::Block::GET_ALIGN_BITS:
530                        Iris::recv.reply.invoke (PAGE_BITS)
531                        break
532                    case Iris::Block::GET_BLOCK:
533                        Iris::Cap reply = Iris::get_reply ()
534                        Iris::Page target = Iris::get_arg ()
535                        Iris::Page source = file->pages.get (Iris::recv.data[1].l >> PAGE_BITS)
536                        source.share (target, Iris::Page::READONLY)
537                        reply.invoke ()
538                        Iris::free_cap (reply)
539                        Iris::free_cap (source)
540                        Iris::free_cap (target)
541                        break
542                    default:
543                        Iris::panic (Iris::recv.data[0].l, "unknown request for init string")
544                break
545            case PROGRAM:
546                Program *caller = (Program *)Iris::recv.protected_data.h
547                switch Iris::recv.data[0].l:
548                    case Iris::Parent::GET_CAPABILITY:
549                        unsigned index = Iris::recv.data[0].h
550                        unsigned type = Iris::recv.data[1].l
551                        if Iris::recv.data[1].h:
552                            Iris::panic (Iris::recv.data[1].h, "high device requested")
553                        //kdebug ("requested device ")
554                        //kdebug_num (type)
555                        //kdebug (":")
556                        //kdebug_num (index)
557                        //kdebug ("\n")
558                        List <Clientdevice>::Item *d
559                        for d = caller->client_devices.begin (); d; d = d->next:
560                            //kdebug ("checking ")
561                            //kdebug_num ((*d)->type)
562                            //kdebug (":")
563                            //kdebug_num ((*d)->index)
564                            //kdebug ("\n")
565                            if (*d)->type == type && (*d)->index == index:
566                                break
567                        if !d:
568                            Iris::debug ("requested %x by %s\n", type, caller->name)
569                            Iris::panic (type, "unregistered device requested")
570                        Iris::recv.reply.invoke (0, 0, (*d)->dev->cap)
571                        //kdebug ("given device ")
572                        //kdebug_num (type)
573                        //kdebug (":")
574                        //kdebug_num (index)
575                        //kdebug ("\n")
576                        break
577                    case Iris::Parent::PROVIDE_CAPABILITY:
578                        if Iris::recv.data[1].h != 0:
579                            kdebug ("init: too high device provided\n")
580                            continue
581                        unsigned type = Iris::recv.data[1].l
582                        unsigned index = Iris::recv.data[0].h
583                        List <Serverdevice>::Item *d
584                        for d = caller->server_devices.begin (); d; d = d->next:
585                            if (*d)->type == type && (*d)->index == index:
586                                break
587                        if !d:
588                            Iris::debug ("caller: %s\n", caller->name)
589                            Iris::panic (type, "unregistered device provided")
590                        (*d)->cap = Iris::get_arg ()
591                        Iris::recv.reply.invoke ()
592                        if (*d)->client:
593                            if !--(*d)->client->num_waiting:
594                                (*d)->client->run ()
595                        //kdebug ("provided ")
596                        //kdebug_num ((*d)->type)
597                        //kdebug (":")
598                        //kdebug_num ((*d)->index)
599                        //kdebug ("\n")
600                        break
601                    case Iris::Parent::INIT_DONE:
602                        //kdebug ("init done\n")
603                        Iris::recv.reply.invoke ()
604                        if caller == sysreq->server:
605                            Iris::Cap cap = Iris::my_receiver.create_capability (SYSREQ)
606                            Iris::Keyboard (sysreq->cap).set_cb (cap.copy ())
607                            Iris::free_cap (cap)
608                            kdebug ("registered sysreq\n")
609                        break
610                    case Iris::Parent::EXIT:
611                        kdebug ("child ")
612                        for unsigned i = 0; i < caller->name_len; ++i:
613                            kdebug_char (caller->name[i])
614                        kdebug (" exits with code ")
615                        kdebug_num (Iris::recv.data[1].h)
616                        kdebug (":")
617                        kdebug_num (Iris::recv.data[1].l)
618                        kdebug ("\n")
619                        top_memory.destroy (caller->memory)
620                        break
621                    default:
622                        // TODO.
623                        kdebug ("child request: ")
624                        kdebug_num (Iris::recv.data[0].l)
625                        kdebug (" from ")
626                        for unsigned i = 0; i < caller->name_len; ++i:
627                            kdebug_char (caller->name[i])
628                        kdebug ("\n")
629

Archive Download this file

Branches:
master



interactive