All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Elf loader fixes
@ 2006-02-22 11:37 Gerd Hoffmann
  2006-02-22 12:51 ` Jan Beulich
  0 siblings, 1 reply; 13+ messages in thread
From: Gerd Hoffmann @ 2006-02-22 11:37 UTC (permalink / raw)
  To: Xen devel list

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

  Hi folks,

The Xen ELF kernel loader is quite quirky wrt. physical and virtual
addresses, probably for historical reasons, linux got that wrong too
until very recently (kexec merge in 2.6.14 or so).  The patch below
fixes that.

Changes:
  * Fix linux kernel ELF entry point (also submitted to lkml)
  * Drop LOAD_OFFSET re-#define hack in xen headers.
  * Fix both dom0 and libxc elf loaders.
  * add quick mode so loading old linux kernels doesn't break.

Linux-wise everything should be OK with that, but it might break other
OS'es which also use the ELF loader (in case they create bug-compatible
ELF headers with broken paddr entries ...).

please apply,

  Gerd


[-- Attachment #2: load-offset-1.diff --]
[-- Type: text/x-patch, Size: 7443 bytes --]

diff -r 5abf652c4c52 linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S
--- a/linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S	Tue Feb 21 18:36:00 2006
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S	Wed Feb 22 12:20:06 2006
@@ -10,7 +10,7 @@
 
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
-ENTRY(phys_startup_32)
+ENTRY(startup_32)
 jiffies = jiffies_64;
 SECTIONS
 {
diff -r 5abf652c4c52 linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h
--- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h	Tue Feb 21 18:36:00 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h	Wed Feb 22 12:20:06 2006
@@ -288,10 +288,6 @@
 #endif
 #define __KERNEL_START		(__PAGE_OFFSET + __PHYSICAL_START)
 
-#undef LOAD_OFFSET
-#define LOAD_OFFSET		0
-
-
 #define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
 #define VMALLOC_RESERVE		((unsigned long)__VMALLOC_RESERVE)
 #define MAXMEM			(HYPERVISOR_VIRT_START-__PAGE_OFFSET-__VMALLOC_RESERVE)
diff -r 5abf652c4c52 tools/libxc/xc_load_elf.c
--- a/tools/libxc/xc_load_elf.c	Tue Feb 21 18:36:00 2006
+++ b/tools/libxc/xc_load_elf.c	Wed Feb 22 12:20:06 2006
@@ -138,10 +138,10 @@
         phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
         if ( !is_loadable_phdr(phdr) )
             continue;
-        if ( phdr->p_paddr < kernstart )
-            kernstart = phdr->p_paddr;
-        if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
-            kernend = phdr->p_paddr + phdr->p_memsz;
+        if ( phdr->p_vaddr < kernstart )
+            kernstart = phdr->p_vaddr;
+        if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
+            kernend = phdr->p_vaddr + phdr->p_memsz;
     }
 
     if ( (kernstart > kernend) || 
@@ -189,7 +189,18 @@
         
         for ( done = 0; done < phdr->p_filesz; done += chunksz )
         {
-            pa = (phdr->p_paddr + done) - dsi->v_start;
+            if (phdr->p_paddr == phdr->p_vaddr) {
+                /*
+                 * Bug compatibility alert: In older linux kernels
+                 * p_paddr is broken, it doesn't contain the physical
+                 * address but instead is identical to p_vaddr.  Thus
+                 * we can't use it directly, instead we'll guess it
+                 * using dsi->v_start.
+                 */
+                pa = (phdr->p_vaddr + done) - dsi->v_start;
+            } else {
+                pa = (phdr->p_paddr + done);
+            }
             va = xc_map_foreign_range(
                 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
             chunksz = phdr->p_filesz - done;
@@ -202,7 +213,12 @@
 
         for ( ; done < phdr->p_memsz; done += chunksz )
         {
-            pa = (phdr->p_paddr + done) - dsi->v_start;
+            if (phdr->p_paddr == phdr->p_vaddr) {
+                /* bug compatibility alert, see above */
+                pa = (phdr->p_vaddr + done) - dsi->v_start;
+            } else {
+                pa = (phdr->p_paddr + done);
+            }
             va = xc_map_foreign_range(
                 xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
             chunksz = phdr->p_memsz - done;
diff -r 5abf652c4c52 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c	Tue Feb 21 18:36:00 2006
+++ b/xen/arch/x86/domain.c	Wed Feb 22 12:20:06 2006
@@ -346,7 +346,7 @@
     struct vcpu *v, struct vcpu_guest_context *c)
 {
     struct domain *d = v->domain;
-    unsigned long phys_basetab;
+    unsigned long phys_basetab = 0;
     int i, rc;
 
     /*
diff -r 5abf652c4c52 xen/common/elf.c
--- a/xen/common/elf.c	Tue Feb 21 18:36:00 2006
+++ b/xen/common/elf.c	Wed Feb 22 12:20:06 2006
@@ -23,7 +23,8 @@
     Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
     Elf_Phdr *phdr;
     Elf_Shdr *shdr;
-    unsigned long kernstart = ~0UL, kernend=0UL;
+    unsigned long v_kernstart = ~0UL, v_kernend=0UL;
+    unsigned long p_kernstart = ~0UL, p_kernend=0UL;
     char *shstrtab, *guestinfo=NULL, *p;
     char *elfbase = (char *)dsi->image_addr;
     int h;
@@ -87,21 +88,31 @@
         phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
         if ( !is_loadable_phdr(phdr) )
             continue;
-        if ( phdr->p_paddr < kernstart )
-            kernstart = phdr->p_paddr;
-        if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
-            kernend = phdr->p_paddr + phdr->p_memsz;
-    }
-
-    if ( (kernstart > kernend) || 
-         (ehdr->e_entry < kernstart) || 
-         (ehdr->e_entry > kernend) )
+        printk("%s: phdr: vaddr %08lx paddr %08lx filesz %08lx\n",
+               __FUNCTION__,
+               (unsigned long)phdr->p_vaddr,
+               (unsigned long)phdr->p_paddr,
+               (unsigned long)phdr->p_filesz);
+        if ( phdr->p_vaddr < v_kernstart )
+            v_kernstart = phdr->p_vaddr;
+        if ( (phdr->p_vaddr + phdr->p_memsz) > v_kernend )
+            v_kernend = phdr->p_vaddr + phdr->p_memsz;
+        if ( phdr->p_paddr < p_kernstart )
+            p_kernstart = phdr->p_paddr;
+        if ( (phdr->p_paddr + phdr->p_memsz) > p_kernend )
+            p_kernend = phdr->p_paddr + phdr->p_memsz;
+    }
+
+    if ( (v_kernstart > v_kernend) || 
+         (p_kernstart > p_kernend) || 
+         (ehdr->e_entry < v_kernstart) || 
+         (ehdr->e_entry > v_kernend) )
     {
         printk("Malformed ELF image.\n");
         return -EINVAL;
     }
 
-    dsi->v_start = kernstart;
+    dsi->v_start = v_kernstart;
 
     if ( guestinfo != NULL )
     {
@@ -112,10 +123,26 @@
             dsi->load_symtab = 1;
     }
 
-    dsi->v_kernstart = kernstart;
-    dsi->v_kernend   = kernend;
+    dsi->v_kernstart = v_kernstart;
+    dsi->v_kernend   = v_kernend;
     dsi->v_kernentry = ehdr->e_entry;
     dsi->v_end       = dsi->v_kernend;
+
+    if (p_kernstart == v_kernstart) {
+        /*
+         * Bug compatibility alert: In older linux kernels
+         * p_paddr is broken, it doesn't contain the physical
+         * address but instead is identical to p_vaddr.  Thus
+         * we can't use it directly, instead we'll guess it
+         * using dsi->v_start.
+         */
+        printk("%s: linux kernel paddr quirk\n", __FUNCTION__);
+        dsi->p_kernstart = v_kernstart - dsi->v_start;
+        dsi->p_kernend   = v_kernend   - dsi->v_start;
+    } else {
+        dsi->p_kernstart = p_kernstart;
+        dsi->p_kernend   = p_kernend;
+    }
 
     loadelfsymtab(dsi, 0);
 
@@ -135,10 +162,10 @@
         if ( !is_loadable_phdr(phdr) )
             continue;
         if ( phdr->p_filesz != 0 )
-            memcpy((char *)phdr->p_paddr, elfbase + phdr->p_offset, 
+            memcpy((char *)phdr->p_vaddr, elfbase + phdr->p_offset, 
                    phdr->p_filesz);
         if ( phdr->p_memsz > phdr->p_filesz )
-            memset((char *)phdr->p_paddr + phdr->p_filesz, 0, 
+            memset((char *)phdr->p_vaddr + phdr->p_filesz, 0, 
                    phdr->p_memsz - phdr->p_filesz);
     }
 
diff -r 5abf652c4c52 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h	Tue Feb 21 18:36:00 2006
+++ b/xen/include/xen/sched.h	Wed Feb 22 12:20:06 2006
@@ -165,6 +165,8 @@
     unsigned long v_end;
     unsigned long v_kernstart;
     unsigned long v_kernend;
+    unsigned long p_kernstart;
+    unsigned long p_kernend;
     unsigned long v_kernentry;
     /* Initialised by loader: Private. */
     unsigned int  load_symtab;

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

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

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2006-03-06 13:40 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <E1F6x4v-0001lS-2n@host-192-168-0-1-bcn-london>
2006-02-22 18:17 ` [PATCH] Elf loader fixes Joe Bonasera
2006-02-23 11:15   ` Gerd Hoffmann
2006-03-01  9:48     ` Christian Limpach
2006-03-01 15:00       ` Gerd Hoffmann
2006-03-06 13:40       ` Gerd Hoffmann
2006-02-22 11:37 Gerd Hoffmann
2006-02-22 12:51 ` Jan Beulich
2006-02-22 13:33   ` Gerd Hoffmann
2006-02-22 15:12   ` Gerd Hoffmann
2006-02-22 15:30     ` Jan Beulich
2006-02-22 16:10       ` Gerd Hoffmann
2006-02-22 16:11         ` Ronald G Minnich
2006-02-22 16:25         ` Jacob Gorm Hansen

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.