Root/userspace/boot/bootinit.ccp

1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/bootinit.ccp: Bootstrapping code.
4// Copyright 2009-2010 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 <elf.h>
22
23#define ELFRUN_NAME "elfrun.elf"
24#define INIT_NAME "init.elf"
25
26// These numbers are only used for elfrun.
27#define NUM_SLOTS 8
28#define NUM_CAPS 32
29
30static unsigned _free
31extern unsigned _end
32
33void init_alloc ():
34    _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
35
36char *alloc_space (unsigned pages):
37    unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
38    _free = ret + (pages << PAGE_BITS)
39    return (char *)ret
40
41void *operator new[] (unsigned size):
42    //kdebug ("new ")
43    void *ret = (void *)_free
44    size = (size + 3) & ~3
45    unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
46    if rest < size:
47        unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
48        for unsigned p = 0; p < pages; ++p:
49            Iris::Page page = Iris::my_memory.create_page ()
50            page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
51            Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
52            Iris::free_cap (page)
53    _free += size
54    //kdebug_num ((unsigned)ret)
55    //kdebug ("+")
56    //kdebug_num (size)
57    //kdebug ("\n")
58    return ret
59
60void *operator new (unsigned size):
61    return new char[size]
62
63static unsigned *bss_mapping
64static Iris::Page bss_page
65
66// Get the initial block device and filesystem.
67static Iris::Directory receive_devices ():
68    Iris::Block device
69    bool have_device = false
70    Iris::Cap reply[2]
71    bool have_reply[2]
72    have_reply[0] = false
73    have_reply[1] = false
74    unsigned next = 2
75    while true:
76        Iris::wait ()
77        kdebug_num (Iris::recv.protected_data.l, 1)
78        kdebug (": ")
79        if Iris::recv.protected_data.l == 0:
80            kdebug ("sd detect event device request\n")
81            // SD detection event device request.
82            // Ignore all; that will result in the driver thinking there is a card.
83            Iris::recv.reply.invoke ()
84            continue
85        switch Iris::recv.data[0].l:
86            case Iris::Parent::PROVIDE_CAPABILITY:
87                switch Iris::recv.data[1].l:
88                    case Iris::Block::ID:
89                    case Iris::WBlock::ID:
90                        // Ignore other partitions.
91                        Iris::Cap r = Iris::get_reply ()
92                        if Iris::recv.data[0].h != 0:
93                            kdebug ("ignoring non-0 partition\n")
94                        else:
95                            if have_device:
96                                Iris::panic (0, "double device provided")
97                            device = Iris::get_arg ()
98                            if have_reply[next - 2]:
99                                kdebug ("block provided (used)\n")
100                                reply[next++ - 2].invoke (0, 0, device.copy ())
101                                Iris::free_cap (device)
102                            else:
103                                kdebug ("block provided (stored)\n")
104                                have_device = true
105                        r.invoke ()
106                        Iris::free_cap (r)
107                        break
108                    case Iris::Directory::ID:
109                        kdebug ("directory provided\n")
110                        Iris::Directory ret = Iris::get_arg ()
111                        Iris::recv.reply.invoke ()
112                        return ret
113                    default:
114                        Iris::panic (Iris::recv.data[1].l, "invalid capability type provided by boot thread")
115                break
116            case Iris::Parent::GET_CAPABILITY:
117                if Iris::recv.data[1].l == Iris::Event::ID:
118                    kdebug ("event requested\n")
119                    // Detection of sd card.
120                    Iris::Cap reply = Iris::get_reply ()
121                    Iris::Cap event = Iris::my_receiver.create_capability (0)
122                    reply.invoke (0, 0, event.copy ())
123                    Iris::free_cap (event)
124                    Iris::free_cap (reply)
125                    break
126                if Iris::recv.data[1].l != Iris::Block::ID && Iris::recv.data[1].l != Iris::WBlock::ID:
127                    Iris::panic (Iris::recv.data[1].l, "invalid capability type requested by boot thread")
128                if next == Iris::recv.protected_data.l && have_device:
129                    kdebug ("block requested (sent)\n")
130                    Iris::recv.reply.invoke (0, 0, device.copy ())
131                    Iris::free_cap (device)
132                    have_device = false
133                    ++next
134                else:
135                    kdebug ("block requested (not sent)\n")
136                    reply[Iris::recv.protected_data.l - 2] = Iris::get_reply ()
137                    have_reply[Iris::recv.protected_data.l - 2] = true
138                break
139            case Iris::Parent::INIT_DONE:
140                kdebug ("init done\n")
141                // Ignore.
142                Iris::recv.reply.invoke ()
143                break
144            case Iris::Parent::EXIT:
145                Iris::panic (Iris::recv.protected_data.l, "boot thread exits")
146            default:
147                Iris::panic (Iris::recv.protected_data.l, "invalid boot request")
148
149static bool stringcmp (char const *s1, char const *s2, unsigned size):
150    for unsigned t = 0; t < size; ++t:
151        if s1[t] != s2[t]:
152            return false
153    return true
154
155static Iris::Block find (Iris::Directory root, char const *name):
156    unsigned size = 0
157    while name[size]:
158        ++size
159    Iris::Num num_files = root.get_size ()
160    for Iris::Num i = 0; i.value () < num_files.value (); i = i.value () + 1:
161        Iris::String n = root.get_name (i)
162        char current_name[16]
163        n.get_chars (0, current_name)
164        Iris::free_cap (n)
165        if !stringcmp (current_name, name, size):
166            continue
167        // Found elfrun.
168        Iris::Block ret = root.get_file_ro (i)
169        return ret
170    Iris::panic (0, "bootfile not found")
171
172static void run (Iris::Block data, Iris::Memory parent_memory, Iris::Cap parent):
173    // Get the size.
174    Iris::Num size = data.get_size ()
175    if size.value () == 0:
176        Iris::panic (0, "elfrun is empty")
177    // Allocate a caps with all the pages.
178    unsigned pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
179    Iris::Caps pages_caps = Iris::my_memory.create_caps (pages)
180    unsigned slot = pages_caps.use ()
181    // Map them into the address space as well.
182    char *mapping = alloc_space (pages)
183    // Create a memory for the program.
184    Iris::Memory mem = parent_memory.create_memory ()
185    // Load the file into memory and map it.
186    for unsigned p = 0; p < pages; ++p:
187        //kdebug_num (p)
188        //kdebug ("/")
189        //kdebug_num (pages)
190        //kdebug ("\n")
191        Iris::set_recv_arg (Iris::Cap (slot, p))
192        Iris::my_memory.create_page ()
193        Iris::Page (slot, p).set_flags (Iris::Page::PAYING)
194        data.get_block (p << PAGE_BITS, PAGE_SIZE, 0, Iris::Cap (slot, p))
195        Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
196    Iris::Thread thread = mem.create_thread (NUM_SLOTS)
197    Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
198    for unsigned j = 0; j < SELFMAG; ++j:
199        if header->e_ident[j] != ELFMAG[j]:
200            Iris::panic (header->e_ident[j], "invalid ELF magic")
201            return
202    if header->e_ident[EI_CLASS] != ELFCLASS32:
203        kdebug ("invalid ELF class:")
204        kdebug_num (header->e_ident[EI_CLASS])
205        kdebug (" != ")
206        kdebug_num (ELFCLASS32)
207        kdebug ("\n")
208        Iris::panic (0)
209        return
210    if header->e_ident[EI_DATA] != ELFDATA2LSB:
211        Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
212    if header->e_ident[EI_VERSION] != EV_CURRENT:
213        Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
214    if header->e_type != ET_EXEC:
215        Iris::panic (header->e_type, "invalid ELF type")
216    if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
217        Iris::panic (header->e_machine, "invalid ELF machine")
218    thread.set_pc (header->e_entry)
219    thread.set_sp (0x80000000)
220    for unsigned section = 0; section < header->e_shnum; ++section:
221        Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
222        if ~shdr->sh_flags & SHF_ALLOC:
223            continue
224        bool readonly = !(shdr->sh_flags & SHF_WRITE)
225        //bool executable = shdr->sh_flags & SHF_EXEC_INSTR
226        if shdr->sh_type != SHT_NOBITS:
227            unsigned file_offset = shdr->sh_offset >> PAGE_BITS
228            if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
229                Iris::panic (shdr->sh_size, "thread too large")
230                return
231            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
232                unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
233                unsigned idx = file_offset + section_offset
234                Iris::Page page = mem.mapping ((void *)p)
235                if Iris::recv.data[0].l == Iris::NO_ERROR:
236                    // The address already has a mapping; assume that it is correct.
237                    Iris::free_cap (page)
238                    continue
239                Iris::free_cap (page)
240                page = mem.create_page ()
241                unsigned f
242                if readonly:
243                    f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
244                else:
245                    f = Iris::Page::PAYING
246                page.set_flags (f)
247                Iris::Page (slot, idx).share (page, 0)
248                //kdebug ("mapping at ")
249                //kdebug_num (p)
250                //if readonly:
251                // kdebug (" (readonly)")
252                //kdebug ("\n")
253                if !mem.map (page, p):
254                    Iris::panic (0, "unable to map page")
255                    return
256                Iris::free_cap (page)
257        else:
258            if readonly:
259                Iris::panic (0, "unwritable bss section")
260                return
261            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
262                Iris::Page page = mem.mapping ((void *)p)
263                if Iris::recv.data[0].l == Iris::NO_ERROR:
264                    // No error means there is a mapping.
265                    page.share (bss_page, 0)
266                    Iris::free_cap (page)
267                    for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
268                        if a >= shdr->sh_addr + shdr->sh_size:
269                            break
270                        if a < shdr->sh_addr:
271                            continue
272                        bss_mapping[(a & ~PAGE_MASK) >> 2] = 0
273                else:
274                    Iris::free_cap (page)
275                    page = mem.create_page ()
276                    if Iris::recv.data[0].l != Iris::NO_ERROR:
277                        Iris::panic (Iris::recv.data[0].l, "out of memory")
278                    if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME):
279                        Iris::panic (0, "out of memory")
280                    if !mem.map (page, p):
281                        Iris::panic (0, "unable to map bss page")
282                    Iris::free_cap (page)
283    for unsigned p = 0; p < pages; ++p:
284        Iris::my_memory.destroy (Iris::Page (slot, p))
285    Iris::my_memory.destroy (pages_caps)
286    Iris::free_slot (slot)
287    Iris::Page stackpage = mem.create_page ()
288    stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
289    if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
290        Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
291    Iris::free_cap (stackpage)
292    Iris::Caps caps = mem.create_caps (NUM_CAPS)
293    thread.use (caps, 0)
294    thread.set_info (Iris::Thread::A0, NUM_SLOTS)
295    thread.set_info (Iris::Thread::A1, NUM_CAPS)
296    Iris::Receiver receiver = mem.create_receiver ()
297    receiver.set_owner (thread.copy ())
298    Iris::Cap call = receiver.create_call_capability ()
299    caps.set (__caps_num, caps.copy ())
300    caps.set (__receiver_num, receiver.copy ())
301    caps.set (__thread_num, thread.copy ())
302    caps.set (__memory_num, mem.copy ())
303    caps.set (__call_num, call.copy ())
304    caps.set (__parent_num, parent)
305    thread.run ()
306    Iris::free_cap (receiver)
307    Iris::free_cap (thread)
308    Iris::free_cap (call)
309    Iris::free_cap (caps)
310
311Iris::Num start ():
312    // Wait for the debugging device to be active, in case there is one.
313    Iris::schedule ()
314    kdebug ("Starting bootinit\n")
315    init_alloc ()
316    bss_mapping = (unsigned *)alloc_space (1)
317    bss_page = Iris::my_memory.create_page ()
318    Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
319
320    Iris::Memory top_memory = Iris::get_top_memory ()
321    Iris::Directory root = receive_devices ()
322    root.lock_ro ()
323    Iris::Block run_block = find (root, ELFRUN_NAME)
324    Iris::Cap parent_cap = Iris::my_receiver.create_capability (0)
325    run (run_block, top_memory, parent_cap)
326    Iris::wait ()
327    if Iris::recv.data[0].l != Iris::Parent::PROVIDE_CAPABILITY || Iris::recv.data[1].l != Iris::Elfrun::ID:
328        Iris::panic (0, "elfrun doesn't provide correct capability")
329    Iris::Cap reply = Iris::get_reply ()
330    Iris::Elfrun elfrun = Iris::get_arg ()
331    Iris::my_caps.set (parent_cap.idx (), Iris::Cap (CAP_NONE))
332    Iris::free_cap (parent_cap)
333    reply.invoke ()
334    Iris::free_cap (reply)
335
336    parent_cap = Iris::my_receiver.create_capability (0)
337    Iris::Block init_block = find (root, INIT_NAME)
338    Iris::Caps init_caps = elfrun.run_block (top_memory.copy (), init_block.copy (), parent_cap.copy (), 8, 63)
339
340    Iris::Thread init = init_caps.get (__thread_num)
341    init.make_priv ()
342    init.run ()
343    Iris::free_cap (init)
344    Iris::free_cap (init_caps)
345
346    bool have_root = false
347    bool have_elfrun = false
348    while true:
349        Iris::wait ()
350        switch Iris::recv.data[0].l:
351            case Iris::Parent::GET_CAPABILITY:
352                switch Iris::recv.data[1].l:
353                    case Iris::Directory::ID:
354                        if have_root:
355                            Iris::panic (0, "Init requests root directory twice")
356                        Iris::recv.reply.invoke (0, 0, root.copy ())
357                        have_root = true
358                        break
359                    case Iris::Elfrun::ID:
360                        if have_elfrun:
361                            Iris::panic (0, "Init requests elfrun twice")
362                        Iris::recv.reply.invoke (0, 0, elfrun.copy ())
363                        have_elfrun = true
364                        break
365                    default:
366                        Iris::panic (0, "Invalid device requested by init")
367                break
368            case Iris::Parent::INIT_DONE:
369                if Iris::recv.data[1].value () != 0:
370                    Iris::recv.reply.invoke ()
371                    break
372                // Special response: kill boot threads.
373                Iris::Cap reply = Iris::get_reply ()
374                root.unlock_ro ()
375                reply.invoke ()
376                Iris::free_cap (reply)
377                top_memory.destroy (Iris::my_memory)
378                Iris::panic (0, "bootinit should be destroyed")
379            default:
380                Iris::panic (Iris::recv.data[0].l, "invalid operation from init")
381

Archive Download this file

Branches:
master



interactive