|
|
5d197d9 |
--- xen-unstable-16606.orig/tools/ioemu/hw/pc.c 2007-12-18 14:15:17.000000000 -0500
|
|
|
5d197d9 |
+++ xen-unstable-16606/tools/ioemu/hw/pc.c 2007-12-18 23:53:56.000000000 -0500
|
|
|
5d197d9 |
@@ -417,6 +417,90 @@ static void generate_bootsect(uint32_t g
|
|
|
5d197d9 |
bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
|
|
|
5d197d9 |
}
|
|
|
5d197d9 |
|
|
|
5d197d9 |
+/*
|
|
|
5d197d9 |
+ * Evil helper for non-relocatable kernels
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * So it works out like this:
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * 0x100000 - Xen HVM firmware lives here. Kernel wants to boot here
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * You can't both live there and HVM firmware is needed first, thus
|
|
|
5d197d9 |
+ * our plan is
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * 0x200000 - kernel is loaded here by QEMU
|
|
|
5d197d9 |
+ * 0x200000+kernel_size - helper code is put here by QEMU
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * code32_switch in kernel header is set to point at out helper
|
|
|
5d197d9 |
+ * code at 0x200000+kernel_size
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * Our helper basically does memmove(0x100000,0x200000,kernel_size)
|
|
|
5d197d9 |
+ * and then jmps to 0x1000000.
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * So we've overwritten the HVM firmware (which was no longer
|
|
|
5d197d9 |
+ * needed) and the non-relocatable kernel can happily boot
|
|
|
5d197d9 |
+ * at its usual address.
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * Simple, eh ?
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * Well the assembler needed to do this is fairly short:
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * # Load segments
|
|
|
5d197d9 |
+ * cld
|
|
|
5d197d9 |
+ * cli
|
|
|
5d197d9 |
+ * movl $0x18,%eax
|
|
|
5d197d9 |
+ * mov %ax,%ds
|
|
|
5d197d9 |
+ * mov %ax,%es
|
|
|
5d197d9 |
+ * mov %ax,%fs
|
|
|
5d197d9 |
+ * mov %ax,%gs
|
|
|
5d197d9 |
+ * mov %ax,%ss
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * # Move the kernel into position
|
|
|
5d197d9 |
+ * xor %edx,%edx
|
|
|
5d197d9 |
+ *_doloop:
|
|
|
5d197d9 |
+ * movzbl 0x600000(%edx),%eax
|
|
|
5d197d9 |
+ * mov %al,0x100000(%edx)
|
|
|
5d197d9 |
+ * add $0x1,%edx
|
|
|
5d197d9 |
+ * cmp $0x500000,%edx
|
|
|
5d197d9 |
+ * jne _doloop
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ * # start kernel
|
|
|
5d197d9 |
+ * xorl %ebx,%ebx
|
|
|
5d197d9 |
+ * mov $0x100000,%ecx
|
|
|
5d197d9 |
+ * jmp *%ecx
|
|
|
5d197d9 |
+ *
|
|
|
5d197d9 |
+ */
|
|
|
5d197d9 |
+static void setup_relocator(target_phys_addr_t addr, target_phys_addr_t src, target_phys_addr_t dst, size_t len)
|
|
|
5d197d9 |
+{
|
|
|
5d197d9 |
+ /* Now this assembler corresponds to follow machine code, with our args from QEMU spliced in :-) */
|
|
|
5d197d9 |
+ unsigned char buf[] = {
|
|
|
5d197d9 |
+ /* Load segments */
|
|
|
5d197d9 |
+ 0xfc, /* cld */
|
|
|
5d197d9 |
+ 0xfa, /* cli */
|
|
|
5d197d9 |
+ 0xb8, 0x18, 0x00, 0x00, 0x00, /* mov $0x18,%eax */
|
|
|
5d197d9 |
+ 0x8e, 0xd8, /* mov %eax,%ds */
|
|
|
5d197d9 |
+ 0x8e, 0xc0, /* mov %eax,%es */
|
|
|
5d197d9 |
+ 0x8e, 0xe0, /* mov %eax,%fs */
|
|
|
5d197d9 |
+ 0x8e, 0xe8, /* mov %eax,%gs */
|
|
|
5d197d9 |
+ 0x8e, 0xd0, /* mov %eax,%ss */
|
|
|
5d197d9 |
+ 0x31, 0xd2, /* xor %edx,%edx */
|
|
|
5d197d9 |
+
|
|
|
5d197d9 |
+ /* Move the kernel into position */
|
|
|
5d197d9 |
+ 0x0f, 0xb6, 0x82, (src&0xff), ((src>>8)&0xff), ((src>>16)&0xff), ((src>>24)&0xff), /* movzbl $src(%edx),%eax */
|
|
|
5d197d9 |
+ 0x88, 0x82, (dst&0xff), ((dst>>8)&0xff), ((dst>>16)&0xff), ((dst>>24)&0xff), /* mov %al,$dst(%edx) */
|
|
|
5d197d9 |
+ 0x83, 0xc2, 0x01, /* add $0x1,%edx */
|
|
|
5d197d9 |
+ 0x81, 0xfa, (len&0xff), ((len>>8)&0xff), ((len>>16)&0xff), ((len>>24)&0xff), /* cmp $len,%edx */
|
|
|
5d197d9 |
+ 0x75, 0xe8, /* jne 13 <_doloop> */
|
|
|
5d197d9 |
+
|
|
|
5d197d9 |
+ /* Start kernel */
|
|
|
5d197d9 |
+ 0x31, 0xdb, /* xor %ebx,%ebx */
|
|
|
5d197d9 |
+ 0xb9, (dst&0xff), ((dst>>8)&0xff), ((dst>>16)&0xff), ((dst>>24)&0xff), /* mov $dst,%ecx */
|
|
|
5d197d9 |
+ 0xff, 0xe1, /* jmp *%ecx */
|
|
|
5d197d9 |
+ };
|
|
|
5d197d9 |
+ cpu_physical_memory_rw(addr, buf, sizeof(buf), 1);
|
|
|
5d197d9 |
+ fprintf(stderr, "qemu: helper at 0x%x of size %d bytes, to move kernel of %d bytes from 0x%x to 0x%x\n",
|
|
|
5d197d9 |
+ (int)addr, (int)sizeof(buf), (int)len, (int)src, (int)dst);
|
|
|
5d197d9 |
+}
|
|
|
5d197d9 |
+
|
|
|
5d197d9 |
|
|
|
5d197d9 |
static long get_file_size(FILE *f)
|
|
|
5d197d9 |
{
|
|
|
5d197d9 |
@@ -597,8 +681,15 @@ static void load_linux(const char *kerne
|
|
|
5d197d9 |
stl_p(header+0x214, reloc_prot_addr);
|
|
|
5d197d9 |
fprintf(stderr, "qemu: kernel is relocatable\n");
|
|
|
5d197d9 |
} else {
|
|
|
5d197d9 |
- fprintf(stderr, "qemu: unable to load non-relocatable kernel\n");
|
|
|
5d197d9 |
- exit(1);
|
|
|
5d197d9 |
+ /* Setup a helper which moves kernel back to
|
|
|
5d197d9 |
+ * its expected addr after firmware has got out
|
|
|
5d197d9 |
+ * of the way. We put a helper at reloc_prot_addr+kernel_size.
|
|
|
5d197d9 |
+ * It moves kernel from reloc_prot_addr to prot_addr and
|
|
|
5d197d9 |
+ * then jumps to prot_addr. Yes this is sick.
|
|
|
5d197d9 |
+ */
|
|
|
5d197d9 |
+ fprintf(stderr, "qemu: kernel is NOT relocatable\n");
|
|
|
5d197d9 |
+ stl_p(header+0x214, reloc_prot_addr + kernel_size);
|
|
|
5d197d9 |
+ setup_relocator(reloc_prot_addr + kernel_size, reloc_prot_addr, prot_addr, kernel_size);
|
|
|
5d197d9 |
}
|
|
|
5d197d9 |
}
|
|
|
5d197d9 |
|