summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2006-10-06 12:27:59 +0900
committerSimon Horman <horms@verge.net.au>2006-10-06 12:46:17 +0900
commit16ec25bd77ba2c4ff1793bd588d5c87fc310485e (patch)
treebda528028de8f6b98dc42448e6d1f56bd416e4b0
parente90343c521b68237c17ea4e4ed376c4a726f0789 (diff)
ia64-vmm
This adds vmm support to kexec-tool for ia64. This is annalogous to the same feature that is present in the latest version of elilo. It is a method of booting a vmm (hypervisor) such as Xen. Essentially it works as follows. * If the --vmm argument is not provided, then the kernel is booted as normal, no changes * Else, the image specified by --vmm is placed loaded into the elf segments, where the Linux kernel image would otherwise have gone. And the Linux kernel image, allong with its length is loaded into a seprate segment, and passed as new entry at the end of the boot parameters. This is somewhat similar to how initramfs/initramd images are passed to a booting kernel, and can work in conjunction with that feature. On boot (or in this case on kexec) the vmm (hypervisor) will be loaded instead of a Linux kernel, and the hypervisor will then load up the Linux kernel as it sees fit. This is needed in order for kexec from Xen to Xen, using the port of kexec to Xen that I am working on, to work. I am not entirely fond of this design, and i think that developing an ia64 variant of multiboot would be much nicer. However it is an existing method that is currently in widespread use through its incarntation in elilo. And if multiboot is added in future, it can be done as a separate boot method, and thus orthogonal to this patch. In order to use this code a number of other changes are needed, in particular: 1. Xen and the corresponding Linux Kernel needs to be patched with the port of kexec to ia64-xen that I have been working on. I will post the latest version of these patches to xen-devel shortly. 2. The currently hardcoded PAGE_OFFSET value in purgatory needs to be changed from the Linux value to the Xen value. I will post a very hackish, definately not to be released, patch after this patch which includes a comment that explains this problem more clearly. Also, xen->linux and linux->xen is still very much work in progress due to the problem described at the following link http://permalink.gmane.org/gmane.linux.ports.ia64/14995 However, from an infastructure point of view I think it would be good to apply this code, so that kexec-tool is one step closer to being able to support vmms (hypervisors). The patch does not alter any existing behaviour, it just adds a new feature. Bugs asside, the only real danger seems to be confusion for end-users, perhaps we could comment out the help text to hide the feature from the lay user, or attach a big fat warning to it. Signed-Off-By: Simon Horman <horms@verge.net.au>
-rw-r--r--kexec/arch/ia64/kexec-elf-ia64.c37
-rw-r--r--purgatory/arch/ia64/entry.S4
-rw-r--r--purgatory/arch/ia64/purgatory-ia64.c7
3 files changed, 40 insertions, 8 deletions
diff --git a/kexec/arch/ia64/kexec-elf-ia64.c b/kexec/arch/ia64/kexec-elf-ia64.c
index 349c812..3c1b1c2 100644
--- a/kexec/arch/ia64/kexec-elf-ia64.c
+++ b/kexec/arch/ia64/kexec-elf-ia64.c
@@ -79,7 +79,8 @@ void elf_ia64_usage(void)
printf(
" --command-line=STRING Set the kernel command line to STRING.\n"
" --append=STRING Set the kernel command line to STRING.\n"
- " --initrd=FILE Use FILE as the kernel's initial ramdisk.\n");
+ " --initrd=FILE Use FILE as the kernel's initial ramdisk.\n"
+ " --vmm=FILE Use FILE as the kernel image for a virtual machine monitor (aka hypervisor)\n");
}
/* Move the crash kerenl physical offset to reserved region
@@ -108,12 +109,12 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
struct kexec_info *info)
{
struct mem_ehdr ehdr;
- const char *command_line, *ramdisk=0;
+ const char *command_line, *ramdisk=0, *vmm=0, *kernel_buf;
char *ramdisk_buf = NULL;
- off_t ramdisk_size = 0;
+ off_t ramdisk_size = 0, kernel_size;
unsigned long command_line_len;
unsigned long entry, max_addr, gp_value;
- unsigned long command_line_base, ramdisk_base;
+ unsigned long command_line_base, ramdisk_base, image_base;
unsigned long efi_memmap_base, efi_memmap_size;
unsigned long boot_param_base;
unsigned long noio=0;
@@ -123,12 +124,14 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
#define OPT_APPEND (OPT_ARCH_MAX+0)
#define OPT_RAMDISK (OPT_ARCH_MAX+1)
#define OPT_NOIO (OPT_ARCH_MAX+2)
+#define OPT_VMM (OPT_ARCH_MAX+3)
static const struct option options[] = {
KEXEC_ARCH_OPTIONS
{"command-line", 1, 0, OPT_APPEND},
{"append", 1, 0, OPT_APPEND},
{"initrd", 1, 0, OPT_RAMDISK},
{"noio", 1, 0, OPT_NOIO},
+ {"vmm", 1, 0, OPT_VMM},
{0, 0, 0, 0},
};
@@ -154,6 +157,9 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
case OPT_NOIO: /* disable PIO and MMIO in purgatory code*/
noio = 1;
break;
+ case OPT_VMM:
+ vmm = optarg;
+ break;
}
}
command_line_len = 0;
@@ -161,8 +167,15 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
command_line_len = strlen(command_line) + 16;
}
+ if (vmm)
+ kernel_buf = slurp_decompress_file(vmm, &kernel_size);
+ else {
+ kernel_buf = buf;
+ kernel_size = len;
+ }
+
/* Parse the Elf file */
- result = build_elf_exec_info(buf, len, &ehdr, 0);
+ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0);
if (result < 0) {
fprintf(stderr, "ELF parse failed\n");
free_elf_info(&ehdr);
@@ -172,7 +185,8 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
if (info->kexec_flags & KEXEC_ON_CRASH ) {
if ((mem_min == 0x00) && (mem_max = ULONG_MAX)) {
fprintf(stderr, "Failed to find crash kernel region in /proc/iomem\n");
- return -1;
+ free_elf_info(&ehdr);
+ return -1;
}
move_loaded_segments(info, &ehdr);
}
@@ -228,7 +242,7 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
char *cmdline = xmalloc(command_line_len);
strcpy(cmdline, command_line);
- if (info->kexec_flags & KEXEC_ON_CRASH) {
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
char buf[128];
sprintf(buf," max_addr=%lluM min_addr=%lluM",
mem_max>>20, mem_min>>20);
@@ -259,6 +273,15 @@ int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
&ramdisk_size, sizeof(long));
}
+ if (vmm) {
+ image_base = add_buffer(info, buf, len, len,
+ getpagesize(), 0, max_addr, -1);
+ elf_rel_set_symbol(&info->rhdr, "__vmcode_base",
+ &image_base, sizeof(long));
+ elf_rel_set_symbol(&info->rhdr, "__vmcode_size",
+ &len, sizeof(long));
+ }
+
gp_value = info->rhdr.rel_addr + 0x200000;
elf_rel_set_symbol(&info->rhdr, "__gp_value", &gp_value,
sizeof(gp_value));
diff --git a/purgatory/arch/ia64/entry.S b/purgatory/arch/ia64/entry.S
index 2cc8302..f05434f 100644
--- a/purgatory/arch/ia64/entry.S
+++ b/purgatory/arch/ia64/entry.S
@@ -42,7 +42,7 @@ purgatory_start:
alloc r2 = ar.pfs, 0, 0, 2, 0
;;
mov out0=r28
- movl out1=__ramdisk_base;;
+ movl out1=__vmcode_base;
br.call.sptk.many b0=ia64_env_setup
movl r10=__kernel_entry;;
ld8 r14=[r10];;
@@ -57,6 +57,8 @@ purgatory_start:
.endp purgatory_start
DECLARE_DATA8(__kernel_entry)
+DECLARE_DATA8(__vmcode_base)
+DECLARE_DATA8(__vmcode_size)
DECLARE_DATA8(__ramdisk_base)
DECLARE_DATA8(__ramdisk_size)
DECLARE_DATA8(__command_line)
diff --git a/purgatory/arch/ia64/purgatory-ia64.c b/purgatory/arch/ia64/purgatory-ia64.c
index 312cdcc..bd54946 100644
--- a/purgatory/arch/ia64/purgatory-ia64.c
+++ b/purgatory/arch/ia64/purgatory-ia64.c
@@ -106,6 +106,9 @@ struct ia64_boot_param {
the fpswa interface */
uint64_t initrd_start;
uint64_t initrd_size;
+
+ uint64_t vmcode_start;
+ uint64_t vmcode_size;
};
typedef struct {
@@ -124,6 +127,8 @@ struct loaded_segment {
};
struct kexec_boot_params {
+ uint64_t vmcode_base;
+ uint64_t vmcode_size;
uint64_t ramdisk_base;
uint64_t ramdisk_size;
uint64_t command_line;
@@ -275,6 +280,8 @@ ia64_env_setup(struct ia64_boot_param *boot_param,
new_boot_param->console_info.orig_y = 0;
new_boot_param->initrd_start = params->ramdisk_base;
new_boot_param->initrd_size = params->ramdisk_size;
+ new_boot_param->vmcode_start = params->vmcode_base;
+ new_boot_param->vmcode_size = params->vmcode_size;
}
/* This function can be used to execute after the SHA256 verification. */