Apparently kvmarm@ is the place for boot-wrapper discussions so apologies for the otherwise Xen related mail ;) The following implements support for a very basic protocol for loading multiple "modules" and providing them to the kernel. The ARM port of Xen uses this to support passing both a dom0 kernel and initrd to the hypervisor "kernel". The Xen side of this can be found in the series at: http://lists.xen.org/archives/html/xen-devel/2012-09/msg00065.html With that you can boot Xen on arm using the semi-hosting feature of the model (paths are host paths): $MODEL linux-system-semi.axf -C cluster.cpu0.semihosting-cmd_line=\ ''--kernel xen-arm.bin \ --module zImage earlyprintk=xenboot console=ttyAMA1 root=/dev/mmcblk0 ro \ --dtb vexpress-v2p-aem-v7a-xen.dtb -- dom0_mem=256M'' Until we know what bootloaders are going to become common in the ARM servers world it hard to know who we should be working with to define a proper protocol going forward and which bootloaders to supply patches for etc. If anyone has any pointers that would be very useful. One thing I''ve been considering is a port of the multiboot protocol[0] used on x86 to ARM. It seems like there is at least the kernel of an idea to port Grub2 to ARM[1] which makes a port of multiboot as well seem like a reasonable thing since grub is the reference implementation of the multiboot spec. Ian. [0] http://www.gnu.org/software/grub/manual/multiboot/multiboot.html [1] https://wiki.linaro.org/OfficeofCTO/Grub2 8<-------------------------------------------- From bb3c6184beb57ba2649970b8e8568b29c0720294 Mon Sep 17 00:00:00 2001 From: Ian Campbell <ian.campbell@citrix.com> Date: Thu, 23 Aug 2012 14:56:26 +0000 Subject: [PATCH] Implement simple multi-module support. This implementation supports up to 2 modules, each with its own command line. --- semi_loader.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- semi_loader.h | 16 +++++++- semihosting.h | 7 +++ 3 files changed, 146 insertions(+), 6 deletions(-) diff --git a/semi_loader.c b/semi_loader.c index 6677527..348a394 100644 --- a/semi_loader.c +++ b/semi_loader.c @@ -46,6 +46,7 @@ static void _print_info(char const **strings) #define CMDLINE_KERNEL "--kernel" #define CMDLINE_INITRD "--initrd" +#define CMDLINE_MODULE "--module" #define CMDLINE_NOINITRD "--no-initrd" #define CMDLINE_DTB "--dtb" #define CMDLINE_FDT "--fdt" /* deprecated */ @@ -99,7 +100,7 @@ static int _fdt_make_node(void *fdt, int parentoffset, const char *name) static void update_fdt(void **dest, struct loader_info *info) { - int e; + int e, m; int _chosen; void *fdt; uint32_t const *p; @@ -184,6 +185,31 @@ no_add_memory: if(e < 0) goto libfdt_error; + /* XXX this should be a loop & some string munging in lieu of printf */ + if(info->nr_modules > 0) { + if ((e = fdt_setprop_cell(fdt, _chosen, "module1-start", + info->module[0].start)) < 0) + goto libfdt_error; + if ((e = fdt_setprop_cell(fdt, _chosen, "module1-end", + info->module[0].end)) < 0) + goto libfdt_error; + if ((e = fdt_setprop_string(fdt, _chosen, "module1-args", + info->module[0].args)) < 0) + goto libfdt_error; + } + if(info->nr_modules > 1) { + if ((e = fdt_setprop_cell(fdt, _chosen, "module2-start", + info->module[1].start)) < 0) + goto libfdt_error; + if ((e = fdt_setprop_cell(fdt, _chosen, "module2-end", + info->module[1].end)) < 0) + goto libfdt_error; + if ((e = fdt_setprop_string(fdt, _chosen, "module2-args", + info->module[1].args)) < 0) + goto libfdt_error; + } + + if(info->initrd_start) { uint32_t initrd_end = info->initrd_start + info->initrd_size; @@ -196,6 +222,12 @@ no_add_memory: goto libfdt_error; } + if (info->nr_modules > 0) { + if ((e = fdt_setprop_cell(fdt, _chosen, "nr-modules", + info->nr_modules)) < 0) + goto libfdt_error; + } + /* success */ /* clean up */ @@ -234,6 +266,18 @@ static void find_space(char **s) *s = t; } +static void find_delim(char **s, char const *delim) +{ + int l = strlen(delim); + char *t = *s; + while (*t) { + if (!strncmp(t, delim, l)) + break; + t++; + } + *s = t; +} + static int match_word(char **s, char const *string) { unsigned l; @@ -260,7 +304,7 @@ static char *match_option(char **s, char const *option_string) return (void *)0; if(!**s) - usage_fatal("Option requires as argument: ", + usage_fatal("Option requires an argument: ", option_string, "\n"); /* otherwise, *s now points to the argument */ @@ -275,6 +319,42 @@ static char *match_option(char **s, char const *option_string) return arg; } +/* Match up to the next -- */ +static int match_module_arg(char **s, + char const *option_string, + int no_more_room, + char **mod, char **args) +{ + char *arg; + if(!match_word(s, option_string)) + return 0; + + if(!**s) + usage_fatal("Option requires an argument: ", + option_string, "\n"); + + if ( no_more_room ) + usage_fatal("Too many modules\n"); + + /* *s points to the module */ + *mod = *s; + + find_space(s); + if(**s) { + *(*s)++ = ''\0''; /* null-terminate if necessary */ + skip_space(s); /* skip any remaining space */ + } + + /* Now find the (optional) module arguments */ + arg = *s; + find_delim(s, "--"); + if (**s) + *((*s)-1) = ''\0''; /* null-terminate if necessary */ + if (arg != *s) + *args = arg; + return 1; +} + static void load_file_essential(void **dest, char const *filename, unsigned *size, char const *failmsg) { @@ -331,17 +411,23 @@ static char *fdt_arg = (void *)0; static char *dtb_arg = (void *)0; static char *cmdline_arg = (void *)0; static char *noinitrd_arg = (void *)0; +static struct module_arg_t { + char *mod; + char *args; +} module_args[MODULES_MAX]; +int nr_modules = 0; static const struct { char const *option_string; char **argp; - enum { OPT_ARG, OPT_BOOL, OPT_REST } action; + enum { OPT_ARG, OPT_BOOL, OPT_MODULE, OPT_REST } action; } options[] = { { CMDLINE_KERNEL, &kernel_arg, OPT_ARG }, { CMDLINE_INITRD, &initrd_arg, OPT_ARG }, { CMDLINE_NOINITRD, &noinitrd_arg, OPT_BOOL }, { CMDLINE_FDT, &fdt_arg, OPT_ARG }, { CMDLINE_DTB, &dtb_arg, OPT_ARG }, + { CMDLINE_MODULE, NULL, OPT_MODULE }, { CMDLINE_REST, &cmdline_arg, OPT_REST }, }; @@ -391,8 +477,19 @@ void load_kernel(struct loader_info *info) options[i].option_string)) continue; - *options[i].argp = cmdline; - goto args_done; + *options[i].argp = cmdline; + goto args_done; + + case OPT_MODULE: + if (!match_module_arg(&cmdline, + options[i].option_string, + nr_modules >= MODULES_MAX, + &module_args[nr_modules].mod, + &module_args[nr_modules].args)) + continue; + + nr_modules++; + goto next_arg; case OPT_ARG: arg = match_option(&cmdline, @@ -420,6 +517,11 @@ args_done: if(initrd_arg && noinitrd_arg) usage_fatal("Option --initrd conflicts with --no-initrd.\n"); + if (initrd_arg && nr_modules) + usage_fatal("Option --initrd and --modules conflict\n"); + if (noinitrd_arg && nr_modules) + usage_fatal("Option --no-initrd and --modules conflict\n"); + if(fdt_arg) { warn("--fdt is deprecated. Please use --dtb instead.\n"); @@ -462,6 +564,23 @@ args_done: } else usage_fatal("Expected " CMDLINE_KERNEL "\n"); + phys = PHYS_OFFSET + MODULES_OFFSET; + for (i = 0 ; i < nr_modules; i++) + { + unsigned size; + + phys = ALIGN(phys, MODULES_ALIGN); + + info->module[i].start = (unsigned)phys; + + load_file_essential(&phys, module_args[i].mod, &size, + "Failed to load module image"); + info("Loaded module: ", module_args[i].mod, "\n"); + info->module[i].end = (unsigned)phys; + info->module[i].args = module_args[i].args; + } + info->nr_modules = nr_modules; + /* move the kernel to the correct place, if necessary */ correct_kernel_location(info); diff --git a/semi_loader.h b/semi_loader.h index 6d9d565..a3a486a 100644 --- a/semi_loader.h +++ b/semi_loader.h @@ -57,7 +57,11 @@ static const char uImage_magic[] = { #define PHYS_OFFSET 0x80000000 #define PHYS_SIZE 0x80000000 /* can limit on kernel cmdline if necessary */ #define ATAGS_OFFSET 0x100 -#define TEXT_OFFSET 0x200000 +#define TEXT_OFFSET 0x200000 +#define MODULES_OFFSET 0xA00000 + +#define MODULES_ALIGN 0x1000 /* Modules are 4K aligned */ + #define INITRD_OFFSET 0xD00000 /* qemu uses the same random offset */ #define FDT_SIZE_MAX 0x10000 /* maximum size allowed for device tree blob */ @@ -71,6 +75,13 @@ static const char uImage_magic[] = { #define ALIGN_INT(n, size) (((n) + ((size) - 1)) & ~((size) - 1)) #define ALIGN(p, size) ((void *)ALIGN_INT((unsigned)(p), size)) +#define MODULES_MAX 2 +struct module_t { + unsigned start; + unsigned end; + char *args; +}; + struct loader_info { unsigned kernel_size; /* nonzero indicates preloaded kernel size */ unsigned initrd_start; /* start of preloaded initrd, if any */ @@ -78,6 +89,9 @@ struct loader_info { unsigned cmdline_start; /* start of cmdline buffer */ unsigned cmdline_size; + struct module_t module[MODULES_MAX]; + int nr_modules; + /* The remaining fields are set by the loader: */ /* There could be a built-in FDT, but currently that it not supported */ diff --git a/semihosting.h b/semihosting.h index 40817c2..baad318 100644 --- a/semihosting.h +++ b/semihosting.h @@ -45,6 +45,13 @@ void semi_exit(void); /* semi_load_file: *dest is advanced to point to the end of the loaded data */ int semi_load_file(void **dest, unsigned *size, char const *filename); +/* Trigger a break point in the fast model... */ +#define MODEL_BKPT() asm volatile(\ + "mov r0, #0x18;\n /* angel_SWIreason_ReportException */\n"\ + "mov r1, #0x20000;/* 0x20020= ADP_Stopped_BreakPoint */\n"\ + "orr r1, r1, #0x20;\n"\ + "swi 0x123456;\n" ::: "r0", "r1") + #endif /* ! __ASSEMBLER__ */ #endif /* ! SEMIHOSTING_H */ -- 1.7.9.1