Root/userspace/glue/elfrun.ccp

1#pypp 0
2// Iris: micro-kernel for a capability-based operating system.
3// source/elfrun.ccp: Process creation server.
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 <elf.h>
22
23static unsigned _free
24extern unsigned _end
25
26void init_alloc ():
27    _free = ((unsigned)&_end + PAGE_SIZE - 1) & PAGE_MASK
28
29char *alloc_space (unsigned pages):
30    unsigned ret = (_free + PAGE_SIZE - 1) & PAGE_MASK
31    _free = ret + (pages << PAGE_BITS)
32    return (char *)ret
33
34void *operator new[] (unsigned size):
35    //kdebug ("new ")
36    void *ret = (void *)_free
37    size = (size + 3) & ~3
38    unsigned rest = PAGE_SIZE - (((_free - 1) & ~PAGE_MASK) + 1)
39    if rest < size:
40        unsigned pages = ((size - rest) + PAGE_SIZE - 1) >> PAGE_BITS
41        for unsigned p = 0; p < pages; ++p:
42            Iris::Page page = Iris::my_memory.create_page ()
43            page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
44            Iris::my_memory.map (page, _free + rest + (p << PAGE_BITS))
45            Iris::free_cap (page)
46    _free += size
47    //kdebug_num ((unsigned)ret)
48    //kdebug ("+")
49    //kdebug_num (size)
50    //kdebug ("\n")
51    return ret
52
53void *operator new (unsigned size):
54    return new char[size]
55
56static Iris::Memory parent_memory
57static Iris::Cap parent
58static unsigned slot
59static char *mapping
60static unsigned pages
61static Iris::Caps pages_caps
62static Iris::Memory mem
63static unsigned *bss_mapping
64static Iris::Page bss_page
65
66static Iris::Caps map_string (Iris::Block data):
67    // Get the size.
68    Iris::Num size = data.get_size ()
69    if size.value () == 0:
70        Iris::panic (0, "data string is empty")
71    // Allocate a caps with all the pages.
72    pages = (size.value () + PAGE_SIZE - 1) >> PAGE_BITS
73    pages_caps = Iris::my_memory.create_caps (pages)
74    slot = pages_caps.use ()
75    // Map them into the address space as well.
76    mapping = alloc_space (pages)
77    // Create a memory for the program.
78    mem = parent_memory.create_memory ()
79    // Load the file into memory and map it.
80    for unsigned p = 0; p < pages; ++p:
81        //kdebug_num (p)
82        //kdebug ("/")
83        //kdebug_num (pages)
84        //kdebug ("\n")
85        Iris::set_recv_arg (Iris::Cap (slot, p))
86        data.get_block (p << PAGE_BITS)
87        Iris::my_memory.map (Iris::Cap (slot, p), (unsigned)&mapping[p << PAGE_BITS])
88
89static Iris::Caps map_caps (Iris::Caps data, unsigned p):
90    // Get the size.
91    if p == 0:
92        Iris::panic (0, "data caps is empty")
93    // Allocate a new caps with all the pages for mapping locally.
94    pages = p
95    pages_caps = Iris::my_memory.create_caps (pages)
96    slot = pages_caps.use ()
97    unsigned src_slot = data.use ()
98    // Map them into the address space as well.
99    mapping = alloc_space (pages)
100    // Create a memory for the program.
101    mem = parent_memory.create_memory ()
102    // Load the file into memory and map it.
103    for unsigned p = 0; p < pages; ++p:
104        //kdebug_num (p)
105        //kdebug ("/")
106        //kdebug_num (pages)
107        //kdebug ("\n")
108        Iris::Page page = Iris::Cap (slot, p)
109        Iris::set_recv_arg (page)
110        Iris::my_memory.create_page ()
111        Iris::Page (Iris::Cap (src_slot, p)).share (page)
112        Iris::my_memory.map (page, (unsigned)&mapping[p << PAGE_BITS])
113    Iris::free_slot (src_slot)
114
115static Iris::Caps run (Iris::Caps data, Iris::Memory parent_memory, Iris::Cap parent, unsigned num_slots, unsigned num_caps):
116    Iris::Thread thread = mem.create_thread (num_slots)
117    Elf32_Ehdr *header = (Elf32_Ehdr *)mapping
118    for unsigned j = 0; j < SELFMAG; ++j:
119        if header->e_ident[j] != ELFMAG[j]:
120            Iris::panic (header->e_ident[j], "invalid ELF magic")
121            return Iris::Caps ()
122    if header->e_ident[EI_CLASS] != ELFCLASS32:
123        kdebug ("invalid ELF class:")
124        kdebug_num (header->e_ident[EI_CLASS])
125        kdebug (" != ")
126        kdebug_num (ELFCLASS32)
127        kdebug ("\n")
128        Iris::panic (0)
129        return Iris::Caps ()
130    if header->e_ident[EI_DATA] != ELFDATA2LSB:
131        Iris::panic (header->e_ident[EI_DATA], "invalid ELF data")
132    if header->e_ident[EI_VERSION] != EV_CURRENT:
133        Iris::panic (header->e_ident[EI_VERSION], "invalid ELF version")
134    if header->e_type != ET_EXEC:
135        Iris::panic (header->e_type, "invalid ELF type")
136    if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
137        Iris::panic (header->e_machine, "invalid ELF machine")
138    thread.set_pc (header->e_entry)
139    thread.set_sp (0x80000000)
140    for unsigned section = 0; section < header->e_shnum; ++section:
141        Elf32_Shdr *shdr = (Elf32_Shdr *)((unsigned)mapping + header->e_shoff + section * header->e_shentsize)
142        if ~shdr->sh_flags & SHF_ALLOC:
143            continue
144        bool readonly = !(shdr->sh_flags & SHF_WRITE)
145        //bool executable = shdr->sh_flags & SHF_EXEC_INSTR
146        if shdr->sh_type != SHT_NOBITS:
147            //kdebug ("loading ")
148            //kdebug_num (shdr->sh_addr)
149            //kdebug ("+")
150            //kdebug_num (shdr->sh_size)
151            //kdebug ("\n")
152            unsigned file_offset = shdr->sh_offset >> PAGE_BITS
153            if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
154                kdebug ("thread size: ")
155                kdebug_num (file_offset)
156                kdebug (",")
157                kdebug_num (shdr->sh_size)
158                kdebug ("\n")
159                Iris::panic (shdr->sh_size, "thread too large")
160                return Iris::Caps ()
161            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
162                unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
163                unsigned idx = file_offset + section_offset
164                Iris::Page page = mem.mapping ((void *)p)
165                if Iris::recv.data[0].l == Iris::NO_ERROR:
166                    // The address already has a mapping; assume that it is correct.
167                    Iris::free_cap (page)
168                    continue
169                Iris::free_cap (page)
170                page = mem.create_page ()
171                unsigned f
172                if readonly:
173                    f = Iris::Page::PAYING | Iris::Page::MAPPED_READONLY
174                else:
175                    f = Iris::Page::PAYING
176                page.set_flags (f)
177                Iris::Page (slot, idx).share (page, 0)
178                //kdebug ("mapping at ")
179                //kdebug_num (p)
180                //if readonly:
181                // kdebug (" (readonly)")
182                //kdebug ("\n")
183                if !mem.map (page, p):
184                    Iris::panic (0, "unable to map page")
185                    return Iris::Caps ()
186                Iris::free_cap (page)
187        else:
188            if readonly:
189                Iris::panic (0, "unwritable bss section")
190                return Iris::Caps ()
191            //kdebug ("clearing ")
192            //kdebug_num (shdr->sh_addr)
193            //kdebug ("+")
194            //kdebug_num (shdr->sh_size)
195            //kdebug ("\n")
196            for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
197                Iris::Page page = mem.mapping ((void *)p)
198                if Iris::recv.data[0].l == Iris::NO_ERROR:
199                    // No error means there is a mapping.
200                    page.share (bss_page, 0)
201                    Iris::free_cap (page)
202                    for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
203                        if a >= shdr->sh_addr + shdr->sh_size:
204                            break
205                        if a < shdr->sh_addr:
206                            continue
207                        bss_mapping[(a & ~PAGE_MASK) >> 2] = 0
208                else:
209                    Iris::free_cap (page)
210                    page = mem.create_page ()
211                    if Iris::recv.data[0].l != Iris::NO_ERROR:
212                        Iris::panic (Iris::recv.data[0].l, "out of memory")
213                    if !page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME):
214                        Iris::panic (0, "out of memory")
215                    if !mem.map (page, p):
216                        Iris::panic (0, "unable to map bss page")
217                    Iris::free_cap (page)
218    //kdebug ("start of program:\n")
219    //for unsigned i = 0; i < 0x40; i += 4:
220    // kdebug_num ((unsigned)mapping + 4 * i, 3)
221    // kdebug (" ==>")
222    // for unsigned j = 0; j < 4; j += 1:
223    // kdebug (" ")
224    // kdebug_num (((unsigned *)mapping)[i + j])
225    // kdebug ("\n")
226    for unsigned p = 0; p < pages; ++p:
227        Iris::my_memory.destroy (Iris::Page (slot, p))
228    Iris::my_memory.destroy (pages_caps)
229    Iris::free_slot (slot)
230    Iris::free_cap (pages_caps)
231    Iris::Page stackpage = mem.create_page ()
232    stackpage.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
233    if Iris::recv.data[0].l != Iris::NO_ERROR || !mem.map (stackpage, 0x7ffff000):
234        Iris::panic (Iris::recv.data[0].l, "unable to map initial stack page")
235    Iris::free_cap (stackpage)
236    Iris::Caps caps = mem.create_caps (num_caps)
237    thread.use (caps, 0)
238    thread.set_info (Iris::Thread::A0, num_slots)
239    thread.set_info (Iris::Thread::A1, num_caps)
240    Iris::Receiver receiver = mem.create_receiver ()
241    receiver.set_owner (thread.copy ())
242    Iris::Cap call = receiver.create_call_capability ()
243    caps.set (__caps_num, caps.copy ())
244    caps.set (__receiver_num, receiver.copy ())
245    caps.set (__thread_num, thread.copy ())
246    caps.set (__memory_num, mem.copy ())
247    caps.set (__call_num, call.copy ())
248    caps.set (__parent_num, parent.copy ())
249    Iris::free_cap (receiver)
250    Iris::free_cap (thread)
251    Iris::free_cap (mem)
252    Iris::free_cap (call)
253    return caps
254
255Iris::Num start ():
256    kdebug ("elfrun started.\n")
257    init_alloc ()
258    Iris::Elfrun dev = Iris::my_receiver.create_capability (0)
259    Iris::my_parent.provide_capability <Iris::Elfrun> (dev.copy ())
260    Iris::free_cap (dev)
261    bss_mapping = (unsigned *)alloc_space (1)
262    bss_page = Iris::my_memory.create_page ()
263    Iris::my_memory.map (bss_page, (unsigned)bss_mapping)
264
265    while true:
266        Iris::wait ()
267        Iris::Cap reply = Iris::get_reply ()
268        Iris::Cap arg = Iris::get_arg ()
269        switch Iris::recv.data[0].l:
270            case Iris::Elfrun::RUN_BLOCK:
271                unsigned num_slots = Iris::recv.data[1].l
272                unsigned num_caps = Iris::recv.data[1].h
273                parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
274                parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
275                Iris::Block data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
276                map_string (data)
277                Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
278                reply.invoke (0, 0, ret.copy ())
279                free_cap (ret)
280                free_cap (parent_memory)
281                free_cap (parent)
282                free_cap (data)
283                break
284            case Iris::Elfrun::RUN_CAPS:
285                unsigned num_slots = Iris::recv.data[1].l
286                unsigned num_caps = Iris::recv.data[1].h
287                unsigned p = Iris::recv.data[0].h
288                parent_memory = Iris::Caps (arg).get (Iris::Elfrun::PARENT_MEMORY)
289                parent = Iris::Caps (arg).get (Iris::Elfrun::PARENT)
290                Iris::Caps data = Iris::Caps (arg).get (Iris::Elfrun::DATA)
291                map_caps (data, p)
292                Iris::Caps ret = run (data, parent_memory, parent, num_slots, num_caps)
293                reply.invoke (0, 0, ret.copy ())
294                free_cap (ret)
295                free_cap (parent_memory)
296                free_cap (parent)
297                free_cap (data)
298                break
299            default:
300                Iris::panic (0, "invalid operation for elfrun")
301                reply.invoke (~0)
302                break
303        Iris::free_cap (arg)
304        Iris::free_cap (reply)
305

Archive Download this file

Branches:
master



interactive