ARMv5 & XScale build.
[barrelfish] / kernel / arch / armv5 / startup_arch.c
1 /*
2  * Copyright (c) 2009, 2010 ETH Zurich.
3  * All rights reserved.
4  *
5  * This file is distributed under the terms in the attached LICENSE file.
6  * If you do not find this file, copies can be found by writing to:
7  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8  */
9
10 #include <kernel.h>
11 #include <dispatch.h>
12 #include <string.h>
13 #include <stdio.h>
14
15 #include <barrelfish_kpi/init.h>
16 #include <barrelfish_kpi/syscalls.h>
17 #include <elf/elf.h>
18
19 #include <arm_hal.h>
20 #include <paging_kernel_arch.h>
21 #include <exceptions.h>
22 #include <cp15.h>
23 #include <cpiobin.h>
24 #include <init.h>
25 #include <phys_mmap.h>
26 #include <barrelfish_kpi/paging_arm_v5.h>
27 #include <startup.h>
28 #include <kcb.h>
29
30 #ifdef __XSCALE__
31 #include <romfs_size.h>
32 #endif
33
34 #define CNODE(cte)              (cte)->cap.u.cnode.cnode
35 #define UNUSED(x)               (x) = (x)
36
37 #define STARTUP_PROGRESS()      debug(SUBSYS_STARTUP, "%s:%d\n",          \
38                                       __FUNCTION__, __LINE__);
39
40 #define BSP_INIT_MODULE_NAME    BF_BINARY_PREFIX "armv5/sbin/init"
41
42 #define INIT_L1_BYTES           (ARM_L1_MAX_ENTRIES * ARM_L1_BYTES_PER_ENTRY)
43
44 #define INIT_L2_PAGES           ((INIT_SPACE_LIMIT - INIT_VBASE) / BASE_PAGE_SIZE)
45 #define INIT_L2_BYTES           INIT_L2_PAGES * ARM_L2_BYTES_PER_ENTRY
46
47 #define INIT_BOOTINFO_VBASE     INIT_VBASE
48 #define INIT_ARGS_VBASE         (INIT_BOOTINFO_VBASE + BOOTINFO_SIZE)
49 #define INIT_DISPATCHER_VBASE   (INIT_ARGS_VBASE + ARGS_SIZE)
50
51 #define INIT_PERM_RO            (ARM_L2_SMALL_CACHEABLE  | \
52                                  ARM_L2_SMALL_BUFFERABLE | \
53                                  ARM_L2_SMALL_USR_RO)
54
55 #define INIT_PERM_RW            (ARM_L2_SMALL_CACHEABLE  | \
56                                  ARM_L2_SMALL_BUFFERABLE | \
57                                  ARM_L2_SMALL_USR_RW)
58
59 static phys_mmap_t* g_phys_mmap;        // Physical memory map
60 static uintptr_t* init_l1;              // L1 page table for init
61 static uintptr_t* init_l2;              // L2 page tables for init
62
63 static struct spawn_state spawn_state;
64
65 static inline uintptr_t round_up(uintptr_t value, size_t unit)
66 {
67     assert(0 == (unit & (unit - 1)));
68     size_t m = unit - 1;
69     return (value + m) & ~m;
70 }
71
72 static inline uintptr_t round_down(uintptr_t value, size_t unit)
73 {
74     assert(0 == (unit & (unit - 1)));
75     size_t m = unit - 1;
76     return value & ~m;
77 }
78
79 static lpaddr_t alloc_phys_aligned(size_t bytes, size_t align)
80 {
81     bytes = round_up(bytes, align);
82     lpaddr_t a = phys_mmap_alloc(g_phys_mmap, bytes, align);
83     assert(0 == (a & (align - 1)));
84     return a;
85 }
86
87 static lpaddr_t alloc_phys(size_t bytes)
88 {
89     return alloc_phys_aligned(bytes, BASE_PAGE_SIZE);
90 }
91
92 static lvaddr_t alloc_mem_aligned(size_t bytes, size_t align)
93 {
94     return local_phys_to_mem(alloc_phys_aligned(bytes, align));
95 }
96
97 static lvaddr_t alloc_mem(size_t bytes)
98 {
99     return local_phys_to_mem(alloc_phys_aligned(bytes, BASE_PAGE_SIZE));
100 }
101
102 /**
103  * Map frames into init process address space. Init has a contiguous set of
104  * l2 entries so this is straightforward.
105  *
106  * @param l2_table      pointer to init's L2 table.
107  * @param l2_base       virtual address represented by first L2 table entry
108  * @param va_base       virtual address to map.
109  * @param pa_base       physical address to associate with virtual address.
110  * @param bytes        number of bytes to map.
111  * @param l2_flags      ARM L2 small page flags for mapped pages.
112  */
113 static void
114 spawn_init_map(uintptr_t* l2_table,
115                lvaddr_t   l2_base,
116                lvaddr_t   va_base,
117                lpaddr_t   pa_base,
118                size_t     bytes,
119                uintptr_t  l2_flags)
120 {
121     assert(va_base >= l2_base);
122     assert(0 == (va_base & (BASE_PAGE_SIZE - 1)));
123     assert(0 == (pa_base & (BASE_PAGE_SIZE - 1)));
124     assert(0 == (bytes & (BASE_PAGE_SIZE - 1)));
125
126     int bi = (va_base - l2_base) / BASE_PAGE_SIZE;
127     int li = bi + bytes / BASE_PAGE_SIZE;
128
129     while (bi < li)
130     {
131         paging_set_l2_entry(&l2_table[bi], pa_base, l2_flags);
132         pa_base += BASE_PAGE_SIZE;
133         bi++;
134     }
135 }
136
137 static uint32_t elf_to_l2_flags(uint32_t eflags)
138 {
139     switch (eflags & (PF_W|PF_R))
140     {
141       case PF_W|PF_R:
142         return (ARM_L2_SMALL_USR_RW |
143                 ARM_L2_SMALL_CACHEABLE |
144                 ARM_L2_SMALL_BUFFERABLE);
145       case PF_R:
146         return (ARM_L2_SMALL_USR_RO |
147                 ARM_L2_SMALL_CACHEABLE |
148                 ARM_L2_SMALL_BUFFERABLE);
149       default:
150         panic("Unknown ELF flags combination.");
151     }
152 }
153
154 struct startup_l2_info
155 {
156     uintptr_t* l2_table;
157     lvaddr_t   l2_base;
158 };
159
160 static errval_t
161 startup_alloc_init(
162     void*      state,
163     genvaddr_t gvbase,
164     size_t     bytes,
165     uint32_t   flags,
166     void**     ret
167     )
168 {
169     const struct startup_l2_info* s2i = (const struct startup_l2_info*)state;
170
171     lvaddr_t sv = round_down((lvaddr_t)gvbase, BASE_PAGE_SIZE);
172     size_t   off = (lvaddr_t)gvbase - sv;
173     lvaddr_t lv = round_up((lvaddr_t)gvbase + bytes, BASE_PAGE_SIZE);
174     lpaddr_t pa;
175
176     STARTUP_PROGRESS();
177     if (lv > sv && ((pa = alloc_phys(lv - sv)) != 0))
178     {
179         spawn_init_map(s2i->l2_table, s2i->l2_base, sv,
180                        pa, lv - sv, elf_to_l2_flags(flags));
181         *ret = (void*)(local_phys_to_mem(pa) + off);
182     }
183     else
184     {
185         *ret = 0;
186     }
187     return SYS_ERR_OK;
188 }
189
190 static void
191 load_init_image(
192     struct startup_l2_info* l2i,
193     const uint8_t*          initrd_base,
194     size_t                  initrd_bytes,
195     genvaddr_t*             init_ep,
196     genvaddr_t*             got_base
197     )
198 {
199     const uint8_t* elf_base;
200     size_t elf_bytes;
201     int found;
202
203     STARTUP_PROGRESS();
204     *init_ep = *got_base = 0;
205
206     found = cpio_get_file_by_name(initrd_base,
207                                   initrd_bytes,
208                                   BSP_INIT_MODULE_NAME,
209                                   &elf_base, &elf_bytes);
210     if (!found)
211     {
212         panic("Failed to find " BSP_INIT_MODULE_NAME "\n");
213     }
214
215     debug(SUBSYS_STARTUP, "load_init_image %p %08x\n", initrd_base, initrd_bytes);
216
217     errval_t err = elf_load(EM_ARM, startup_alloc_init, l2i,
218                             (lvaddr_t)elf_base, elf_bytes, init_ep);
219     if (err_is_fail(err))
220     {
221         panic("ELF load of " BSP_INIT_MODULE_NAME " failed!\n");
222     }
223
224     // TODO: Fix application linkage so that it's non-PIC.
225     struct Elf32_Shdr* got_shdr =
226         elf32_find_section_header_name((lvaddr_t)elf_base, elf_bytes, ".got");
227     if (got_shdr)
228     {
229         *got_base = got_shdr->sh_addr;
230     }
231 }
232
233 static void
234 create_modules_from_initrd(struct bootinfo* bi,
235                            const uint8_t*   initrd_base,
236                            size_t           initrd_bytes)
237 {
238     errval_t err;
239     lvaddr_t mmstrings_base = 0;
240     lvaddr_t mmstrings      = 0;
241
242     // CPIO archive is crafted such that first file is
243     // command-line strings for "modules" - ie menu.lst. The
244     // subsequent file follow in the order they appear in
245     // menu.lst.arm.
246     const uint8_t* data;
247     size_t bytes;
248
249     if (cpio_get_file_by_name(initrd_base, initrd_bytes,
250                               "menu.lst.modules",
251                               &data, &bytes))
252     {
253         assert(bytes < BASE_PAGE_SIZE);
254
255         mmstrings_base = alloc_mem(BASE_PAGE_SIZE);
256         mmstrings      = mmstrings_base;
257
258         STARTUP_PROGRESS();
259
260         // Create cap for strings area in first slot of modulecn
261         err = caps_create_new(
262                   ObjType_Frame,
263                   mem_to_local_phys(mmstrings_base),
264                   BASE_PAGE_BITS, BASE_PAGE_BITS,
265                   my_core_id,
266                   caps_locate_slot(
267                       CNODE(spawn_state.modulecn),
268                       spawn_state.modulecn_slot++)
269                   );
270         assert(err_is_ok(err));
271
272         STARTUP_PROGRESS();
273
274         // Copy strings from file into allocated page
275         memcpy((void*)mmstrings_base, data, bytes);
276         ((char*)mmstrings_base)[bytes] = '\0';
277
278         STARTUP_PROGRESS();
279
280         // Skip first line (corresponds to bootscript in archive)
281         strtok((char*)mmstrings_base, "\r\n");
282
283         STARTUP_PROGRESS();
284
285         assert(bi->regions_length == 0);
286         int ord = 1;
287         const char* name;
288         while ((mmstrings = (lvaddr_t)strtok(NULL, "\r\n")) != 0)
289         {
290             if (!cpio_get_file_by_ordinal(initrd_base, initrd_bytes, ord,
291                                           &name, &data, &bytes))
292             {
293                 panic("Failed to find file\n");
294             }
295             ord++;
296
297             debug(SUBSYS_STARTUP,
298                   "Creating caps for \"%s\" (Command-line \"%s\")\n",
299                    name, (char*)mmstrings);
300
301             // Copy file from archive into RAM.
302             // TODO: Give up archive space.
303             size_t   pa_bytes = round_up(bytes, BASE_PAGE_SIZE);
304             lpaddr_t pa       = alloc_phys(pa_bytes);
305             memcpy((void*)local_phys_to_mem(pa), data, bytes);
306
307             struct mem_region* region = &bi->regions[bi->regions_length++];
308             region->mr_type    = RegionType_Module;
309             region->mrmod_slot = spawn_state.modulecn_slot;
310             region->mrmod_size = pa_bytes;
311             region->mrmod_data = mmstrings - mmstrings_base;
312
313             assert((pa & BASE_PAGE_MASK) == 0);
314             assert((pa_bytes & BASE_PAGE_MASK) == 0);
315
316             while (pa_bytes != 0)
317             {
318                 assert(spawn_state.modulecn_slot
319                        < (1UL << spawn_state.modulecn->cap.u.cnode.bits));
320                 // create as DevFrame cap to avoid zeroing memory contents
321                 err = caps_create_new(
322                           ObjType_DevFrame, pa, BASE_PAGE_BITS,
323                           BASE_PAGE_BITS,
324                           my_core_id,
325                           caps_locate_slot(
326                               CNODE(spawn_state.modulecn),
327                               spawn_state.modulecn_slot++)
328                           );
329                 assert(err_is_ok(err));
330                 pa       += BASE_PAGE_SIZE;
331                 pa_bytes -= BASE_PAGE_SIZE;
332             }
333         }
334     }
335     else
336     {
337         panic("No command-line file.\n");
338     }
339 }
340
341 /// Create physical address range or RAM caps to unused physical memory
342 static void
343 create_phys_caps(struct capability *physaddrcn_cap, struct bootinfo* bi)
344 {
345     STARTUP_PROGRESS();
346     int i;
347     for (i = 0; i < g_phys_mmap->region_count; i++)
348     {
349         // TODO: Add RegionType_PhyAddr entries for memory mapped I/O
350         // regions.
351         const phys_region_t* r = &g_phys_mmap->regions[i];
352         if (r->limit - r->start >= BASE_PAGE_SIZE) {
353             create_caps_to_cnode(r->start, r->limit - r->start,
354                                  RegionType_Empty, &spawn_state, bi);
355         }
356     }
357     g_phys_mmap->region_count = 0;
358     STARTUP_PROGRESS();
359 }
360
361 static void __attribute__ ((noreturn))
362 spawn_init(const char*      name,
363            int32_t          kernel_id,
364            const uint8_t*   initrd_base,
365            size_t           initrd_bytes)
366 {
367     assert(0 == kernel_id);
368
369     // Create page table for init
370
371     init_l1 =  (uintptr_t*)alloc_mem_aligned(INIT_L1_BYTES, ARM_L1_ALIGN);
372     memset(init_l1, 0, INIT_L1_BYTES);
373
374     init_l2 = (uintptr_t*)alloc_mem_aligned(INIT_L2_BYTES, ARM_L2_ALIGN);
375     memset(init_l2, 0, INIT_L2_BYTES);
376
377     STARTUP_PROGRESS();
378
379     /* Allocate bootinfo */
380     lpaddr_t bootinfo_phys = alloc_phys(BOOTINFO_SIZE);
381     memset((void *)local_phys_to_mem(bootinfo_phys), 0, BOOTINFO_SIZE);
382
383     STARTUP_PROGRESS();
384
385     /* Construct cmdline args */
386     char bootinfochar[16];
387     snprintf(bootinfochar, sizeof(bootinfochar), "%u", INIT_BOOTINFO_VBASE);
388     const char *argv[] = { "init", bootinfochar };
389
390     lvaddr_t paramaddr;
391     struct dcb *init_dcb = spawn_module(&spawn_state, name,
392                                         ARRAY_LENGTH(argv), argv,
393                                         bootinfo_phys, INIT_ARGS_VBASE,
394                                         alloc_phys, &paramaddr);
395
396     STARTUP_PROGRESS();
397
398     /*
399      * Create a capability that allows user-level applications to
400      * access device memory. This capability will be passed to Kaluga,
401      * split up into smaller pieces and distributed to among device
402      * drivers.
403      *
404      * For armv5, this is currently a dummy capability. We do not
405      * have support for user-level device drivers in gem5 yet, so we
406      * do not allocate any memory as device memory. Some cap_copy
407      * operations in the bootup code fail if this capability is not
408      * present.
409      */
410     struct cte *iocap = caps_locate_slot(CNODE(spawn_state.taskcn), TASKCN_SLOT_IO);
411     errval_t  err = caps_create_new(ObjType_IO, 0, 0, 0, my_core_id, iocap);
412     assert(err_is_ok(err));
413
414     struct dispatcher_shared_generic *disp
415         = get_dispatcher_shared_generic(init_dcb->disp);
416     struct dispatcher_shared_arm *disp_arm
417         = get_dispatcher_shared_arm(init_dcb->disp);
418     assert(NULL != disp);
419
420     STARTUP_PROGRESS();
421
422     /* Initialize dispatcher */
423     disp->udisp = INIT_DISPATCHER_VBASE;
424
425     STARTUP_PROGRESS();
426     init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_l1);
427
428     STARTUP_PROGRESS();
429
430     /* Page table setup */
431
432     /* Map pagetables into page CN */
433     int pagecn_pagemap = 0;
434
435     /*
436      * ARM has:
437      *
438      * L1 has 4096 entries (16KB).
439      * L2 Coarse has 256 entries (256 * 4B = 1KB).
440      *
441      * CPU driver currently fakes having 1024 entries in L1 and
442      * L2 with 1024 entries by treating a page as 4 consecutive
443      * L2 tables and mapping this as a unit in L1.
444      */
445     caps_create_new(
446         ObjType_VNode_ARM_l1,
447         mem_to_local_phys((lvaddr_t)init_l1),
448             vnode_objbits(ObjType_VNode_ARM_l1), 0,
449             my_core_id,
450             caps_locate_slot(CNODE(spawn_state.pagecn), pagecn_pagemap++)
451         );
452
453     STARTUP_PROGRESS();
454
455     // Map L2 into successive slots in pagecn
456     size_t i;
457     for (i = 0; i < INIT_L2_BYTES / BASE_PAGE_SIZE; i++) {
458         size_t objbits_vnode = vnode_objbits(ObjType_VNode_ARM_l2);
459         assert(objbits_vnode == BASE_PAGE_BITS);
460         caps_create_new(
461             ObjType_VNode_ARM_l2,
462             mem_to_local_phys((lvaddr_t)init_l2) + (i << objbits_vnode),
463             objbits_vnode, 0,
464             my_core_id,
465             caps_locate_slot(CNODE(spawn_state.pagecn), pagecn_pagemap++)
466             );
467     }
468
469     /*
470      * Initialize init page tables - this just wires the L1
471      * entries through to the corresponding L2 entries.
472      */
473     STATIC_ASSERT(0 == (INIT_VBASE % ARM_L1_SECTION_BYTES), "");
474     for (lvaddr_t vaddr = INIT_VBASE; vaddr < INIT_SPACE_LIMIT; vaddr += ARM_L1_SECTION_BYTES)
475     {
476         uintptr_t section = (vaddr - INIT_VBASE) / ARM_L1_SECTION_BYTES;
477         uintptr_t l2_off = section * ARM_L2_TABLE_BYTES;
478         lpaddr_t paddr = mem_to_local_phys((lvaddr_t)init_l2) + l2_off;
479         paging_map_user_pages_l1((lvaddr_t)init_l1, vaddr, paddr);
480     }
481
482     paging_make_good((lvaddr_t)init_l1, INIT_L1_BYTES);
483
484     STARTUP_PROGRESS();
485
486     printf("XXX: Debug print to make Bram's code work\n");
487
488     paging_context_switch(mem_to_local_phys((lvaddr_t)init_l1));
489
490     STARTUP_PROGRESS();
491
492     // Map cmdline arguments in VSpace at ARGS_BASE
493     STATIC_ASSERT(0 == (ARGS_SIZE % BASE_PAGE_SIZE), "");
494
495     STARTUP_PROGRESS();
496
497     spawn_init_map(init_l2, INIT_VBASE, INIT_ARGS_VBASE,
498                    spawn_state.args_page, ARGS_SIZE, INIT_PERM_RW);
499
500     STARTUP_PROGRESS();
501
502     // Map bootinfo
503     spawn_init_map(init_l2, INIT_VBASE, INIT_BOOTINFO_VBASE,
504                    bootinfo_phys, BOOTINFO_SIZE, INIT_PERM_RW);
505
506     struct startup_l2_info l2_info = { init_l2, INIT_VBASE };
507
508     genvaddr_t init_ep, got_base;
509     load_init_image(&l2_info, initrd_base, initrd_bytes, &init_ep, &got_base);
510
511     // Set startup arguments (argc, argv)
512     disp_arm->enabled_save_area.named.r0   = paramaddr;
513     disp_arm->enabled_save_area.named.cpsr = ARM_MODE_USR | CPSR_F_MASK;
514     disp_arm->enabled_save_area.named.rtls = INIT_DISPATCHER_VBASE;
515     disp_arm->enabled_save_area.named.r10  = got_base;
516
517     disp_arm->got_base = got_base;
518
519     struct bootinfo* bootinfo = (struct bootinfo*)INIT_BOOTINFO_VBASE;
520     bootinfo->regions_length = 0;
521
522     STARTUP_PROGRESS();
523
524     create_modules_from_initrd(bootinfo, initrd_base, initrd_bytes);
525     debug(SUBSYS_STARTUP, "used %"PRIuCSLOT" slots in modulecn\n", spawn_state.modulecn_slot);
526
527     STARTUP_PROGRESS();
528     create_phys_caps(&spawn_state.physaddrcn->cap, bootinfo);
529
530     STARTUP_PROGRESS();
531
532     bootinfo->mem_spawn_core  = ~0;     // Size of kernel if bringing up others
533
534     // Map dispatcher
535     spawn_init_map(init_l2, INIT_VBASE, INIT_DISPATCHER_VBASE,
536                    mem_to_local_phys(init_dcb->disp), DISPATCHER_SIZE,
537                    INIT_PERM_RW);
538
539     STARTUP_PROGRESS();
540
541     // NB libbarrelfish initialization sets up the stack.
542     disp_arm->disabled_save_area.named.pc   = init_ep;
543     disp_arm->disabled_save_area.named.cpsr = ARM_MODE_USR | CPSR_F_MASK;
544     disp_arm->disabled_save_area.named.rtls = INIT_DISPATCHER_VBASE;
545     disp_arm->disabled_save_area.named.r10  = got_base;
546
547 #ifdef __XSCALE__
548     cp15_disable_cache();
549 #endif
550
551     printf("Kernel ready.\n");
552
553     pit_start();
554
555     // On to userland...
556     STARTUP_PROGRESS();
557     dispatch(init_dcb);
558
559     panic("Not reached.");
560 }
561
562 void arm_kernel_startup(phys_mmap_t* mmap,
563                         lpaddr_t     initrd_base,
564                         size_t       initrd_bytes)
565 {
566     g_phys_mmap = mmap;
567
568     STARTUP_PROGRESS();
569
570 #ifdef __XSCALE__
571     //Hardcoded because bootloader alter image if we pass the correct location
572     //Size of image is obtained by header file which is generated during compilation
573     initrd_base = 0x20000000;
574     initrd_bytes = romfs_cpio_archive_size;
575 #endif
576
577     const uint8_t* initrd_cpio_base = (uint8_t*)local_phys_to_mem(initrd_base);
578
579     if (!cpio_archive_valid(initrd_cpio_base, initrd_bytes))
580     {
581                 panic("Invalid initrd filesystem\n");
582     }
583
584     /* allocate initial KCB */
585     kcb_current = (struct kcb *) local_phys_to_mem(alloc_phys(sizeof(*kcb_current)));
586     memset(kcb_current, 0, sizeof(*kcb_current));
587     assert(kcb_current);
588
589     spawn_init(BSP_INIT_MODULE_NAME, 0, initrd_cpio_base, initrd_bytes);
590 }