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