Adding some initializations
[barrelfish] / usr / drivers / xeon_phi / boot.c
1 /**
2  * \file
3  * \brief Boot module for the Xeon Phi
4  *
5  * Loads the co processor OS onto the card and boots it
6  */
7
8 /*
9  * Copyright (c) 2014 ETH Zurich.
10  * All rights reserved.
11  *
12  * This file is distributed under the terms in the attached LICENSE file.
13  * If you do not find this file, copies can be found by writing to:
14  * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
15  */
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <ctype.h>
20
21 #include <barrelfish/barrelfish.h>
22 #include <spawndomain/spawndomain.h>
23 #include <vfs/vfs.h>
24 #include <elf/elf.h>
25
26 #include <xeon_phi/xeon_phi.h>
27 #include <tftp/tftp.h>
28
29 #include <multiboot.h>
30
31 #include <dev/xeon_phi/xeon_phi_boot_dev.h>
32 #include <dev/xeon_phi/xeon_phi_apic_dev.h>
33
34 struct bootinfo *bi = NULL;
35
36 #include "xeon_phi_internal.h"
37 #include "interphi.h"
38 #include "sleep.h"
39
40 #define TFTP_BUF_SIZE (1<<20)
41 #define TFTP_BUF_SIZE_MODULES (1<<30)
42
43 typedef errval_t (*loadfile_fn_t)(char *path, void *buf, size_t buflen, size_t *ret_size);
44
45 #define BOOT_TIMEOUT 3000
46 #define BOOT_COUNTER 0xFFFFF
47
48 /*
49  * TODO: Verify these values if they are really needed
50  */
51 #define MEMORY_RESERVE_PERCENT 50
52 #define UOS_RESERVE_SIZE_MIN    ((128) * 1024 * 1024)
53 #define UOS_RESERVE_SIZE_MAX    (((4) * 1024 * 1024 * 1024ULL) - ((4) * 1024))
54
55 #define ALIGN(x) ROUND_UP(x, BASE_PAGE_SIZE)
56
57 static xeon_phi_boot_t boot_registers;
58 static xeon_phi_apic_t apic_registers;
59
60 /**
61  * \brief   get the load offset to where to place the bootloader
62  *
63  * The bootstrap on the card will write the offset into the SBOX_SCRATCH2
64  * register once the bootstrap is finished
65  */
66 static inline lvaddr_t get_load_offset(struct xeon_phi *phi)
67 {
68     return ((lvaddr_t) xeon_phi_boot_download_offset_rdf(&boot_registers)) << 12;
69 }
70
71 static uint64_t get_adapter_memsize(void)
72 {
73     xeon_phi_boot_meminfo_t meminfo = xeon_phi_boot_meminfo_rd(&boot_registers);
74
75     uint64_t memsize = xeon_phi_boot_meminfo_size_kb_extract(meminfo);
76     memsize *= 1024;
77
78     switch (xeon_phi_boot_meminfo_usage_extract(meminfo)) {
79         case xeon_phi_boot_mem_all:
80             return memsize;
81         case xeon_phi_boot_mem_half:
82             return (memsize / 2);
83         case xeon_phi_boot_mem_third:
84             return (memsize / 3);
85             break;
86         case xeon_phi_boot_mem_fourth:
87             return (memsize / 4);
88         default:
89             return memsize;
90     }
91 }
92
93 /**
94  * \brief   generates the cmdline supplied to the card kernel
95  *
96  * \param   phi         the card information structure
97  * \param   load_offset offset where to load the cmdline
98  * \param   ret_size    size of the cmdline in bytes
99  */
100 static errval_t load_cmdline(struct xeon_phi *phi, lvaddr_t load_offset)
101 {
102     uint32_t cmdlen = 0;
103
104     struct xeon_phi_boot_params *bp;
105     bp = (struct xeon_phi_boot_params *)(phi->apt.vbase + phi->os_offset);
106
107     void *buf = (void *) (phi->apt.vbase + load_offset);
108
109     if (phi->cmdline) {
110         cmdlen += sprintf(buf + cmdlen, "%s", phi->cmdline);
111     }
112
113     cmdlen += sprintf(buf + cmdlen, "card_id=%i", phi->id);
114
115     /*
116      * id
117      */
118     /*
119      * TODO: Add multihop / communication information here..
120      */
121
122     XBOOT_DEBUG("cmdline @ 0x%" PRIx32 " '%s'\n", (uint32_t)load_offset, (char*)buf);
123
124     phi->cmdline = buf;
125     phi->cmdlen = cmdlen;
126
127
128     bp->cmdline_ptr = (uint32_t)(load_offset);
129     bp->cmdline_size = (uint32_t)cmdlen;
130
131     return SYS_ERR_OK;
132 }
133
134 static errval_t bootstrap_notify(struct xeon_phi *phi)
135 {
136     // set the bootimage size to tell the bootloader
137     xeon_phi_boot_os_size_rawwr(&boot_registers, phi->os_size);
138
139     uint64_t memsize = get_adapter_memsize();
140
141     uint64_t reserved = (memsize * MEMORY_RESERVE_PERCENT / 100);
142
143     // Keep in mind maximum uos reserve size is uint32_t, so we never overflow
144     reserved = MIN(reserved, UOS_RESERVE_SIZE_MAX);
145     reserved = MAX(reserved, UOS_RESERVE_SIZE_MIN);
146
147     // Always align uos reserve size to a page
148     reserved = (reserved & ~(BASE_PAGE_SIZE - 1));
149
150     xeon_phi_boot_res_size_rawwr(&boot_registers, (uint32_t) reserved);
151
152     // sending the bootstrap interrupt
153     xeon_phi_apic_icr_lo_t icr_lo = xeon_phi_apic_icr_lo_default;
154     icr_lo = xeon_phi_apic_icr_lo_vector_insert(icr_lo, xeon_phi_apic_vec_bsp);
155     icr_lo = xeon_phi_apic_icr_lo_boot_notify_insert(icr_lo, 0x1);
156
157     assert(icr_lo == (229 | (1 << 13)));
158
159     xeon_phi_apic_icr_hi_wr(&apic_registers, xeon_phi_apic_bootstrap, phi->apicid);
160
161     xeon_phi_apic_icr_lo_wr(&apic_registers, xeon_phi_apic_bootstrap, icr_lo);
162
163     return SYS_ERR_OK;
164 }
165
166 /*
167  * -------------------------------------------------------------------------------
168  * VFS helper function
169  * -------------------------------------------------------------------------------
170  */
171
172 static vfs_handle_t file_open(char *file, uint8_t nfs)
173 {
174     errval_t err;
175
176     vfs_handle_t fh;
177     char *path = file;
178     if (nfs) {
179         size_t path_size = strlen(file) + strlen(XEON_PHI_NFS_MNT) + 2;
180         path = malloc(path_size);
181         if (path == NULL) {
182             return NULL;
183         }
184         if (file[0] == '/') {
185             snprintf(path, path_size, "%s%s", XEON_PHI_NFS_MNT, file);
186         } else {
187             snprintf(path, path_size, "%s/%s", XEON_PHI_NFS_MNT, file);
188         }
189     }
190
191     err = vfs_open(path, &fh);
192     if (nfs) {
193         free(path);
194     }
195     switch(err_no(err)) {
196         case SYS_ERR_OK :
197             return fh;
198             break;
199         case FS_ERR_NOTFOUND :
200             err = vfs_open(file, &fh);
201             if (err_is_ok(err)) {
202                 return fh;
203             }
204             return NULL;
205             break;
206         default:
207             return NULL;
208     }
209
210     return NULL;
211 }
212
213 static errval_t file_load(vfs_handle_t fh, void *buf, size_t length)
214 {
215     errval_t err;
216     size_t pos = 0, readlen = 0;
217     do {
218         err = vfs_read(fh, buf+pos, length - pos, &readlen);
219         if (err_is_fail(err)) {
220             return err;
221         } else if (readlen == 0) {
222             return SPAWN_ERR_LOAD; // XXX
223         } else {
224             pos += readlen;
225         }
226     } while (err_is_ok(err) && readlen > 0 && pos < length);
227
228     return SYS_ERR_OK;
229 }
230
231
232 static errval_t download_file_vfs(char *file, void *card_buffer, size_t use_nfs,
233                                   size_t *bytes)
234 {
235     errval_t err;
236
237     vfs_handle_t fh = file_open(file, use_nfs);
238     if (fh == NULL) {
239         return FS_ERR_INVALID_FH;
240     }
241
242     struct vfs_fileinfo info;
243     err = vfs_stat(fh, &info);
244     if (err_is_fail(err)) {
245         goto out;
246     }
247
248     if (bytes) {
249         *bytes = info.size;
250     }
251
252     assert(info.type == VFS_FILE);
253     assert(info.size < 4UL<<30);
254
255     err = file_load(fh, card_buffer, info.size);
256     out:
257     vfs_close(fh);
258     return err;
259 }
260
261 /*
262  * -------------------------------------------------------------------------------
263  * boot loader
264  * -------------------------------------------------------------------------------
265  */
266
267 #define SETUP_SECTORS 2
268 #define SECTOR_SIZE 512
269 #define HEADER_SIZE (SETUP_SECTORS*SECTOR_SIZE)
270
271 static errval_t download_bootloader_generic(struct xeon_phi *phi, char *bootloader,
272                                             loadfile_fn_t loadfn, size_t args)
273 {
274     errval_t err;
275
276     lvaddr_t loadoffset = get_load_offset(phi);
277     size_t imgsize;
278
279     char *buf = (void *) (phi->apt.vbase + loadoffset);
280
281     /* fill in the header */
282     memset(buf, 0, HEADER_SIZE);
283
284     /*
285      * This is the signature. Without this the kernel does not boot.
286      * Signature is reads "HdrS"
287      */
288     buf[514] = 0x48;
289     buf[515] = 0x64;
290     buf[516] = 0x72;
291     buf[517] = 0x53;
292     buf[0x1f1] = SETUP_SECTORS-1;
293
294     XBOOT_DEBUG("loading %s @ 0x%lx\n", bootloader, loadoffset);
295
296     err = loadfn(bootloader, buf + HEADER_SIZE, args, &imgsize);
297     if (err_is_fail(err)) {
298         return err;
299     }
300
301     size_t sys_size = (imgsize + 15) / 16;
302     buf[0x1f4] = sys_size;
303     buf[0x1f5] = sys_size >> 8;
304     buf[0x1f6] = sys_size >> 16;
305     buf[0x1f7] = sys_size >> 24;
306
307     phi->apicid = xeon_phi_boot_download_apicid_rdf(&boot_registers);
308
309     phi->os_offset = loadoffset;
310     phi->os_size = imgsize;
311
312     XBOOT_DEBUG("Xeon Phi bootloader %s loaded @ 0x%lx size %lu kB\n", bootloader,
313                 loadoffset, imgsize >> 10);
314
315     return SYS_ERR_OK;
316 }
317
318
319 static inline errval_t download_bootloader_vfs(struct xeon_phi *phi, char *bootloader,
320                                                uint8_t use_nfs)
321 {
322    return download_bootloader_generic(phi, bootloader, download_file_vfs, use_nfs);
323 }
324
325 static inline errval_t download_bootloader_tftp(struct xeon_phi *phi, char *bootloader)
326 {
327     return download_bootloader_generic(phi, bootloader, tftp_client_read_file,
328                                        TFTP_BUF_SIZE_MODULES);
329 }
330
331
332 /*
333  * -------------------------------------------------------------------------------
334  * multiboot modules
335  * -------------------------------------------------------------------------------
336  */
337
338 static uint32_t prepare_multiboot_strings(void *strings, char **mods,
339                                           uint32_t num_mods)
340 {
341     uint32_t bytes = 0;
342     for (uint32_t i = 0; i < num_mods; ++i) {
343         bytes += snprintf(strings+bytes, 1<<20, "%s", mods[i]) + 1;
344     }
345     return bytes;
346 }
347
348 static inline char *get_module_path(char *cmdline)
349 {
350     while(*cmdline) {
351         if (isspace((int)*cmdline)) {
352             return cmdline;
353         }
354         cmdline++;
355     }
356     return cmdline;
357 }
358
359 static uint32_t prepare_multiboot_info(void *aptvbase, lpaddr_t offset,
360                                        char **mmaps, uint32_t num_mods,
361                                        uint32_t num_mmaps)
362 {
363     void *mbibuf = aptvbase + offset;
364     /*
365      * Layout of multi boot information on card:
366      * [multiboot_info]
367      * [n x multiboot_modinfo]
368      * [m x multiboot_mmap]
369      * [strings]
370      */
371
372     /* set the host virtual pointers of the multiboot structures */
373     struct multiboot_info *mbi = mbibuf;
374     struct multiboot_modinfo *mbi_mods = (struct multiboot_modinfo *)(mbi + 1);
375     struct multiboot_mmap *mbi_mmaps = (struct multiboot_mmap *)(mbi_mods + num_mods);
376
377     /* card physical modules array */
378     offset += (uint32_t)sizeof(struct multiboot_info);
379     mbi->mods_count = num_mods;
380     mbi->mods_addr = offset;
381
382     /* card physical mmap array */
383     offset += num_mods * (uint32_t)sizeof(struct multiboot_modinfo);
384     mbi->mmap_addr = offset;
385     mbi->mmap_length = num_mmaps * sizeof(struct multiboot_mmap);
386
387     offset += num_mmaps * (uint32_t)sizeof(struct multiboot_mmap);
388
389     /* set the multiboot flags */
390     mbi->flags = MULTIBOOT_INFO_FLAG_HAS_CMDLINE | MULTIBOOT_INFO_FLAG_HAS_MODS
391                     | MULTIBOOT_INFO_FLAG_HAS_ELF_SYMS| MULTIBOOT_INFO_FLAG_HAS_MMAP;
392
393     for (uint32_t i = 0; i < num_mmaps; ++i) {
394         uint32_t parsed = sscanf(mmaps[i],"map%*[ \n\t]%" SCNx64
395                                  "%*[ \n\t]%" SCNx64 "%*[ \n\t]%" SCNu32,
396                                  &mbi_mmaps[i].base_addr,
397                                  &mbi_mmaps[i].length,
398                                  &mbi_mmaps[i].type);
399         if (parsed !=3) {
400             debug_printf("INVALID mmap: {%s}\n", mmaps[i]);
401             mbi_mmaps[i].size = 0;
402             continue;
403         }
404         mbi_mmaps[i].size = sizeof(struct multiboot_mmap);
405     }
406
407     return sizeof(*mbi) + num_mods * sizeof(*mbi_mods) + num_mmaps * sizeof(*mbi_mmaps);
408 }
409
410 static errval_t download_modules_generic(struct xeon_phi *phi, size_t offset,
411                                          char **mods, uint32_t num_mods,
412                                          uint32_t num_mmaps, loadfile_fn_t loadfn,
413                                          size_t args)
414 {
415     errval_t err;
416
417     struct xeon_phi_boot_params *bp;
418     bp = (struct xeon_phi_boot_params *)(phi->apt.vbase + phi->os_offset);
419
420     struct multiboot_info *mbi = (void *)phi->apt.vbase + offset;
421     struct multiboot_modinfo *mbi_mods = (struct multiboot_modinfo *)(mbi + 1);
422
423     bp->ramdisk_image = offset;
424     bp->mbi = offset;
425
426     offset += prepare_multiboot_info((void *)phi->apt.vbase, offset, mods + num_mods,
427                                      num_mods, num_mmaps);
428
429     lpaddr_t strings_offset = offset;
430     offset += prepare_multiboot_strings((void *)phi->apt.vbase + strings_offset,
431                                         mods, num_mods);
432
433     offset = ALIGN(offset);
434
435     for (uint32_t i = 0; i < num_mods; ++i) {
436         char *strings = (void *)phi->apt.vbase + strings_offset;
437         size_t cmdlength = strlen(strings);
438         size_t imgsize = 0;
439         mbi_mods[i].mod_start = offset;
440         mbi_mods[i].string = strings_offset;
441
442         char *delim = get_module_path(mods[i]);
443         *delim = 0;
444
445         err = loadfn(mods[i], (void *)phi->apt.vbase + offset, args, &imgsize);
446         if (err_is_fail(err)) {
447             return err;
448         }
449         mbi_mods[i].mod_end = mbi_mods[i].mod_start + imgsize;
450
451         offset = ALIGN(offset + imgsize);
452
453         XBOOT_DEBUG("module %35s @ 0x08%lx  size %lu kB\n",
454                     (char *)phi->apt.vbase + strings_offset, offset, imgsize >> 10);
455
456         strings_offset += (cmdlength + 1);
457     }
458
459     bp->ramdisk_size = offset - bp->ramdisk_image;
460
461     return SYS_ERR_OK;
462 }
463
464
465 static errval_t download_modules_vfs(struct xeon_phi *phi, size_t offset,
466                                      char **mods, uint32_t num_mods,
467                                      uint32_t num_mmaps, uint8_t use_nfs)
468 {
469     return download_modules_generic(phi, offset, mods, num_mods, num_mmaps,
470                                     download_file_vfs, use_nfs);
471 }
472
473 static errval_t download_modules_tftp(struct xeon_phi *phi, lpaddr_t offset,
474                                       char **mods, uint32_t num_mods,
475                                       uint32_t num_mmaps)
476 {
477     return download_modules_generic(phi, offset, mods, num_mods, num_mmaps,
478                                     tftp_client_read_file, TFTP_BUF_SIZE_MODULES);
479 }
480
481 /*
482  * -------------------------------------------------------------------------------
483  * Parsing modules
484  * -------------------------------------------------------------------------------
485  */
486
487 static inline char *discard_leading_white_spaces(char *string)
488 {
489     while(*string) {
490         if (!isspace((int)*string)) {
491             break;
492         }
493         string++;
494     }
495     return string;
496 }
497
498
499 static errval_t parse_mod_list(char *modules, uint32_t *mods, uint32_t *mmaps,
500                                uint8_t *kernel, char ***parsed_modules)
501 {
502     uint32_t num_mod = 0, num_mmap = 0;
503     uint8_t has_kernel = 0;
504
505     char *line = modules;
506
507     /* how many modules we have */
508     while (line != NULL)
509     {
510         if (*line == '\n') {
511             line++;
512         }
513         if (strncmp(line, "module", 6)==0) {
514             num_mod ++;
515         } else if (strncmp(line, "kernel", 6) == 0) {
516             assert(has_kernel == 0);
517             has_kernel = 1;
518         } else if (strncmp(line, "mmap", 4) == 0) {
519             num_mmap++;
520         }
521         line=strchr(line+1,'\n');
522     }
523
524
525     /* allocate parsed array */
526     char **parsed = calloc(num_mod + num_mmap + 1, sizeof(char *));
527     if (parsed == NULL) {
528         return LIB_ERR_MALLOC_FAIL;
529     }
530
531     uint32_t mod_idx = 1;
532     uint32_t mmap_idx = num_mod + num_mmap;
533     line = modules;
534     while (line != NULL)
535     {
536         if (*line == '\n') {
537             *line = 0;
538             line++;
539         }
540         if (strncmp(line, "module", 6)==0) {
541             parsed[mod_idx++] = discard_leading_white_spaces(line + 6);
542         } else if (strncmp(line, "kernel", 6) == 0) {
543             parsed[0] = discard_leading_white_spaces(line + 6);
544         } else if (strncmp(line, "mmap", 4) == 0) {
545             parsed[mmap_idx--] = discard_leading_white_spaces(line + 4);
546         }
547         line=strchr(line+1,'\n');
548     }
549
550     if (parsed_modules) {
551         *parsed_modules = parsed;
552     } else  {
553         free(parsed_modules);
554     }
555
556     if (mods) {
557         *mods = num_mod;
558     }
559
560     if (mmaps) {
561         *mmaps = num_mmap;
562     }
563
564     if (kernel) {
565         *kernel = has_kernel;
566     }
567
568     XBOOT_DEBUG("parsing modules found: %u kernel, %u modules, %u mmaps\n",
569                 has_kernel, num_mod, num_mmap);
570
571     return SYS_ERR_OK;
572 }
573
574
575 static errval_t load_mod_list_tftp(char *mod_list, void **modules, size_t *size)
576 {
577     errval_t err;
578
579     void *buf = calloc(1, TFTP_BUF_SIZE);
580
581     XBOOT_DEBUG("loading modules list %s over TFTP\n", mod_list);
582
583     err = tftp_client_read_file(mod_list, buf, TFTP_BUF_SIZE, size);
584     if (err_is_fail(err)) {
585         USER_PANIC("reading tftp file");
586     }
587
588     if (modules) {
589         *modules = buf;
590     }
591
592     return SYS_ERR_OK;
593 }
594
595 static errval_t load_mod_list_vfs(char *mod_list, uint8_t use_nfs,
596                                   void **modules, size_t *size)
597 {
598     errval_t err;
599
600     XBOOT_DEBUG("loading modules list %s %s\n", mod_list,
601                 (use_nfs==1 ? "over NFS" : "from ramfs"));
602
603     /* load the menu lst file */
604     vfs_handle_t fh = file_open(mod_list, use_nfs);
605     if (fh == NULL) {
606         return SPAWN_ERR_LOAD;
607     }
608
609     struct vfs_fileinfo info;
610     err = vfs_stat(fh, &info);
611     if (err_is_fail(err)) {
612         vfs_close(fh);
613         return err_push(err, SPAWN_ERR_LOAD);
614     }
615
616     assert(info.type == VFS_FILE);
617
618     char *menulst = calloc(info.size + 1, 1);
619     if (menulst == NULL) {
620         vfs_close(fh);
621         return LIB_ERR_MALLOC_FAIL;
622     }
623
624     err = file_load(fh, menulst, info.size);
625     if (err_is_fail(err)) {
626         USER_PANIC_ERR(err, "file loading failed.\n");
627         vfs_close(fh);
628         free(menulst);
629         return err;
630     }
631
632     if (modules) {
633         *modules = menulst;
634     }
635
636     if (size) {
637         *size = info.size;
638     }
639
640     return SYS_ERR_OK;
641 }
642
643 /**
644  * \brief boots the card with the given loader and multiboot image
645  *
646  * \param phi           pointer to the card information
647  * \param mod_uri       name of to the modules location uri
648  * \param mod_list      name of the modules list
649  */
650 errval_t xeon_phi_boot(struct xeon_phi *phi,
651                        char *mod_uri,
652                        char *mod_list)
653 {
654     errval_t err;
655     lvaddr_t offset;
656
657     xeon_phi_boot_initialize(&boot_registers,
658                              XEON_PHI_MMIO_TO_SBOX(phi),
659                              XEON_PHI_MMIO_TO_DBOX(phi));
660     xeon_phi_apic_initialize(&apic_registers, XEON_PHI_MMIO_TO_SBOX(phi));
661
662     phi->apicid = xeon_phi_boot_download_apicid_rdf(&boot_registers);
663
664     void *modules = NULL;
665     size_t modules_size = 0;
666     uint8_t use_nfs = 0, use_tftp = 0;
667     if (strncmp(mod_uri, "nfs://", 6) == 0) {
668         XBOOT_DEBUG("using nfs share: %s\n", mod_uri);
669         use_nfs = 1;
670         err = load_mod_list_vfs(mod_list, 1, &modules, &modules_size);
671     } else if (strncmp(mod_uri, "tftp://", 7) == 0) {
672         use_tftp = 1;
673         char *del = strchr(mod_uri+7, ':');\
674         uint16_t port = 69; // default tftp port
675         if (del != NULL) {
676             port = atoi(del + 1);
677             *del = 0;
678         }
679
680         XBOOT_DEBUG("using tftp server: %s @ port %u\n", mod_uri + 7, port);
681
682         err = tftp_client_connect(mod_uri + 7, port);
683         if (err_is_fail(err)) {
684             USER_PANIC_ERR(err, "Could not connect to the tftp service");
685         }
686         err = load_mod_list_tftp(mod_list, &modules, &modules_size);
687     } else  {
688         err = load_mod_list_vfs(mod_list, 0, &modules, &modules_size);
689     }
690
691     if (err_is_fail(err)) {
692         USER_PANIC_ERR(err, "failed to load modules list");
693     }
694
695     char **modules_parsed = NULL;
696     uint32_t num_mods = 0, num_mmaps = 0;
697     uint8_t has_kernel = 0;
698     err = parse_mod_list(modules, &num_mods, &num_mmaps, &has_kernel, &modules_parsed);
699     if (err_is_fail(err)) {
700         return err;
701     }
702
703     if (!has_kernel) {
704         return SPAWN_ERR_FIND_MODULE;
705     }
706
707     // load the coprocessor OS (boot loader)
708     if (use_tftp) {
709         err = download_bootloader_tftp(phi, modules_parsed[0]);
710     } else {
711         err = download_bootloader_vfs(phi, modules_parsed[0], use_nfs);
712     }
713     if (err_is_fail(err)) {
714         USER_PANIC_ERR(err, "Could not load bootloader image");
715     }
716
717     // round to next page
718     offset = ALIGN(phi->os_offset + phi->os_size);
719
720     // load cmdline
721     err = load_cmdline(phi, offset);
722     if (err_is_fail(err)) {
723         USER_PANIC_ERR(err, "Could not load multiboot image");
724     }
725
726     // round to next page
727     offset = ALIGN(offset+phi->cmdlen);
728
729     if (use_tftp) {
730         err = download_modules_tftp(phi, offset, modules_parsed + 1, num_mods, num_mmaps);
731     } else {
732         err = download_modules_vfs(phi, offset, modules_parsed + 1, num_mods, num_mmaps, use_nfs);
733     }
734     if (err_is_fail(err)) {
735          USER_PANIC_ERR(err, "Could not load multiboot image");
736     }
737
738     free(modules_parsed);
739
740     if (use_tftp) {
741         tftp_client_disconnect();
742     }
743
744     struct xeon_phi_boot_params *bp;
745     bp = (struct xeon_phi_boot_params *)(phi->apt.vbase + phi->os_offset);
746     bp->xeon_phi_id = 0xFF00;
747     bp->xeon_phi_id += phi->id;
748
749     err = interphi_init(phi, NULL_CAP);
750     if (err_is_fail(err)) {
751         USER_PANIC_ERR(err, "Could not initialize messaging");
752     }
753
754     xeon_phi_boot_download_status_wrf(&boot_registers, 0x0);
755
756     phi->apicid = xeon_phi_boot_download_apicid_rdf(&boot_registers);
757
758     // notify the bootstrap
759     bootstrap_notify(phi);
760
761     xeon_phi_boot_postcode_t postcode;
762     xeon_phi_boot_postcodes_t pc, pc_prev = 0;
763     uint32_t counter = BOOT_COUNTER;
764     while (--counter) {
765         postcode = xeon_phi_boot_postcode_rd(&boot_registers);
766         pc = xeon_phi_boot_postcode_code_extract(postcode);
767         if (pc_prev != pc) {
768             debug_printf("Xeon Phi Booting: %s\n",
769                          xeon_phi_boot_postcodes_describe(pc));
770         }
771         if (postcode == xeon_phi_boot_postcode_done) {
772             break;
773         }
774         pc_prev = pc;
775     }
776
777     XBOOT_DEBUG("Bootstrap has finished execution. Waiting for Firmware...\n");
778
779     uint32_t time = 0, time_steps = 0;
780     while (time < BOOT_TIMEOUT) {
781         /* read all the pending messages */
782         xeon_phi_serial_handle_recv();
783         milli_sleep(100);
784         if (xeon_phi_boot_download_status_rdf(&boot_registers)) {
785             XBOOT_DEBUG("Firmware signaled with ready bit. \n");
786             break;
787         }
788         if (!(time % 50)) {
789             debug_printf("Xeon Phi Booting: Waiting for ready signal %u\n",
790                          time_steps);
791             time_steps += 5;
792         }
793         time++;
794     }
795
796     if (!xeon_phi_boot_download_status_rdf(&boot_registers)) {
797         USER_PANIC("Firmware not responding with ready bit");
798         // TODO return error code
799     }
800
801     // we don't need the aperture mapped anymore so unmap it
802     err = xeon_phi_unmap_aperture(phi);
803     if (err_is_fail(err)) {
804         USER_PANIC_ERR(err, "Failed to map aperture range");
805     }
806
807     return SYS_ERR_OK;
808 }