diff -r bcd2960d6dfd tools/libxc/xc_load_elf.c --- a/tools/libxc/xc_load_elf.c Mon Nov 20 21:10:59 2006 -0700 +++ b/tools/libxc/xc_load_elf.c Wed Nov 22 13:05:27 2006 +0100 @@ -6,6 +6,66 @@ #include "xc_elf.h" #include #include + +#if defined(__ia64__) + +static int do_swap = 0; + +static __inline uint64_t +bswap64(uint64_t x) +{ + uint64_t r; + asm __volatile("mux1 %0=%1,@rev" : "=r" (r) : "r"(x)); + return r; +} + +static __inline uint64_t +xen_swap64(uint64_t x) +{ + if(do_swap) + return (bswap64(x)); + else return x; +} + +static __inline uint32_t +xen_swap32(uint32_t x) +{ + if(do_swap) + return (bswap64(x) >> 32); + else return x; +} + +static __inline uint16_t +xen_swap16(uint16_t x) +{ + + if(do_swap) + return (bswap64(x) >> 48); + else return x; +} + + +#define xenswap(x,sz) ( \ + ((sz)==1)? (uint8_t)(x): \ + ((sz)==2)? xen_swap16(x): \ + ((sz)==4)? xen_swap32(x): \ + ((sz)==8)? xen_swap64(x): \ + ~0l ) + +#define SWAP(x) xenswap((x), sizeof((x))) + + +#define SET_SWAP do_swap = 1; +#define SET_NOSWAP do_swap = 0; + +#else /* defined(__ia64__) */ + +#define SWAP(x) x +#define SET_SWAP +#define SET_NOSWAP + +#endif /* defined(__ia64__) */ + #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) #define round_pgdown(_p) ((_p)&PAGE_MASK) @@ -62,8 +122,8 @@ int probe_elf(const char *image, static inline int is_loadable_phdr(Elf_Phdr *phdr) { - return ((phdr->p_type == PT_LOAD) && - ((phdr->p_flags & (PF_W|PF_X)) != 0)); + return ((SWAP(phdr->p_type) == PT_LOAD) && + ((SWAP(phdr->p_flags) & (PF_W|PF_X)) != 0)); } /* @@ -72,7 +132,7 @@ static inline int is_loadable_phdr(Elf_P */ static int is_xen_guest_section(Elf_Shdr *shdr, const char *shstrtab) { - return strcmp(&shstrtab[shdr->sh_name], "__xen_guest") == 0; + return strcmp(&shstrtab[SWAP(shdr->sh_name)], "__xen_guest") == 0; } static const char *xen_guest_lookup(struct domain_setup_info *dsi, int type) @@ -157,11 +217,11 @@ static int is_xen_elfnote_section(const { Elf_Note *note; - if ( shdr->sh_type != SHT_NOTE ) - return 0; - - for ( note = (Elf_Note *)(image + shdr->sh_offset); - note < (Elf_Note *)(image + shdr->sh_offset + shdr->sh_size); + if ( SWAP(shdr->sh_type) != SHT_NOTE ) + return 0; + + for ( note = (Elf_Note *)(image + SWAP(shdr->sh_offset)); + note < (Elf_Note *)(image + SWAP(shdr->sh_offset) + SWAP(shdr->sh_size)); note = ELFNOTE_NEXT(note) ) { if ( !strncmp(ELFNOTE_NAME(note), "Xen", 4) ) @@ -254,61 +314,75 @@ static int parseelfimage(const char *ima return -EINVAL; } + SET_NOSWAP /* Default is no byte swapping. */ + if(ehdr->e_ident[EI_DATA] != ELFDATA) + { +#if defined(__ia64__) + if(ehdr->e_ident[EI_DATA] != ELFDATA2MSB) + { + ERROR("Kernel not a Xen-compatible Elf image."); + return -EINVAL; + } + SET_SWAP /* Switch on byte swapping. */ +#else /* defined(__ia64__) */ + ERROR("Kernel not a Xen-compatible Elf image."); + return -EINVAL; +#endif /* defined(__ia64__) */ + } if ( (ehdr->e_ident[EI_CLASS] != ELFCLASS) || - (ehdr->e_machine != ELFMACHINE) || - (ehdr->e_ident[EI_DATA] != ELFDATA) || - (ehdr->e_type != ET_EXEC) ) + (SWAP(ehdr->e_machine) != ELFMACHINE) || + (SWAP(ehdr->e_type) != ET_EXEC) ) { ERROR("Kernel not a Xen-compatible Elf image."); return -EINVAL; } - if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > image_len ) + if ( (SWAP(ehdr->e_phoff) + (SWAP(ehdr->e_phnum)*SWAP(ehdr->e_phentsize))) > image_len ) { ERROR("ELF program headers extend beyond end of image."); return -EINVAL; } - if ( (ehdr->e_shoff + (ehdr->e_shnum*ehdr->e_shentsize)) > image_len ) + if ( (SWAP(ehdr->e_shoff) + (SWAP(ehdr->e_shnum)*SWAP(ehdr->e_shentsize))) > image_len ) { ERROR("ELF section headers extend beyond end of image."); return -EINVAL; } + /* Find the section-header strings table. */ - if ( ehdr->e_shstrndx == SHN_UNDEF ) + if ( SWAP(ehdr->e_shstrndx) == SHN_UNDEF ) { ERROR("ELF image has no section-header strings table (shstrtab)."); return -EINVAL; } - shdr = (Elf_Shdr *)(image + ehdr->e_shoff + - (ehdr->e_shstrndx*ehdr->e_shentsize)); - shstrtab = image + shdr->sh_offset; + shdr = (Elf_Shdr *)(image + SWAP(ehdr->e_shoff) + + (SWAP(ehdr->e_shstrndx)*SWAP(ehdr->e_shentsize))); + shstrtab = image + SWAP(shdr->sh_offset); dsi->__elfnote_section = NULL; dsi->__xen_guest_string = NULL; /* Look for .notes segment containing at least one Xen note */ - for ( h = 0; h < ehdr->e_shnum; h++ ) - { - shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize)); + for ( h = 0; h < SWAP(ehdr->e_shnum); h++ ) + { + shdr = (Elf_Shdr *)(image + SWAP(ehdr->e_shoff) + (h*SWAP(ehdr->e_shentsize))); if ( !is_xen_elfnote_section(image, shdr) ) continue; - dsi->__elfnote_section = (void *)image + shdr->sh_offset; + dsi->__elfnote_section = (void *)image + SWAP(shdr->sh_offset); dsi->__elfnote_section_end = - (void *)image + shdr->sh_offset + shdr->sh_size; + (void *)image + SWAP(shdr->sh_offset) + SWAP(shdr->sh_size); break; } - /* Fall back to looking for the special '__xen_guest' section. */ if ( dsi->__elfnote_section == NULL ) { - for ( h = 0; h < ehdr->e_shnum; h++ ) - { - shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize)); + for ( h = 0; h < SWAP(ehdr->e_shnum); h++ ) + { + shdr = (Elf_Shdr *)(image + SWAP(ehdr->e_shoff) + (h*SWAP(ehdr->e_shentsize))); if ( is_xen_guest_section(shdr, shstrtab) ) { - dsi->__xen_guest_string = (char *)image + shdr->sh_offset; + dsi->__xen_guest_string = (char *)image + SWAP(shdr->sh_offset); break; } } @@ -368,7 +442,6 @@ static int parseelfimage(const char *ima dsi->pae_kernel = PAEKERN_extended_cr3; } } - /* Initial guess for v_start is 0 if it is not explicitly defined. */ dsi->v_start = xen_elfnote_numeric(dsi, XEN_ELFNOTE_VIRT_BASE, &virt_base_defined); @@ -393,34 +466,29 @@ static int parseelfimage(const char *ima else dsi->elf_paddr_offset = dsi->v_start; } - if ( elf_pa_off_defined && !virt_base_defined ) { ERROR("Neither ELF_PADDR_OFFSET nor VIRT_BASE found in ELF " " notes or __xen_guest section."); return -EINVAL; } - - for ( h = 0; h < ehdr->e_phnum; h++ ) - { - phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize)); + for ( h = 0; h < SWAP(ehdr->e_phnum); h++ ) + { + phdr = (Elf_Phdr *)(image + SWAP(ehdr->e_phoff) + (h*SWAP(ehdr->e_phentsize))); if ( !is_loadable_phdr(phdr) ) continue; - vaddr = phdr->p_paddr - dsi->elf_paddr_offset + dsi->v_start; - if ( (vaddr + phdr->p_memsz) < vaddr ) + vaddr = SWAP(phdr->p_paddr) - dsi->elf_paddr_offset + dsi->v_start; + if ( (vaddr + SWAP(phdr->p_memsz)) < vaddr ) { ERROR("ELF program header %d is too large.", h); return -EINVAL; } - if ( vaddr < kernstart ) kernstart = vaddr; - if ( (vaddr + phdr->p_memsz) > kernend ) - kernend = vaddr + phdr->p_memsz; - } - - dsi->v_kernentry = ehdr->e_entry; - + if ( (vaddr + SWAP(phdr->p_memsz)) > kernend ) + kernend = vaddr + SWAP(phdr->p_memsz); + } + dsi->v_kernentry = SWAP(ehdr->e_entry); virt_entry = xen_elfnote_numeric(dsi, XEN_ELFNOTE_ENTRY, &virt_entry_defined); if ( virt_entry_defined ) @@ -434,7 +502,6 @@ static int parseelfimage(const char *ima ERROR("ELF start or entries are out of bounds."); return -EINVAL; } - p = xen_elfnote_string(dsi, XEN_ELFNOTE_BSD_SYMTAB); if ( p != NULL && strncmp(p, "yes", 3) == 0 ) dsi->load_symtab = 1; @@ -460,42 +527,39 @@ loadelfimage( char *va; unsigned long pa, done, chunksz; - for ( h = 0; h < ehdr->e_phnum; h++ ) - { - phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize)); + for ( h = 0; h < SWAP(ehdr->e_phnum); h++ ) + { + phdr = (Elf_Phdr *)(image + SWAP(ehdr->e_phoff) + (h*SWAP(ehdr->e_phentsize))); if ( !is_loadable_phdr(phdr) ) continue; - - for ( done = 0; done < phdr->p_filesz; done += chunksz ) - { - pa = (phdr->p_paddr + done) - dsi->elf_paddr_offset; + for ( done = 0; done < SWAP(phdr->p_filesz); done += chunksz ) + { + pa = (SWAP(phdr->p_paddr) + done) - dsi->elf_paddr_offset; va = xc_map_foreign_range( xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]); if ( va == NULL ) return -1; - chunksz = phdr->p_filesz - done; + chunksz = SWAP(phdr->p_filesz) - done; if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) ) chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1)); memcpy(va + (pa & (PAGE_SIZE-1)), - image + phdr->p_offset + done, chunksz); + image + SWAP(phdr->p_offset) + done, chunksz); munmap(va, PAGE_SIZE); } - - for ( ; done < phdr->p_memsz; done += chunksz ) - { - pa = (phdr->p_paddr + done) - dsi->elf_paddr_offset; + for ( ; done < SWAP(phdr->p_memsz); done += chunksz ) + { + pa = (SWAP(phdr->p_paddr) + done) - dsi->elf_paddr_offset; va = xc_map_foreign_range( xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]); if ( va == NULL ) return -1; - chunksz = phdr->p_memsz - done; + chunksz = SWAP(phdr->p_memsz) - done; if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) ) chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1)); memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz); munmap(va, PAGE_SIZE); } } - loadelfsymtab(image, xch, dom, parray, dsi); return 0; @@ -518,7 +582,7 @@ loadelfsymtab( return 0; p = malloc(sizeof(int) + sizeof(Elf_Ehdr) + - ehdr->e_shnum * sizeof(Elf_Shdr)); + SWAP(ehdr->e_shnum) * sizeof(Elf_Shdr)); if (p == NULL) return 0; @@ -527,42 +591,42 @@ loadelfsymtab( maxva += sizeof(int); dsi->symtab_addr = maxva; dsi->symtab_len = 0; - maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr); + maxva += sizeof(Elf_Ehdr) + SWAP(ehdr->e_shnum) * sizeof(Elf_Shdr); maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr)); - memcpy(shdr, image + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr)); - - for ( h = 0; h < ehdr->e_shnum; h++ ) - { - if ( shdr[h].sh_type == SHT_STRTAB ) + memcpy(shdr, image + SWAP(ehdr->e_shoff), SWAP(ehdr->e_shnum) * sizeof(Elf_Shdr)); + + for ( h = 0; h < SWAP(ehdr->e_shnum); h++ ) + { + if ( SWAP(shdr[h].sh_type) == SHT_STRTAB ) { /* Look for a strtab @i linked to symtab @h. */ - for ( i = 0; i < ehdr->e_shnum; i++ ) - if ( (shdr[i].sh_type == SHT_SYMTAB) && - (shdr[i].sh_link == h) ) + for ( i = 0; i < SWAP(ehdr->e_shnum); i++ ) + if ( (SWAP(shdr[i].sh_type) == SHT_SYMTAB) && + (SWAP(shdr[i].sh_link) == h) ) break; /* Skip symtab @h if we found no corresponding strtab @i. */ - if ( i == ehdr->e_shnum ) + if ( i == SWAP(ehdr->e_shnum) ) { shdr[h].sh_offset = 0; continue; } } - if ( (shdr[h].sh_type == SHT_STRTAB) || - (shdr[h].sh_type == SHT_SYMTAB) ) + if ( (SWAP(shdr[h].sh_type) == SHT_STRTAB) || + (SWAP(shdr[h].sh_type) == SHT_SYMTAB) ) { if ( parray != NULL ) - xc_map_memcpy(maxva, image + shdr[h].sh_offset, - shdr[h].sh_size, + xc_map_memcpy(maxva, image + SWAP(shdr[h].sh_offset), + SWAP(shdr[h].sh_size), xch, dom, parray, dsi->v_start); /* Mangled to be based on ELF header location. */ shdr[h].sh_offset = maxva - dsi->symtab_addr; - dsi->symtab_len += shdr[h].sh_size; - maxva += shdr[h].sh_size; + dsi->symtab_len += SWAP(shdr[h].sh_size); + maxva += SWAP(shdr[h].sh_size); maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1); } @@ -588,7 +652,7 @@ loadelfsymtab( /* Copy total length, crafted ELF header and section header table */ xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) + - ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray, + SWAP(ehdr->e_shnum) * sizeof(Elf_Shdr), xch, dom, parray, dsi->v_start); }