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