All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrange" <berrange@redhat.com>
To: xen-devel@lists.xensource.com
Subject: Re: PATCH 3/3: Support boot of NON-relocatable kernels
Date: Wed, 19 Dec 2007 05:43:44 +0000	[thread overview]
Message-ID: <20071219054344.GE19526@redhat.com> (raw)
In-Reply-To: <20071219053821.GB19526@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 1916 bytes --]

This patch introduces a hack to make non-relocatable kernels
bootable too. Non-relocatable kernels absolutely want to run
at 0x100000 and are not at all happy about being at 0x200000.
Fortunately, thanks to crazy programs like LOADLIN, Linux has
a couple of hooks in its boot process which can be used to
play games. The 'code32_switch' hook is executed immediately
following the switch to protected mode. To quote the kernel
docs

[quote Documentation/i386/boot.txt]
  code32_start:
        A 32-bit flat-mode routine *jumped* to immediately after the
        transition to protected mode, but before the kernel is
        uncompressed.  No segments, except CS, are set up; you should
        set them up to KERNEL_DS (0x18) yourself.

        After completing your hook, you should jump to the address
        that was in this field before your boot loader overwrote it.

   IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
  %edi across invocation.
[/quote]


So, this patch installs a hook at 0x200000+kernel_size. The hook
is hand crafted assembly which sets up all the segments as needed,
then essentially does memmove(0x100000,0x200000,kernel_size) and
finally does an unconditional jmp to 0x100000.

Amazingly this actually really does work. It has been successfully
tested with RHEL-2.1 and Fedora Core 6 install kernels on i386.

NB x86_64 is not yet tested


 pc.c |   95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 93 insertions(+), 2 deletions(-)


   Signed-off-by: Daniel P. Berrange <berrange@redhat.com>

Regards,
Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 

[-- Attachment #2: xen-hvm-kernel-boot-nonrelocatable.patch --]
[-- Type: text/plain, Size: 4735 bytes --]

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

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

  parent reply	other threads:[~2007-12-19  5:43 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-19  5:38 PATCH 0/3: Direct linux kernel boot for HVM Daniel P. Berrange
2007-12-19  5:41 ` PATCH 1/3: XenD changes for HVM kernel boot Daniel P. Berrange
2007-12-19  5:42 ` PATCH 2/3: Support booting relocatable kernels Daniel P. Berrange
2007-12-19  5:44   ` Daniel P. Berrange
2007-12-19  5:43 ` Daniel P. Berrange [this message]
2007-12-19 10:48 ` PATCH 0/3: Direct linux kernel boot for HVM Keir Fraser
2007-12-19 13:00   ` Daniel P. Berrange
2007-12-19 14:43     ` Keir Fraser

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20071219054344.GE19526@redhat.com \
    --to=berrange@redhat.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.