Root/mips/init.ccp

1#pypp 0
2// vim: set filetype=cpp : //
3// Iris: micro-kernel for a capability-based operating system.
4// mips/init.ccp: mips-specific boot code.
5// Copyright 2009 Bas Wijnen <wijnen@debian.org>
6//
7// This program is free software: you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20// Also declare things which only work during kernel init.
21#define INIT
22#define ARCH
23#include "kernel.hh"
24#include <elf.h>
25
26#define NUM_SLOTS 8
27#define NUM_CAPS 32
28
29static void init_idle ():
30    // initialize idle task as if it is currently running.
31    idle.prev = NULL
32    idle.next = NULL
33    idle.schedule_prev = NULL
34    idle.schedule_next = NULL
35    idle.address_space = &idle_memory
36    idle.refs.reset ()
37    idle.flags = Iris::Thread::RUNNING | Iris::Thread::PRIV
38    // initialize idle_memory.
39    idle_memory.prev = NULL
40    idle_memory.next = NULL
41    idle_memory.address_space = NULL
42    idle_memory.refs.reset ()
43    idle_memory.pages = &idle_page
44    idle_memory.threads = &idle
45    idle_memory.memories = NULL
46    idle_memory.limit = 0
47    idle_memory.used = 0
48    idle_memory.arch.directory = (Table **)0x80000000
49    // Shadow is never used for the idle task.
50    idle_memory.arch.shadow = NULL
51    idle_memory.arch.asid = 0
52    // initialize idle_page
53    idle_page.prev = NULL
54    idle_page.next = NULL
55    idle_page.frame = 0x80000000
56    idle_page.flags = Iris::Page::PAYING | Iris::Page::FRAME
57    idle_page.refs.reset ()
58    idle_page.address_space = NULL
59    current = &idle
60    directory = idle_memory.arch.directory
61    kdebug ("idle thread is ")
62    kdebug_num ((unsigned)&idle)
63    kdebug ("\n")
64
65static void init_cp0 ():
66    // Disable watchpoint interrupts.
67    cp0_set0 (CP0_WATCH_LO)
68    // Use the interrupt vector for interrupts; clear interrupt pending flags.
69    cp0_set (CP0_CAUSE, 1 << 23)
70    // Disable interrupts and set interrupt vectors to normal.
71    cp0_set0 (CP0_STATUS)
72    // Reset exception base address.
73    cp0_set0 (CP0_EBASE)
74    // Use non-vectored interrupts.
75    cp0_set0 (CP0_INT_CTL)
76
77    // Get number of tlb entries (is 31).
78    unsigned num
79    cp0_get (CP0_CONFIG1, num)
80    num >>= 25
81    num &= 0x3f
82    // Clear the tlb.
83    cp0_set (CP0_WIRED, 0)
84    cp0_set0 (CP0_PAGE_MASK)
85    cp0_set0 (CP0_ENTRY_LO0)
86    cp0_set0 (CP0_ENTRY_LO1)
87    for unsigned i = 0; i <= num; ++i:
88        // with asid 0, no page faults will be triggered, so it's safe to map memory anywhere.
89        // And it's set to invalid anyway.
90        cp0_set (CP0_ENTRY_HI, 0x2000 * (i + 1))
91        cp0_set (CP0_INDEX, i)
92        // write the data.
93        __asm__ volatile ("tlbwi")
94    // Fill the idle task's page in useg. Set it to non-cachable.
95    // its directory entry is at 1fc, so it's number 7f (0fe00000).
96    // its table entry is at 1f8, so it's number 7e (0007e000).
97    // its address is 280 (00000280), used below for EPC.
98    unsigned const idle_entry_hi = 0x0fe7e000
99    cp0_set (CP0_ENTRY_HI, idle_entry_hi)
100    cp0_set (CP0_ENTRY_LO0, 0x00000012)
101    // The following value doesn't make much sense, but it is what is
102    // filled in at run-time. So for robustness it's used here as well.
103    cp0_set (CP0_ENTRY_LO1, 0x80000000)
104    __asm__ volatile ("tlbwr")
105    // Allow eret to be used to jump to the idle task.
106    cp0_set (CP0_EPC, (idle_entry_hi & PAGE_MASK) | 0x280)
107    // Wait with initializing the status register until the last moment, so that
108    // exceptions in the bootup code will fill EPC and friends.
109
110static void init_threads ():
111    kThread *previous = NULL
112    first_scheduled = NULL
113    first_alarm = NULL
114    kReceiver *init_receiver = NULL
115    unsigned i = 0
116    while thread_start[i + 1] != 0:
117        kMemory *mem = top_memory.alloc_memory ()
118        assert (mem)
119        kThread *thread = mem->alloc_thread (NUM_SLOTS)
120        kdebug ("Starting thread ")
121        kdebug_num (i, 2)
122        kdebug (" at ")
123        kdebug_num ((unsigned)thread)
124        kdebug ("\n")
125        #ifndef NDEBUG
126        thread->id = i
127        #endif
128        Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
129        for unsigned j = 0; j < SELFMAG; ++j:
130            if header->e_ident[j] != ELFMAG[j]:
131                panic (i * 0x1000 + j, "invalid ELF magic")
132                return
133        if header->e_ident[EI_CLASS] != ELFCLASS32:
134            panic (i * 0x1000 + EI_CLASS, "invalid ELF class")
135            return
136        if header->e_ident[EI_DATA] != ELFDATA2LSB:
137            panic (i * 0x1000 + EI_DATA, "invalid ELF data")
138            return
139        if header->e_ident[EI_VERSION] != EV_CURRENT:
140            panic (i * 0x1000 + EI_VERSION, "invalid ELF version")
141            return
142        if header->e_type != ET_EXEC:
143            panic (i * 0x1000 + 0x10, "invalid ELF type")
144            return
145        if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
146            panic (i * 0x1000 + 0x12, "invalid ELF machine")
147            return
148        thread->pc = header->e_entry
149        thread->sp = 0x80000000
150        kPage **used = (kPage **)mem->zalloc ()
151        for unsigned section = 0; section < header->e_shnum; ++section:
152            Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
153            if ~shdr->sh_flags & SHF_ALLOC:
154                continue
155            bool readonly = !(shdr->sh_flags & SHF_WRITE)
156            //bool executable = shdr->sh_flags & SHF_EXEC_INSTR
157            if shdr->sh_type != SHT_NOBITS:
158                unsigned file_offset = shdr->sh_offset >> PAGE_BITS
159                if (file_offset + ((shdr->sh_size + PAGE_SIZE - 1) >> PAGE_BITS)) >= (PAGE_SIZE >> 2):
160                    panic (0x87446809, "initial thread too large")
161                    return
162                for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
163                    unsigned section_offset = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
164                    unsigned idx = file_offset + section_offset
165                    kPage *page = mem->get_mapping (p)
166                    if page:
167                        if page->frame != thread_start[i] + (idx << PAGE_BITS):
168                            panic (0, "different pages mapped to one address in intitial file")
169                            return
170                        continue
171                    page = mem->alloc_page ()
172                    page->frame = thread_start[i] + (idx << PAGE_BITS)
173                    page->flags = Iris::Page::PAYING | Iris::Page::FRAME
174                    if used[idx]:
175                        page->share_next = used[idx]
176                        used[idx]->share_prev = page
177                        used[idx]->flags |= Iris::Page::SHARED
178                        used[idx] = page
179                        page->flags |= Iris::Page::SHARED
180                    else:
181                        used[idx] = page
182                    if readonly:
183                        page->flags |= Iris::Page::MAPPED_READONLY
184                    if !mem->map (page, p):
185                        panic (0x22446688, "unable to map initial page")
186                        return
187                    //kdebug ("mapped page ")
188                    //if readonly:
189                    // kdebug ("as readonly ")
190                    //kdebug ("at address ")
191                    //kdebug_num (p)
192                    //kdebug (" for ")
193                    //kdebug_num (i, 1)
194                    //kdebug ('\n')
195            else:
196                if readonly:
197                    panic (0x33399993, "unwritable bss section")
198                    return
199                for unsigned p = (shdr->sh_addr & PAGE_MASK); p < shdr->sh_addr + shdr->sh_size; p += PAGE_SIZE:
200                    kPage *page = mem->get_mapping (p)
201                    if !page:
202                        page = mem->alloc_page ()
203                        if !page:
204                            panic (0x00220022, "out of memory")
205                            return
206                        page->frame = mem->zalloc ()
207                        if !page->frame:
208                            panic (0x02220022, "out of memory");
209                            return
210                        page->flags = Iris::Page::PAYING | Iris::Page::FRAME
211                        if !mem->map (page, p):
212                            panic (0x33557799, "unable to map initial bss page")
213                            return
214                        kdebug ("mapped bss page at address ")
215                        kdebug_num (p)
216                        kdebug (" for ")
217                        kdebug_num (i, 1)
218                        kdebug ('\n')
219                    else:
220                        if page->flags & Iris::Page::MAPPED_READONLY:
221                            panic (0x20203030, "bss section starts on read-only page")
222                            return
223                        for unsigned a = p; a < ((p + PAGE_SIZE) & PAGE_MASK); a += 4:
224                            if a >= shdr->sh_addr + shdr->sh_size:
225                                break
226                            if a < shdr->sh_addr:
227                                continue
228                            ((unsigned *)page->frame)[(a & ~PAGE_MASK) >> 2] = 0
229        for unsigned p = 0; p <= ((thread_start[i + 1] - thread_start[i] - 1) >> PAGE_BITS); ++p:
230            ++top_memory.limit
231            if used[p]:
232                mem->use ()
233                continue
234            //kdebug ("freeing unused page from initial file\n")
235            top_memory.pfree (thread_start[i] + (p << PAGE_BITS))
236        //kdebug ("freeing unused page list\n")
237        mem->pfree ((unsigned)used)
238        kPage *stackpage = mem->alloc_page ()
239        stackpage->frame = mem->zalloc ()
240        stackpage->flags = Iris::Page::PAYING | Iris::Page::FRAME
241        if !stackpage || !mem->map (stackpage, 0x7ffff000):
242            panic (0x13151719, "unable to map initial stack page")
243            return
244        thread->slot[0].caps = mem->alloc_caps (NUM_CAPS)
245        thread->slot[0].caps->first_slot.thread = thread
246        thread->slot[0].caps->first_slot.index = 0
247        thread->arch.a[0] = NUM_SLOTS
248        thread->arch.a[1] = NUM_CAPS
249        kReceiver *recv = mem->alloc_receiver ()
250        recv->owner = thread
251        thread->receivers = recv
252        thread->slot[0].caps->set (__caps_num, (kReceiverP)(CAPTYPE_CAPS | CAP_MASTER), Iris::Num ((unsigned)thread->slot[0].caps), kCapRef (), &thread->slot[0].caps->refs)
253        thread->slot[0].caps->set (__receiver_num, (kReceiverP)(CAPTYPE_RECEIVER | CAP_MASTER), Iris::Num ((unsigned)recv), kCapRef (), &recv->refs)
254        thread->slot[0].caps->set (__thread_num, (kReceiverP)(CAPTYPE_THREAD | CAP_MASTER), Iris::Num ((unsigned)thread), kCapRef (), &thread->refs)
255        thread->slot[0].caps->set (__memory_num, (kReceiverP)(CAPTYPE_MEMORY | CAP_MASTER), Iris::Num ((unsigned)mem), kCapRef (), &mem->refs)
256        thread->slot[0].caps->set (__call_num, (kReceiverP)(CAPTYPE_RECEIVER | Iris::Receiver::CALL), Iris::Num ((unsigned)recv), kCapRef (), &recv->refs)
257        thread->flags = Iris::Thread::RUNNING | Iris::Thread::PRIV
258        if !i:
259            first_scheduled = thread
260            init_receiver = recv
261        else:
262            thread->slot[0].caps->set (__parent_num, init_receiver, i, kCapRef (), &init_receiver->capabilities)
263            previous->schedule_next = thread
264        thread->schedule_prev = previous
265        thread->schedule_next = NULL
266        previous = thread
267        ++i
268
269// Initialize the kernel, finish by falling into the idle task.
270void init (unsigned mem):
271    // Initialize board-specific things.
272    board_init ()
273    must_wait = false
274    // Initialize kernel variables to empty.
275    unsigned count = init_memory (mem)
276    // Set up invoke system.
277    reply_caps.init (1)
278    replied_caps.init (1)
279    // initialize system control coprocessor.
280    init_cp0 ()
281    // initialize everything about the idle task.
282    init_idle ()
283    // initialize top_memory.
284    top_memory.prev = NULL
285    top_memory.next = NULL
286    top_memory.address_space = NULL
287    top_memory.refs.reset ()
288    top_memory.pages = NULL
289    top_memory.threads = NULL
290    top_memory.memories = NULL
291    top_memory.limit = count
292    top_memory.used = 0
293    top_memory.arch.directory = NULL
294    top_memory.arch.asid = 0
295
296    // Record all asids as unused.
297    for unsigned i = 0; i < 63; ++i:
298        asids[i] = i + 1
299    asids[63] = 0
300
301    // Set up initial threads.
302    init_threads ()
303
304    // Unset all interrupt handlers.
305    for unsigned i = 0; i < 32; ++i:
306        arch_interrupt_receiver[i] = NULL
307
308    // Enable timer interrupts.
309    intc_unmask_irq (TIMER_INTERRUPT)
310
311    // Say we're handling an exception. Since we're going to enter the idle task, allow access to cp0.
312    // All interrupts enter the CPU through the interrupt controller at IP2, so enable that.
313    cp0_set (CP0_STATUS, 0x10000413)
314
315    for int a = 0; a < 0x300; a += 0x80:
316        kdebug("addr ")
317        kdebug_num(a)
318        kdebug(":")
319        for int b = 0; b < 0x10; b += 4:
320            kdebug(" ")
321            kdebug_num(*(unsigned *)(0x80000000 | (a + b)))
322        kdebug('\n')
323
324    kdebug ("entering idle task\n")
325    // Done; return to user space (the idle task).
326    __asm__ volatile ("eret")
327

Archive Download this file

Branches:
master



interactive