Bugfix: Switching to other supercn cnode while in the loop.
[barrelfish] / kernel / startup.c
1 /**
2  * \file
3  * \brief Architecture-independent bootstrap code.
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2011, ETH Zurich.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <string.h>
16 #include <stdio.h>
17 #include <kernel.h>
18 #include <startup.h>
19 #include <exec.h>
20 #include <dispatch.h>
21 #include <barrelfish_kpi/init.h>
22 #include <barrelfish_kpi/paging_arch.h>
23 #include <barrelfish_kpi/domain_params.h>
24 #include <trace/trace.h>
25
26 coreid_t my_core_id;
27
28 /// Quick way to find the base address of a cnode capability
29 #define CNODE(cte)     (cte)->cap.u.cnode.cnode
30
31 /// Size of the physaddrcn (in terms of cspace bits resolved, ie. 2^n slots)
32 #define PHYSADDRCN_BITS (DEFAULT_CNODE_BITS + 2)
33
34 /**
35  * \brief Create caps in 'cnode'
36  *
37  * This function creates untyped caps to the RAM at physical address 'base_addr'
38  * and size 'size' and adds them to a cnode for the init task. The bootinfo is
39  * updated accordingly.
40  *
41  * \param base_addr The physical base address of the RAM for which caps have to
42  *                  be created
43  * \param size      The size of the physical region
44  * \param type      Region type to create
45  * \param st        spawn_state structure to update
46  * \param bootinfo  bootinfo structure to update
47  */
48 errval_t create_caps_to_cnode(lpaddr_t base_addr, size_t size,
49                               enum region_type type,
50                               struct spawn_state *st, struct bootinfo *bootinfo)
51 {
52     size_t remain = size;
53     struct mem_region *regions = bootinfo->regions;
54     size_t *regions_index = &bootinfo->regions_length;
55     struct capability *cnode;
56     cslot_t *slot;
57     enum objtype cap_type;
58     errval_t err;
59
60     // determine destination and cap type
61     switch(type) {
62     case RegionType_Empty:
63         cap_type = ObjType_RAM;
64         cnode = &st->supercn0->cap;
65         slot = &st->supercn0_slot;
66         if (*slot >= 1UL << cnode->u.cnode.bits) {
67             slot = &st->supercn1_slot;
68             cnode = &st->supercn1->cap;
69         }
70         break;
71
72     case RegionType_PhyAddr:
73     case RegionType_PlatformData:
74         cap_type = ObjType_PhysAddr;
75         cnode = &st->physaddrcn->cap;
76         slot = &st->physaddrcn_slot;
77         break;
78
79     case RegionType_RootTask:
80         cap_type = ObjType_Frame;
81         cnode = &st->segcn->cap;
82         slot = &st->segcn_slot;
83         break;
84
85     default:
86         panic("Cannot handle bootinfo region type!");
87     }
88
89     while (remain > 0) {
90         /* Cannot insert anymore into this cnode */
91         if (*slot >= 1UL << cnode->u.cnode.bits) {
92             /*
93              * it may be the case that we run over so switch to the other
94              * supercn1 the switching should only happen once during this loop
95              */
96             if (cnode == &st->supercn0->cap) {
97                 slot = &st->supercn1_slot;
98                 cnode = &st->supercn1->cap;
99                 assert(*slot < 1UL << cnode->u.cnode.bits);
100             } else {
101                 printk(LOG_WARN, "create_caps_to_cnode: Cannot create more caps "
102                        "in CNode\n");
103                 return -1;
104             }
105         }
106         /* Cannot insert anymore into the mem_region */
107         if (*regions_index >= MAX_MEM_REGIONS) {
108             printk(LOG_WARN, "create_caps_to_cnode: mem_region out of space\n");
109             return -1;
110         }
111
112         uint8_t block_size = bitaddralign(remain, base_addr);
113
114         /* Create the capability */
115         err = caps_create_new(cap_type, base_addr, block_size, block_size,
116                             caps_locate_slot(cnode->u.cnode.cnode, (*slot)++));
117         if (err_is_fail(err)) {
118             return err;
119         }
120
121         assert(regions != NULL);
122         regions[*regions_index].mr_base = base_addr;
123         regions[*regions_index].mr_type = type;
124         regions[*regions_index].mr_bits = block_size;
125         regions[*regions_index].mr_consumed = false;
126         regions[*regions_index].mrmod_size = 0;
127         regions[*regions_index].mrmod_data = 0;
128         (*regions_index)++;
129
130         // Advance physical memory pointer
131         base_addr += (1UL << block_size);
132         remain -= (1UL << block_size);
133     }
134
135     return SYS_ERR_OK;
136 }
137
138
139 struct dcb *spawn_module(struct spawn_state *st,
140                          const char *name, int argc, const char** argv,
141                          lpaddr_t bootinfo, lvaddr_t args_base,
142                          alloc_phys_func alloc_phys, lvaddr_t *retparamaddr)
143 {
144     errval_t err;
145
146     printf("spawn module: %s\n", name);
147
148     // check for reuse of static state
149 #ifndef NDEBUG
150     static bool once_only;
151     assert(!once_only);
152     once_only = true;
153 #endif
154
155     /* Set up root cnode and the caps it contains */
156     // must be static, because this CTE will be entered into the MDB!
157     static struct cte rootcn;
158     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
159                         BASE_PAGE_BITS, DEFAULT_CNODE_BITS, &rootcn);
160     assert(err_is_ok(err));
161
162     // Task cnode in root cnode
163     st->taskcn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_TASKCN);
164     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
165                           BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->taskcn);
166     assert(err_is_ok(err));
167     st->taskcn->cap.u.cnode.guard_size = GUARD_REMAINDER(2 * DEFAULT_CNODE_BITS);
168
169     // Page cnode in root cnode
170     st->pagecn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_PAGECN);
171     err = caps_create_new(ObjType_CNode,
172                           alloc_phys(1UL << (OBJBITS_CTE + PAGE_CNODE_BITS)),
173                           PAGE_CNODE_BITS + OBJBITS_CTE,
174                           PAGE_CNODE_BITS, st->pagecn);
175     assert(err_is_ok(err));
176
177     // Base page cnode in root cnode
178     st->basepagecn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_BASE_PAGE_CN);
179     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
180                           BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->basepagecn);
181     assert(err_is_ok(err));
182
183     // Super cnode in root cnode
184     st->supercn0 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SUPERCN0);
185     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
186                           BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->supercn0);
187     assert(err_is_ok(err));
188     st->supercn1 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SUPERCN1);
189     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
190                           BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->supercn1);
191     assert(err_is_ok(err));
192
193
194     // slot_alloc cnodes in root cnode
195     st->slot_alloc_cn0 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SLOT_ALLOC0);
196     err = caps_create_new(ObjType_CNode,
197                           alloc_phys(1UL << (OBJBITS_CTE + SLOT_ALLOC_CNODE_BITS)),
198                           SLOT_ALLOC_CNODE_BITS + OBJBITS_CTE,
199                           SLOT_ALLOC_CNODE_BITS,
200                           st->slot_alloc_cn0);
201     assert(err_is_ok(err));
202
203     st->slot_alloc_cn1 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SLOT_ALLOC1);
204     err = caps_create_new(ObjType_CNode,
205                           alloc_phys(1UL << (OBJBITS_CTE + SLOT_ALLOC_CNODE_BITS)),
206                           SLOT_ALLOC_CNODE_BITS + OBJBITS_CTE,
207                           SLOT_ALLOC_CNODE_BITS,
208                           st->slot_alloc_cn1);
209     assert(err_is_ok(err));
210
211     st->slot_alloc_cn2 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SLOT_ALLOC2);
212     err = caps_create_new(ObjType_CNode,
213                           alloc_phys(1UL << (OBJBITS_CTE + SLOT_ALLOC_CNODE_BITS)),
214                           SLOT_ALLOC_CNODE_BITS + OBJBITS_CTE,
215                           SLOT_ALLOC_CNODE_BITS,
216                           st->slot_alloc_cn2);
217     assert(err_is_ok(err));
218
219     // Seg cnode in root cnode
220     st->segcn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SEGCN);
221     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
222                         BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->segcn);
223     assert(err_is_ok(err));
224
225     // Physaddr cnode in root cnode
226     st->physaddrcn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_PACN);
227     err = caps_create_new(ObjType_CNode,
228                         alloc_phys(1UL << (OBJBITS_CTE + PHYSADDRCN_BITS)),
229                         OBJBITS_CTE + PHYSADDRCN_BITS,
230                         PHYSADDRCN_BITS, st->physaddrcn);
231     assert(err_is_ok(err));
232
233     if (arch_core_is_bsp()) {
234         // Cnode for Boot loaded modules
235         st->modulecn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_MODULECN);
236         err = caps_create_new(ObjType_CNode,
237                               alloc_phys(1UL << (OBJBITS_CTE + MODULECN_SIZE_BITS)),
238                               MODULECN_SIZE_BITS + OBJBITS_CTE, MODULECN_SIZE_BITS,
239                               st->modulecn);
240         assert(err_is_ok(err));
241     }
242
243     /* Managing caps in task cnode */
244     // Dcb cap
245     struct cte *init_dcb_cte = caps_locate_slot(CNODE(st->taskcn),
246                                                 TASKCN_SLOT_DISPATCHER);
247     err = caps_create_new(ObjType_Dispatcher,
248                           alloc_phys(1UL << OBJBITS_DISPATCHER),
249                           OBJBITS_DISPATCHER, 0, init_dcb_cte);
250     assert(err_is_ok(err));
251     struct dcb *init_dcb = init_dcb_cte->cap.u.dispatcher.dcb;
252
253     // Copy root cnode to task cnode
254     err = caps_copy_to_cnode(st->taskcn, TASKCN_SLOT_ROOTCN, &rootcn, 0, 0, 0);
255     assert(err_is_ok(err));
256
257     // Dispatcher frame in task cnode
258     struct cte *init_dispframe_cte = caps_locate_slot(CNODE(st->taskcn),
259                                                       TASKCN_SLOT_DISPFRAME);
260     err = caps_create_new(ObjType_Frame, alloc_phys(1 << DISPATCHER_FRAME_BITS),
261                         DISPATCHER_FRAME_BITS, DISPATCHER_FRAME_BITS,
262                         init_dispframe_cte);
263     assert(err_is_ok(err));
264
265     // Copy dispatcher frame to the dcb struct
266     err = caps_copy_to_cte(&init_dcb->disp_cte, init_dispframe_cte, false, 0, 0);
267     assert(err_is_ok(err));
268
269     // Argspage in task cnode
270     struct cte *init_args_cte = caps_locate_slot(CNODE(st->taskcn),
271                                                  TASKCN_SLOT_ARGSPAGE);
272     err = caps_create_new(ObjType_Frame, alloc_phys(ARGS_SIZE),
273                           ARGS_FRAME_BITS, ARGS_FRAME_BITS, init_args_cte);
274     st->args_page = gen_phys_to_local_phys(init_args_cte->cap.u.frame.base);
275
276     if (arch_core_is_bsp()) {
277         assert(bootinfo != 0);
278
279         // Map bootinfo (in task cnode)
280         struct cte *bootinfo_cte = caps_locate_slot(CNODE(st->taskcn),
281                                                     TASKCN_SLOT_BOOTINFO);
282         /* DevFrame to prevent zeroing! */
283         err = caps_create_new(ObjType_DevFrame, bootinfo,
284                               BOOTINFO_SIZEBITS, BOOTINFO_SIZEBITS, bootinfo_cte);
285         assert(err_is_ok(err));
286     }
287
288     // Map kernel Cap in task cnode
289     struct cte *kernelcap_cte = caps_locate_slot(CNODE(st->taskcn),
290                                                  TASKCN_SLOT_KERNELCAP);
291     err = caps_create_new(ObjType_Kernel, 0, 0, 0, kernelcap_cte);
292     assert(err_is_ok(err));
293
294     // Create capability for performance monitoring
295     struct cte *perfmoncap_cte = caps_locate_slot(CNODE(st->taskcn),
296                                                    TASKCN_SLOT_PERF_MON);
297     err = caps_create_new(ObjType_PerfMon, 0, 0, 0, perfmoncap_cte);
298     assert(err_is_ok(err));
299
300     // Map IRQ table in task cnode
301     err = caps_create_new(ObjType_IRQTable, 0, 0, 0,
302                           caps_locate_slot(CNODE(st->taskcn), TASKCN_SLOT_IRQ));
303     assert(err_is_ok(err));
304
305     /* Initialize dispatcher */
306     dispatcher_handle_t init_handle
307         = local_phys_to_mem(init_dispframe_cte->cap.u.frame.base);
308     struct dispatcher_shared_generic *init_disp =
309         get_dispatcher_shared_generic(init_handle);
310     init_disp->disabled = true;
311     init_disp->fpu_trap = 1;
312     strncpy(init_disp->name, argv[0], DISP_NAME_LEN);
313
314     /* Set fields in DCB */
315     // Set cspace
316     err = caps_copy_to_cte(&init_dcb->cspace, &rootcn, 0, 0, 0);
317     assert(err_is_ok(err));
318
319     // Set disp and add to run queue
320     init_dcb->disp = init_handle;
321     init_dcb->disabled = true;
322     make_runnable(init_dcb);
323
324     // XXX: hack for 1:1 mapping
325     if (args_base == 0) {
326         args_base = st->args_page;
327     }
328
329     /* Construct args page */
330     struct spawn_domain_params *params = (void *)local_phys_to_mem(st->args_page);
331     memset(params, 0, sizeof(*params));
332     char *buf = (char *)local_phys_to_mem(st->args_page
333                                           + sizeof(struct spawn_domain_params));
334     size_t buflen = ARGS_SIZE - sizeof(struct spawn_domain_params);
335     assert(argc < MAX_CMDLINE_ARGS);
336     params->argc = argc;
337     for (int i = 0; i < argc; i++) {
338         size_t arglen = strlen(argv[i]);
339         assert(arglen < buflen);
340         params->argv[i] = (void *)(args_base + mem_to_local_phys((lvaddr_t)buf)
341                                    - st->args_page);
342         strcpy(buf, argv[i]);
343         buf += arglen + 1;
344         buflen -= arglen + 1;
345     }
346
347     assert(retparamaddr != NULL);
348     *retparamaddr = args_base;
349
350     /* Fill up base page CN (pre-allocated 4K pages) */
351     for(size_t i = 0; i < (1UL << (BASE_PAGE_BITS - OBJBITS_CTE)); i++) {
352         err = caps_create_new(ObjType_RAM, alloc_phys(BASE_PAGE_SIZE),
353                               BASE_PAGE_BITS, BASE_PAGE_BITS,
354                               caps_locate_slot(CNODE(st->basepagecn), i));
355         assert(err_is_ok(err));
356     }
357
358     // Store the application in the boot applications.
359         trace_new_boot_application((char*) name, (uintptr_t) init_dcb);
360
361     return init_dcb;
362 }