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