armv7-m (heteropanda) builds.
[barrelfish] / kernel / arch / armv7-m / init.c
1 /*
2  * Copyright (c) 2009-2013, ETH Zurich. All rights reserved.
3  *
4  * This file is distributed under the terms in the attached LICENSE file.
5  * If you do not find this file, copies can be found by writing to:
6  * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
7  * Attn: Systems Group.
8  */
9
10 /**
11  * \file
12  * \brief cortex-m3 CPU driver init code for the OMAP44xx series SoCs.
13  */
14
15 #include <kernel.h>
16 #include <string.h>
17 #include <init.h>
18 #include <exceptions.h>
19 #include <exec.h>
20 #include <offsets.h>
21 #include <paging_kernel_arch.h>
22 #include <phys_mmap.h>
23 #include <serial.h>
24 #include <spinlock.h>
25 #include <stdio.h>
26 #include <arm_hal.h>
27 #include <getopt/getopt.h>
28 #include <elf/elf.h>
29 #include <barrelfish_kpi/arm_core_data.h>
30 #include <startup_arch.h>
31 #include <kernel_multiboot.h>
32 #include <global.h>
33 #include <start_aps.h> // AP_WAIT_*, AUX_CORE_BOOT_*  and friends
34 #include <irq.h>
35
36 #include <omap44xx_map.h>
37 #include <dev/omap/omap44xx_id_dev.h>
38 #include <dev/omap/omap44xx_gpio_dev.h>
39
40 /// Round up n to the next multiple of size
41 #define ROUND_UP(n, size)           ((((n) + (size) - 1)) & (~((size) - 1)))
42
43 /**
44  * Used to store the address of global struct passed during boot across kernel
45  * relocations.
46  */
47 //static uint32_t addr_global;
48
49 /**
50  * \brief Kernel stack.
51  *
52  * This is the one and only kernel stack for a kernel instance.
53  */
54 uintptr_t kernel_stack[KERNEL_STACK_SIZE/sizeof(uintptr_t)]
55 __attribute__ ((aligned(8)));
56
57 #define MIN(a,b) ((a) < (b) ? (a) : (b))
58 #define MAX(a,b) ((a) > (b) ? (a) : (b))
59 #define CONSTRAIN(x, a, b) MIN(MAX(x, a), b)
60
61 //
62 // Kernel command line variables and binding options
63 //
64 //XXX: SysTick actually counts cycles, so time can at most be estimated
65 static int timeslice  = 5; //interval in ms in which the scheduler gets called
66
67 static struct cmdarg cmdargs[] = {
68     { "consolePort",    ArgType_UInt, { .uinteger = &serial_console_port}},
69     { "debugPort",      ArgType_UInt, { .uinteger = &serial_debug_port}},
70     { "loglevel",       ArgType_Int, { .integer = &kernel_loglevel }},
71     { "logmask",        ArgType_Int, { .integer = &kernel_log_subsystem_mask }},
72     { "timeslice",      ArgType_Int, { .integer = &timeslice }},
73     {NULL, 0, {NULL}}
74 };
75
76 static inline void __attribute__ ((always_inline))
77 relocate_stack(lvaddr_t offset)
78 {
79     __asm volatile (
80                     "add        sp, sp, %[offset]\n\t" ::[offset] "r" (offset)
81                     );
82 }
83
84 static inline void __attribute__ ((always_inline))
85 relocate_got_base(lvaddr_t offset)
86 {
87     __asm volatile (
88                     "add        r10, r10, %[offset]\n\t" ::[offset] "r" (offset)
89                     );
90 }
91
92
93 void kernel_startup_early(void)
94 {
95     const char *cmdline;
96     assert(glbl_core_data != NULL);
97     cmdline = MBADDR_ASSTRING(glbl_core_data->cmdline);
98     parse_commandline(cmdline, cmdargs);
99     timeslice = CONSTRAIN(timeslice, 1, 20);
100 }
101
102 /**
103  * \brief Continue kernel initialization in kernel address space.
104  *
105  * This function resets paging to map out low memory and map in physical
106  * address space, relocating all remaining data structures. It sets up exception handling,
107  * initializes devices and transitions into handler mode.
108  */
109 static void  __attribute__ ((noinline,noreturn)) text_init(void)
110 {
111     errval_t errval;
112
113     if ((glbl_core_data->multiboot_flags & MULTIBOOT_INFO_FLAG_HAS_MMAP)) {
114         // BSP core: set final page tables
115         struct arm_coredata_mmap *mmap = (struct arm_coredata_mmap *)
116             local_phys_to_mem(glbl_core_data->mmap_addr);
117         paging_arm_reset(mmap->base_addr, mmap->length);
118         //printf("paging_arm_reset: base: 0x%"PRIx64", length: 0x%"PRIx64".\n", mmap->base_addr, mmap->length);
119     } else {
120         // AP core
121         //  FIXME: Not sure what to do, so map the whole memory for now
122         paging_arm_reset(PHYS_MEMORY_START, 0x40000000);
123     }
124
125
126     //printf("startup_early\n");
127     kernel_startup_early();
128     //printf("kernel_startup_early done!\n");
129
130     //initialize console
131     serial_init(serial_console_port, 1);
132     spinlock_init();
133
134     printf("Barrelfish CPU driver starting on ARMv7-M OMAP44xx"
135            " Board id 0x%08"PRIx32"\n", hal_get_board_id());
136     printf("The address of paging_map_kernel_section is %p\n",
137            paging_map_kernel_section);
138
139     errval = serial_debug_init();
140     if (err_is_fail(errval)) {
141             printf("Failed to initialize debug port: %d", serial_debug_port);
142     }
143
144     if (my_core_id != hal_get_cpu_id()) {
145         printf("** setting my_core_id (="PRIuCOREID") to match hal_get_cpu_id() (=%u)\n");
146         my_core_id = hal_get_cpu_id();
147     }
148
149     // Test MMU by remapping the device identifier and reading it using a
150     // virtual address
151     lpaddr_t id_code_section = OMAP44XX_MAP_L4_CFG_SYSCTRL_GENERAL_CORE & ~ARM_L1_SECTION_MASK;
152     lvaddr_t id_code_remapped = paging_map_device(id_code_section,
153                                                   ARM_L1_SECTION_BYTES);
154     omap44xx_id_t id;
155     omap44xx_id_initialize(&id, (mackerel_addr_t)(id_code_remapped +
156              (OMAP44XX_MAP_L4_CFG_SYSCTRL_GENERAL_CORE & ARM_L1_SECTION_MASK)));
157
158     char buf[200];
159     omap44xx_id_code_pr(buf,200,&id);
160     printf("Using MMU, %s", buf);
161
162     
163     nvic_init();
164     printf("nvic_init done\n");
165     //XXX: cachemarker: these counts are intended for no caching, adjust if we have caching
166     //systick_init(0xFFFFFF);//maximum value
167     //systick_init(0x0AC000);//absolute minimum for -O2: very little progress and much thrashing
168     systick_init(0x0C0000);//reasonable: many interrupts, no thrashing (with -O2)
169     printf("systick_init done\n");
170     
171
172     //transition into handler mode, will call text_init_continued
173     exceptions_early_init();
174     panic("exceptions_early_init has returned. this should never happen!");
175 }
176
177 /*
178  * \brief last bit of initialization before calling arm_kernel_startup()
179  *  called by a special exception handler -> we are now in handler mode
180  *  properly set up exceptions here
181  */
182 void  __attribute__ ((noinline,noreturn)) text_init_continued(void){
183     printf("entered text_init_continued - we are now in handler mode\n");
184     
185     //now all devices should have been mapped -> release the lock on their TLB entries
186     set_tlb_lock_basevalue(0);
187     
188     //now is probably the time to set up the vectortable?
189     printf("overwriting TLB mapping for page 0 (vectortable).\n");
190     printf("physical address of vectortable: 0x%x\n", (uint32_t) &vectortable);
191     add_tlb_mapping(0, (lpaddr_t) &vectortable, 1, 2);
192     printf("mapped vectortable page to address 0 in TLB.\n");
193     set_tlb_lock_basevalue(2);//XXX: hack, to make sure the already preserved entry in there stays preserved
194     //(entry 1 is a preserved mapping of the section containing the TLB flush code)
195     //XXX: cachemarker: as soon as caching is up, we can flush the TLB safely
196     // -> remove the preserved-bit for the entry with the flushing code on
197     
198     
199     exceptions_init();//set up proper exception handlers in the relocated vectortable
200     
201     printf("starting SysTick timer\n");
202     systick_start();
203     arm_kernel_startup();
204 }
205
206
207 /*
208  * Doesn't work yet on the second LED for some reason...
209  */
210 static void set_leds(void)
211 {
212     uint32_t r, nr;
213     omap44xx_gpio_t g;
214     //char buf[8001];
215
216     omap44xx_gpio_initialize(&g, (mackerel_addr_t)OMAP44XX_MAP_L4_WKUP_GPIO1);
217     // Output enable
218     r = omap44xx_gpio_oe_rd(&g) & (~(1<<8));
219     omap44xx_gpio_oe_wr(&g,r);
220     // Write data out
221     r = omap44xx_gpio_dataout_rd(&g);
222     nr = r  |(1<<8); 
223     for(int i = 0; i < 5; i++) {
224         omap44xx_gpio_dataout_wr(&g,r);
225         for(int j = 0; j < 2000; j++) { 
226             printf(".");
227         }
228         omap44xx_gpio_dataout_wr(&g,nr);
229         for(int j = 0; j < 2000; j++) { 
230             printf(".");
231         }
232     }
233     return;
234
235     omap44xx_gpio_initialize(&g, (mackerel_addr_t)OMAP44XX_MAP_L4_PER_GPIO4);
236
237     // Output enable
238     r = omap44xx_gpio_oe_rd(&g) & (~(1<<14));
239     omap44xx_gpio_oe_wr(&g,r);
240     // Write data out
241     r = omap44xx_gpio_dataout_rd(&g);
242     nr = r  |(1<<14); 
243     for(int i = 0; i < 100; i++) {
244         omap44xx_gpio_dataout_wr(&g,r);
245         for(int j = 0; j < 2000; j++) { 
246             printf(".");
247         }
248         omap44xx_gpio_dataout_wr(&g,nr);
249         for(int j = 0; j < 2000; j++) { 
250             printf(".");
251         }
252     }
253 }
254
255 /**
256  * Entry point called from boot.S for bootstrap processor.
257  * if is_bsp == true, then pointer points to multiboot_info
258  * else pointer points to a global struct
259  */
260 void arch_init(void *pointer)
261 {
262
263     serial_early_init(serial_console_port);
264     spinlock_early_init();//from here on we can safely use printf
265
266 #if 0 //XXX: HACK: we currently are seperate from the other cores, so we can not use
267         // either of the "normal" cases
268     if (hal_cpu_is_bsp()) {
269         struct multiboot_info *mb = pointer;
270
271         memset(glbl_core_data, 0, sizeof(struct arm_core_data));
272
273         size_t max_addr = max(multiboot_end_addr(mb), (uintptr_t)&kernel_final_byte);
274         glbl_core_data->start_free_ram = ROUND_UP(max_addr, BASE_PAGE_SIZE);
275         glbl_core_data->mods_addr = mb->mods_addr;
276         glbl_core_data->mods_count = mb->mods_count;
277         glbl_core_data->cmdline = mb->cmdline;
278         glbl_core_data->mmap_length = mb->mmap_length;
279         glbl_core_data->mmap_addr = mb->mmap_addr;
280         glbl_core_data->multiboot_flags = mb->flags;
281
282         memset(&global->locks, 0, sizeof(global->locks));
283     } else {
284         global = (struct global *)GLOBAL_VBASE;
285         // zeroing locks for the app core seems bogus to me --AKK
286         //memset(&global->locks, 0, sizeof(global->locks));
287
288         // our core data (struct arm_core_data) is placed one page before the
289         // first byte of the kernel image
290         glbl_core_data = (struct arm_core_data *)
291                             ((lpaddr_t)&kernel_first_byte - BASE_PAGE_SIZE);
292         glbl_core_data->cmdline = (lpaddr_t)&glbl_core_data->kernel_cmdline;
293         my_core_id = glbl_core_data->dst_core_id;
294
295         // tell BSP that we are started up
296         // See Section 27.4.4 in the OMAP44xx manual for how this should work.
297         // we do this early, to avoid having to map the registers
298         lpaddr_t aux_core_boot_0 = AUX_CORE_BOOT_0;
299         lpaddr_t ap_wait = AP_WAIT_PHYS;
300
301         *((volatile lvaddr_t *)aux_core_boot_0) = 2<<2;
302         //__sync_synchronize();
303         *((volatile lvaddr_t *)ap_wait) = AP_STARTED;
304
305     }
306 #else    
307     //XXX: HACK
308     //since the M3 currently thinks it is a bsp core, we do most of the bsp stuff
309     //exept for truly global variables
310     
311     //not sure what address to use for our core_data
312     glbl_core_data = (struct arm_core_data*)((lvaddr_t)&kernel_first_byte - BASE_PAGE_SIZE);
313     
314     memset(glbl_core_data, 0, sizeof(struct arm_core_data));
315        
316     struct multiboot_info *mb = (struct multiboot_info *)pointer;
317     
318         glbl_core_data->start_free_ram =
319                         ROUND_UP(max(multiboot_end_addr(mb), (uintptr_t)&kernel_final_byte),
320                                  BASE_PAGE_SIZE);
321
322     glbl_core_data->mods_addr = mb->mods_addr;
323     glbl_core_data->mods_count = mb->mods_count;
324     glbl_core_data->cmdline = mb->cmdline;
325     glbl_core_data->mmap_length = mb->mmap_length;
326     glbl_core_data->mmap_addr = mb->mmap_addr;
327     glbl_core_data->multiboot_flags = mb->flags;
328     
329 //    global = (struct global *)GLOBAL_VBASE;//we currently do not need global
330 #endif //0
331
332
333     // XXX: print kernel address for debugging with gdb
334     printf("Barrelfish OMAP44xx cortex-m3 CPU driver starting at addr 0x%"PRIxLVADDR"\n", 
335            local_phys_to_mem((uint32_t)&kernel_first_byte));
336
337
338     if (1) {
339         set_leds();
340     }
341
342     //we already are in a virtual address space, so we do not have to do MMU stuff already
343     text_init();
344 }
345
346 struct kcb;
347 errval_t irq_table_notify_domains(struct kcb *kcb)
348 {
349     return SYS_ERR_OK;
350 }