added entries to gitignore
[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->supercn->cap;
65         slot = &st->supercn_slot;
66         break;
67
68     case RegionType_PhyAddr:
69     case RegionType_PlatformData:
70         cap_type = ObjType_PhysAddr;
71         cnode = &st->physaddrcn->cap;
72         slot = &st->physaddrcn_slot;
73         break;
74
75     case RegionType_RootTask:
76         cap_type = ObjType_Frame;
77         cnode = &st->segcn->cap;
78         slot = &st->segcn_slot;
79         break;
80
81     default:
82         panic("Cannot handle bootinfo region type!");
83     }
84
85     while (remain > 0) {
86         /* Cannot insert anymore into this cnode */
87         if (*slot >= 1UL << cnode->u.cnode.bits) {
88             printk(LOG_WARN, "create_caps_to_cnode: Cannot create more caps "
89                    "in CNode\n");
90             return -1;
91         }
92         /* Cannot insert anymore into the mem_region */
93         if (*regions_index >= MAX_MEM_REGIONS) {
94             printk(LOG_WARN, "create_caps_to_cnode: mem_region out of space\n");
95             return -1;
96         }
97
98         uint8_t block_size = bitaddralign(remain, base_addr);
99
100         /* Create the capability */
101         err = caps_create_new(cap_type, base_addr, block_size, block_size,
102                             caps_locate_slot(cnode->u.cnode.cnode, (*slot)++));
103         if (err_is_fail(err)) {
104             return err;
105         }
106
107         assert(regions != NULL);
108         regions[*regions_index].mr_base = base_addr;
109         regions[*regions_index].mr_type = type;
110         regions[*regions_index].mr_bits = block_size;
111         regions[*regions_index].mr_consumed = false;
112         regions[*regions_index].mrmod_size = 0;
113         regions[*regions_index].mrmod_data = 0;
114         (*regions_index)++;
115
116         // Advance physical memory pointer
117         base_addr += (1UL << block_size);
118         remain -= (1UL << block_size);
119     }
120
121     return SYS_ERR_OK;
122 }
123
124
125 struct dcb *spawn_module(struct spawn_state *st,
126                          const char *name, int argc, const char** argv,
127                          lpaddr_t bootinfo, lvaddr_t args_base,
128                          alloc_phys_func alloc_phys, lvaddr_t *retparamaddr)
129 {
130     errval_t err;
131
132     printf("spawn module: %s\n", name);
133
134     // check for reuse of static state
135 #ifndef NDEBUG
136     static bool once_only;
137     assert(!once_only);
138     once_only = true;
139 #endif
140
141     /* Set up root cnode and the caps it contains */
142     // must be static, because this CTE will be entered into the MDB!
143     static struct cte rootcn;
144     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
145                         BASE_PAGE_BITS, DEFAULT_CNODE_BITS, &rootcn);
146     assert(err_is_ok(err));
147
148     // Task cnode in root cnode
149     st->taskcn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_TASKCN);
150     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
151                           BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->taskcn);
152     assert(err_is_ok(err));
153     st->taskcn->cap.u.cnode.guard_size = GUARD_REMAINDER(2 * DEFAULT_CNODE_BITS);
154
155     // Page cnode in root cnode
156     st->pagecn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_PAGECN);
157     err = caps_create_new(ObjType_CNode,
158                           alloc_phys(1UL << (OBJBITS_CTE + PAGE_CNODE_BITS)),
159                           PAGE_CNODE_BITS + OBJBITS_CTE,
160                           PAGE_CNODE_BITS, st->pagecn);
161     assert(err_is_ok(err));
162
163     // Base page cnode in root cnode
164     st->basepagecn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_BASE_PAGE_CN);
165     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
166                           BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->basepagecn);
167     assert(err_is_ok(err));
168
169     // Super cnode in root cnode
170     st->supercn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SUPERCN);
171     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
172                           BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->supercn);
173     assert(err_is_ok(err));
174
175     // slot_alloc cnodes in root cnode
176     st->slot_alloc_cn0 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SLOT_ALLOC0);
177     err = caps_create_new(ObjType_CNode,
178                           alloc_phys(1UL << (OBJBITS_CTE + SLOT_ALLOC_CNODE_BITS)),
179                           SLOT_ALLOC_CNODE_BITS + OBJBITS_CTE,
180                           SLOT_ALLOC_CNODE_BITS,
181                           st->slot_alloc_cn0);
182     assert(err_is_ok(err));
183
184     st->slot_alloc_cn1 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SLOT_ALLOC1);
185     err = caps_create_new(ObjType_CNode,
186                           alloc_phys(1UL << (OBJBITS_CTE + SLOT_ALLOC_CNODE_BITS)),
187                           SLOT_ALLOC_CNODE_BITS + OBJBITS_CTE,
188                           SLOT_ALLOC_CNODE_BITS,
189                           st->slot_alloc_cn1);
190     assert(err_is_ok(err));
191
192     st->slot_alloc_cn2 = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SLOT_ALLOC2);
193     err = caps_create_new(ObjType_CNode,
194                           alloc_phys(1UL << (OBJBITS_CTE + SLOT_ALLOC_CNODE_BITS)),
195                           SLOT_ALLOC_CNODE_BITS + OBJBITS_CTE,
196                           SLOT_ALLOC_CNODE_BITS,
197                           st->slot_alloc_cn2);
198     assert(err_is_ok(err));
199
200     // Seg cnode in root cnode
201     st->segcn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_SEGCN);
202     err = caps_create_new(ObjType_CNode, alloc_phys(BASE_PAGE_SIZE),
203                         BASE_PAGE_BITS, DEFAULT_CNODE_BITS, st->segcn);
204     assert(err_is_ok(err));
205
206     // Physaddr cnode in root cnode
207     st->physaddrcn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_PACN);
208     err = caps_create_new(ObjType_CNode,
209                         alloc_phys(1UL << (OBJBITS_CTE + PHYSADDRCN_BITS)),
210                         OBJBITS_CTE + PHYSADDRCN_BITS,
211                         PHYSADDRCN_BITS, st->physaddrcn);
212     assert(err_is_ok(err));
213
214     if (arch_core_is_bsp()) {
215         // Cnode for Boot loaded modules
216         st->modulecn = caps_locate_slot(CNODE(&rootcn), ROOTCN_SLOT_MODULECN);
217         err = caps_create_new(ObjType_CNode,
218                               alloc_phys(1UL << (OBJBITS_CTE + MODULECN_SIZE_BITS)),
219                               MODULECN_SIZE_BITS + OBJBITS_CTE, MODULECN_SIZE_BITS,
220                               st->modulecn);
221         assert(err_is_ok(err));
222     }
223
224     /* Managing caps in task cnode */
225     // Dcb cap
226     struct cte *init_dcb_cte = caps_locate_slot(CNODE(st->taskcn),
227                                                 TASKCN_SLOT_DISPATCHER);
228     err = caps_create_new(ObjType_Dispatcher,
229                           alloc_phys(1UL << OBJBITS_DISPATCHER),
230                           OBJBITS_DISPATCHER, 0, init_dcb_cte);
231     assert(err_is_ok(err));
232     struct dcb *init_dcb = init_dcb_cte->cap.u.dispatcher.dcb;
233
234     // Copy root cnode to task cnode
235     err = caps_copy_to_cnode(st->taskcn, TASKCN_SLOT_ROOTCN, &rootcn, 0, 0, 0);
236     assert(err_is_ok(err));
237
238     // Dispatcher frame in task cnode
239     struct cte *init_dispframe_cte = caps_locate_slot(CNODE(st->taskcn),
240                                                       TASKCN_SLOT_DISPFRAME);
241     err = caps_create_new(ObjType_Frame, alloc_phys(1 << DISPATCHER_FRAME_BITS),
242                         DISPATCHER_FRAME_BITS, DISPATCHER_FRAME_BITS,
243                         init_dispframe_cte);
244     assert(err_is_ok(err));
245
246     // Copy dispatcher frame to the dcb struct
247     err = caps_copy_to_cte(&init_dcb->disp_cte, init_dispframe_cte, false, 0, 0);
248     assert(err_is_ok(err));
249
250     // Argspage in task cnode
251     struct cte *init_args_cte = caps_locate_slot(CNODE(st->taskcn),
252                                                  TASKCN_SLOT_ARGSPAGE);
253     err = caps_create_new(ObjType_Frame, alloc_phys(ARGS_SIZE),
254                           ARGS_FRAME_BITS, ARGS_FRAME_BITS, init_args_cte);
255     st->args_page = gen_phys_to_local_phys(init_args_cte->cap.u.frame.base);
256
257     if (arch_core_is_bsp()) {
258         assert(bootinfo != 0);
259
260         // Map bootinfo (in task cnode)
261         struct cte *bootinfo_cte = caps_locate_slot(CNODE(st->taskcn),
262                                                     TASKCN_SLOT_BOOTINFO);
263         /* DevFrame to prevent zeroing! */
264         err = caps_create_new(ObjType_DevFrame, bootinfo,
265                               BOOTINFO_SIZEBITS, BOOTINFO_SIZEBITS, bootinfo_cte);
266         assert(err_is_ok(err));
267     }
268
269     // Map kernel Cap in task cnode
270     struct cte *kernelcap_cte = caps_locate_slot(CNODE(st->taskcn),
271                                                  TASKCN_SLOT_KERNELCAP);
272     err = caps_create_new(ObjType_Kernel, 0, 0, 0, kernelcap_cte);
273     assert(err_is_ok(err));
274
275     // Create capability for performance monitoring
276     struct cte *perfmoncap_cte = caps_locate_slot(CNODE(st->taskcn),
277                                                    TASKCN_SLOT_PERF_MON);
278     err = caps_create_new(ObjType_PerfMon, 0, 0, 0, perfmoncap_cte);
279     assert(err_is_ok(err));
280
281     // Map IRQ table in task cnode
282     err = caps_create_new(ObjType_IRQTable, 0, 0, 0,
283                           caps_locate_slot(CNODE(st->taskcn), TASKCN_SLOT_IRQ));
284     assert(err_is_ok(err));
285
286     /* Initialize dispatcher */
287     dispatcher_handle_t init_handle
288         = local_phys_to_mem(init_dispframe_cte->cap.u.frame.base);
289     struct dispatcher_shared_generic *init_disp =
290         get_dispatcher_shared_generic(init_handle);
291     init_disp->disabled = true;
292     init_disp->fpu_trap = 1;
293     strncpy(init_disp->name, argv[0], DISP_NAME_LEN);
294
295     /* Set fields in DCB */
296     // Set cspace
297     err = caps_copy_to_cte(&init_dcb->cspace, &rootcn, 0, 0, 0);
298     assert(err_is_ok(err));
299
300     // Set disp and add to run queue
301     init_dcb->disp = init_handle;
302     init_dcb->disabled = true;
303     make_runnable(init_dcb);
304
305     // XXX: hack for 1:1 mapping
306     if (args_base == 0) {
307         args_base = st->args_page;
308     }
309
310     /* Construct args page */
311     struct spawn_domain_params *params = (void *)local_phys_to_mem(st->args_page);
312     memset(params, 0, sizeof(*params));
313     char *buf = (char *)local_phys_to_mem(st->args_page
314                                           + sizeof(struct spawn_domain_params));
315     size_t buflen = ARGS_SIZE - sizeof(struct spawn_domain_params);
316     assert(argc < MAX_CMDLINE_ARGS);
317     params->argc = argc;
318     for (int i = 0; i < argc; i++) {
319         size_t arglen = strlen(argv[i]);
320         assert(arglen < buflen);
321         params->argv[i] = (void *)(args_base + mem_to_local_phys((lvaddr_t)buf)
322                                    - st->args_page);
323         strcpy(buf, argv[i]);
324         buf += arglen + 1;
325         buflen -= arglen + 1;
326     }
327
328     assert(retparamaddr != NULL);
329     *retparamaddr = args_base;
330
331     /* Fill up base page CN (pre-allocated 4K pages) */
332     for(size_t i = 0; i < (1UL << (BASE_PAGE_BITS - OBJBITS_CTE)); i++) {
333         err = caps_create_new(ObjType_RAM, alloc_phys(BASE_PAGE_SIZE),
334                               BASE_PAGE_BITS, BASE_PAGE_BITS,
335                               caps_locate_slot(CNODE(st->basepagecn), i));
336         assert(err_is_ok(err));
337     }
338
339     // Store the application in the boot applications.
340         trace_new_boot_application((char*) name, (uintptr_t) init_dcb);
341
342     return init_dcb;
343 }