[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] Elf loader fixes
> 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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |