1/*
2 * M5 boot image tool.
3 *
4 * Molly: a fish that starts with an "M" and has 5 letters in it.
5 *
6 * This file processes a menu.lst to generate C definitions for the
7 * multiboot structures.  It refers to additional object files
8 * which contain the contents of the kernel and modules as blobs of
9 * data.  (Generated using objcopy via build_data_files.sh)
10 *
11 * The resulting files are then linked against molly_boot.S,
12 * molly_init.c, and an ELF loader.  This results in a single kernel
13 * image that M5 can boot.
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <stdint.h>
19#include <stddef.h>
20#include <stdbool.h>
21#include <string.h>
22#include <assert.h>
23#include <ctype.h>
24#include <inttypes.h>
25#include "elf.h"
26
27#define MAX_MODULES 256
28
29static char *kernel_symbol_prefix;
30static char *kernel_cmd_line;
31static char *module_symbol_prefix[MAX_MODULES];
32static char *module_cmd_line[MAX_MODULES];
33
34static char *get_symbol_name_prefix(char *original) {
35  char *prefix = "_binary__";
36  char *r = malloc(strlen(prefix) + strlen(original) + 1);
37  sprintf(r, "%s%s", prefix, original);
38  for (int i = 0; i < strlen(r); i ++) {
39    if (r[i] == '/') {
40      r[i] = '_';
41    }
42  }
43  return r;
44}
45
46int main(int argc, char *argv[])
47{
48  int got_kernel = 0;
49  int n_modules = 0;
50  int n_mmaps = 0;
51
52  if(argc < 3) {
53    printf("Usage: %s <menu.lst> <output.c>\n", argv[0]);
54    return 0;
55  }
56
57  FILE *f = fopen(argv[1], "r");
58  assert((f != NULL) && "Could not open input file");
59
60  FILE *o = fopen(argv[2], "w");
61  assert((o != NULL) && "Could not open output file");
62
63  // Output initial part of file: include basic types etc.
64  fprintf(o, "#include <assert.h>\n");
65  fprintf(o, "#include <stdio.h>\n");
66  fprintf(o, "#include <stdint.h>\n");
67  fprintf(o, "#include <stddef.h>\n");
68  fprintf(o, "#include <string.h>\n");
69  fprintf(o, "#include <barrelfish_kpi/types.h>\n");
70  fprintf(o, "#include <errors/errno.h>\n");
71  fprintf(o, "#include <elf/elf.h>\n");
72  fprintf(o, "#include <multiboot.h>\n");
73
74  // Process menu.lst, generating definitions
75  char cmd[1024], args[1024], image[1024];
76  while(!feof(f)) {
77    char line[1024];
78
79    cmd[0] = args[0] = image[0] = line[0] = '\0';
80
81    fgets(line, 1024, f);
82    sscanf(line, "%s %s %[^\n]", cmd, image, args);
83
84    if(!strcmp(cmd, "kernel")) {
85      kernel_symbol_prefix = get_symbol_name_prefix(image);
86      kernel_cmd_line = malloc(strlen(line) + 1);
87      sprintf(kernel_cmd_line, "%s %s", image, args);
88      fprintf(o, "extern char %s_start;\n", kernel_symbol_prefix);
89      fprintf(o, "extern char %s_end;\n", kernel_symbol_prefix);
90      got_kernel = 1;
91    } else if(!strcmp(cmd, "module")) {
92      assert(n_modules < MAX_MODULES);
93      module_symbol_prefix[n_modules] = get_symbol_name_prefix(image);
94      module_cmd_line[n_modules] = malloc(strlen(line) + 1);
95      sprintf(module_cmd_line[n_modules], "%s %s", image, args);
96      fprintf(o, "extern char %s_start;\n", module_symbol_prefix[n_modules]);
97      fprintf(o, "extern char %s_end;\n", module_symbol_prefix[n_modules]);
98      n_modules ++;
99    } else if(!strcmp(cmd, "mmap")) {
100      uint64_t base, len;
101      int type;
102      sscanf(args, "%" SCNi64 " %" SCNi64 " %i",
103             &base, &len, &type);
104      printf("Inserting MMAP %d: [0x%" PRIx64 ", 0x%" PRIx64 "], type %d\n",
105             n_mmaps, base, len, type);
106      fprintf(o, "static uint64_t mbi_mmap%d[] = {0x%llx, 0x%llx, %d};\n",
107              n_mmaps, base, len, type);
108      n_mmaps ++;
109    } else {
110      bool iscmd = false;
111      for(int i = 0; i < strlen(cmd); i++) {
112        if(cmd[i] == '#') {
113          break;
114        }
115        if(!isspace(cmd[i])) {
116          iscmd = true;
117          break;
118        }
119      }
120      if(iscmd) {
121        printf("Ignoring command '%s'\n", cmd);
122      }
123    }
124  }
125
126  // Generate multiboot-structure initialization code
127  fprintf(o, "static struct multiboot_modinfo mbi_mods[%d];\n", n_modules + 1);
128  fprintf(o, "static struct multiboot_mmap mbi_mmaps[%d];\n", n_mmaps);
129  fprintf(o, "static struct multiboot_info mbi;\n\n");
130  fprintf(o, "struct multiboot_info *molly_get_mbi(void) {\n");
131
132  // Flags:
133  fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_CMDLINE;\n");
134  fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_MODS;\n");
135  fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_ELF_SYMS;\n");
136  fprintf(o, "  mbi.flags |= MULTIBOOT_INFO_FLAG_HAS_MMAP;\n");
137
138  // Kernel command line:
139  fprintf(o, "  mbi.cmdline = (uint32_t)(uint64_t) \"%s\";\n", kernel_cmd_line);
140
141  // Modules:
142  fprintf(o, "  mbi.mods_count = %d;\n", n_modules + 1);
143  fprintf(o, "  mbi.mods_addr = (uint32_t)(uint64_t) mbi_mods;\n");
144  fprintf(o, "  mbi_mods[0].mod_start = (uint32_t)(uint64_t) &%s_start;\n",
145	  kernel_symbol_prefix);
146  fprintf(o, "  mbi_mods[0].mod_end = (uint32_t)(uint64_t) &%s_end;\n",
147	  kernel_symbol_prefix);
148  fprintf(o, "  mbi_mods[0].string = (uint32_t)(uint64_t) \"%s\";\n",
149	  kernel_cmd_line);
150
151  for (int i = 0; i < n_modules; i ++) {
152    fprintf(o, "  mbi_mods[%d].mod_start = (uint32_t)(uint64_t) &%s_start;\n",
153	    i+1, module_symbol_prefix[i]);
154    fprintf(o, "  mbi_mods[%d].mod_end = (uint32_t)(uint64_t) &%s_end;\n",
155	    i+1, module_symbol_prefix[i]);
156    fprintf(o, "  mbi_mods[%d].string = (uint32_t)(uint64_t) \"%s\";\n",
157	    i+1, module_cmd_line[i]);
158  }
159
160  // MMAPS:
161  fprintf(o, "  mbi.mmap_length = sizeof(mbi_mmaps);\n");
162  fprintf(o, "  mbi.mmap_addr = (uint32_t)(uint64_t) mbi_mmaps;\n");
163  for (int i = 0; i < n_mmaps; i ++) {
164    fprintf(o, "  mbi_mmaps[%d].size = sizeof(struct multiboot_mmap);\n", i);
165    fprintf(o, "  mbi_mmaps[%d].base_addr = mbi_mmap%d[0];\n", i, i);
166    fprintf(o, "  mbi_mmaps[%d].length = mbi_mmap%d[1];\n", i, i);
167    fprintf(o, "  mbi_mmaps[%d].type = (int)mbi_mmap%d[2];\n", i, i);
168  }
169  fprintf(o, "  return &mbi;\n");
170  fprintf(o, "}\n\n");
171
172  fclose(f);
173  fclose(o);
174
175  return 0;
176}
177