> some with p_vaddr == p_paddr on purpose and some which don't. We rely on a
> "boot loader" (ie grub or domain builder) that only cares about p_paddr.
Same goes for the x86_64 linux kernel with the vsyscall page ...
I've settled for a slightly different approach now. To keep behaviour
as close as possible to classic i386 boot loaders I'll check paddr only
and use the virt_base value from the __xen_guest section to shift the
addresses. For bug compatibility with old linux kernels I compare paddr
+ virt_base. New patch below, this time tested both 32 and 64 bit
(linux only though), I think it should be ok for OpenSolaris too ;)
cheers,
Gerd
--
Gerd 'just married' Hoffmann <kraxel@xxxxxxx>
I'm the hacker formerly known as Gerd Knorr.
http://www.suse.de/~kraxel/just-married.jpeg
diff -r 175ad739d8bc linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S
--- a/linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S Wed Feb 22
20:52:30 2006
+++ b/linux-2.6-xen-sparse/arch/i386/kernel/vmlinux.lds.S Thu Feb 23
10:31:01 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 175ad739d8bc 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 Wed Feb 22
20:52:30 2006
+++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/page.h Thu Feb 23
10:31:01 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 175ad739d8bc linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h
--- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h Wed Feb
22 20:52:30 2006
+++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/page.h Thu Feb
23 10:31:01 2006
@@ -259,9 +259,6 @@
#define __PAGE_OFFSET 0xffff880000000000
#endif /* !__ASSEMBLY__ */
-#undef LOAD_OFFSET
-#define LOAD_OFFSET 0
-
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
diff -r 175ad739d8bc tools/libxc/xc_load_elf.c
--- a/tools/libxc/xc_load_elf.c Wed Feb 22 20:52:30 2006
+++ b/tools/libxc/xc_load_elf.c Thu Feb 23 10:31:01 2006
@@ -60,6 +60,7 @@
Elf_Phdr *phdr;
Elf_Shdr *shdr;
unsigned long kernstart = ~0UL, kernend=0UL;
+ unsigned long sstart, send;
char *shstrtab, *guestinfo=NULL, *p;
int h;
@@ -117,6 +118,8 @@
}
if ( (strstr(guestinfo, "PAE=yes") != NULL) )
dsi->pae_kernel = 1;
+ if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
+ dsi->virt_base = strtoul(p+10, &p, 0);
break;
}
@@ -138,10 +141,27 @@
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;
+ sstart = phdr->p_paddr;
+ send = phdr->p_paddr + phdr->p_memsz;
+ /*
+ * bug comparibility alert: old linux kernels used to have
+ * virtual addresses in the paddr headers, whereas newer ones
+ * (since kexec merge, around 2.6.14) correctly use physical
+ * addresses.
+ *
+ * As we want to be able to boot both kinds of kernels we'll
+ * do some guesswork here: If paddr is greater than virt_base
+ * we assume it is a old kernel and use it as-is. Otherwise
+ * we'll add virt_base to get the correct address.
+ */
+ if (sstart < dsi->virt_base) {
+ sstart += dsi->virt_base;
+ send += dsi->virt_base;
+ }
+ if ( sstart < kernstart )
+ kernstart = sstart;
+ if ( send > kernend )
+ kernend = send;
}
if ( (kernstart > kernend) ||
@@ -189,7 +209,11 @@
for ( done = 0; done < phdr->p_filesz; done += chunksz )
{
- pa = (phdr->p_paddr + done) - dsi->v_start;
+ /* bug compatibility alert, see above */
+ pa = phdr->p_paddr + done;
+ if (pa > dsi->virt_base)
+ pa -= dsi->virt_base;
+
va = xc_map_foreign_range(
xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
chunksz = phdr->p_filesz - done;
@@ -202,7 +226,11 @@
for ( ; done < phdr->p_memsz; done += chunksz )
{
- pa = (phdr->p_paddr + done) - dsi->v_start;
+ /* bug compatibility alert, see above */
+ pa = phdr->p_paddr + done;
+ if (pa > dsi->virt_base)
+ pa -= dsi->virt_base;
+
va = xc_map_foreign_range(
xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
chunksz = phdr->p_memsz - done;
diff -r 175ad739d8bc tools/libxc/xg_private.h
--- a/tools/libxc/xg_private.h Wed Feb 22 20:52:30 2006
+++ b/tools/libxc/xg_private.h Thu Feb 23 10:31:01 2006
@@ -131,6 +131,7 @@
unsigned long v_kernstart;
unsigned long v_kernend;
unsigned long v_kernentry;
+ unsigned long virt_base;
unsigned int load_symtab;
unsigned int pae_kernel;
diff -r 175ad739d8bc xen/common/elf.c
--- a/xen/common/elf.c Wed Feb 22 20:52:30 2006
+++ b/xen/common/elf.c Thu Feb 23 10:31:01 2006
@@ -24,6 +24,7 @@
Elf_Phdr *phdr;
Elf_Shdr *shdr;
unsigned long kernstart = ~0UL, kernend=0UL;
+ unsigned long sstart, send;
char *shstrtab, *guestinfo=NULL, *p;
char *elfbase = (char *)dsi->image_addr;
int h;
@@ -77,6 +78,8 @@
return -EINVAL;
}
+ if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
+ dsi->virt_base = simple_strtoul(p+10, &p, 0);
break;
}
@@ -87,11 +90,38 @@
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;
- }
+ sstart = phdr->p_paddr;
+ send = phdr->p_paddr + phdr->p_memsz;
+ /*
+ * bug comparibility alert: old linux kernels used to have
+ * virtual addresses in the paddr headers, whereas newer ones
+ * (since kexec merge, around 2.6.14) correctly use physical
+ * addresses.
+ *
+ * As we want to be able to boot both kinds of kernels we'll
+ * do some guesswork here: If paddr is greater than virt_base
+ * we assume it is a old kernel and use it as-is. Otherwise
+ * we'll add virt_base to get the correct address.
+ */
+ if (sstart < dsi->virt_base) {
+ sstart += dsi->virt_base;
+ send += dsi->virt_base;
+ }
+ printk("%s: program hdr: %08lx (=vaddr) "
+ "paddr: %08lx filesz: %08lx memsz: %08lx => %08lx-%08lx\n",
+ __FUNCTION__,
+ (unsigned long)phdr->p_vaddr,
+ (unsigned long)phdr->p_paddr,
+ (unsigned long)phdr->p_filesz,
+ (unsigned long)phdr->p_memsz,
+ sstart, send);
+ if ( sstart < kernstart )
+ kernstart = sstart;
+ if ( send > kernend )
+ kernend = send;
+ }
+ printk("%s: entry point: %08lx\n", __FUNCTION__,
+ (unsigned long)ehdr->e_entry);
if ( (kernstart > kernend) ||
(ehdr->e_entry < kernstart) ||
@@ -127,6 +157,7 @@
char *elfbase = (char *)dsi->image_addr;
Elf_Ehdr *ehdr = (Elf_Ehdr *)dsi->image_addr;
Elf_Phdr *phdr;
+ unsigned long vaddr;
int h;
for ( h = 0; h < ehdr->e_phnum; h++ )
@@ -134,11 +165,15 @@
phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
if ( !is_loadable_phdr(phdr) )
continue;
+ vaddr = phdr->p_paddr;
+ if (vaddr < dsi->virt_base)
+ vaddr += dsi->virt_base;
if ( phdr->p_filesz != 0 )
- memcpy((char *)phdr->p_paddr, elfbase + phdr->p_offset,
+ memcpy((char *)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 175ad739d8bc xen/include/xen/sched.h
--- a/xen/include/xen/sched.h Wed Feb 22 20:52:30 2006
+++ b/xen/include/xen/sched.h Thu Feb 23 10:31:01 2006
@@ -166,6 +166,7 @@
unsigned long v_kernstart;
unsigned long v_kernend;
unsigned long v_kernentry;
+ unsigned long virt_base;
/* Initialised by loader: Private. */
unsigned int load_symtab;
unsigned long symtab_addr;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|