1/*
2 * M5 boot image tool.
3 *
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdint.h>
9#include <stddef.h>
10#include <stdbool.h>
11#include <string.h>
12#include <assert.h>
13#include <ctype.h>
14#include <inttypes.h>
15#include "elf.h"
16
17
18//XXX: hardcoded start address of ramdisk
19//     has to match the address specified in tools/arm_gem5/gem5script.py
20#define INITRD_BASE			0x10000000
21
22#define MAX_MODULES 256
23
24static char *kernel_symbol_prefix;
25static char *kernel_cmd_line;
26static char *module_symbol_prefix[MAX_MODULES];
27static char *module_cmd_line[MAX_MODULES];
28
29
30static char *get_symbol_name_prefix(char *original) {
31    char *prefix = "_binary__";
32    char *r = malloc(strlen(prefix) + strlen(original) + 1);
33    sprintf(r, "%s%s", prefix, original);
34    for (int i = 0; i < strlen(r); i ++) {
35        if (r[i] == '/') {
36            r[i] = '_';
37        }
38        if (r[i] == '-') {//needed for armv7-m
39            r[i] = '_';
40        }
41    }
42    return r;
43}
44
45int main(int argc, char *argv[])
46{
47    int n_modules = 0;
48    int n_mmaps = 0;
49    bool aarch64 = false;
50
51    if(argc < 3 || (argc == 4 && strcmp("-64", argv[3])
52                              && strcmp("-32", argv[3]))) {
53        printf("Usage: %s <menu.lst> <output.c> [-64|-32]\n", argv[0]);
54        return 0;
55    }
56
57    if(argc >= 4 && !strcmp("-64", argv[3])) aarch64 = true;
58
59    FILE *f = fopen(argv[1], "r");
60    assert((f != NULL) && "Could not open input file");
61
62    FILE *o = fopen(argv[2], "w");
63    assert((o != NULL) && "Could not open output file");
64
65    // Output initial part of file: include basic types etc.
66    fprintf(o, "#include <assert.h>\n");
67    fprintf(o, "#include <stdio.h>\n");
68    fprintf(o, "#include <stdint.h>\n");
69    fprintf(o, "#include <stddef.h>\n");
70    fprintf(o, "#include <string.h>\n");
71    fprintf(o, "#include <barrelfish_kpi/types.h>\n");
72    fprintf(o, "#include <errors/errno.h>\n");
73    fprintf(o, "#include <elf/elf.h>\n");
74    fprintf(o, "#include <multiboot.h>\n");
75
76    // Process menu.lst, generating definitions
77    char cmd[1024], args[1024], image[1024];
78    while(!feof(f)) {
79        char line[1024], *l;
80
81        cmd[0] = args[0] = image[0] = line[0] = '\0';
82
83        l = fgets(line, 1024, f);
84        if (!l) {
85            /* error or EOF, check for EOF with next iteration */
86            continue;
87        }
88        sscanf(line, "%s %s %[^\n]", cmd, image, args);
89
90        if(!strcmp(cmd, "kernel")) {
91            kernel_symbol_prefix = get_symbol_name_prefix(image);
92            kernel_cmd_line = malloc(strlen(line) + 1);
93            sprintf(kernel_cmd_line, "%s %s", image, args);
94            fprintf(o, "extern char %s_start;\n", kernel_symbol_prefix);
95            fprintf(o, "extern char %s_end;\n", kernel_symbol_prefix);
96        } else if(!strcmp(cmd, "module") || !strcmp(cmd, "modulenounzip")) {
97            assert(n_modules < MAX_MODULES);
98            module_symbol_prefix[n_modules] = get_symbol_name_prefix(image);
99            module_cmd_line[n_modules] = malloc(strlen(line) + 1);
100            sprintf(module_cmd_line[n_modules], "%s %s", image, args);
101            fprintf(o, "extern char %s_start;\n", module_symbol_prefix[n_modules]);
102            fprintf(o, "extern char %s_end;\n", module_symbol_prefix[n_modules]);
103            n_modules ++;
104        } else if(!strcmp(cmd, "mmap")) {
105            if(aarch64) {
106                uint64_t base, len;
107                int type;
108                sscanf(args, "%" SCNi64 " %" SCNi64 " %i",
109                        &base, &len, &type);
110                printf("Inserting MMAP %d: [0x%" PRIx64 ", 0x%" PRIx64 "], type %d\n",
111                        n_mmaps, base, len, type);
112                fprintf(o, "static uint64_t mbi_mmap%d[] = {0x%" PRIx64
113                           ", 0x%" PRIx64 ", %d};\n",
114                        n_mmaps, base, len, type);
115            }
116            else {
117                uint32_t base, len;
118                int type;
119                sscanf(args, "%" SCNi32 " %" SCNi32 " %i",
120                        &base, &len, &type);
121                printf("Inserting MMAP %d: [0x%" PRIx32 ", 0x%" PRIx32 "], type %d\n",
122                        n_mmaps, base, len, type);
123                fprintf(o, "static uint32_t mbi_mmap%d[] = {0x%" PRIx32
124                           ", 0x%" PRIx32 ", %d};\n",
125                        n_mmaps, base, len, type);
126            }
127            n_mmaps ++;
128        } else {
129            bool iscmd = false;
130            for(int i = 0; i < strlen(cmd); i++) {
131                if(cmd[i] == '#') {
132                    break;
133                }
134                if(!isspace(cmd[i])) {
135                    iscmd = true;
136                    break;
137                }
138            }
139            if(iscmd) {
140                printf("Ignoring command '%s'\n", cmd);
141            }
142        }
143    }
144
145    // Generate multiboot-structure initialization code
146    fprintf(o, "static struct multiboot_modinfo mbi_mods[%d];\n", n_modules + 1);
147    fprintf(o, "static struct multiboot_mmap mbi_mmaps[%d];\n", n_mmaps);
148    fprintf(o, "static struct multiboot_info mbi;\n\n");
149    fprintf(o, "struct multiboot_info *molly_get_mbi(void) {\n");
150
151    // Initialize all static data structures
152    fprintf(o, "memset(&mbi, 0, sizeof(struct multiboot_info));\n");
153    fprintf(o, "memset(&mbi_mods, 0, sizeof(mbi_mods));\n");
154    fprintf(o, "memset(&mbi_mmaps, 0, sizeof(mbi_mmaps));\n");
155
156    // Flags:
157    fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_CMDLINE;\n");
158    fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_MODS;\n");
159    fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_ELF_SYMS;\n");
160    fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_MMAP;\n");
161
162    // Kernel command line:
163    if(aarch64)
164        fprintf(o, "  mbi.cmdline = (uint64_t) \"%s\";\n", kernel_cmd_line);
165    else
166        fprintf(o, "  mbi.cmdline = (uint32_t) \"%s\";\n", kernel_cmd_line);
167
168    // Modules:
169    fprintf(o, "  mbi.mods_count = %d;\n", n_modules + 1);
170    if(aarch64) {
171        fprintf(o, "  mbi.mods_addr = (uint64_t) mbi_mods;\n");
172        fprintf(o, "  mbi_mods[0].mod_start = (uint64_t) &%s_start;\n",
173                kernel_symbol_prefix);
174        fprintf(o, "  mbi_mods[0].mod_end = (uint64_t) &%s_end;\n",
175                kernel_symbol_prefix);
176        fprintf(o, "  mbi_mods[0].string = (uint64_t)\"%s\";\n",
177                kernel_cmd_line);
178
179        for (int i = 0; i < n_modules; i ++) {
180            fprintf(o, "  mbi_mods[%d].mod_start = (uint64_t) &%s_start;\n",
181                    i+1, module_symbol_prefix[i]);
182            fprintf(o, "  mbi_mods[%d].mod_end = (uint64_t) &%s_end;\n",
183                    i+1, module_symbol_prefix[i]);
184            fprintf(o, "  mbi_mods[%d].string = (uint64_t) \"%s\";\n",
185                    i+1, module_cmd_line[i]);
186        }
187    } else {
188        fprintf(o, "  mbi.mods_addr = (uint32_t) mbi_mods;\n");
189        fprintf(o, "  mbi_mods[0].mod_start = (uint32_t) &%s_start;\n",
190                kernel_symbol_prefix);
191        fprintf(o, "  mbi_mods[0].mod_end = (uint32_t) &%s_end;\n",
192                kernel_symbol_prefix);
193        fprintf(o, "  mbi_mods[0].string = (uint32_t)\"%s\";\n",
194                kernel_cmd_line);
195
196        for (int i = 0; i < n_modules; i ++) {
197            fprintf(o, "  mbi_mods[%d].mod_start = (uint32_t) &%s_start;\n",
198                    i+1, module_symbol_prefix[i]);
199            fprintf(o, "  mbi_mods[%d].mod_end = (uint32_t) &%s_end;\n",
200                    i+1, module_symbol_prefix[i]);
201            fprintf(o, "  mbi_mods[%d].string = (uint32_t) \"%s\";\n",
202                    i+1, module_cmd_line[i]);
203        }
204    }
205
206    // MMAPS:
207    fprintf(o, "  mbi.mmap_length = sizeof(mbi_mmaps);\n");
208    if(aarch64)
209        fprintf(o, "  mbi.mmap_addr = (uint64_t) mbi_mmaps;\n");
210    else
211        fprintf(o, "  mbi.mmap_addr = (uint32_t) mbi_mmaps;\n");
212    for (int i = 0; i < n_mmaps; i ++) {
213        fprintf(o, "  mbi_mmaps[%d].size = sizeof(struct multiboot_mmap);\n", i);
214        fprintf(o, "  mbi_mmaps[%d].base_addr = mbi_mmap%d[0];\n", i, i);
215        fprintf(o, "  mbi_mmaps[%d].length = mbi_mmap%d[1];\n", i, i);
216        fprintf(o, "  mbi_mmaps[%d].type = (int)mbi_mmap%d[2];\n", i, i);
217    }
218    fprintf(o, "  return &mbi;\n");
219    fprintf(o, "}\n\n");
220
221    fclose(f);
222    fclose(o);
223
224    return 0;
225}
226