* [RFC v3 PATCH 0/4] Relocatable kernel support for PPC64 @ 2008-07-17 18:33 Mohan Kumar M 2008-07-17 18:40 ` [RFC v3 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M ` (3 more replies) 0 siblings, 4 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-17 18:33 UTC (permalink / raw) To: ppcdev; +Cc: paulus, miltonm Hi, Following four patches enable the "relocatable kernel" feature for PPC64 kernels. 1. extract_relocation_info.patch 2. relocation_build.patch 3. apply_relocation.patch 4. relocation_support.patch With the patchset, vmcore image of a crashed system can be captured using the same kernel binary. Still the kernel is not a fully relocatable kernel. It can either run at 0 or 32MB based on which address its loaded. If its loaded by 'kexec -p', it behaves as a relocatable kernel and runs at 32MB(even though its compiled for 0). If the same kernel is loaded by yaboot or kexec -l, it will behave as a normal kernel and will run at the compiled address. Difference between v3 and v2 * Relocatable kernel build process is integrated with the kernel build. * The problem kdump kernel boot fail on some specific systems is fixed now. Issues: * Relocatable vmlinux image is built in arch/powerpc/boot as vmlinux.reloc. But it should be built in top level directory of kernel source as vmlinux instead of vmlinux.reloc * During kdump kernel boot, all secondary processors are stuck up. But during yaboot all secondary processors are brought online. Tested on POWER5 systems. Please send me your suggestions and feedbacks. Regards, Mohan. ^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC v3 PATCH 1/4] Extract list of relocation offsets 2008-07-17 18:33 [RFC v3 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M @ 2008-07-17 18:40 ` Mohan Kumar M 2008-07-17 20:06 ` Benjamin Herrenschmidt 2008-07-17 18:42 ` [RFC v3 PATCH 2/4] Build files needed for relocation support Mohan Kumar M ` (2 subsequent siblings) 3 siblings, 1 reply; 22+ messages in thread From: Mohan Kumar M @ 2008-07-17 18:40 UTC (permalink / raw) To: ppcdev; +Cc: paulus, miltonm Extract list of relocation offsets Extract list of offsets in the vmlinux file for which the relocation delta has to be patched. Currently only following type of relocation types are considered: R_PPC64_ADDR16_HI, R_PPC64_TOC and R_PPC64_ADDR64 The offsets are sorted according to the relocation type and this information is appended to the normal vmlinux file by using the patch relocation_build.patch Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/boot/relocs.c | 865 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 865 insertions(+) Index: linux-2.6.26/arch/powerpc/boot/relocs.c =================================================================== --- /dev/null +++ linux-2.6.26/arch/powerpc/boot/relocs.c @@ -0,0 +1,865 @@ +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <elf.h> +#include <byteswap.h> +#define USE_BSD +#include <endian.h> + +#define MAX_SHDRS 100 +static Elf64_Ehdr ehdr; +static Elf64_Shdr shdr[MAX_SHDRS]; +static Elf64_Sym *symtab[MAX_SHDRS]; +static Elf64_Rel *reltab[MAX_SHDRS]; +static Elf64_Rela *reltaba[MAX_SHDRS]; +static char *strtab[MAX_SHDRS]; +static unsigned long reloc_count, reloc_idx; + +struct reloc_info { + unsigned int rel_type; + unsigned long long offset; +}; + +static struct reloc_info *relocs; + +/* + * Following symbols have been audited. There values are constant and do + * not change if bzImage is loaded at a different physical address than + * the address for which it has been compiled. Don't warn user about + * absolute relocations present w.r.t these symbols. + */ +static const char* safe_abs_relocs[] = { + "__kernel_vsyscall", + "__kernel_rt_sigreturn", + "__kernel_sigreturn", + "SYSENTER_RETURN", +}; + +static int is_safe_abs_reloc(const char* sym_name) +{ + int i, array_size; + + array_size = sizeof(safe_abs_relocs)/sizeof(char*); + + for(i = 0; i < array_size; i++) { + if (!strcmp(sym_name, safe_abs_relocs[i])) + /* Match found */ + return 1; + } + if (strncmp(sym_name, "__crc_", 6) == 0) + return 1; + return 0; +} + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static const char *sym_type(unsigned type) +{ + static const char *type_name[] = { +#define SYM_TYPE(X) [X] = #X + SYM_TYPE(STT_NOTYPE), + SYM_TYPE(STT_OBJECT), + SYM_TYPE(STT_FUNC), + SYM_TYPE(STT_SECTION), + SYM_TYPE(STT_FILE), + SYM_TYPE(STT_COMMON), + SYM_TYPE(STT_TLS), +#undef SYM_TYPE + }; + const char *s_type = "unknown sym type name"; + if (type < sizeof(type_name)/sizeof(type_name[0])) { + s_type = type_name[type]; + } + return s_type; +} + +static const char *sym_bind(unsigned bind) +{ + static const char *bind_name[] = { +#define SYM_BIND(X) [X] = #X + SYM_BIND(STB_LOCAL), + SYM_BIND(STB_GLOBAL), + SYM_BIND(STB_WEAK), +#undef SYM_BIND + }; + const char *s_bind = "unknown sym bind name"; + if (bind < sizeof(bind_name)/sizeof(bind_name[0])) { + s_bind = bind_name[bind]; + } + return s_bind; +} + +static const char *sym_visibility(unsigned visibility) +{ + static const char *visibility_name[] = { +#define SYM_VISIBILITY(X) [X] = #X + SYM_VISIBILITY(STV_DEFAULT), + SYM_VISIBILITY(STV_INTERNAL), + SYM_VISIBILITY(STV_HIDDEN), + SYM_VISIBILITY(STV_PROTECTED), +#undef SYM_VISIBILITY + }; + const char *name = "unknown sym visibility name"; + if (visibility < sizeof(visibility_name)/sizeof(visibility_name[0])) { + name = visibility_name[visibility]; + } + return name; +} + +static const char *rel_type(unsigned type) +{ + static const char *type_name[] = { +#define REL_TYPE(X) [X] = #X + REL_TYPE(R_PPC64_NONE), + REL_TYPE(R_PPC64_ADDR32), + REL_TYPE(R_PPC64_ADDR24), + REL_TYPE(R_PPC64_ADDR16), + REL_TYPE(R_PPC64_ADDR16_LO), + REL_TYPE(R_PPC64_ADDR16_HI), + REL_TYPE(R_PPC64_ADDR16_HA), + REL_TYPE(R_PPC64_ADDR14 ), + REL_TYPE(R_PPC64_ADDR14_BRTAKEN), + REL_TYPE(R_PPC64_ADDR14_BRNTAKEN), + REL_TYPE(R_PPC64_REL24), + REL_TYPE(R_PPC64_REL14), + REL_TYPE(R_PPC64_REL14_BRTAKEN), + REL_TYPE(R_PPC64_REL14_BRNTAKEN), + REL_TYPE(R_PPC64_GOT16), + REL_TYPE(R_PPC64_GOT16_LO), + REL_TYPE(R_PPC64_GOT16_HI), + REL_TYPE(R_PPC64_GOT16_HA), + REL_TYPE(R_PPC64_COPY), + REL_TYPE(R_PPC64_GLOB_DAT), + REL_TYPE(R_PPC64_JMP_SLOT), + REL_TYPE(R_PPC64_RELATIVE), + REL_TYPE(R_PPC64_UADDR32), + REL_TYPE(R_PPC64_UADDR16), + REL_TYPE(R_PPC64_REL32), + REL_TYPE(R_PPC64_PLT32), + REL_TYPE(R_PPC64_PLTREL32), + REL_TYPE(R_PPC64_PLT16_LO), + REL_TYPE(R_PPC64_PLT16_HI), + REL_TYPE(R_PPC64_PLT16_HA), + REL_TYPE(R_PPC64_SECTOFF), + REL_TYPE(R_PPC64_SECTOFF_LO), + REL_TYPE(R_PPC64_SECTOFF_HI), + REL_TYPE(R_PPC64_SECTOFF_HA), + REL_TYPE(R_PPC64_ADDR30), + REL_TYPE(R_PPC64_ADDR64), + REL_TYPE(R_PPC64_ADDR16_HIGHER), + REL_TYPE(R_PPC64_ADDR16_HIGHERA), + REL_TYPE(R_PPC64_ADDR16_HIGHEST), + REL_TYPE(R_PPC64_ADDR16_HIGHESTA), + REL_TYPE(R_PPC64_UADDR64), + REL_TYPE(R_PPC64_REL64), + REL_TYPE(R_PPC64_PLT64), + REL_TYPE(R_PPC64_PLTREL64), + REL_TYPE(R_PPC64_TOC16), + REL_TYPE(R_PPC64_TOC16_LO), + REL_TYPE(R_PPC64_TOC16_HI), + REL_TYPE(R_PPC64_TOC16_HA), + REL_TYPE(R_PPC64_TOC), + REL_TYPE(R_PPC64_PLTGOT16), + REL_TYPE(R_PPC64_PLTGOT16_LO), + REL_TYPE(R_PPC64_PLTGOT16_HI), + REL_TYPE(R_PPC64_PLTGOT16_HA), + REL_TYPE(R_PPC64_ADDR16_DS), + REL_TYPE(R_PPC64_ADDR16_LO_DS), + REL_TYPE(R_PPC64_GOT16_DS), + REL_TYPE(R_PPC64_GOT16_LO_DS), + REL_TYPE(R_PPC64_PLT16_LO_DS), + REL_TYPE(R_PPC64_SECTOFF_DS), + REL_TYPE(R_PPC64_SECTOFF_LO_DS), + REL_TYPE(R_PPC64_TOC16_DS), + REL_TYPE(R_PPC64_TOC16_LO_DS), + REL_TYPE(R_PPC64_PLTGOT16_DS), + REL_TYPE(R_PPC64_PLTGOT16_LO_DS), + REL_TYPE(R_PPC64_TLS), + REL_TYPE(R_PPC64_DTPMOD64), + REL_TYPE(R_PPC64_TPREL16), + REL_TYPE(R_PPC64_TPREL16_LO), + REL_TYPE(R_PPC64_TPREL16_HI), + REL_TYPE(R_PPC64_TPREL16_HA), + REL_TYPE(R_PPC64_TPREL64), + REL_TYPE(R_PPC64_DTPREL16), + REL_TYPE(R_PPC64_DTPREL16_LO), + REL_TYPE(R_PPC64_DTPREL16_HI), + REL_TYPE(R_PPC64_DTPREL16_HA), + REL_TYPE(R_PPC64_DTPREL64), + REL_TYPE(R_PPC64_GOT_TLSGD16), + REL_TYPE(R_PPC64_GOT_TLSGD16_LO), + REL_TYPE(R_PPC64_GOT_TLSGD16_HI), + REL_TYPE(R_PPC64_GOT_TLSGD16_HA), + REL_TYPE(R_PPC64_GOT_TLSLD16), + REL_TYPE(R_PPC64_GOT_TLSLD16_LO), + REL_TYPE(R_PPC64_GOT_TLSLD16_HI), + REL_TYPE(R_PPC64_GOT_TLSLD16_HA), + REL_TYPE(R_PPC64_GOT_TPREL16_DS), + REL_TYPE(R_PPC64_GOT_TPREL16_LO_DS), + REL_TYPE(R_PPC64_GOT_TPREL16_HI), + REL_TYPE(R_PPC64_GOT_TPREL16_HA), + REL_TYPE(R_PPC64_GOT_DTPREL16_DS), + REL_TYPE(R_PPC64_GOT_DTPREL16_LO_DS), + REL_TYPE(R_PPC64_GOT_DTPREL16_HI), + REL_TYPE(R_PPC64_GOT_DTPREL16_HA), + REL_TYPE(R_PPC64_TPREL16_DS), + REL_TYPE(R_PPC64_TPREL16_LO_DS), + REL_TYPE(R_PPC64_TPREL16_HIGHER), + REL_TYPE(R_PPC64_TPREL16_HIGHERA), + REL_TYPE(R_PPC64_TPREL16_HIGHEST), + REL_TYPE(R_PPC64_TPREL16_HIGHESTA), + REL_TYPE(R_PPC64_DTPREL16_DS), + REL_TYPE(R_PPC64_DTPREL16_LO_DS), + REL_TYPE(R_PPC64_DTPREL16_HIGHER), + REL_TYPE(R_PPC64_DTPREL16_HIGHERA), + REL_TYPE(R_PPC64_DTPREL16_HIGHEST), + REL_TYPE(R_PPC64_DTPREL16_HIGHESTA), +#undef REL_TYPE + }; + const char *name = "unknown type rel type name"; + if (type < sizeof(type_name)/sizeof(type_name[0])) { + name = type_name[type]; + } + return name; +} + +static const char *sec_name(unsigned shndx) +{ + const char *sec_strtab; + const char *name; + sec_strtab = strtab[ehdr.e_shstrndx]; + name = "<noname>"; + if (shndx < ehdr.e_shnum) { + name = sec_strtab + shdr[shndx].sh_name; + } + else if (shndx == SHN_ABS) { + name = "ABSOLUTE"; + } + else if (shndx == SHN_COMMON) { + name = "COMMON"; + } + return name; +} + +static const char *sym_name(const char *sym_strtab, Elf64_Sym *sym) +{ + const char *name; + name = "<noname>"; + if (sym->st_name) { + name = sym_strtab + sym->st_name; + } + else { + name = sec_name(shdr[sym->st_shndx].sh_name); + } + return name; +} + + + +#if BYTE_ORDER == BIG_ENDIAN +#define be16_to_cpu(val) (val) +#define be32_to_cpu(val) (val) +#define be64_to_cpu(val) (val) +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +#define be16_to_cpu(val) bswap_16(val) +#define be32_to_cpu(val) bswap_32(val) +#define be64_to_cpu(val) bswap_64(val) +#endif + +static uint16_t elf16_to_cpu(uint16_t val) +{ + return be16_to_cpu(val); +} + +static uint32_t elf32_to_cpu(uint32_t val) +{ + return be32_to_cpu(val); +} + +static uint64_t elf64_to_cpu(uint64_t val) +{ + return be64_to_cpu(val); +} + +static void read_ehdr(FILE *fp) +{ + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { + die("Cannot read ELF header: %s\n", + strerror(errno)); + } + if (memcmp(ehdr.e_ident, ELFMAG, 4) != 0) { + die("No ELF magic\n"); + } + if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) { + die("Not a 64 bit executable\n"); + } + if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { + die("Not a MSB ELF executable\n"); + } + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { + die("Unknown ELF version\n"); + } + /* Convert the fields to native endian */ + ehdr.e_type = elf16_to_cpu(ehdr.e_type); + ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); + ehdr.e_version = elf32_to_cpu(ehdr.e_version); + ehdr.e_entry = elf64_to_cpu(ehdr.e_entry); + ehdr.e_phoff = elf64_to_cpu(ehdr.e_phoff); + ehdr.e_shoff = elf64_to_cpu(ehdr.e_shoff); + ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); + ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); + ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); + ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); + ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); + ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); + ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); + + if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { + die("Unsupported ELF header type\n"); + } + if (ehdr.e_machine != EM_PPC64) { + die("Not for PPC64\n"); + } + if (ehdr.e_version != EV_CURRENT) { + die("Unknown ELF version\n"); + } + if (ehdr.e_ehsize != sizeof(Elf64_Ehdr)) { + die("Bad Elf header size\n"); + } + if (ehdr.e_phentsize != sizeof(Elf64_Phdr)) { + die("Bad program header entry\n"); + } + if (ehdr.e_shentsize != sizeof(Elf64_Shdr)) { + die("Bad section header entry\n"); + } + if (ehdr.e_shstrndx >= ehdr.e_shnum) { + die("String table index out of bounds\n"); + } +} + +static void read_shdrs(FILE *fp) +{ + int i; + if (ehdr.e_shnum > MAX_SHDRS) { + die("%d section headers supported: %d\n", + ehdr.e_shnum, MAX_SHDRS); + } + if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + ehdr.e_shoff, strerror(errno)); + } + if (fread(&shdr, sizeof(shdr[0]), ehdr.e_shnum, fp) != ehdr.e_shnum) { + die("Cannot read ELF section headers: %s\n", + strerror(errno)); + } + for(i = 0; i < ehdr.e_shnum; i++) { + shdr[i].sh_name = elf32_to_cpu(shdr[i].sh_name); + shdr[i].sh_type = elf32_to_cpu(shdr[i].sh_type); + shdr[i].sh_flags = elf64_to_cpu(shdr[i].sh_flags); + shdr[i].sh_addr = elf64_to_cpu(shdr[i].sh_addr); + shdr[i].sh_offset = elf64_to_cpu(shdr[i].sh_offset); + shdr[i].sh_size = elf64_to_cpu(shdr[i].sh_size); + shdr[i].sh_link = elf32_to_cpu(shdr[i].sh_link); + shdr[i].sh_info = elf32_to_cpu(shdr[i].sh_info); + shdr[i].sh_addralign = elf64_to_cpu(shdr[i].sh_addralign); + shdr[i].sh_entsize = elf64_to_cpu(shdr[i].sh_entsize); + } + +} + +static void read_strtabs(FILE *fp) +{ + int i; + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_STRTAB) { + continue; + } + strtab[i] = malloc(shdr[i].sh_size); + if (!strtab[i]) { + die("malloc of %d bytes for strtab failed\n", + shdr[i].sh_size); + } + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(strtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + } +} + +static void read_symtabs(FILE *fp) +{ + int i,j; + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_SYMTAB) { + continue; + } + symtab[i] = malloc(shdr[i].sh_size); + if (!symtab[i]) { + die("malloc of %d bytes for symtab failed\n", + shdr[i].sh_size); + } + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(symtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + for(j = 0; j < shdr[i].sh_size/sizeof(symtab[i][0]); j++) { + symtab[i][j].st_name = elf32_to_cpu(symtab[i][j].st_name); + symtab[i][j].st_value = elf64_to_cpu(symtab[i][j].st_value); + symtab[i][j].st_size = elf64_to_cpu(symtab[i][j].st_size); + symtab[i][j].st_shndx = elf16_to_cpu(symtab[i][j].st_shndx); + } + } +} + + +static void read_relocs(FILE *fp) +{ + int i,j; + void *relp; + + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_REL && shdr[i].sh_type != SHT_RELA) + continue; + + if (shdr[i].sh_type == SHT_REL) { + reltab[i] = malloc(shdr[i].sh_size); + if (!reltab[i]) { + die("malloc of %d bytes for relocs failed\n", + shdr[i].sh_size); + } + relp = reltab[i]; + } else { + reltaba[i] = malloc(shdr[i].sh_size); + if (!reltaba[i]) { + die("malloc of %d bytes for relocs failed\n", + shdr[i].sh_size); + } + relp = reltaba[i]; + } + + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(relp, 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + + if (shdr[i].sh_type == SHT_REL) + for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) { + reltab[i][j].r_offset = elf64_to_cpu(reltab[i][j].r_offset); + reltab[i][j].r_info = elf64_to_cpu(reltab[i][j].r_info); + } + else + for(j = 0; j < shdr[i].sh_size/sizeof(reltaba[0][0]); j++) { + reltaba[i][j].r_offset = elf64_to_cpu(reltaba[i][j].r_offset); + reltaba[i][j].r_info = elf64_to_cpu(reltaba[i][j].r_info); + reltaba[i][j].r_addend = elf64_to_cpu(reltaba[i][j].r_addend); + } + } +} + + +static void print_absolute_symbols(void) +{ + int i; + printf("Absolute symbols\n"); + printf(" Num: Value Size Type Bind Visibility Name\n"); + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf64_Sym *sh_symtab; + int j; + if (shdr[i].sh_type != SHT_SYMTAB) { + continue; + } + sh_symtab = symtab[i]; + sym_strtab = strtab[shdr[i].sh_link]; + for(j = 0; j < shdr[i].sh_size/sizeof(symtab[0][0]); j++) { + Elf64_Sym *sym; + const char *name; + sym = &symtab[i][j]; + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + printf("type:[%s]\n", + sym_type(ELF64_ST_TYPE(sym->st_info))); + printf("%5d %016llx %5d type:%s bind:%10s %12s %s %s\n", \ + j, sym->st_value, sym->st_size, \ + sym_type(ELF64_ST_TYPE(sym->st_info)), \ + sym_bind(ELF64_ST_BIND(sym->st_info)), \ + sym_visibility(ELF64_ST_VISIBILITY(sym->st_other)), \ + name); + } + } + printf("\n"); +} + +static void print_absolute_relocs(void) +{ + int i, printed = 0; + int nr, sh_type; + + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf64_Sym *sh_symtab; + unsigned sec_applies, sec_symtab; + int j; + if (shdr[i].sh_type != SHT_REL && shdr[i].sh_type != SHT_RELA) { + continue; + } + sec_symtab = shdr[i].sh_link; + sec_applies = shdr[i].sh_info; + if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) { + continue; + } + if (shdr[i].sh_type == SHT_REL) { + sh_type = SHT_REL; + nr = shdr[i].sh_size/sizeof(reltab[0][0]); + } else { + sh_type = SHT_RELA; + nr = shdr[i].sh_size/sizeof(reltaba[0][0]); + } + + sh_symtab = symtab[sec_symtab]; + sym_strtab = strtab[shdr[sec_symtab].sh_link]; + + for(j = 0; j < nr; j++) { + Elf64_Rel *rel; + Elf64_Rela *rela; + Elf64_Sym *sym; + const char *name; + + if (sh_type == SHT_REL) { + rel = &reltab[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rel->r_info)]; + } else { + rela = &reltaba[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rela->r_info)]; + } + + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + + /* Absolute symbols are not relocated if vmlinux is + * loaded at a non-compiled address. Display a warning + * to user at compile time about the absolute + * relocations present. + * + * User need to audit the code to make sure + * some symbols which should have been section + * relative have not become absolute because of some + * linker optimization or wrong programming usage. + * + * Before warning check if this absolute symbol + * relocation is harmless. + */ + if (is_safe_abs_reloc(name)) + continue; + + if (!printed) { + printf("WARNING: Absolute relocations" + " present\n"); + printf("Offset Info Type Sym.Value " + "Sym.Name\n"); + printed = 1; + } + + if (sh_type == SHT_REL) + printf("%016llx %016llx %10s %016llx %s\n", + rel->r_offset, + rel->r_info, + rel_type(ELF64_R_TYPE(rel->r_info)), + sym->st_value, + name); + else + printf("%016llx %016llx %10s %016llx %s\n", + rela->r_offset, + rela->r_info, + rel_type(ELF64_R_TYPE(rela->r_info)), + sym->st_value, + name); + } + } + + if (printed) + printf("\n"); +} + +static void walk_relocs(void (*visit)(void *relp, Elf64_Sym *sym, int sh_type)) +{ + int i; + /* Walk through the relocations */ + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf64_Sym *sh_symtab; + unsigned sec_applies, sec_symtab; + int j, nr_entries, sh_type; + if (shdr[i].sh_type != SHT_REL && shdr[i].sh_type != SHT_RELA) { + continue; + } + sec_symtab = shdr[i].sh_link; + sec_applies = shdr[i].sh_info; + if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) { + continue; + } + sh_symtab = symtab[sec_symtab]; + sym_strtab = strtab[shdr[sec_symtab].sh_link]; + if (shdr[i].sh_type == SHT_REL) { + sh_type = SHT_REL; + nr_entries = shdr[i].sh_size/sizeof(reltab[0][0]); + } else { + sh_type = SHT_RELA; + nr_entries = shdr[i].sh_size/sizeof(reltaba[0][0]); + } + + for(j = 0; j < nr_entries; j++) { + Elf64_Rel *rel; + Elf64_Rela *rela; + Elf64_Sym *sym; + void *relp; + unsigned r_type; + + if (sh_type == SHT_REL) { + rel = &reltab[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rel->r_info)]; + r_type = ELF64_R_TYPE(rel->r_info); + relp = rel; + } else { + rela = &reltaba[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rela->r_info)]; + r_type = ELF64_R_TYPE(rela->r_info); + relp = rela; + } + /* Don't visit relocations to absolute symbols */ + if (sym->st_shndx == SHN_ABS) { + continue; + } + /* PC relative relocations don't need to be adjusted */ + switch (r_type) { + case R_PPC64_ADDR32: + case R_PPC64_ADDR16: + case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR24: + case R_PPC64_ADDR64: + case R_PPC64_TOC: + /* Visit relocations that need to be adjusted */ + visit(relp, sym, sh_type); + break; + case R_PPC64_ADDR16_LO: + case R_PPC64_REL24: + case R_PPC64_REL64: + case R_PPC64_TOC16: + case R_PPC64_ADDR16_LO_DS: + case R_PPC64_ADDR16_HIGHEST: + case R_PPC64_ADDR16_HIGHER: + case R_PPC64_GOT16_DS: + case R_PPC64_TOC16_DS: + case R_PPC64_REL14: + default: + break; + } + } + } +} + +static void count_reloc(void *relp, Elf64_Sym *sym, int sh_type) +{ + reloc_count += 1; +} + +static void collect_reloc(void *relp, Elf64_Sym *sym, int sh_type) +{ + Elf64_Rel *rel; + Elf64_Rela *rela; + + /* Remember the address that needs to be adjusted. */ + if (sh_type == SHT_REL) { + rel = (Elf64_Rel *)relp; + relocs[reloc_idx].offset = rel->r_offset; + relocs[reloc_idx++].rel_type = ELF64_R_TYPE(rel->r_info); + } else { + rela = (Elf64_Rela *)relp; + relocs[reloc_idx].offset = rela->r_offset; + relocs[reloc_idx++].rel_type = ELF64_R_TYPE(rela->r_info); + } +} + +static int cmp_relocs(const void *va, const void *vb) +{ + const struct reloc_info *a, *b; + a = va; b = vb; + return (a->rel_type == b->rel_type)? 0 : (a->rel_type > b->rel_type)? 1 : -1; +} + +static void emit_relocs(int as_text) +{ + int i; + int prev_r_type; + /* Count how many relocations I have and allocate space for them. */ + reloc_count = 0; + walk_relocs(count_reloc); + relocs = malloc(reloc_count * sizeof(relocs[0])); + if (!relocs) { + die("malloc of %d entries for relocs failed\n", + reloc_count); + } + /* Collect up the relocations */ + reloc_idx = 0; + walk_relocs(collect_reloc); + + /* Order the relocations for more efficient processing */ + qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); + + /* Print the relocations */ + if (as_text) { + /* Print the relocations in a form suitable that + * gas will like. + */ + printf(".section \".data.reloc\",\"a\"\n"); + printf(".balign 4\n"); + + printf("\t .long 0x%016llx\n", relocs[0].offset); + prev_r_type = relocs[0].rel_type; + + for(i = 1; i < reloc_count; i++) { + if (prev_r_type != relocs[i].rel_type && prev_r_type == R_PPC64_ADDR16_HI) { + printf("\t .long 0xffffffffffffffff\n"); + prev_r_type = relocs[i].rel_type; + } + printf("\t .long 0x%016llx\n", relocs[i].offset); + } + printf("\n"); + } + else { + unsigned char buf[8]; + buf[0] = buf[1] = buf[2] = buf[3] = 0; + buf[4] = buf[5] = buf[6] = buf[7] = 0; + + /* Print a stop */ + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + printf("%c%c%c%c", buf[4], buf[5], buf[6], buf[7]); + + buf[7] = (relocs[0].offset >> 0) & 0xff; + buf[6] = (relocs[0].offset >> 8) & 0xff; + buf[5] = (relocs[0].offset >> 16) & 0xff; + buf[4] = (relocs[0].offset >> 24) & 0xff; + buf[3] = (relocs[0].offset >> 32) & 0xff; + buf[2] = (relocs[0].offset >> 40) & 0xff; + buf[1] = (relocs[0].offset >> 48) & 0xff; + buf[0] = (relocs[0].offset >> 56) & 0xff; + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + printf("%c%c%c%c", buf[4], buf[5], buf[6], buf[7]); + + prev_r_type = relocs[0].rel_type; + + /* Now print each relocation */ + for(i = 1; i < reloc_count; i++) { + if (prev_r_type != relocs[i].rel_type && prev_r_type == R_PPC64_ADDR16_HI) { + printf("%c%c%c%c", 0xff, 0xff, 0xff, 0xff); + printf("%c%c%c%c", 0xff, 0xff, 0xff, 0xff); + prev_r_type = relocs[i].rel_type; + } + buf[7] = (relocs[i].offset >> 0) & 0xff; + buf[6] = (relocs[i].offset >> 8) & 0xff; + buf[5] = (relocs[i].offset >> 16) & 0xff; + buf[4] = (relocs[i].offset >> 24) & 0xff; + buf[3] = (relocs[i].offset >> 32) & 0xff; + buf[2] = (relocs[i].offset >> 40) & 0xff; + buf[1] = (relocs[i].offset >> 48) & 0xff; + buf[0] = (relocs[i].offset >> 56) & 0xff; + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + printf("%c%c%c%c", buf[4], buf[5], buf[6], buf[7]); + } + buf[0] = buf[1] = buf[2] = buf[3] = 0; + buf[4] = buf[5] = buf[6] = buf[7] = 0; + } +} + +static void usage(void) +{ + die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n"); +} + +int main(int argc, char **argv) +{ + int show_absolute_syms, show_absolute_relocs; + int as_text; + const char *fname; + FILE *fp; + int i; + + show_absolute_syms = 0; + show_absolute_relocs = 0; + as_text = 0; + fname = NULL; + for(i = 1; i < argc; i++) { + char *arg = argv[i]; + if (*arg == '-') { + if (strcmp(argv[1], "--abs-syms") == 0) { + show_absolute_syms = 1; + continue; + } + + if (strcmp(argv[1], "--abs-relocs") == 0) { + show_absolute_relocs = 1; + continue; + } + else if (strcmp(argv[1], "--text") == 0) { + as_text = 1; + continue; + } + } + else if (!fname) { + fname = arg; + continue; + } + usage(); + } + if (!fname) { + usage(); + } + fp = fopen(fname, "r"); + if (!fp) { + die("Cannot open %s: %s\n", + fname, strerror(errno)); + } + read_ehdr(fp); + read_shdrs(fp); + read_strtabs(fp); + read_symtabs(fp); + read_relocs(fp); + if (show_absolute_syms) { + print_absolute_symbols(); + return 0; + } + if (show_absolute_relocs) { + print_absolute_relocs(); + return 0; + } + emit_relocs(as_text); + return 0; +} ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 1/4] Extract list of relocation offsets 2008-07-17 18:40 ` [RFC v3 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M @ 2008-07-17 20:06 ` Benjamin Herrenschmidt 2008-07-18 5:32 ` Mohan Kumar M 0 siblings, 1 reply; 22+ messages in thread From: Benjamin Herrenschmidt @ 2008-07-17 20:06 UTC (permalink / raw) To: mohan; +Cc: ppcdev, paulus, miltonm On Fri, 2008-07-18 at 00:10 +0530, Mohan Kumar M wrote: > Extract list of relocation offsets > > Extract list of offsets in the vmlinux file for which the relocation > delta has to be patched. Currently only following type of relocation > types are considered: R_PPC64_ADDR16_HI, R_PPC64_TOC and R_PPC64_ADDR64 > > The offsets are sorted according to the relocation type and this > information is appended to the normal vmlinux file by using the patch > relocation_build.patch Please, provide an indication of what changed since the previous version of the patch to make the reviewer's life easier ! Thanks, Ben. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 1/4] Extract list of relocation offsets 2008-07-17 20:06 ` Benjamin Herrenschmidt @ 2008-07-18 5:32 ` Mohan Kumar M 2008-07-18 17:00 ` Milton Miller 0 siblings, 1 reply; 22+ messages in thread From: Mohan Kumar M @ 2008-07-18 5:32 UTC (permalink / raw) To: benh; +Cc: ppcdev, paulus, miltonm Benjamin Herrenschmidt wrote: > On Fri, 2008-07-18 at 00:10 +0530, Mohan Kumar M wrote: >> Extract list of relocation offsets >> >> Extract list of offsets in the vmlinux file for which the relocation >> delta has to be patched. Currently only following type of relocation >> types are considered: R_PPC64_ADDR16_HI, R_PPC64_TOC and R_PPC64_ADDR64 >> >> The offsets are sorted according to the relocation type and this >> information is appended to the normal vmlinux file by using the patch >> relocation_build.patch > > Please, provide an indication of what changed since the previous > version of the patch to make the reviewer's life easier ! > Hi, Oops, I missed out the detailed change description. Thanks Ben for pointing this. Here is a change summary from v2 to v3: PATCH 1: The difference is relocs.c is moved to arch/powerpc/boot from arch/powerpc/ PATCH 2: Relocation build support is now 90% integrated with kernel build process. Earlier one has to run separately different make to build vmlinux.reloc image. Required linker scripts are moved to arch/powerpc/boot from arch/powerpc PATCH 3: The difference is reloc_apply.S is moved to arch/powerpc/boot from arch/powerpc/ PATCH 4: Enough care is taken when creating bolted mapping for kdump kernel. Now it creates bolted mapping from 32MB to of size "crash kernel size" in case of crash kernel. Regards, Mohan. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 1/4] Extract list of relocation offsets 2008-07-18 5:32 ` Mohan Kumar M @ 2008-07-18 17:00 ` Milton Miller 2008-07-21 19:17 ` Mohan Kumar M ` (5 more replies) 0 siblings, 6 replies; 22+ messages in thread From: Milton Miller @ 2008-07-18 17:00 UTC (permalink / raw) To: Mohan Kumar M; +Cc: paulus, ppcdev On Jul 18, 2008, at 12:32 AM, Mohan Kumar M wrote: > Benjamin Herrenschmidt wrote: >> On Fri, 2008-07-18 at 00:10 +0530, Mohan Kumar M wrote: >>> Extract list of relocation offsets >>> >> Please, provide an indication of what changed since the previous >> version of the patch to make the reviewer's life easier ! >> > Hi, > > Oops, I missed out the detailed change description. Thanks Ben for > pointing this. > > Here is a change summary from v2 to v3: Last night I was trying the patches on the current upstream git, but was not able to get the dump kernel to user space. Part of the problem was my own making (my default kernel is patched to crash dump to 16M instead of 32M among other patches, so I needed to go to a normal kernel first, but couldn't use the reloc kernel because the slaves would stick and then the code would wait in the IPI). I now understand why the remaining cpus do not make it into the crash kernel. In fact they don't make it from kexec of a good kernel into a reloc kernel. I'm ignoring that for now because, as I told you via chat, I realize from looking at the patches that the reloc_apply code needs to move from the external wrapper to inside the kernel init section or maybe the head, even if the reloc data is applied after the link of vmlinux. While I still need to work out the details to supply it with the data, I'm convinced its the best way to eliminate the extra move of the kernel image. (My current guess is to count the relocations on the first vmlinux and supply a dummy section of the correct size that can be replaced with objcopy once the link is complete). If I don't get this done, we should change the build to just use the slave hold loop from the kernel directly, similar to what I put in kexec-tools with purgatory. > PATCH 1: > The difference is relocs.c is moved to arch/powerpc/boot from > arch/powerpc/ > > PATCH 2: > Relocation build support is now 90% integrated with kernel build > process. Earlier one has to run separately different make to build > vmlinux.reloc image. Required linker scripts are moved to > arch/powerpc/boot from arch/powerpc vmlinux-reloc.scr was missing. I found it in v2. Also, I had to find it in $(srctree)/$(src) since it is not generated like lds files. > > PATCH 3: > The difference is reloc_apply.S is moved to arch/powerpc/boot from > arch/powerpc/ > > PATCH 4: > Enough care is taken when creating bolted mapping for kdump kernel. > Now it creates bolted mapping from 32MB to of size "crash kernel size" > in case of crash kernel. The patch does not apply anymore because create_trampoline has changed. There seem to be way too many places we have RELOC and the relocation offset applied. While I expected the uses of PHYSICAL_OFFSET and existing uses of CONFIG_CRASH_DUMP, there seem to be lots of other changes, and to me it feels like trying to make up for missing relocation processing with code. That is precisely what we were trying to avoid when we selected the emit_relocs and process them approach. I might give another go at using the existing patches, but if you rediff, can you sepearte patch 4 into two parts, one that does stuff around PHYSICAL_START or CRASH_DUMP, and one that does the rest? Thanks, milton ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 1/4] Extract list of relocation offsets 2008-07-18 17:00 ` Milton Miller @ 2008-07-21 19:17 ` Mohan Kumar M 2008-07-22 6:29 ` Paul Mackerras 2008-07-21 19:20 ` [RFC v3 PATCH 2/4] Build files needed for relocation Mohan Kumar M ` (4 subsequent siblings) 5 siblings, 1 reply; 22+ messages in thread From: Mohan Kumar M @ 2008-07-21 19:17 UTC (permalink / raw) To: Milton Miller; +Cc: paulus, naren, ppcdev [-- Attachment #1: Type: text/plain, Size: 248 bytes --] Hi Milton, I am resending the patches generated against latest powerpc git tree. I am facing kdump kernel hang issue with the git tree. It hangs in unflatten_devicetree call in prom.c Note: These patches are not fully tested. Regards, Mohan. [-- Attachment #2: 0001-Extract-list-of-relocation-offsets.patch --] [-- Type: text/x-patch, Size: 24353 bytes --] Extract list of relocation offsets Extract list of offsets in the vmlinux file for which the relocation delta has to be patched. Currently only following type of relocation types are considered: R_PPC64_ADDR16_HI, R_PPC64_TOC and R_PPC64_ADDR64 The offsets are sorted according to the relocation type and this information is appended to the normal vmlinux file by using the patch relocation_build.patch Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/boot/relocs.c | 865 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 865 insertions(+), 0 deletions(-) create mode 100644 arch/powerpc/boot/relocs.c diff --git a/arch/powerpc/boot/relocs.c b/arch/powerpc/boot/relocs.c new file mode 100644 index 0000000..31ca903 --- /dev/null +++ b/arch/powerpc/boot/relocs.c @@ -0,0 +1,865 @@ +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <elf.h> +#include <byteswap.h> +#define USE_BSD +#include <endian.h> + +#define MAX_SHDRS 100 +static Elf64_Ehdr ehdr; +static Elf64_Shdr shdr[MAX_SHDRS]; +static Elf64_Sym *symtab[MAX_SHDRS]; +static Elf64_Rel *reltab[MAX_SHDRS]; +static Elf64_Rela *reltaba[MAX_SHDRS]; +static char *strtab[MAX_SHDRS]; +static unsigned long reloc_count, reloc_idx; + +struct reloc_info { + unsigned int rel_type; + unsigned long long offset; +}; + +static struct reloc_info *relocs; + +/* + * Following symbols have been audited. There values are constant and do + * not change if bzImage is loaded at a different physical address than + * the address for which it has been compiled. Don't warn user about + * absolute relocations present w.r.t these symbols. + */ +static const char* safe_abs_relocs[] = { + "__kernel_vsyscall", + "__kernel_rt_sigreturn", + "__kernel_sigreturn", + "SYSENTER_RETURN", +}; + +static int is_safe_abs_reloc(const char* sym_name) +{ + int i, array_size; + + array_size = sizeof(safe_abs_relocs)/sizeof(char*); + + for(i = 0; i < array_size; i++) { + if (!strcmp(sym_name, safe_abs_relocs[i])) + /* Match found */ + return 1; + } + if (strncmp(sym_name, "__crc_", 6) == 0) + return 1; + return 0; +} + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static const char *sym_type(unsigned type) +{ + static const char *type_name[] = { +#define SYM_TYPE(X) [X] = #X + SYM_TYPE(STT_NOTYPE), + SYM_TYPE(STT_OBJECT), + SYM_TYPE(STT_FUNC), + SYM_TYPE(STT_SECTION), + SYM_TYPE(STT_FILE), + SYM_TYPE(STT_COMMON), + SYM_TYPE(STT_TLS), +#undef SYM_TYPE + }; + const char *s_type = "unknown sym type name"; + if (type < sizeof(type_name)/sizeof(type_name[0])) { + s_type = type_name[type]; + } + return s_type; +} + +static const char *sym_bind(unsigned bind) +{ + static const char *bind_name[] = { +#define SYM_BIND(X) [X] = #X + SYM_BIND(STB_LOCAL), + SYM_BIND(STB_GLOBAL), + SYM_BIND(STB_WEAK), +#undef SYM_BIND + }; + const char *s_bind = "unknown sym bind name"; + if (bind < sizeof(bind_name)/sizeof(bind_name[0])) { + s_bind = bind_name[bind]; + } + return s_bind; +} + +static const char *sym_visibility(unsigned visibility) +{ + static const char *visibility_name[] = { +#define SYM_VISIBILITY(X) [X] = #X + SYM_VISIBILITY(STV_DEFAULT), + SYM_VISIBILITY(STV_INTERNAL), + SYM_VISIBILITY(STV_HIDDEN), + SYM_VISIBILITY(STV_PROTECTED), +#undef SYM_VISIBILITY + }; + const char *name = "unknown sym visibility name"; + if (visibility < sizeof(visibility_name)/sizeof(visibility_name[0])) { + name = visibility_name[visibility]; + } + return name; +} + +static const char *rel_type(unsigned type) +{ + static const char *type_name[] = { +#define REL_TYPE(X) [X] = #X + REL_TYPE(R_PPC64_NONE), + REL_TYPE(R_PPC64_ADDR32), + REL_TYPE(R_PPC64_ADDR24), + REL_TYPE(R_PPC64_ADDR16), + REL_TYPE(R_PPC64_ADDR16_LO), + REL_TYPE(R_PPC64_ADDR16_HI), + REL_TYPE(R_PPC64_ADDR16_HA), + REL_TYPE(R_PPC64_ADDR14 ), + REL_TYPE(R_PPC64_ADDR14_BRTAKEN), + REL_TYPE(R_PPC64_ADDR14_BRNTAKEN), + REL_TYPE(R_PPC64_REL24), + REL_TYPE(R_PPC64_REL14), + REL_TYPE(R_PPC64_REL14_BRTAKEN), + REL_TYPE(R_PPC64_REL14_BRNTAKEN), + REL_TYPE(R_PPC64_GOT16), + REL_TYPE(R_PPC64_GOT16_LO), + REL_TYPE(R_PPC64_GOT16_HI), + REL_TYPE(R_PPC64_GOT16_HA), + REL_TYPE(R_PPC64_COPY), + REL_TYPE(R_PPC64_GLOB_DAT), + REL_TYPE(R_PPC64_JMP_SLOT), + REL_TYPE(R_PPC64_RELATIVE), + REL_TYPE(R_PPC64_UADDR32), + REL_TYPE(R_PPC64_UADDR16), + REL_TYPE(R_PPC64_REL32), + REL_TYPE(R_PPC64_PLT32), + REL_TYPE(R_PPC64_PLTREL32), + REL_TYPE(R_PPC64_PLT16_LO), + REL_TYPE(R_PPC64_PLT16_HI), + REL_TYPE(R_PPC64_PLT16_HA), + REL_TYPE(R_PPC64_SECTOFF), + REL_TYPE(R_PPC64_SECTOFF_LO), + REL_TYPE(R_PPC64_SECTOFF_HI), + REL_TYPE(R_PPC64_SECTOFF_HA), + REL_TYPE(R_PPC64_ADDR30), + REL_TYPE(R_PPC64_ADDR64), + REL_TYPE(R_PPC64_ADDR16_HIGHER), + REL_TYPE(R_PPC64_ADDR16_HIGHERA), + REL_TYPE(R_PPC64_ADDR16_HIGHEST), + REL_TYPE(R_PPC64_ADDR16_HIGHESTA), + REL_TYPE(R_PPC64_UADDR64), + REL_TYPE(R_PPC64_REL64), + REL_TYPE(R_PPC64_PLT64), + REL_TYPE(R_PPC64_PLTREL64), + REL_TYPE(R_PPC64_TOC16), + REL_TYPE(R_PPC64_TOC16_LO), + REL_TYPE(R_PPC64_TOC16_HI), + REL_TYPE(R_PPC64_TOC16_HA), + REL_TYPE(R_PPC64_TOC), + REL_TYPE(R_PPC64_PLTGOT16), + REL_TYPE(R_PPC64_PLTGOT16_LO), + REL_TYPE(R_PPC64_PLTGOT16_HI), + REL_TYPE(R_PPC64_PLTGOT16_HA), + REL_TYPE(R_PPC64_ADDR16_DS), + REL_TYPE(R_PPC64_ADDR16_LO_DS), + REL_TYPE(R_PPC64_GOT16_DS), + REL_TYPE(R_PPC64_GOT16_LO_DS), + REL_TYPE(R_PPC64_PLT16_LO_DS), + REL_TYPE(R_PPC64_SECTOFF_DS), + REL_TYPE(R_PPC64_SECTOFF_LO_DS), + REL_TYPE(R_PPC64_TOC16_DS), + REL_TYPE(R_PPC64_TOC16_LO_DS), + REL_TYPE(R_PPC64_PLTGOT16_DS), + REL_TYPE(R_PPC64_PLTGOT16_LO_DS), + REL_TYPE(R_PPC64_TLS), + REL_TYPE(R_PPC64_DTPMOD64), + REL_TYPE(R_PPC64_TPREL16), + REL_TYPE(R_PPC64_TPREL16_LO), + REL_TYPE(R_PPC64_TPREL16_HI), + REL_TYPE(R_PPC64_TPREL16_HA), + REL_TYPE(R_PPC64_TPREL64), + REL_TYPE(R_PPC64_DTPREL16), + REL_TYPE(R_PPC64_DTPREL16_LO), + REL_TYPE(R_PPC64_DTPREL16_HI), + REL_TYPE(R_PPC64_DTPREL16_HA), + REL_TYPE(R_PPC64_DTPREL64), + REL_TYPE(R_PPC64_GOT_TLSGD16), + REL_TYPE(R_PPC64_GOT_TLSGD16_LO), + REL_TYPE(R_PPC64_GOT_TLSGD16_HI), + REL_TYPE(R_PPC64_GOT_TLSGD16_HA), + REL_TYPE(R_PPC64_GOT_TLSLD16), + REL_TYPE(R_PPC64_GOT_TLSLD16_LO), + REL_TYPE(R_PPC64_GOT_TLSLD16_HI), + REL_TYPE(R_PPC64_GOT_TLSLD16_HA), + REL_TYPE(R_PPC64_GOT_TPREL16_DS), + REL_TYPE(R_PPC64_GOT_TPREL16_LO_DS), + REL_TYPE(R_PPC64_GOT_TPREL16_HI), + REL_TYPE(R_PPC64_GOT_TPREL16_HA), + REL_TYPE(R_PPC64_GOT_DTPREL16_DS), + REL_TYPE(R_PPC64_GOT_DTPREL16_LO_DS), + REL_TYPE(R_PPC64_GOT_DTPREL16_HI), + REL_TYPE(R_PPC64_GOT_DTPREL16_HA), + REL_TYPE(R_PPC64_TPREL16_DS), + REL_TYPE(R_PPC64_TPREL16_LO_DS), + REL_TYPE(R_PPC64_TPREL16_HIGHER), + REL_TYPE(R_PPC64_TPREL16_HIGHERA), + REL_TYPE(R_PPC64_TPREL16_HIGHEST), + REL_TYPE(R_PPC64_TPREL16_HIGHESTA), + REL_TYPE(R_PPC64_DTPREL16_DS), + REL_TYPE(R_PPC64_DTPREL16_LO_DS), + REL_TYPE(R_PPC64_DTPREL16_HIGHER), + REL_TYPE(R_PPC64_DTPREL16_HIGHERA), + REL_TYPE(R_PPC64_DTPREL16_HIGHEST), + REL_TYPE(R_PPC64_DTPREL16_HIGHESTA), +#undef REL_TYPE + }; + const char *name = "unknown type rel type name"; + if (type < sizeof(type_name)/sizeof(type_name[0])) { + name = type_name[type]; + } + return name; +} + +static const char *sec_name(unsigned shndx) +{ + const char *sec_strtab; + const char *name; + sec_strtab = strtab[ehdr.e_shstrndx]; + name = "<noname>"; + if (shndx < ehdr.e_shnum) { + name = sec_strtab + shdr[shndx].sh_name; + } + else if (shndx == SHN_ABS) { + name = "ABSOLUTE"; + } + else if (shndx == SHN_COMMON) { + name = "COMMON"; + } + return name; +} + +static const char *sym_name(const char *sym_strtab, Elf64_Sym *sym) +{ + const char *name; + name = "<noname>"; + if (sym->st_name) { + name = sym_strtab + sym->st_name; + } + else { + name = sec_name(shdr[sym->st_shndx].sh_name); + } + return name; +} + + + +#if BYTE_ORDER == BIG_ENDIAN +#define be16_to_cpu(val) (val) +#define be32_to_cpu(val) (val) +#define be64_to_cpu(val) (val) +#endif +#if BYTE_ORDER == LITTLE_ENDIAN +#define be16_to_cpu(val) bswap_16(val) +#define be32_to_cpu(val) bswap_32(val) +#define be64_to_cpu(val) bswap_64(val) +#endif + +static uint16_t elf16_to_cpu(uint16_t val) +{ + return be16_to_cpu(val); +} + +static uint32_t elf32_to_cpu(uint32_t val) +{ + return be32_to_cpu(val); +} + +static uint64_t elf64_to_cpu(uint64_t val) +{ + return be64_to_cpu(val); +} + +static void read_ehdr(FILE *fp) +{ + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { + die("Cannot read ELF header: %s\n", + strerror(errno)); + } + if (memcmp(ehdr.e_ident, ELFMAG, 4) != 0) { + die("No ELF magic\n"); + } + if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) { + die("Not a 64 bit executable\n"); + } + if (ehdr.e_ident[EI_DATA] != ELFDATA2MSB) { + die("Not a MSB ELF executable\n"); + } + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { + die("Unknown ELF version\n"); + } + /* Convert the fields to native endian */ + ehdr.e_type = elf16_to_cpu(ehdr.e_type); + ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); + ehdr.e_version = elf32_to_cpu(ehdr.e_version); + ehdr.e_entry = elf64_to_cpu(ehdr.e_entry); + ehdr.e_phoff = elf64_to_cpu(ehdr.e_phoff); + ehdr.e_shoff = elf64_to_cpu(ehdr.e_shoff); + ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); + ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); + ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); + ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); + ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); + ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); + ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); + + if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { + die("Unsupported ELF header type\n"); + } + if (ehdr.e_machine != EM_PPC64) { + die("Not for PPC64\n"); + } + if (ehdr.e_version != EV_CURRENT) { + die("Unknown ELF version\n"); + } + if (ehdr.e_ehsize != sizeof(Elf64_Ehdr)) { + die("Bad Elf header size\n"); + } + if (ehdr.e_phentsize != sizeof(Elf64_Phdr)) { + die("Bad program header entry\n"); + } + if (ehdr.e_shentsize != sizeof(Elf64_Shdr)) { + die("Bad section header entry\n"); + } + if (ehdr.e_shstrndx >= ehdr.e_shnum) { + die("String table index out of bounds\n"); + } +} + +static void read_shdrs(FILE *fp) +{ + int i; + if (ehdr.e_shnum > MAX_SHDRS) { + die("%d section headers supported: %d\n", + ehdr.e_shnum, MAX_SHDRS); + } + if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + ehdr.e_shoff, strerror(errno)); + } + if (fread(&shdr, sizeof(shdr[0]), ehdr.e_shnum, fp) != ehdr.e_shnum) { + die("Cannot read ELF section headers: %s\n", + strerror(errno)); + } + for(i = 0; i < ehdr.e_shnum; i++) { + shdr[i].sh_name = elf32_to_cpu(shdr[i].sh_name); + shdr[i].sh_type = elf32_to_cpu(shdr[i].sh_type); + shdr[i].sh_flags = elf64_to_cpu(shdr[i].sh_flags); + shdr[i].sh_addr = elf64_to_cpu(shdr[i].sh_addr); + shdr[i].sh_offset = elf64_to_cpu(shdr[i].sh_offset); + shdr[i].sh_size = elf64_to_cpu(shdr[i].sh_size); + shdr[i].sh_link = elf32_to_cpu(shdr[i].sh_link); + shdr[i].sh_info = elf32_to_cpu(shdr[i].sh_info); + shdr[i].sh_addralign = elf64_to_cpu(shdr[i].sh_addralign); + shdr[i].sh_entsize = elf64_to_cpu(shdr[i].sh_entsize); + } + +} + +static void read_strtabs(FILE *fp) +{ + int i; + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_STRTAB) { + continue; + } + strtab[i] = malloc(shdr[i].sh_size); + if (!strtab[i]) { + die("malloc of %d bytes for strtab failed\n", + shdr[i].sh_size); + } + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(strtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + } +} + +static void read_symtabs(FILE *fp) +{ + int i,j; + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_SYMTAB) { + continue; + } + symtab[i] = malloc(shdr[i].sh_size); + if (!symtab[i]) { + die("malloc of %d bytes for symtab failed\n", + shdr[i].sh_size); + } + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(symtab[i], 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + for(j = 0; j < shdr[i].sh_size/sizeof(symtab[i][0]); j++) { + symtab[i][j].st_name = elf32_to_cpu(symtab[i][j].st_name); + symtab[i][j].st_value = elf64_to_cpu(symtab[i][j].st_value); + symtab[i][j].st_size = elf64_to_cpu(symtab[i][j].st_size); + symtab[i][j].st_shndx = elf16_to_cpu(symtab[i][j].st_shndx); + } + } +} + + +static void read_relocs(FILE *fp) +{ + int i,j; + void *relp; + + for(i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type != SHT_REL && shdr[i].sh_type != SHT_RELA) + continue; + + if (shdr[i].sh_type == SHT_REL) { + reltab[i] = malloc(shdr[i].sh_size); + if (!reltab[i]) { + die("malloc of %d bytes for relocs failed\n", + shdr[i].sh_size); + } + relp = reltab[i]; + } else { + reltaba[i] = malloc(shdr[i].sh_size); + if (!reltaba[i]) { + die("malloc of %d bytes for relocs failed\n", + shdr[i].sh_size); + } + relp = reltaba[i]; + } + + if (fseek(fp, shdr[i].sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + shdr[i].sh_offset, strerror(errno)); + } + if (fread(relp, 1, shdr[i].sh_size, fp) != shdr[i].sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + + if (shdr[i].sh_type == SHT_REL) + for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) { + reltab[i][j].r_offset = elf64_to_cpu(reltab[i][j].r_offset); + reltab[i][j].r_info = elf64_to_cpu(reltab[i][j].r_info); + } + else + for(j = 0; j < shdr[i].sh_size/sizeof(reltaba[0][0]); j++) { + reltaba[i][j].r_offset = elf64_to_cpu(reltaba[i][j].r_offset); + reltaba[i][j].r_info = elf64_to_cpu(reltaba[i][j].r_info); + reltaba[i][j].r_addend = elf64_to_cpu(reltaba[i][j].r_addend); + } + } +} + + +static void print_absolute_symbols(void) +{ + int i; + printf("Absolute symbols\n"); + printf(" Num: Value Size Type Bind Visibility Name\n"); + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf64_Sym *sh_symtab; + int j; + if (shdr[i].sh_type != SHT_SYMTAB) { + continue; + } + sh_symtab = symtab[i]; + sym_strtab = strtab[shdr[i].sh_link]; + for(j = 0; j < shdr[i].sh_size/sizeof(symtab[0][0]); j++) { + Elf64_Sym *sym; + const char *name; + sym = &symtab[i][j]; + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + printf("type:[%s]\n", + sym_type(ELF64_ST_TYPE(sym->st_info))); + printf("%5d %016llx %5d type:%s bind:%10s %12s %s\n", \ + j, sym->st_value, (int)(sym->st_size), \ + sym_type(ELF64_ST_TYPE(sym->st_info)), \ + sym_bind(ELF64_ST_BIND(sym->st_info)), \ + sym_visibility(ELF64_ST_VISIBILITY(sym->st_other)), \ + name); + } + } + printf("\n"); +} + +static void print_absolute_relocs(void) +{ + int i, printed = 0; + int nr, sh_type; + + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf64_Sym *sh_symtab; + unsigned sec_applies, sec_symtab; + int j; + if (shdr[i].sh_type != SHT_REL && shdr[i].sh_type != SHT_RELA) { + continue; + } + sec_symtab = shdr[i].sh_link; + sec_applies = shdr[i].sh_info; + if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) { + continue; + } + if (shdr[i].sh_type == SHT_REL) { + sh_type = SHT_REL; + nr = shdr[i].sh_size/sizeof(reltab[0][0]); + } else { + sh_type = SHT_RELA; + nr = shdr[i].sh_size/sizeof(reltaba[0][0]); + } + + sh_symtab = symtab[sec_symtab]; + sym_strtab = strtab[shdr[sec_symtab].sh_link]; + + for(j = 0; j < nr; j++) { + Elf64_Rel *rel = NULL; + Elf64_Rela *rela = NULL; + Elf64_Sym *sym; + const char *name; + + if (sh_type == SHT_REL) { + rel = &reltab[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rel->r_info)]; + } else { + rela = &reltaba[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rela->r_info)]; + } + + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + + /* Absolute symbols are not relocated if vmlinux is + * loaded at a non-compiled address. Display a warning + * to user at compile time about the absolute + * relocations present. + * + * User need to audit the code to make sure + * some symbols which should have been section + * relative have not become absolute because of some + * linker optimization or wrong programming usage. + * + * Before warning check if this absolute symbol + * relocation is harmless. + */ + if (is_safe_abs_reloc(name)) + continue; + + if (!printed) { + printf("WARNING: Absolute relocations" + " present\n"); + printf("Offset Info Type Sym.Value " + "Sym.Name\n"); + printed = 1; + } + + if (sh_type == SHT_REL) + printf("%016llx %016llx %10s %016llx %s\n", + rel->r_offset, + rel->r_info, + rel_type(ELF64_R_TYPE(rel->r_info)), + sym->st_value, + name); + else + printf("%016llx %016llx %10s %016llx %s\n", + rela->r_offset, + rela->r_info, + rel_type(ELF64_R_TYPE(rela->r_info)), + sym->st_value, + name); + } + } + + if (printed) + printf("\n"); +} + +static void walk_relocs(void (*visit)(void *relp, Elf64_Sym *sym, int sh_type)) +{ + int i; + /* Walk through the relocations */ + for(i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf64_Sym *sh_symtab; + unsigned sec_applies, sec_symtab; + int j, nr_entries, sh_type; + if (shdr[i].sh_type != SHT_REL && shdr[i].sh_type != SHT_RELA) { + continue; + } + sec_symtab = shdr[i].sh_link; + sec_applies = shdr[i].sh_info; + if (!(shdr[sec_applies].sh_flags & SHF_ALLOC)) { + continue; + } + sh_symtab = symtab[sec_symtab]; + sym_strtab = strtab[shdr[sec_symtab].sh_link]; + if (shdr[i].sh_type == SHT_REL) { + sh_type = SHT_REL; + nr_entries = shdr[i].sh_size/sizeof(reltab[0][0]); + } else { + sh_type = SHT_RELA; + nr_entries = shdr[i].sh_size/sizeof(reltaba[0][0]); + } + + for(j = 0; j < nr_entries; j++) { + Elf64_Rel *rel; + Elf64_Rela *rela; + Elf64_Sym *sym; + void *relp; + unsigned r_type; + + if (sh_type == SHT_REL) { + rel = &reltab[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rel->r_info)]; + r_type = ELF64_R_TYPE(rel->r_info); + relp = rel; + } else { + rela = &reltaba[i][j]; + sym = &sh_symtab[ELF64_R_SYM(rela->r_info)]; + r_type = ELF64_R_TYPE(rela->r_info); + relp = rela; + } + /* Don't visit relocations to absolute symbols */ + if (sym->st_shndx == SHN_ABS) { + continue; + } + /* PC relative relocations don't need to be adjusted */ + switch (r_type) { + case R_PPC64_ADDR32: + case R_PPC64_ADDR16: + case R_PPC64_ADDR16_HI: + case R_PPC64_ADDR24: + case R_PPC64_ADDR64: + case R_PPC64_TOC: + /* Visit relocations that need to be adjusted */ + visit(relp, sym, sh_type); + break; + case R_PPC64_ADDR16_LO: + case R_PPC64_REL24: + case R_PPC64_REL64: + case R_PPC64_TOC16: + case R_PPC64_ADDR16_LO_DS: + case R_PPC64_ADDR16_HIGHEST: + case R_PPC64_ADDR16_HIGHER: + case R_PPC64_GOT16_DS: + case R_PPC64_TOC16_DS: + case R_PPC64_REL14: + default: + break; + } + } + } +} + +static void count_reloc(void *relp, Elf64_Sym *sym, int sh_type) +{ + reloc_count += 1; +} + +static void collect_reloc(void *relp, Elf64_Sym *sym, int sh_type) +{ + Elf64_Rel *rel; + Elf64_Rela *rela; + + /* Remember the address that needs to be adjusted. */ + if (sh_type == SHT_REL) { + rel = (Elf64_Rel *)relp; + relocs[reloc_idx].offset = rel->r_offset; + relocs[reloc_idx++].rel_type = ELF64_R_TYPE(rel->r_info); + } else { + rela = (Elf64_Rela *)relp; + relocs[reloc_idx].offset = rela->r_offset; + relocs[reloc_idx++].rel_type = ELF64_R_TYPE(rela->r_info); + } +} + +static int cmp_relocs(const void *va, const void *vb) +{ + const struct reloc_info *a, *b; + a = va; b = vb; + return (a->rel_type == b->rel_type)? 0 : (a->rel_type > b->rel_type)? 1 : -1; +} + +static void emit_relocs(int as_text) +{ + int i; + int prev_r_type; + /* Count how many relocations I have and allocate space for them. */ + reloc_count = 0; + walk_relocs(count_reloc); + relocs = malloc(reloc_count * sizeof(relocs[0])); + if (!relocs) { + die("malloc of %d entries for relocs failed\n", + reloc_count); + } + /* Collect up the relocations */ + reloc_idx = 0; + walk_relocs(collect_reloc); + + /* Order the relocations for more efficient processing */ + qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); + + /* Print the relocations */ + if (as_text) { + /* Print the relocations in a form suitable that + * gas will like. + */ + printf(".section \".data.reloc\",\"a\"\n"); + printf(".balign 4\n"); + + printf("\t .long 0x%016llx\n", relocs[0].offset); + prev_r_type = relocs[0].rel_type; + + for(i = 1; i < reloc_count; i++) { + if (prev_r_type != relocs[i].rel_type && prev_r_type == R_PPC64_ADDR16_HI) { + printf("\t .long 0xffffffffffffffff\n"); + prev_r_type = relocs[i].rel_type; + } + printf("\t .long 0x%016llx\n", relocs[i].offset); + } + printf("\n"); + } + else { + unsigned char buf[8]; + buf[0] = buf[1] = buf[2] = buf[3] = 0; + buf[4] = buf[5] = buf[6] = buf[7] = 0; + + /* Print a stop */ + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + printf("%c%c%c%c", buf[4], buf[5], buf[6], buf[7]); + + buf[7] = (relocs[0].offset >> 0) & 0xff; + buf[6] = (relocs[0].offset >> 8) & 0xff; + buf[5] = (relocs[0].offset >> 16) & 0xff; + buf[4] = (relocs[0].offset >> 24) & 0xff; + buf[3] = (relocs[0].offset >> 32) & 0xff; + buf[2] = (relocs[0].offset >> 40) & 0xff; + buf[1] = (relocs[0].offset >> 48) & 0xff; + buf[0] = (relocs[0].offset >> 56) & 0xff; + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + printf("%c%c%c%c", buf[4], buf[5], buf[6], buf[7]); + + prev_r_type = relocs[0].rel_type; + + /* Now print each relocation */ + for(i = 1; i < reloc_count; i++) { + if (prev_r_type != relocs[i].rel_type && prev_r_type == R_PPC64_ADDR16_HI) { + printf("%c%c%c%c", 0xff, 0xff, 0xff, 0xff); + printf("%c%c%c%c", 0xff, 0xff, 0xff, 0xff); + prev_r_type = relocs[i].rel_type; + } + buf[7] = (relocs[i].offset >> 0) & 0xff; + buf[6] = (relocs[i].offset >> 8) & 0xff; + buf[5] = (relocs[i].offset >> 16) & 0xff; + buf[4] = (relocs[i].offset >> 24) & 0xff; + buf[3] = (relocs[i].offset >> 32) & 0xff; + buf[2] = (relocs[i].offset >> 40) & 0xff; + buf[1] = (relocs[i].offset >> 48) & 0xff; + buf[0] = (relocs[i].offset >> 56) & 0xff; + printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); + printf("%c%c%c%c", buf[4], buf[5], buf[6], buf[7]); + } + buf[0] = buf[1] = buf[2] = buf[3] = 0; + buf[4] = buf[5] = buf[6] = buf[7] = 0; + } +} + +static void usage(void) +{ + die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n"); +} + +int main(int argc, char **argv) +{ + int show_absolute_syms, show_absolute_relocs; + int as_text; + const char *fname; + FILE *fp; + int i; + + show_absolute_syms = 0; + show_absolute_relocs = 0; + as_text = 0; + fname = NULL; + for(i = 1; i < argc; i++) { + char *arg = argv[i]; + if (*arg == '-') { + if (strcmp(argv[1], "--abs-syms") == 0) { + show_absolute_syms = 1; + continue; + } + + if (strcmp(argv[1], "--abs-relocs") == 0) { + show_absolute_relocs = 1; + continue; + } + else if (strcmp(argv[1], "--text") == 0) { + as_text = 1; + continue; + } + } + else if (!fname) { + fname = arg; + continue; + } + usage(); + } + if (!fname) { + usage(); + } + fp = fopen(fname, "r"); + if (!fp) { + die("Cannot open %s: %s\n", + fname, strerror(errno)); + } + read_ehdr(fp); + read_shdrs(fp); + read_strtabs(fp); + read_symtabs(fp); + read_relocs(fp); + if (show_absolute_syms) { + print_absolute_symbols(); + return 0; + } + if (show_absolute_relocs) { + print_absolute_relocs(); + return 0; + } + emit_relocs(as_text); + return 0; +} -- 1.5.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 1/4] Extract list of relocation offsets 2008-07-21 19:17 ` Mohan Kumar M @ 2008-07-22 6:29 ` Paul Mackerras 2008-07-22 7:58 ` Mohan Kumar M 0 siblings, 1 reply; 22+ messages in thread From: Paul Mackerras @ 2008-07-22 6:29 UTC (permalink / raw) To: Mohan Kumar M; +Cc: naren, Milton Miller, ppcdev Mohan Kumar M writes: > diff --git a/arch/powerpc/boot/relocs.c b/arch/powerpc/boot/relocs.c > new file mode 100644 > index 0000000..31ca903 Where did this file come from? Did you write it all yourself? If not, then you need to credit the original author in the patch description at least. Also it needs a copyright notice. There is some evidence that this has been copied from a similar program for x86. For instance, this: +/* + * Following symbols have been audited. There values are constant and do + * not change if bzImage is loaded at a different physical address than + * the address for which it has been compiled. Don't warn user about + * absolute relocations present w.r.t these symbols. + */ +static const char* safe_abs_relocs[] = { + "__kernel_vsyscall", + "__kernel_rt_sigreturn", + "__kernel_sigreturn", + "SYSENTER_RETURN", +}; refers to symbols that don't exist on powerpc but (presumably) do on x86. Also, this: + if (shdr[i].sh_type == SHT_REL) { + reltab[i] = malloc(shdr[i].sh_size); + if (!reltab[i]) { + die("malloc of %d bytes for relocs failed\n", + shdr[i].sh_size); + } + relp = reltab[i]; is, I think, unnecessary, since as far as I know we never get SHT_REL sections on powerpc. Paul. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 1/4] Extract list of relocation offsets 2008-07-22 6:29 ` Paul Mackerras @ 2008-07-22 7:58 ` Mohan Kumar M 0 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-22 7:58 UTC (permalink / raw) To: Paul Mackerras; +Cc: naren, Milton Miller, ppcdev Paul Mackerras wrote: > Mohan Kumar M writes: > >> diff --git a/arch/powerpc/boot/relocs.c b/arch/powerpc/boot/relocs.c >> new file mode 100644 >> index 0000000..31ca903 > > Where did this file come from? Did you write it all yourself? If > not, then you need to credit the original author in the patch > description at least. Also it needs a copyright notice. > > There is some evidence that this has been copied from a similar > program for x86. For instance, this: Hi Paul, Yes, its taken from x86 relocs.c. I will include proper credits to the original author in the next patch. > > Also, this: > > + if (shdr[i].sh_type == SHT_REL) { > + reltab[i] = malloc(shdr[i].sh_size); > + if (!reltab[i]) { > + die("malloc of %d bytes for relocs failed\n", > + shdr[i].sh_size); > + } > + relp = reltab[i]; > > is, I think, unnecessary, since as far as I know we never get SHT_REL > sections on powerpc. Ok, I will remove SHT_REL code in the relocs.c file. Regards, Mohan. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 2/4] Build files needed for relocation 2008-07-18 17:00 ` Milton Miller 2008-07-21 19:17 ` Mohan Kumar M @ 2008-07-21 19:20 ` Mohan Kumar M 2008-07-21 19:21 ` [RFC v3 PATCH 3/4] Apply relocation Mohan Kumar M ` (3 subsequent siblings) 5 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-21 19:20 UTC (permalink / raw) To: Milton Miller; +Cc: paulus, naren, ppcdev [-- Attachment #1: Type: text/plain, Size: 1 bytes --] [-- Attachment #2: 0002-Build-files-needed-for-relocation.patch --] [-- Type: text/x-patch, Size: 6643 bytes --] Build files needed for relocation This patch builds vmlinux file with relocation sections and contents so that relocs user space program can extract the required relocation offsets. This packs final relocatable vmlinux kernel as following: earlier part of relocation apply code, vmlinux, rest of relocation apply code. TODO: Relocatable vmlinux image is built in arch/powerpc/boot as vmlinux.reloc. But it should be built in top level directory of kernel source as vmlinux instead of vmlinux.reloc Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/Kconfig | 15 ++++++++++-- arch/powerpc/Makefile | 9 ++++++- arch/powerpc/boot/Makefile | 39 ++++++++++++++++++++++++++++++++-- arch/powerpc/boot/vmlinux.lds.S | 28 +++++++++++++++++++++++++ arch/powerpc/boot/vmlinux.reloc.scr | 8 +++++++ 5 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 arch/powerpc/boot/vmlinux.lds.S create mode 100644 arch/powerpc/boot/vmlinux.reloc.scr diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index f2a0f50..366a622 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -317,6 +317,15 @@ config CRASH_DUMP Don't change this unless you know what you are doing. +config RELOCATABLE_PPC64 + bool "Build a relocatable kernel (EXPERIMENTAL)" + depends on PPC_MULTIPLATFORM && PPC64 && CRASH_DUMP && EXPERIMENTAL + help + Build a kernel suitable for use as regular kernel and kdump capture + kernel. + + Don't change this unless you know what you are doing. + config PHYP_DUMP bool "Hypervisor-assisted dump (EXPERIMENTAL)" depends on PPC_PSERIES && EXPERIMENTAL @@ -662,7 +671,7 @@ config LOWMEM_SIZE default "0x30000000" config RELOCATABLE - bool "Build a relocatable kernel (EXPERIMENTAL)" + bool "Build relocatable kernel (EXPERIMENTAL)" depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && FSL_BOOKE help This builds a kernel image that is capable of running at the @@ -782,11 +791,11 @@ config PAGE_OFFSET default "0xc000000000000000" config KERNEL_START hex - default "0xc000000002000000" if CRASH_DUMP + default "0xc000000002000000" if CRASH_DUMP && !RELOCATABLE_PPC64 default "0xc000000000000000" config PHYSICAL_START hex - default "0x02000000" if CRASH_DUMP + default "0x02000000" if CRASH_DUMP && !RELOCATABLE_PPC64 default "0x00000000" endif diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 59ae7d9..58ccb7f 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -63,7 +63,7 @@ override CC += -m$(CONFIG_WORD_SIZE) override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR) endif -LDFLAGS_vmlinux := -Bstatic +LDFLAGS_vmlinux := --emit-relocs CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none -mcall-aixdesc CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple @@ -146,11 +146,16 @@ core-$(CONFIG_KVM) += arch/powerpc/kvm/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ # Default to zImage, override when needed + +ifneq ($(CONFIG_RELOCATABLE_PPC64),y) all: zImage +else +all: zImage vmlinux.reloc +endif CPPFLAGS_vmlinux.lds := -Upowerpc -BOOT_TARGETS = zImage zImage.initrd uImage zImage% dtbImage% treeImage.% cuImage.% simpleImage.% +BOOT_TARGETS = zImage vmlinux.reloc zImage.initrd uImage zImage% dtbImage% treeImage.% cuImage.% simpleImage.% PHONY += $(BOOT_TARGETS) diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 751a6e6..1a62036 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -17,7 +17,7 @@ # CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE # in the toplevel makefile. -all: $(obj)/zImage +all: $(obj)/zImage $(obj)/vmlinux.reloc BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -Os -msoft-float -pipe \ @@ -122,18 +122,51 @@ $(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE $(obj)/wrapper.a: $(obj-wlib) FORCE $(call if_changed,bootar) -hostprogs-y := addnote addRamDisk hack-coff mktree dtc +hostprogs-y := addnote addRamDisk hack-coff mktree dtc relocs targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a) extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ $(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds +ifeq ($(CONFIG_RELOCATABLE_PPC64),y) +extra-y += $(obj)/vmlinux.lds +endif + dtstree := $(srctree)/$(src)/dts wrapper :=$(srctree)/$(src)/wrapper -wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \ +wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc relocs) \ $(wrapper) FORCE +ifeq ($(CONFIG_RELOCATABLE_PPC64),y) + +targets += vmlinux.offsets vmlinux.bin vmlinux.bin.all vmlinux.reloc.elf vmlinux.reloc reloc_apply.o vmlinux.lds + +OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +quiet_cmd_relocbin = BUILD $@ + cmd_relocbin = cat $(filter-out FORCE,$^) > $@ + +quiet_cmd_relocs = RELOCS $@ + cmd_relocs = $(obj)/relocs $< > $@ + +$(obj)/vmlinux.offsets: vmlinux $(obj)/relocs FORCE + $(call if_changed,relocs) + +$(obj)/vmlinux.bin.all: $(obj)/vmlinux.bin $(obj)/vmlinux.offsets FORCE + $(call if_changed,relocbin) + +LDFLAGS_vmlinux.reloc.elf := -T $(obj)/vmlinux.reloc.scr -r --format binary --oformat elf64-powerpc +$(obj)/vmlinux.reloc.elf: $(obj)/vmlinux.bin.all FORCE + $(call if_changed,ld) + +LDFLAGS_vmlinux.reloc := -T $(obj)/vmlinux.lds +$(obj)/vmlinux.reloc: $(obj)/reloc_apply.o $(obj)/vmlinux.reloc.elf FORCE + $(call if_changed,ld) +endif + ############# # Bits for building dtc # DTC_GENPARSER := 1 # Uncomment to rebuild flex/bison output diff --git a/arch/powerpc/boot/vmlinux.lds.S b/arch/powerpc/boot/vmlinux.lds.S new file mode 100644 index 0000000..245c667 --- /dev/null +++ b/arch/powerpc/boot/vmlinux.lds.S @@ -0,0 +1,28 @@ +#include <asm/page.h> +#include <asm-generic/vmlinux.lds.h> + +ENTRY(start_wrap) + +OUTPUT_ARCH(powerpc:common64) +SECTIONS +{ + . = KERNELBASE; + +/* + * Text, read only data and other permanent read-only sections + */ + /* Text and gots */ + .text : { + _head = .; + *(.text.head) + _ehead = .; + + _text = .; + *(.vmlinux) + _etext = .; + + _reloc = .; + *(.text.reloc) + _ereloc = .; + } +} diff --git a/arch/powerpc/boot/vmlinux.reloc.scr b/arch/powerpc/boot/vmlinux.reloc.scr new file mode 100644 index 0000000..7240b6b --- /dev/null +++ b/arch/powerpc/boot/vmlinux.reloc.scr @@ -0,0 +1,8 @@ +SECTIONS +{ + .vmlinux : { + input_len = .; + *(.data) + output_len = . - 8; + } +} -- 1.5.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 3/4] Apply relocation 2008-07-18 17:00 ` Milton Miller 2008-07-21 19:17 ` Mohan Kumar M 2008-07-21 19:20 ` [RFC v3 PATCH 2/4] Build files needed for relocation Mohan Kumar M @ 2008-07-21 19:21 ` Mohan Kumar M 2008-07-21 19:23 ` [RFC v3 PATCH 4/4] Relocation support Mohan Kumar M ` (2 subsequent siblings) 5 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-21 19:21 UTC (permalink / raw) To: Milton Miller; +Cc: paulus, naren, ppcdev [-- Attachment #1: Type: text/plain, Size: 1 bytes --] [-- Attachment #2: 0003-Apply-relocation.patch --] [-- Type: text/x-patch, Size: 5555 bytes --] Apply relocation This code is a wrapper around regular kernel. This checks whether the kernel is loaded at 32MB, if its not loaded at 32MB, its treated as a regular kernel and the control is given to the kernel immediately. If the kernel is loaded at 32MB, it applies relocation delta to each offset in the list which was generated and appended by patch 1 and 2. After updating all offsets, control is given to relocatable kernel. Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/boot/reloc_apply.S | 229 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 229 insertions(+), 0 deletions(-) create mode 100644 arch/powerpc/boot/reloc_apply.S diff --git a/arch/powerpc/boot/reloc_apply.S b/arch/powerpc/boot/reloc_apply.S new file mode 100644 index 0000000..4049976 --- /dev/null +++ b/arch/powerpc/boot/reloc_apply.S @@ -0,0 +1,229 @@ +#include <asm/ppc_asm.h> + +#define RELOC_DELTA 0x4000000002000000 + +#define LOADADDR(rn,name) \ + lis rn,name##@highest; \ + ori rn,rn,name##@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name##@h; \ + ori rn,rn,name##@l + + +/* + * Layout of vmlinux.reloc file + * Minimal part of relocation applying code + + * vmlinux + + * Rest of the relocation applying code + */ + +.section .text.head + +.globl start_wrap +start_wrap: + /* Get relocation offset in r15 */ + bl 1f +1: mflr r15 + LOAD_REG_IMMEDIATE(r16,1b) + subf r15,r16,r15 + + LOAD_REG_IMMEDIATE(r17, _reloc) + add r17,r17,r15 + mtctr r17 + bctr /* Jump to start_reloc in section ".text.reloc" */ + +/* Secondary cpus spin code */ +. = 0x60 + /* Get relocation offset in r15 */ + bl 1f +1: mflr r15 + LOAD_REG_IMMEDIATE(r16,1b) + subf r15,r16,r15 + + LOADADDR(r18, __spinloop) + add r18,r18,r15 +100: ld r19,0(r18) + cmpwi 0,r19,1 + bne 100b + + LOAD_REG_IMMEDIATE(r17, _reloc) + add r17,r17,r15 + addi r17,r17,0x60 + mtctr r17 + /* Jump to start_reloc + 0x60 in section ".text.reloc" */ + bctr + +/* + * Layout of vmlinux.reloc file + * Minimal part of relocation applying code + + * vmlinux + + * Rest of the relocation applying code + */ + + +.section .text.reloc + +start_reloc: + b master + +.org start_reloc + 0x60 + LOADADDR(r18, __spinloop) + add r18,r18,r15 +100: ld r19,0(r18) + cmpwi 0,r19,2 + bne 100b + + /* Now vmlinux is at _head */ + LOAD_REG_IMMEDIATE(r17, _head) + add r17,r17,r15 + addi r17,r17,0x60 + mtctr r17 + bctr + +master: + LOAD_REG_IMMEDIATE(r16, output_len) + add r16,r16,r15 + + /* + * Load the delimiter to distinguish between different relocation + * types + */ + LOAD_REG_IMMEDIATE(r24, __delimiter) + add r24,r24,r15 + ld r24,0(r24) + + LOAD_REG_IMMEDIATE(r17, _head) + LOAD_REG_IMMEDIATE(r21, _ehead) + sub r21,r21,r17 /* Number of bytes in head section */ + + sub r16,r16,r21 /* Original output_len */ + + /* Destination address */ + LOAD_REG_IMMEDIATE(r17, _head) /* KERNELBASE */ + add r17,r17,r15 + + /* Source address */ + LOAD_REG_IMMEDIATE(r18, _text) /* Regular vmlinux */ + add r18,r18,r15 + + /* Number of bytes to copy */ + LOAD_REG_IMMEDIATE(r19, _etext) + add r19,r19,r15 + sub r19,r19,r18 + + /* Move cpu spin code to "text.reloc" section */ + LOADADDR(r23, __spinloop) + add r23,r23,r15 + li r25,1 + stw r25,0(r23) + + /* Copy vmlinux code to physical address 0 */ + bl .copy /* copy(_head, _text, _etext-_text) */ + + /* + * If its not running at 32MB, assume it to be a normal kernel. + * Copy the vmlinux code to KERNELBASE and jump to KERNELBASE + */ + LOAD_REG_IMMEDIATE(r21, RELOC_DELTA) + cmpd r15,r21 + beq apply_relocation + li r6,0 + b skip_apply +apply_relocation: + + /* Kernel is running at 32MB */ + mr r22,r15 + xor r23,r23,r23 + addi r23,r23,16 + srw r22,r22,r23 + + li r25,0 + + LOAD_REG_IMMEDIATE(r26, _head) + + /* + * Start reading the relocation offset list from end of file + * Based on the relocation type either add the relocation delta + * or do logical ORing the relocation delta + */ +3: + addi r16,r16,-8 + ld r18,0(r16) + cmpdi r18,0 /* Processed all offsets */ + beq 4f /* Start vmlinux */ + /* Are we processing reloction type R_PPC64_ADDR16_HI */ + cmpdi r25,1 + beq rel_hi + cmpd r18,r24 + beq set_rel_hi + /* Process 64bit absolute relocation update */ +rel_addr64: + add r18,r18,r15 + ld r28,0(r18) + cmpdi r28,0 + beq next + add r28,r28,r15 /* add relocation offset */ + add r28,r28,r26 /* add KERNELBASE */ + std r28,0(r18) + b next +set_rel_hi: /* Enable R_PPC64_ADDR16_HI flag */ + addi r25,r25,1 + b 3b +rel_hi: + add r18,r18,r15 + lhz r28,0(r18) + or r28,r28,r22 + sth r28,0(r18) +next: + b 3b +4: + mr r6,r15 + + +skip_apply: + isync + sync + + /* Now vmlinux is at _head */ + LOAD_REG_IMMEDIATE(r17, _head) + add r17,r17,r15 + mtctr r17 + + /* Move cpu spin code to "text.reloc" section */ + LOADADDR(r23, __spinloop) + add r23,r23,r15 + li r25,2 + stw r25,0(r23) + + bctr + +/* r17 destination, r18 source, r19 size */ +.copy: + addi r19,r19,-8 + li r22,-8 +4: li r21,8 /* Use the smallest common */ + /* denominator cache line */ + /* size. This results in */ + /* extra cache line flushes */ + /* but operation is correct. */ + /* Can't get cache line size */ + /* from NACA as it is being */ + /* moved too. */ + + mtctr r21 /* put # words/line in ctr */ +3: addi r22,r22,8 /* copy a cache line */ + ldx r21,r22,r18 + stdx r21,r22,r17 + bdnz 3b + dcbst r22,r17 /* write it to memory */ + sync + icbi r22,r17 /* flush the icache line */ + cmpld 0,r22,r19 + blt 4b + sync + blr + +__delimiter: + .llong 0xffffffffffffffff +__spinloop: + .llong 0x0 -- 1.5.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 4/4] Relocation support 2008-07-18 17:00 ` Milton Miller ` (2 preceding siblings ...) 2008-07-21 19:21 ` [RFC v3 PATCH 3/4] Apply relocation Mohan Kumar M @ 2008-07-21 19:23 ` Mohan Kumar M 2008-07-21 19:25 ` [RFC v3 PATCH 5/4] Relocation support for kdump kernel Mohan Kumar M 2008-07-21 19:26 ` [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros Mohan Kumar M 5 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-21 19:23 UTC (permalink / raw) To: Milton Miller; +Cc: paulus, naren, ppcdev [-- Attachment #1: Type: text/plain, Size: 179 bytes --] I split the patch 4: Relocation support into 3 patches 1. Generic kernel support for relocatable 2. Kdump kernel support for relocatable 3. LOAD_REG_IMMEDIATE macro replacement [-- Attachment #2: 0004-Relocation-support.patch --] [-- Type: text/x-patch, Size: 9689 bytes --] Relocation support Add relocatable kernel support like take care when accessing absolute symbols in the code by adding the relocation kernel base address. Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/kernel/head_64.S | 53 ++++++++++++++++++++++++++++++- arch/powerpc/kernel/machine_kexec_64.c | 4 +- arch/powerpc/kernel/prom_init.c | 27 ++++++++++++++-- arch/powerpc/kernel/prom_init_check.sh | 2 +- arch/powerpc/kernel/setup_64.c | 5 +-- arch/powerpc/mm/init_64.c | 7 ++-- arch/powerpc/mm/mem.c | 3 +- include/asm-powerpc/prom.h | 2 + include/asm-powerpc/sections.h | 4 ++- include/asm-powerpc/system.h | 5 +++ 10 files changed, 95 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index ecced1e..8adf3b5 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -102,6 +102,12 @@ __secondary_hold_acknowledge: .llong hvReleaseData-KERNELBASE #endif /* CONFIG_PPC_ISERIES */ +#ifdef CONFIG_RELOCATABLE_PPC64 + /* Used as static variable to initialize the reloc_delta */ +__initialized: + .long 0x0 +#endif + . = 0x60 /* * The following code is used to hold secondary processors @@ -1247,6 +1253,38 @@ _STATIC(__mmu_off) * */ _GLOBAL(__start_initialization_multiplatform) +#ifdef CONFIG_RELOCATABLE_PPC64 + mr r21,r3 + mr r22,r4 + mr r23,r5 + bl .reloc_offset + mr r26,r3 + mr r3,r21 + mr r4,r22 + mr r5,r23 + + LOAD_REG_IMMEDIATE(r27, __initialized) + add r27,r26,r27 + ld r7,0(r27) + cmpdi r7,0 + bne 4f + + li r7,1 + stw r7,0(r27) + + cmpdi r6,0 + beq 4f + LOAD_REG_IMMEDIATE(r27, reloc_delta) + add r27,r27,r26 + std r6,0(r27) + + LOAD_REG_IMMEDIATE(r27, KERNELBASE) + add r7,r6,r27 + LOAD_REG_IMMEDIATE(r27, kernel_base) + add r27,r27,r26 + std r7,0(r27) +4: +#endif /* * Are we booted from a PROM Of-type client-interface ? */ @@ -1322,6 +1360,19 @@ _INIT_STATIC(__boot_from_prom) trap _STATIC(__after_prom_start) + bl .reloc_offset + mr r26,r3 +#ifdef CONFIG_RELOCATABLE_PPC64 + /* + * If its a relocatable kernel, no need to copy the kernel + * to PHYSICAL_START. Continue running from the same location + */ + LOAD_REG_IMMEDIATE(r27, reloc_delta) + add r27,r27,r26 + ld r28,0(r27) + cmpdi r28,0 + bne .start_here_multiplatform +#endif /* * We need to run with __start at physical address PHYSICAL_START. @@ -1335,8 +1386,6 @@ _STATIC(__after_prom_start) * r26 == relocation offset * r27 == KERNELBASE */ - bl .reloc_offset - mr r26,r3 LOAD_REG_IMMEDIATE(r27, KERNELBASE) LOAD_REG_IMMEDIATE(r3, PHYSICAL_START) /* target addr */ diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 631dfd6..09ce39d 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c @@ -43,7 +43,7 @@ int default_machine_kexec_prepare(struct kimage *image) * overlaps kernel static data or bss. */ for (i = 0; i < image->nr_segments; i++) - if (image->segment[i].mem < __pa(_end)) + if (image->segment[i].mem < (__pa(_end) + kernel_base)) return -ETXTBSY; /* @@ -317,7 +317,7 @@ static void __init export_htab_values(void) if (!node) return; - kernel_end = __pa(_end); + kernel_end = __pa(_end) + kernel_base; prom_add_property(node, &kernel_end_prop); /* On machines with no htab htab_address is NULL */ diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 1ea8c8d..1b67219 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -91,11 +91,9 @@ extern const struct linux_logo logo_linux_clut224; * fortunately don't get interpreted as two arguments). */ #ifdef CONFIG_PPC64 -#define RELOC(x) (*PTRRELOC(&(x))) #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) #define OF_WORKAROUNDS 0 #else -#define RELOC(x) (x) #define ADDR(x) (u32) (x) #define OF_WORKAROUNDS of_workarounds int of_workarounds; @@ -1073,7 +1071,12 @@ static void __init prom_init_mem(void) } } +#ifndef CONFIG_RELOCATABLE_PPC64 RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000); +#else + RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000 + + RELOC(reloc_delta)); +#endif /* Check if we have an initrd after the kernel, if we do move our bottom * point to after it @@ -1337,10 +1340,19 @@ static void __init prom_hold_cpus(void) unsigned int cpu_threads, hw_cpu_num; int propsize; struct prom_t *_prom = &RELOC(prom); + +#ifndef CONFIG_RELOCATABLE_PPC64 unsigned long *spinloop = (void *) LOW_ADDR(__secondary_hold_spinloop); unsigned long *acknowledge = (void *) LOW_ADDR(__secondary_hold_acknowledge); +#else + unsigned long *spinloop + = (void *) &__secondary_hold_spinloop; + unsigned long *acknowledge + = (void *) &__secondary_hold_acknowledge; +#endif + #ifdef CONFIG_PPC64 /* __secondary_hold is actually a descriptor, not the text address */ unsigned long secondary_hold @@ -2402,8 +2414,15 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, /* * Copy the CPU hold code */ - if (RELOC(of_platform) != PLATFORM_POWERMAC) - copy_and_flush(0, KERNELBASE + offset, 0x100, 0); + if (RELOC(of_platform) != PLATFORM_POWERMAC) { +#ifdef CONFIG_RELOCATABLE_PPC64 + if (RELOC(reloc_delta)) + copy_and_flush(0, KERNELBASE + RELOC(reloc_delta), + 0x100, 0); + else +#endif + copy_and_flush(0, KERNELBASE + offset, 0x100, 0); + } /* * Do early parsing of command line diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index 2c7e8e8..3cc7e24 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh @@ -20,7 +20,7 @@ WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush _end enter_prom memcpy memset reloc_offset __secondary_hold __secondary_hold_acknowledge __secondary_hold_spinloop __start strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 -reloc_got2 kernstart_addr" +reloc_got2 kernstart_addr reloc_delta" NM="$1" OBJ="$2" diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 04d8de9..91fab43 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -208,7 +208,6 @@ void __init early_setup(unsigned long dt_ptr) /* Probe the machine type */ probe_machine(); - setup_kdump_trampoline(); DBG("Found, Initializing memory management...\n"); @@ -526,9 +525,9 @@ void __init setup_arch(char **cmdline_p) if (ppc_md.panic) setup_panic(); - init_mm.start_code = (unsigned long)_stext; + init_mm.start_code = (unsigned long)_stext + kernel_base; init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; + init_mm.end_data = (unsigned long) _edata + kernel_base; init_mm.brk = klimit; irqstack_early_init(); diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 6ef63ca..1b908d4 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -79,10 +79,11 @@ phys_addr_t kernstart_addr; void free_initmem(void) { - unsigned long addr; + unsigned long long addr, eaddr; - addr = (unsigned long)__init_begin; - for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) { + addr = (unsigned long long )__init_begin + kernel_base; + eaddr = (unsigned long long ) __init_end + kernel_base; + for (; addr < eaddr; addr += PAGE_SIZE) { memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 776ba6a..f727de6 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -401,7 +401,8 @@ void __init mem_init(void) } } - codesize = (unsigned long)&_sdata - (unsigned long)&_stext; + codesize = (unsigned long)&_sdata - (unsigned long)&_stext + + kernel_base; datasize = (unsigned long)&_edata - (unsigned long)&_sdata; initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h index eb3bd2e..4d7aa4f 100644 --- a/include/asm-powerpc/prom.h +++ b/include/asm-powerpc/prom.h @@ -39,6 +39,8 @@ #define OF_DT_VERSION 0x10 +extern unsigned long reloc_delta, kernel_base; + /* * This is what gets passed to the kernel by prom_init or kexec * diff --git a/include/asm-powerpc/sections.h b/include/asm-powerpc/sections.h index 916018e..f19dab3 100644 --- a/include/asm-powerpc/sections.h +++ b/include/asm-powerpc/sections.h @@ -7,10 +7,12 @@ #ifdef __powerpc64__ extern char _end[]; +extern unsigned long kernel_base; static inline int in_kernel_text(unsigned long addr) { - if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end) + if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end + + kernel_base) return 1; return 0; diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h index 0c12c66..4f98967 100644 --- a/include/asm-powerpc/system.h +++ b/include/asm-powerpc/system.h @@ -534,6 +534,11 @@ extern unsigned long add_reloc_offset(unsigned long); extern void reloc_got2(unsigned long); #define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x))) +#ifdef CONFIG_PPC64 +#define RELOC(x) (*PTRRELOC(&(x))) +#else +#define RELOC(x) (x) +#endif #ifdef CONFIG_VIRT_CPU_ACCOUNTING extern void account_system_vtime(struct task_struct *); -- 1.5.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 5/4] Relocation support for kdump kernel 2008-07-18 17:00 ` Milton Miller ` (3 preceding siblings ...) 2008-07-21 19:23 ` [RFC v3 PATCH 4/4] Relocation support Mohan Kumar M @ 2008-07-21 19:25 ` Mohan Kumar M 2008-07-21 19:26 ` [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros Mohan Kumar M 5 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-21 19:25 UTC (permalink / raw) To: Milton Miller; +Cc: paulus, naren, ppcdev [-- Attachment #1: Type: text/plain, Size: 1 bytes --] [-- Attachment #2: 0005-Relocation-support-for-kdump-kernels.patch --] [-- Type: text/x-patch, Size: 7055 bytes --] Relocation support for kdump kernel This patch adds relocation support for the kdump kernel path Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/kernel/crash_dump.c | 19 +++++++++++++++ arch/powerpc/kernel/iommu.c | 7 ++++- arch/powerpc/kernel/machine_kexec.c | 6 ++++ arch/powerpc/kernel/misc.S | 40 +++++++++++++++++++++++++------ arch/powerpc/kernel/prom.c | 13 +++++++++- arch/powerpc/mm/hash_utils_64.c | 5 ++- arch/powerpc/platforms/pseries/iommu.c | 5 +++- 7 files changed, 81 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index e0debcc..91d5ad2 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -29,7 +29,12 @@ void __init reserve_kdump_trampoline(void) { +#ifdef CONFIG_RELOCATABLE_PPC64 + if (RELOC(reloc_delta)) + lmb_reserve(0, KDUMP_RESERVE_LIMIT); +#else lmb_reserve(0, KDUMP_RESERVE_LIMIT); +#endif } static void __init create_trampoline(unsigned long addr) @@ -45,7 +50,11 @@ static void __init create_trampoline(unsigned long addr) * two instructions it doesn't require any registers. */ patch_instruction(p, PPC_NOP_INSTR); +#ifndef CONFIG_RELOCATABLE_PPC64 patch_branch(++p, addr + PHYSICAL_START, 0); +#else + patch_branch(++p, addr + RELOC(reloc_delta), 0); +#endif } void __init setup_kdump_trampoline(void) @@ -54,13 +63,23 @@ void __init setup_kdump_trampoline(void) DBG(" -> setup_kdump_trampoline()\n"); +#ifdef CONFIG_RELOCATABLE_PPC64 + if (!RELOC(reloc_delta)) + return; +#endif + for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) { create_trampoline(i); } #ifdef CONFIG_PPC_PSERIES +#ifndef CONFIG_RELOCATABLE_PPC64 create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START); create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START); +#else + create_trampoline(__pa(system_reset_fwnmi) - RELOC(reloc_delta)); + create_trampoline(__pa(machine_check_fwnmi) - RELOC(reloc_delta)); +#endif #endif /* CONFIG_PPC_PSERIES */ DBG(" <- setup_kdump_trampoline()\n"); diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 0c66366..ccd98c2 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -473,7 +473,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) spin_lock_init(&tbl->it_lock); #ifdef CONFIG_CRASH_DUMP - if (ppc_md.tce_get) { + if (reloc_delta && ppc_md.tce_get) { unsigned long index; unsigned long tceval; unsigned long tcecount = 0; @@ -499,7 +499,10 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid) index < tbl->it_size; index++) __clear_bit(index, tbl->it_map); } - } + } else + /* Clear the hardware table in case firmware left allocations + in it */ + ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); #else /* Clear the hardware table in case firmware left allocations in it */ ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); diff --git a/arch/powerpc/kernel/machine_kexec.c b/arch/powerpc/kernel/machine_kexec.c index 29a0e03..f2ed554 100644 --- a/arch/powerpc/kernel/machine_kexec.c +++ b/arch/powerpc/kernel/machine_kexec.c @@ -67,6 +67,12 @@ void __init reserve_crashkernel(void) unsigned long long crash_size, crash_base; int ret; +#ifdef CONFIG_RELOCATABLE_PPC64 + /* Return if its kdump kernel */ + if (reloc_delta) + return; +#endif + /* this is necessary because of lmb_phys_mem_size() */ lmb_analyze(); diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 85cb6f3..28718ed 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -20,6 +20,8 @@ #include <asm/asm-compat.h> #include <asm/asm-offsets.h> +#define RELOC_DELTA 0x4000000002000000 + .text /* @@ -33,6 +35,17 @@ _GLOBAL(reloc_offset) 1: mflr r3 LOAD_REG_IMMEDIATE(r4,1b) subf r3,r4,r3 +#ifdef CONFIG_RELOCATABLE_PPC64 + LOAD_REG_IMMEDIATE(r5, RELOC_DELTA) + cmpd r3,r5 + bne 2f + /* + * Don't return the offset if the difference is + * RELOC_DELTA + */ + li r3,0 +2: +#endif mtlr r0 blr @@ -40,14 +53,25 @@ _GLOBAL(reloc_offset) * add_reloc_offset(x) returns x + reloc_offset(). */ _GLOBAL(add_reloc_offset) - mflr r0 - bl 1f -1: mflr r5 - LOAD_REG_IMMEDIATE(r4,1b) - subf r5,r4,r5 - add r3,r3,r5 - mtlr r0 - blr + mflr r0 + bl 1f +1: mflr r5 + LOAD_REG_IMMEDIATE(r4,1b) + subf r5,r4,r5 +#ifdef CONFIG_RELOCATABLE_PPC64 + LOAD_REG_IMMEDIATE(r4, RELOC_DELTA) + cmpd r5,r4 + bne 2f + /* + * Don't add the offset if the difference is + * RELOC_DELTA + */ + li r5,0 +2: +#endif + add r3,r3,r5 + mtlr r0 + blr _GLOBAL(kernel_execve) li r0,__NR_execve diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 87d83c5..453dc98 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -65,6 +65,9 @@ static int __initdata dt_root_addr_cells; static int __initdata dt_root_size_cells; +unsigned long reloc_delta __attribute__ ((__section__ (".data"))); +unsigned long kernel_base __attribute__ ((__section__ (".data"))); + #ifdef CONFIG_PPC64 int __initdata iommu_is_off; int __initdata iommu_force_on; @@ -1163,8 +1166,16 @@ void __init early_init_devtree(void *params) parse_early_param(); /* Reserve LMB regions used by kernel, initrd, dt, etc... */ - lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); reserve_kdump_trampoline(); +#ifdef CONFIG_RELOCATABLE_PPC64 + if (RELOC(kernel_base)) { + lmb_reserve(0, KDUMP_RESERVE_LIMIT); + lmb_reserve(kernel_base, __pa(klimit) - PHYSICAL_START); + } else + lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); +#else + lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); +#endif reserve_crashkernel(); early_reserve_mem(); phyp_dump_reserve_mem(); diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 8d3b58e..78c7774 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -636,8 +636,9 @@ void __init htab_initialize(void) continue; } #endif /* CONFIG_U3_DART */ - BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), - mode_rw, mmu_linear_psize, mmu_kernel_ssize)); + BUG_ON(htab_bolt_mapping(base + kernel_base, base + size, + __pa(base) + kernel_base, mode_rw, mmu_linear_psize, + mmu_kernel_ssize)); } /* diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 9a12908..948ad57 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -265,7 +265,10 @@ static void iommu_table_setparms(struct pci_controller *phb, tbl->it_base = (unsigned long)__va(*basep); -#ifndef CONFIG_CRASH_DUMP +#ifdef CONFIG_CRASH_DUMP + if (!reloc_delta) + memset((void *)tbl->it_base, 0, *sizep); +#else memset((void *)tbl->it_base, 0, *sizep); #endif -- 1.5.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros 2008-07-18 17:00 ` Milton Miller ` (4 preceding siblings ...) 2008-07-21 19:25 ` [RFC v3 PATCH 5/4] Relocation support for kdump kernel Mohan Kumar M @ 2008-07-21 19:26 ` Mohan Kumar M 2008-07-22 2:03 ` Paul Mackerras 5 siblings, 1 reply; 22+ messages in thread From: Mohan Kumar M @ 2008-07-21 19:26 UTC (permalink / raw) To: Milton Miller; +Cc: paulus, naren, ppcdev [-- Attachment #1: Type: text/plain, Size: 1 bytes --] [-- Attachment #2: 0006-Use-LOAD_REG_IMMEDIATE-macros.patch --] [-- Type: text/x-patch, Size: 3654 bytes --] Use LOAD_REG_IMMEDIATE macros This patch changes all LOAD_REG_ADDR macro calls to LOAD_REG_IMMEDIATE to make sure that we load the correct address. Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/kernel/entry_64.S | 4 ++-- arch/powerpc/mm/hash_low_64.S | 8 ++++---- arch/powerpc/mm/slb_low.S | 2 +- arch/powerpc/platforms/pseries/hvCall.S | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 12eb95a..37e5d95 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -714,7 +714,7 @@ _GLOBAL(enter_rtas) std r6,PACASAVEDMSR(r13) /* Setup our real return addr */ - LOAD_REG_ADDR(r4,.rtas_return_loc) + LOAD_REG_IMMEDIATE(r4,.rtas_return_loc) clrldi r4,r4,2 /* convert to realmode address */ mtlr r4 @@ -730,7 +730,7 @@ _GLOBAL(enter_rtas) sync /* disable interrupts so SRR0/1 */ mtmsrd r0 /* don't get trashed */ - LOAD_REG_ADDR(r4, rtas) + LOAD_REG_IMMEDIATE(r4, rtas) ld r5,RTASENTRY(r4) /* get the rtas->entry value */ ld r4,RTASBASE(r4) /* get the rtas->base value */ diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index a719f53..e9ba872 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S @@ -83,7 +83,7 @@ _GLOBAL(__hash_page_4K) std r29,STK_REG(r29)(r1) std r30,STK_REG(r30)(r1) std r31,STK_REG(r31)(r1) - + /* Step 1: * * Check permissions, atomically mark the linux PTE busy @@ -168,7 +168,7 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) std r3,STK_PARM(r4)(r1) /* Get htab_hash_mask */ - ld r4,htab_hash_mask@got(2) + LOAD_REG_IMMEDIATE(r4, htab_hash_mask) ld r27,0(r4) /* htab_hash_mask -> r27 */ /* Check if we may already be in the hashtable, in this case, we @@ -461,7 +461,7 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) std r3,STK_PARM(r4)(r1) /* Get htab_hash_mask */ - ld r4,htab_hash_mask@got(2) + LOAD_REG_IMMEDIATE(r4, htab_hash_mask) ld r27,0(r4) /* htab_hash_mask -> r27 */ /* Check if we may already be in the hashtable, in this case, we @@ -792,7 +792,7 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) std r3,STK_PARM(r4)(r1) /* Get htab_hash_mask */ - ld r4,htab_hash_mask@got(2) + LOAD_REG_IMMEDIATE(r4, htab_hash_mask) ld r27,0(r4) /* htab_hash_mask -> r27 */ /* Check if we may already be in the hashtable, in this case, we diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index bc44dc4..502099e 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -128,7 +128,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) /* Now get to the array and obtain the sllp */ ld r11,PACATOC(r13) - ld r11,mmu_psize_defs@got(r11) + LOAD_REG_IMMEDIATE(r11, mmu_psize_defs) add r11,r11,r9 ld r11,MMUPSIZESLLP(r11) ori r11,r11,SLB_VSID_USER diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index c1427b3..43c18f0 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -55,7 +55,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_PURR); \ /* calculate address of stat structure r4 = opcode */ \ srdi r4,r4,2; /* index into array */ \ mulli r4,r4,HCALL_STAT_SIZE; \ - LOAD_REG_ADDR(r7, per_cpu__hcall_stats); \ + LOAD_REG_IMMEDIATE(r7, per_cpu__hcall_stats); \ add r4,r4,r7; \ ld r7,PACA_DATA_OFFSET(r13); /* per cpu offset */ \ add r4,r4,r7; \ -- 1.5.4 ^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros 2008-07-21 19:26 ` [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros Mohan Kumar M @ 2008-07-22 2:03 ` Paul Mackerras 2008-07-22 4:37 ` Mohan Kumar M 0 siblings, 1 reply; 22+ messages in thread From: Paul Mackerras @ 2008-07-22 2:03 UTC (permalink / raw) To: Mohan Kumar M; +Cc: naren, Milton Miller, ppcdev Mohan Kumar M writes: @@ -714,7 +714,7 @@ _GLOBAL(enter_rtas) std r6,PACASAVEDMSR(r13) /* Setup our real return addr */ - LOAD_REG_ADDR(r4,.rtas_return_loc) + LOAD_REG_IMMEDIATE(r4,.rtas_return_loc) If LOAD_REG_ADDR doesn't work, then how are all the TOC loads in gcc-generated code going to work? Paul. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros 2008-07-22 2:03 ` Paul Mackerras @ 2008-07-22 4:37 ` Mohan Kumar M 2008-07-22 6:37 ` Paul Mackerras 0 siblings, 1 reply; 22+ messages in thread From: Mohan Kumar M @ 2008-07-22 4:37 UTC (permalink / raw) To: Paul Mackerras; +Cc: naren, Milton Miller, ppcdev Paul Mackerras wrote: > Mohan Kumar M writes: > > @@ -714,7 +714,7 @@ _GLOBAL(enter_rtas) > std r6,PACASAVEDMSR(r13) > > /* Setup our real return addr */ > - LOAD_REG_ADDR(r4,.rtas_return_loc) > + LOAD_REG_IMMEDIATE(r4,.rtas_return_loc) > > If LOAD_REG_ADDR doesn't work, then how are all the TOC loads in > gcc-generated code going to work? > Hi Paul, We have a problem only when there is a reference to a variable through got. Following mail sent to Segher yesterday may explain it. I was going through the output generated by objdump -D vmlinux and readelf -h vmlinux. <Snip objdump of vmlinux> Disassembly of section .got: c000000000805010 <__toc_start>: c000000000805010: c0 00 00 00 lfs f0,0(0) c000000000805014: 00 80 d0 10 .long 0x80d010 c000000000805018: c0 00 00 00 lfs f0,0(0) c00000000080501c: 00 00 83 58 .long 0x8358 c000000000805020: c0 00 00 00 lfs f0,0(0) c000000000805024: 00 85 1f e8 .long 0x851fe8 c000000000805028: c0 00 00 00 lfs f0,0(0) c00000000080502c: 00 00 8d 84 .long 0x8d84 c000000000805030: c0 00 00 00 lfs f0,0(0) c000000000805034: 00 85 03 38 .long 0x850338 c000000000805038: c0 00 00 00 lfs f0,0(0) c00000000080503c: 00 85 28 b8 .long 0x8528b8 c000000000805040: c0 00 00 00 lfs f0,0(0) c000000000805044: 00 85 28 b0 .long 0x8528b0 c000000000805048: c0 00 00 00 lfs f0,0(0) c00000000080504c: 00 6d ef 60 .long 0x6def60 All of the variables references through @got translated into relocation type R_PPC64_GOT16_DS entries. All these entries correspond to one of the above entries in the .got section. But none of the entries in .got section are relocated. For example the instruction with relocation type R_PPC64_GOT16_DS, c00000000000830c: e8 62 80 10 ld r3,-32752(r2) refers to current_set variable. r2 will be pointing to 0xc00000000280d010 (relocated __toc_start + 0x8000). So the instruction loads r3 with the content 0xc000000000851fe8 at location 0xc000000002805020, but which is not a relocated entry (0xc000000000851fe8) But when there is a relocation type of R_PPC64_ADDR16_HI, like c000000000008110: 64 84 00 00 oris r4,r4,0 we could easily get more info about this relocation from readelf like: c000000000008112 000100000005 R_PPC64_ADDR16_HI c000000000000000 .text + 8124 So from above output we can identify that instruction at address c000000000008112 needs to be patched with the relocation delta. Now I have two options left: 1. Check for R_PPC64_GOT16_DS entries and check whether the contents addressed by r2+offset is relocated or not and apply relocation if its not. 2. Change all LOAD_REG_ADDR macros to LOAD_REG_IMMEDIATE. This I have already done. Regards, Mohan. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros 2008-07-22 4:37 ` Mohan Kumar M @ 2008-07-22 6:37 ` Paul Mackerras 2008-07-22 17:13 ` Segher Boessenkool 0 siblings, 1 reply; 22+ messages in thread From: Paul Mackerras @ 2008-07-22 6:37 UTC (permalink / raw) To: Mohan Kumar M; +Cc: naren, Milton Miller, ppcdev Mohan Kumar M writes: > All of the variables references through @got translated into relocation > type R_PPC64_GOT16_DS entries. All these entries correspond to one of > the above entries in the .got section. But none of the entries in .got > section are relocated. If that last statement is really true, then that would be an absolute show-stopper, since you're not going to stop the compiler generating loads from the TOC to get addresses of things. However, I don't think it's true. I compiled up a kernel using --emit-relocs on the final link, and with readelf -e I can see a .rela.got section containing a bunch of R_PPC64_ADDR64 relocs for entries in the .got section. So the problem appears to be either just that you are ignoring R_PPC64_ADDR64 relocs, or else that your relocs.c program has a bug and isn't seeing the .rela.got section. > Now I have two options left: > 1. Check for R_PPC64_GOT16_DS entries and check whether the contents > addressed by r2+offset is relocated or not and apply relocation if its not. > 2. Change all LOAD_REG_ADDR macros to LOAD_REG_IMMEDIATE. This I have > already done. I was trying to point out that this can't possibly be a viable solution to the problem, because most of the TOC loads in the binary are generated by the C compiler, and only a few of them come from use of the LOAD_REG_ADDR macro in assembly code. Paul. ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros 2008-07-22 6:37 ` Paul Mackerras @ 2008-07-22 17:13 ` Segher Boessenkool 0 siblings, 0 replies; 22+ messages in thread From: Segher Boessenkool @ 2008-07-22 17:13 UTC (permalink / raw) To: Paul Mackerras; +Cc: ppcdev, naren, Milton Miller >> All of the variables references through @got translated into >> relocation >> type R_PPC64_GOT16_DS entries. All these entries correspond to one of >> the above entries in the .got section. But none of the entries in .got >> section are relocated. > > If that last statement is really true, then that would be an absolute > show-stopper, since you're not going to stop the compiler generating > loads from the TOC to get addresses of things. > > However, I don't think it's true. I compiled up a kernel using > --emit-relocs on the final link, and with readelf -e I can see a > .rela.got section containing a bunch of R_PPC64_ADDR64 relocs for > entries in the .got section. > > So the problem appears to be either just that you are ignoring > R_PPC64_ADDR64 relocs, or else that your relocs.c program has a bug > and isn't seeing the .rela.got section. I analysed this further. .rela.got does have lots of relocs in it, but _not_ for relocations create with @got in the assembler code. GCC never does this AFAICS, it explicitly creates a TOC entry and uses that. So, the workaround would be to manually create TOC entries in the LOAD_REG_ADDR code as well. I'll work on that, feel free to beat me to it of course. >> Now I have two options left: >> 1. Check for R_PPC64_GOT16_DS entries and check whether the contents >> addressed by r2+offset is relocated or not and apply relocation if >> its not. >> 2. Change all LOAD_REG_ADDR macros to LOAD_REG_IMMEDIATE. This I have >> already done. > > I was trying to point out that this can't possibly be a viable > solution to the problem, because most of the TOC loads in the binary > are generated by the C compiler, and only a few of them come from use > of the LOAD_REG_ADDR macro in assembly code. binutils has a problem only with the @gotXXX relocations, where the _linker_ creates the GOT entry (it doesn't emit a reloc for -emit-relocs in that case). Segher ^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC v3 PATCH 2/4] Build files needed for relocation support 2008-07-17 18:33 [RFC v3 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M 2008-07-17 18:40 ` [RFC v3 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M @ 2008-07-17 18:42 ` Mohan Kumar M 2008-07-17 18:45 ` [RFC v3 PATCH 3/4] Apply relocation info to vmlinux Mohan Kumar M 2008-07-17 18:48 ` [RFC v3 PATCH 4/4] Relocation support Mohan Kumar M 3 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-17 18:42 UTC (permalink / raw) To: ppcdev; +Cc: paulus, miltonm Build files needed for relocation This patch builds vmlinux file with relocation sections and contents so that relocs user space program can extract the required relocation offsets. This packs final relocatable vmlinux kernel as following: earlier part of relocation apply code, vmlinux, rest of relocation apply code. TODO: Relocatable vmlinux image is built in arch/powerpc/boot as vmlinux.reloc. But it should be built in top level directory of kernel source as vmlinux instead of vmlinux.reloc Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/Kconfig | 15 ++++++++++++--- arch/powerpc/Makefile | 9 +++++++-- arch/powerpc/boot/Makefile | 39 ++++++++++++++++++++++++++++++++++++--- arch/powerpc/boot/vmlinux.lds.S | 28 ++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 8 deletions(-) Index: linux-2.6.26/arch/powerpc/Kconfig =================================================================== --- linux-2.6.26.orig/arch/powerpc/Kconfig +++ linux-2.6.26/arch/powerpc/Kconfig @@ -317,6 +317,15 @@ config CRASH_DUMP Don't change this unless you know what you are doing. +config RELOCATABLE_PPC64 + bool "Build a relocatable kernel (EXPERIMENTAL)" + depends on PPC_MULTIPLATFORM && PPC64 && CRASH_DUMP && EXPERIMENTAL + help + Build a kernel suitable for use as regular kernel and kdump capture + kernel. + + Don't change this unless you know what you are doing. + config PHYP_DUMP bool "Hypervisor-assisted dump (EXPERIMENTAL)" depends on PPC_PSERIES && EXPERIMENTAL @@ -656,7 +665,7 @@ config LOWMEM_SIZE default "0x30000000" config RELOCATABLE - bool "Build a relocatable kernel (EXPERIMENTAL)" + bool "Build relocatable kernel (EXPERIMENTAL)" depends on EXPERIMENTAL && ADVANCED_OPTIONS && FLATMEM && FSL_BOOKE help This builds a kernel image that is capable of running at the @@ -776,11 +785,11 @@ config PAGE_OFFSET default "0xc000000000000000" config KERNEL_START hex - default "0xc000000002000000" if CRASH_DUMP + default "0xc000000002000000" if CRASH_DUMP && !RELOCATABLE_PPC64 default "0xc000000000000000" config PHYSICAL_START hex - default "0x02000000" if CRASH_DUMP + default "0x02000000" if CRASH_DUMP && !RELOCATABLE_PPC64 default "0x00000000" endif Index: linux-2.6.26/arch/powerpc/Makefile =================================================================== --- linux-2.6.26.orig/arch/powerpc/Makefile +++ linux-2.6.26/arch/powerpc/Makefile @@ -69,7 +69,7 @@ override CC += -m$(CONFIG_WORD_SIZE) override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR) endif -LDFLAGS_vmlinux := -Bstatic +LDFLAGS_vmlinux := --emit-relocs CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none -mcall-aixdesc CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple @@ -152,11 +152,16 @@ core-$(CONFIG_KVM) += arch/powerpc/kvm drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ # Default to zImage, override when needed + +ifneq ($(CONFIG_RELOCATABLE_PPC64),y) all: zImage +else +all: zImage vmlinux.reloc +endif CPPFLAGS_vmlinux.lds := -Upowerpc -BOOT_TARGETS = zImage zImage.initrd uImage zImage% dtbImage% treeImage.% cuImage.% simpleImage.% +BOOT_TARGETS = zImage vmlinux.reloc zImage.initrd uImage zImage% dtbImage% treeImage.% cuImage.% simpleImage.% PHONY += $(BOOT_TARGETS) Index: linux-2.6.26/arch/powerpc/boot/Makefile =================================================================== --- linux-2.6.26.orig/arch/powerpc/boot/Makefile +++ linux-2.6.26/arch/powerpc/boot/Makefile @@ -17,7 +17,7 @@ # CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE # in the toplevel makefile. -all: $(obj)/zImage +all: $(obj)/zImage $(obj)/vmlinux.reloc BOOTCFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -Os -msoft-float -pipe \ @@ -120,18 +120,51 @@ $(patsubst %.S,%.o, $(filter %.S, $(src- $(obj)/wrapper.a: $(obj-wlib) FORCE $(call if_changed,bootar) -hostprogs-y := addnote addRamDisk hack-coff mktree dtc +hostprogs-y := addnote addRamDisk hack-coff mktree dtc relocs targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a) extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \ $(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds +ifeq ($(CONFIG_RELOCATABLE_PPC64),y) +extra-y += $(obj)/vmlinux.lds +endif + dtstree := $(srctree)/$(src)/dts wrapper :=$(srctree)/$(src)/wrapper -wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \ +wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc relocs) \ $(wrapper) FORCE +ifeq ($(CONFIG_RELOCATABLE_PPC64),y) + +targets += vmlinux.offsets vmlinux.bin vmlinux.bin.all vmlinux.reloc.elf vmlinux.reloc reloc_apply.o vmlinux.lds + +OBJCOPYFLAGS_vmlinux.bin := -O binary -R .note -R .comment -S +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +quiet_cmd_relocbin = BUILD $@ + cmd_relocbin = cat $(filter-out FORCE,$^) > $@ + +quiet_cmd_relocs = RELOCS $@ + cmd_relocs = $(obj)/relocs $< > $@ + +$(obj)/vmlinux.offsets: vmlinux $(obj)/relocs FORCE + $(call if_changed,relocs) + +$(obj)/vmlinux.bin.all: $(obj)/vmlinux.bin $(obj)/vmlinux.offsets FORCE + $(call if_changed,relocbin) + +LDFLAGS_vmlinux.reloc.elf := -T $(obj)/vmlinux.reloc.scr -r --format binary --oformat elf64-powerpc +$(obj)/vmlinux.reloc.elf: $(obj)/vmlinux.bin.all FORCE + $(call if_changed,ld) + +LDFLAGS_vmlinux.reloc := -T $(obj)/vmlinux.lds +$(obj)/vmlinux.reloc: $(obj)/reloc_apply.o $(obj)/vmlinux.reloc.elf FORCE + $(call if_changed,ld) +endif + ############# # Bits for building dtc # DTC_GENPARSER := 1 # Uncomment to rebuild flex/bison output Index: linux-2.6.26/arch/powerpc/boot/vmlinux.lds.S =================================================================== --- /dev/null +++ linux-2.6.26/arch/powerpc/boot/vmlinux.lds.S @@ -0,0 +1,28 @@ +#include <asm/page.h> +#include <asm-generic/vmlinux.lds.h> + +ENTRY(start_wrap) + +OUTPUT_ARCH(powerpc:common64) +SECTIONS +{ + . = KERNELBASE; + +/* + * Text, read only data and other permanent read-only sections + */ + /* Text and gots */ + .text : { + _head = .; + *(.text.head) + _ehead = .; + + _text = .; + *(.vmlinux) + _etext = .; + + _reloc = .; + *(.text.reloc) + _ereloc = .; + } +} ^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC v3 PATCH 3/4] Apply relocation info to vmlinux 2008-07-17 18:33 [RFC v3 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M 2008-07-17 18:40 ` [RFC v3 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M 2008-07-17 18:42 ` [RFC v3 PATCH 2/4] Build files needed for relocation support Mohan Kumar M @ 2008-07-17 18:45 ` Mohan Kumar M 2008-07-17 18:48 ` [RFC v3 PATCH 4/4] Relocation support Mohan Kumar M 3 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-17 18:45 UTC (permalink / raw) To: ppcdev; +Cc: paulus, miltonm Apply relocation This code is a wrapper around regular kernel. This checks whether the kernel is loaded at 32MB, if its not loaded at 32MB, its treated as a regular kernel and the control is given to the kernel immediately. If the kernel is loaded at 32MB, it applies relocation delta to each offset in the list which was generated and appended by patch 1 and 2. After updating all offsets, control is given to relocatable kernel. Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/boot/reloc_apply.S | 229 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) Index: linux-2.6.26/arch/powerpc/boot/reloc_apply.S =================================================================== --- /dev/null +++ linux-2.6.26/arch/powerpc/boot/reloc_apply.S @@ -0,0 +1,229 @@ +#include <asm/ppc_asm.h> + +#define RELOC_DELTA 0x4000000002000000 + +#define LOADADDR(rn,name) \ + lis rn,name##@highest; \ + ori rn,rn,name##@higher; \ + rldicr rn,rn,32,31; \ + oris rn,rn,name##@h; \ + ori rn,rn,name##@l + + +/* + * Layout of vmlinux.reloc file + * Minimal part of relocation applying code + + * vmlinux + + * Rest of the relocation applying code + */ + +.section .text.head + +.globl start_wrap +start_wrap: + /* Get relocation offset in r15 */ + bl 1f +1: mflr r15 + LOAD_REG_IMMEDIATE(r16,1b) + subf r15,r16,r15 + + LOAD_REG_IMMEDIATE(r17, _reloc) + add r17,r17,r15 + mtctr r17 + bctr /* Jump to start_reloc in section ".text.reloc" */ + +/* Secondary cpus spin code */ +. = 0x60 + /* Get relocation offset in r15 */ + bl 1f +1: mflr r15 + LOAD_REG_IMMEDIATE(r16,1b) + subf r15,r16,r15 + + LOADADDR(r18, __spinloop) + add r18,r18,r15 +100: ld r19,0(r18) + cmpwi 0,r19,1 + bne 100b + + LOAD_REG_IMMEDIATE(r17, _reloc) + add r17,r17,r15 + addi r17,r17,0x60 + mtctr r17 + /* Jump to start_reloc + 0x60 in section ".text.reloc" */ + bctr + +/* + * Layout of vmlinux.reloc file + * Minimal part of relocation applying code + + * vmlinux + + * Rest of the relocation applying code + */ + + +.section .text.reloc + +start_reloc: + b master + +.org start_reloc + 0x60 + LOADADDR(r18, __spinloop) + add r18,r18,r15 +100: ld r19,0(r18) + cmpwi 0,r19,2 + bne 100b + + /* Now vmlinux is at _head */ + LOAD_REG_IMMEDIATE(r17, _head) + add r17,r17,r15 + addi r17,r17,0x60 + mtctr r17 + bctr + +master: + LOAD_REG_IMMEDIATE(r16, output_len) + add r16,r16,r15 + + /* + * Load the delimiter to distinguish between different relocation + * types + */ + LOAD_REG_IMMEDIATE(r24, __delimiter) + add r24,r24,r15 + ld r24,0(r24) + + LOAD_REG_IMMEDIATE(r17, _head) + LOAD_REG_IMMEDIATE(r21, _ehead) + sub r21,r21,r17 /* Number of bytes in head section */ + + sub r16,r16,r21 /* Original output_len */ + + /* Destination address */ + LOAD_REG_IMMEDIATE(r17, _head) /* KERNELBASE */ + add r17,r17,r15 + + /* Source address */ + LOAD_REG_IMMEDIATE(r18, _text) /* Regular vmlinux */ + add r18,r18,r15 + + /* Number of bytes to copy */ + LOAD_REG_IMMEDIATE(r19, _etext) + add r19,r19,r15 + sub r19,r19,r18 + + /* Move cpu spin code to "text.reloc" section */ + LOADADDR(r23, __spinloop) + add r23,r23,r15 + li r25,1 + stw r25,0(r23) + + /* Copy vmlinux code to physical address 0 */ + bl .copy /* copy(_head, _text, _etext-_text) */ + + /* + * If its not running at 32MB, assume it to be a normal kernel. + * Copy the vmlinux code to KERNELBASE and jump to KERNELBASE + */ + LOAD_REG_IMMEDIATE(r21, RELOC_DELTA) + cmpd r15,r21 + beq apply_relocation + li r6,0 + b skip_apply +apply_relocation: + + /* Kernel is running at 32MB */ + mr r22,r15 + xor r23,r23,r23 + addi r23,r23,16 + srw r22,r22,r23 + + li r25,0 + + LOAD_REG_IMMEDIATE(r26, _head) + + /* + * Start reading the relocation offset list from end of file + * Based on the relocation type either add the relocation delta + * or do logical ORing the relocation delta + */ +3: + addi r16,r16,-8 + ld r18,0(r16) + cmpdi r18,0 /* Processed all offsets */ + beq 4f /* Start vmlinux */ + /* Are we processing reloction type R_PPC64_ADDR16_HI */ + cmpdi r25,1 + beq rel_hi + cmpd r18,r24 + beq set_rel_hi + /* Process 64bit absolute relocation update */ +rel_addr64: + add r18,r18,r15 + ld r28,0(r18) + cmpdi r28,0 + beq next + add r28,r28,r15 /* add relocation offset */ + add r28,r28,r26 /* add KERNELBASE */ + std r28,0(r18) + b next +set_rel_hi: /* Enable R_PPC64_ADDR16_HI flag */ + addi r25,r25,1 + b 3b +rel_hi: + add r18,r18,r15 + lhz r28,0(r18) + or r28,r28,r22 + sth r28,0(r18) +next: + b 3b +4: + mr r6,r15 + + +skip_apply: + isync + sync + + /* Now vmlinux is at _head */ + LOAD_REG_IMMEDIATE(r17, _head) + add r17,r17,r15 + mtctr r17 + + /* Move cpu spin code to "text.reloc" section */ + LOADADDR(r23, __spinloop) + add r23,r23,r15 + li r25,2 + stw r25,0(r23) + + bctr + +/* r17 destination, r18 source, r19 size */ +.copy: + addi r19,r19,-8 + li r22,-8 +4: li r21,8 /* Use the smallest common */ + /* denominator cache line */ + /* size. This results in */ + /* extra cache line flushes */ + /* but operation is correct. */ + /* Can't get cache line size */ + /* from NACA as it is being */ + /* moved too. */ + + mtctr r21 /* put # words/line in ctr */ +3: addi r22,r22,8 /* copy a cache line */ + ldx r21,r22,r18 + stdx r21,r22,r17 + bdnz 3b + dcbst r22,r17 /* write it to memory */ + sync + icbi r22,r17 /* flush the icache line */ + cmpld 0,r22,r19 + blt 4b + sync + blr + +__delimiter: + .llong 0xffffffffffffffff +__spinloop: + .llong 0x0 ^ permalink raw reply [flat|nested] 22+ messages in thread
* [RFC v3 PATCH 4/4] Relocation support 2008-07-17 18:33 [RFC v3 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M ` (2 preceding siblings ...) 2008-07-17 18:45 ` [RFC v3 PATCH 3/4] Apply relocation info to vmlinux Mohan Kumar M @ 2008-07-17 18:48 ` Mohan Kumar M 2008-07-18 17:48 ` Segher Boessenkool 3 siblings, 1 reply; 22+ messages in thread From: Mohan Kumar M @ 2008-07-17 18:48 UTC (permalink / raw) To: ppcdev; +Cc: paulus, miltonm Relocation support This patch changes all LOAD_REG_ADDR macro calls to LOAD_REG_IMMEDIATE to make sure that we load the correct address. It also takes care of when accessing absolute symbols in the code by adding the relocation kernel base address. Signed-off-by: Mohan Kumar M <mohan@in.ibm.com> --- arch/powerpc/kernel/crash_dump.c | 19 +++++++++ arch/powerpc/kernel/entry_64.S | 4 +- arch/powerpc/kernel/head_64.S | 63 ++++++++++++++++++++++++++++---- arch/powerpc/kernel/iommu.c | 7 ++- arch/powerpc/kernel/machine_kexec.c | 5 ++ arch/powerpc/kernel/machine_kexec_64.c | 4 +- arch/powerpc/kernel/misc.S | 40 ++++++++++++++++---- arch/powerpc/kernel/prom.c | 13 ++++++ arch/powerpc/kernel/prom_init.c | 27 +++++++++++-- arch/powerpc/kernel/prom_init_check.sh | 2 - arch/powerpc/kernel/setup_64.c | 5 +- arch/powerpc/mm/hash_low_64.S | 8 ++-- arch/powerpc/mm/hash_utils_64.c | 5 +- arch/powerpc/mm/init_64.c | 7 ++- arch/powerpc/mm/mem.c | 3 + arch/powerpc/mm/slb_low.S | 2 - arch/powerpc/platforms/pseries/hvCall.S | 2 - arch/powerpc/platforms/pseries/iommu.c | 5 ++ include/asm-powerpc/exception.h | 6 --- include/asm-powerpc/prom.h | 2 + include/asm-powerpc/sections.h | 4 +- include/asm-powerpc/system.h | 5 ++ 22 files changed, 189 insertions(+), 49 deletions(-) Index: linux-2.6.26/arch/powerpc/kernel/crash_dump.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/crash_dump.c +++ linux-2.6.26/arch/powerpc/kernel/crash_dump.c @@ -28,7 +28,12 @@ void __init reserve_kdump_trampoline(void) { +#ifdef CONFIG_RELOCATABLE_PPC64 + if (RELOC(reloc_delta)) + lmb_reserve(0, KDUMP_RESERVE_LIMIT); +#else lmb_reserve(0, KDUMP_RESERVE_LIMIT); +#endif } static void __init create_trampoline(unsigned long addr) @@ -42,7 +47,11 @@ static void __init create_trampoline(uns * two instructions it doesn't require any registers. */ create_instruction(addr, 0x60000000); /* nop */ +#ifndef CONFIG_RELOCATABLE_PPC64 create_branch(addr + 4, addr + PHYSICAL_START, 0); +#else + create_branch(addr + 4, addr + RELOC(reloc_delta), 0); +#endif } void __init setup_kdump_trampoline(void) @@ -51,13 +60,23 @@ void __init setup_kdump_trampoline(void) DBG(" -> setup_kdump_trampoline()\n"); +#ifdef CONFIG_RELOCATABLE_PPC64 + if (!RELOC(reloc_delta)) + return; +#endif + for (i = KDUMP_TRAMPOLINE_START; i < KDUMP_TRAMPOLINE_END; i += 8) { create_trampoline(i); } #ifdef CONFIG_PPC_PSERIES +#ifndef CONFIG_RELOCATABLE_PPC64 create_trampoline(__pa(system_reset_fwnmi) - PHYSICAL_START); create_trampoline(__pa(machine_check_fwnmi) - PHYSICAL_START); +#else + create_trampoline(__pa(system_reset_fwnmi) - RELOC(reloc_delta)); + create_trampoline(__pa(machine_check_fwnmi) - RELOC(reloc_delta)); +#endif #endif /* CONFIG_PPC_PSERIES */ DBG(" <- setup_kdump_trampoline()\n"); Index: linux-2.6.26/arch/powerpc/kernel/entry_64.S =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/entry_64.S +++ linux-2.6.26/arch/powerpc/kernel/entry_64.S @@ -709,7 +709,7 @@ _GLOBAL(enter_rtas) std r6,PACASAVEDMSR(r13) /* Setup our real return addr */ - LOAD_REG_ADDR(r4,.rtas_return_loc) + LOAD_REG_IMMEDIATE(r4,.rtas_return_loc) clrldi r4,r4,2 /* convert to realmode address */ mtlr r4 @@ -725,7 +725,7 @@ _GLOBAL(enter_rtas) sync /* disable interrupts so SRR0/1 */ mtmsrd r0 /* don't get trashed */ - LOAD_REG_ADDR(r4, rtas) + LOAD_REG_IMMEDIATE(r4, rtas) ld r5,RTASENTRY(r4) /* get the rtas->entry value */ ld r4,RTASBASE(r4) /* get the rtas->base value */ Index: linux-2.6.26/arch/powerpc/kernel/head_64.S =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/head_64.S +++ linux-2.6.26/arch/powerpc/kernel/head_64.S @@ -102,6 +102,12 @@ __secondary_hold_acknowledge: .llong hvReleaseData-KERNELBASE #endif /* CONFIG_PPC_ISERIES */ +#ifdef CONFIG_RELOCATABLE_PPC64 + /* Used as static variable to initialize the reloc_delta */ +__initialized: + .long 0x0 +#endif + . = 0x60 /* * The following code is used to hold secondary processors @@ -121,11 +127,13 @@ _GLOBAL(__secondary_hold) /* Tell the master cpu we're here */ /* Relocation is off & we are located at an address less */ /* than 0x100, so only need to grab low order offset. */ - std r24,__secondary_hold_acknowledge@l(0) + LOAD_REG_IMMEDIATE(r25, __secondary_hold_acknowledge) + std r24,0(r25) sync /* All secondary cpus wait here until told to start. */ -100: ld r4,__secondary_hold_spinloop@l(0) + LOAD_REG_IMMEDIATE(r25, __secondary_hold_spinloop) +100: ld r4,0(r25) cmpdi 0,r4,1 bne 100b @@ -1176,6 +1184,38 @@ _STATIC(__mmu_off) * */ _GLOBAL(__start_initialization_multiplatform) +#ifdef CONFIG_RELOCATABLE_PPC64 + mr r21,r3 + mr r22,r4 + mr r23,r5 + bl .reloc_offset + mr r26,r3 + mr r3,r21 + mr r4,r22 + mr r5,r23 + + LOAD_REG_IMMEDIATE(r27, __initialized) + add r27,r26,r27 + ld r7,0(r27) + cmpdi r7,0 + bne 4f + + li r7,1 + stw r7,0(r27) + + cmpdi r6,0 + beq 4f + LOAD_REG_IMMEDIATE(r27, reloc_delta) + add r27,r27,r26 + std r6,0(r27) + + LOAD_REG_IMMEDIATE(r27, KERNELBASE) + add r7,r6,r27 + LOAD_REG_IMMEDIATE(r27, kernel_base) + add r27,r27,r26 + std r7,0(r27) +4: +#endif /* * Are we booted from a PROM Of-type client-interface ? */ @@ -1251,6 +1291,19 @@ _INIT_STATIC(__boot_from_prom) trap _STATIC(__after_prom_start) + bl .reloc_offset + mr r26,r3 +#ifdef CONFIG_RELOCATABLE_PPC64 + /* + * If its a relocatable kernel, no need to copy the kernel + * to PHYSICAL_START. Continue running from the same location + */ + LOAD_REG_IMMEDIATE(r27, reloc_delta) + add r27,r27,r26 + ld r28,0(r27) + cmpdi r28,0 + bne .start_here_multiplatform +#endif /* * We need to run with __start at physical address PHYSICAL_START. @@ -1264,8 +1317,6 @@ _STATIC(__after_prom_start) * r26 == relocation offset * r27 == KERNELBASE */ - bl .reloc_offset - mr r26,r3 LOAD_REG_IMMEDIATE(r27, KERNELBASE) LOAD_REG_IMMEDIATE(r3, PHYSICAL_START) /* target addr */ @@ -1411,7 +1462,7 @@ __secondary_start: bl .early_setup_secondary /* Initialize the kernel stack. Just a repeat for iSeries. */ - LOAD_REG_ADDR(r3, current_set) + LOAD_REG_IMMEDIATE(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ ldx r1,r3,r28 addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD @@ -1422,7 +1473,7 @@ __secondary_start: mtlr r7 /* enable MMU and jump to start_secondary */ - LOAD_REG_ADDR(r3, .start_secondary_prolog) + LOAD_REG_IMMEDIATE(r3, .start_secondary_prolog) LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) #ifdef CONFIG_PPC_ISERIES BEGIN_FW_FTR_SECTION Index: linux-2.6.26/arch/powerpc/kernel/machine_kexec.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/machine_kexec.c +++ linux-2.6.26/arch/powerpc/kernel/machine_kexec.c @@ -67,6 +67,11 @@ void __init reserve_crashkernel(void) unsigned long long crash_size, crash_base; int ret; +#ifdef CONFIG_RELOCATABLE_PPC64 + if (reloc_delta) + return; +#endif + /* this is necessary because of lmb_phys_mem_size() */ lmb_analyze(); Index: linux-2.6.26/arch/powerpc/kernel/machine_kexec_64.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/machine_kexec_64.c +++ linux-2.6.26/arch/powerpc/kernel/machine_kexec_64.c @@ -43,7 +43,7 @@ int default_machine_kexec_prepare(struct * overlaps kernel static data or bss. */ for (i = 0; i < image->nr_segments; i++) - if (image->segment[i].mem < __pa(_end)) + if (image->segment[i].mem < (__pa(_end) + kernel_base)) return -ETXTBSY; /* @@ -317,7 +317,7 @@ static void __init export_htab_values(vo if (!node) return; - kernel_end = __pa(_end); + kernel_end = __pa(_end) + kernel_base; prom_add_property(node, &kernel_end_prop); /* On machines with no htab htab_address is NULL */ Index: linux-2.6.26/arch/powerpc/kernel/misc.S =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/misc.S +++ linux-2.6.26/arch/powerpc/kernel/misc.S @@ -20,6 +20,8 @@ #include <asm/asm-compat.h> #include <asm/asm-offsets.h> +#define RELOC_DELTA 0x4000000002000000 + .text /* @@ -33,6 +35,17 @@ _GLOBAL(reloc_offset) 1: mflr r3 LOAD_REG_IMMEDIATE(r4,1b) subf r3,r4,r3 +#ifdef CONFIG_RELOCATABLE_PPC64 + LOAD_REG_IMMEDIATE(r5, RELOC_DELTA) + cmpd r3,r5 + bne 2f + /* + * Don't return the offset if the difference is + * RELOC_DELTA + */ + li r3,0 +2: +#endif mtlr r0 blr @@ -40,14 +53,25 @@ _GLOBAL(reloc_offset) * add_reloc_offset(x) returns x + reloc_offset(). */ _GLOBAL(add_reloc_offset) - mflr r0 - bl 1f -1: mflr r5 - LOAD_REG_IMMEDIATE(r4,1b) - subf r5,r4,r5 - add r3,r3,r5 - mtlr r0 - blr + mflr r0 + bl 1f +1: mflr r5 + LOAD_REG_IMMEDIATE(r4,1b) + subf r5,r4,r5 +#ifdef CONFIG_RELOCATABLE_PPC64 + LOAD_REG_IMMEDIATE(r4, RELOC_DELTA) + cmpd r5,r4 + bne 2f + /* + * Don't add the offset if the difference is + * RELOC_DELTA + */ + li r5,0 +2: +#endif + add r3,r3,r5 + mtlr r0 + blr _GLOBAL(kernel_execve) li r0,__NR_execve Index: linux-2.6.26/arch/powerpc/kernel/prom.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/prom.c +++ linux-2.6.26/arch/powerpc/kernel/prom.c @@ -65,6 +65,9 @@ static int __initdata dt_root_addr_cells; static int __initdata dt_root_size_cells; +unsigned long reloc_delta __attribute__ ((__section__ (".data"))); +unsigned long kernel_base __attribute__ ((__section__ (".data"))); + #ifdef CONFIG_PPC64 int __initdata iommu_is_off; int __initdata iommu_force_on; @@ -1159,8 +1162,16 @@ void __init early_init_devtree(void *par parse_early_param(); /* Reserve LMB regions used by kernel, initrd, dt, etc... */ - lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); reserve_kdump_trampoline(); +#ifdef CONFIG_RELOCATABLE_PPC64 + if (RELOC(kernel_base)) { + lmb_reserve(0, KDUMP_RESERVE_LIMIT); + lmb_reserve(kernel_base, __pa(klimit) - PHYSICAL_START); + } else + lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); +#else + lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START); +#endif reserve_crashkernel(); early_reserve_mem(); phyp_dump_reserve_mem(); Index: linux-2.6.26/arch/powerpc/kernel/prom_init.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/prom_init.c +++ linux-2.6.26/arch/powerpc/kernel/prom_init.c @@ -91,11 +91,9 @@ extern const struct linux_logo logo_linu * fortunately don't get interpreted as two arguments). */ #ifdef CONFIG_PPC64 -#define RELOC(x) (*PTRRELOC(&(x))) #define ADDR(x) (u32) add_reloc_offset((unsigned long)(x)) #define OF_WORKAROUNDS 0 #else -#define RELOC(x) (x) #define ADDR(x) (u32) (x) #define OF_WORKAROUNDS of_workarounds int of_workarounds; @@ -1070,7 +1068,12 @@ static void __init prom_init_mem(void) } } +#ifndef CONFIG_RELOCATABLE_PPC64 RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000); +#else + RELOC(alloc_bottom) = PAGE_ALIGN((unsigned long)&RELOC(_end) + 0x4000 + + RELOC(reloc_delta)); +#endif /* Check if we have an initrd after the kernel, if we do move our bottom * point to after it @@ -1334,10 +1337,19 @@ static void __init prom_hold_cpus(void) unsigned int cpu_threads, hw_cpu_num; int propsize; struct prom_t *_prom = &RELOC(prom); + +#ifndef CONFIG_RELOCATABLE_PPC64 unsigned long *spinloop = (void *) LOW_ADDR(__secondary_hold_spinloop); unsigned long *acknowledge = (void *) LOW_ADDR(__secondary_hold_acknowledge); +#else + unsigned long *spinloop + = (void *) &__secondary_hold_spinloop; + unsigned long *acknowledge + = (void *) &__secondary_hold_acknowledge; +#endif + #ifdef CONFIG_PPC64 /* __secondary_hold is actually a descriptor, not the text address */ unsigned long secondary_hold @@ -2399,8 +2411,15 @@ unsigned long __init prom_init(unsigned /* * Copy the CPU hold code */ - if (RELOC(of_platform) != PLATFORM_POWERMAC) - copy_and_flush(0, KERNELBASE + offset, 0x100, 0); + if (RELOC(of_platform) != PLATFORM_POWERMAC) { +#ifdef CONFIG_RELOCATABLE_PPC64 + if (RELOC(reloc_delta)) + copy_and_flush(0, KERNELBASE + RELOC(reloc_delta), + 0x100, 0); + else +#endif + copy_and_flush(0, KERNELBASE + offset, 0x100, 0); + } /* * Do early parsing of command line Index: linux-2.6.26/arch/powerpc/kernel/prom_init_check.sh =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/prom_init_check.sh +++ linux-2.6.26/arch/powerpc/kernel/prom_init_check.sh @@ -20,7 +20,7 @@ WHITELIST="add_reloc_offset __bss_start _end enter_prom memcpy memset reloc_offset __secondary_hold __secondary_hold_acknowledge __secondary_hold_spinloop __start strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 -reloc_got2 kernstart_addr" +reloc_got2 kernstart_addr reloc_delta" NM="$1" OBJ="$2" Index: linux-2.6.26/arch/powerpc/kernel/setup_64.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/setup_64.c +++ linux-2.6.26/arch/powerpc/kernel/setup_64.c @@ -208,7 +208,6 @@ void __init early_setup(unsigned long dt /* Probe the machine type */ probe_machine(); - setup_kdump_trampoline(); DBG("Found, Initializing memory management...\n"); @@ -524,9 +523,9 @@ void __init setup_arch(char **cmdline_p) if (ppc_md.panic) setup_panic(); - init_mm.start_code = (unsigned long)_stext; + init_mm.start_code = (unsigned long)_stext + kernel_base; init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; + init_mm.end_data = (unsigned long) _edata + kernel_base; init_mm.brk = klimit; irqstack_early_init(); Index: linux-2.6.26/arch/powerpc/mm/hash_low_64.S =================================================================== --- linux-2.6.26.orig/arch/powerpc/mm/hash_low_64.S +++ linux-2.6.26/arch/powerpc/mm/hash_low_64.S @@ -83,7 +83,7 @@ _GLOBAL(__hash_page_4K) std r29,STK_REG(r29)(r1) std r30,STK_REG(r30)(r1) std r31,STK_REG(r31)(r1) - + /* Step 1: * * Check permissions, atomically mark the linux PTE busy @@ -168,7 +168,7 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FT std r3,STK_PARM(r4)(r1) /* Get htab_hash_mask */ - ld r4,htab_hash_mask@got(2) + LOAD_REG_IMMEDIATE(r4, htab_hash_mask) ld r27,0(r4) /* htab_hash_mask -> r27 */ /* Check if we may already be in the hashtable, in this case, we @@ -461,7 +461,7 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FT std r3,STK_PARM(r4)(r1) /* Get htab_hash_mask */ - ld r4,htab_hash_mask@got(2) + LOAD_REG_IMMEDIATE(r4, htab_hash_mask) ld r27,0(r4) /* htab_hash_mask -> r27 */ /* Check if we may already be in the hashtable, in this case, we @@ -792,7 +792,7 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FT std r3,STK_PARM(r4)(r1) /* Get htab_hash_mask */ - ld r4,htab_hash_mask@got(2) + LOAD_REG_IMMEDIATE(r4, htab_hash_mask) ld r27,0(r4) /* htab_hash_mask -> r27 */ /* Check if we may already be in the hashtable, in this case, we Index: linux-2.6.26/arch/powerpc/mm/init_64.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/mm/init_64.c +++ linux-2.6.26/arch/powerpc/mm/init_64.c @@ -79,10 +79,11 @@ phys_addr_t kernstart_addr; void free_initmem(void) { - unsigned long addr; + unsigned long long addr, eaddr; - addr = (unsigned long)__init_begin; - for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) { + addr = (unsigned long long )__init_begin + kernel_base; + eaddr = (unsigned long long ) __init_end + kernel_base; + for (; addr < eaddr; addr += PAGE_SIZE) { memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); Index: linux-2.6.26/arch/powerpc/mm/mem.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/mm/mem.c +++ linux-2.6.26/arch/powerpc/mm/mem.c @@ -400,7 +400,8 @@ void __init mem_init(void) } } - codesize = (unsigned long)&_sdata - (unsigned long)&_stext; + codesize = (unsigned long)&_sdata - (unsigned long)&_stext + + kernel_base; datasize = (unsigned long)&_edata - (unsigned long)&_sdata; initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; Index: linux-2.6.26/arch/powerpc/mm/slb_low.S =================================================================== --- linux-2.6.26.orig/arch/powerpc/mm/slb_low.S +++ linux-2.6.26/arch/powerpc/mm/slb_low.S @@ -128,7 +128,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT /* Now get to the array and obtain the sllp */ ld r11,PACATOC(r13) - ld r11,mmu_psize_defs@got(r11) + LOAD_REG_IMMEDIATE(r11, mmu_psize_defs) add r11,r11,r9 ld r11,MMUPSIZESLLP(r11) ori r11,r11,SLB_VSID_USER Index: linux-2.6.26/arch/powerpc/platforms/pseries/hvCall.S =================================================================== --- linux-2.6.26.orig/arch/powerpc/platforms/pseries/hvCall.S +++ linux-2.6.26/arch/powerpc/platforms/pseries/hvCall.S @@ -55,7 +55,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_PURR); /* calculate address of stat structure r4 = opcode */ \ srdi r4,r4,2; /* index into array */ \ mulli r4,r4,HCALL_STAT_SIZE; \ - LOAD_REG_ADDR(r7, per_cpu__hcall_stats); \ + LOAD_REG_IMMEDIATE(r7, per_cpu__hcall_stats); \ add r4,r4,r7; \ ld r7,PACA_DATA_OFFSET(r13); /* per cpu offset */ \ add r4,r4,r7; \ Index: linux-2.6.26/include/asm-powerpc/exception.h =================================================================== --- linux-2.6.26.orig/include/asm-powerpc/exception.h +++ linux-2.6.26/include/asm-powerpc/exception.h @@ -47,12 +47,6 @@ #define EX_R3 64 #define EX_LR 72 -/* - * We're short on space and time in the exception prolog, so we can't - * use the normal SET_REG_IMMEDIATE macro. Normally we just need the - * low halfword of the address, but for Kdump we need the whole low - * word. - */ #ifdef CONFIG_CRASH_DUMP #define LOAD_HANDLER(reg, label) \ oris reg,reg,(label)@h; /* virt addr of handler ... */ \ Index: linux-2.6.26/include/asm-powerpc/system.h =================================================================== --- linux-2.6.26.orig/include/asm-powerpc/system.h +++ linux-2.6.26/include/asm-powerpc/system.h @@ -517,6 +517,11 @@ extern unsigned long add_reloc_offset(un extern void reloc_got2(unsigned long); #define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x))) +#ifdef CONFIG_PPC64 +#define RELOC(x) (*PTRRELOC(&(x))) +#else +#define RELOC(x) (x) +#endif static inline void create_instruction(unsigned long addr, unsigned int instr) { Index: linux-2.6.26/include/asm-powerpc/sections.h =================================================================== --- linux-2.6.26.orig/include/asm-powerpc/sections.h +++ linux-2.6.26/include/asm-powerpc/sections.h @@ -7,10 +7,12 @@ #ifdef __powerpc64__ extern char _end[]; +extern unsigned long kernel_base; static inline int in_kernel_text(unsigned long addr) { - if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end) + if (addr >= (unsigned long)_stext && addr < (unsigned long)__init_end + + kernel_base) return 1; return 0; Index: linux-2.6.26/include/asm-powerpc/prom.h =================================================================== --- linux-2.6.26.orig/include/asm-powerpc/prom.h +++ linux-2.6.26/include/asm-powerpc/prom.h @@ -39,6 +39,8 @@ #define OF_DT_VERSION 0x10 +extern unsigned long reloc_delta, kernel_base; + /* * This is what gets passed to the kernel by prom_init or kexec * Index: linux-2.6.26/arch/powerpc/kernel/iommu.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/kernel/iommu.c +++ linux-2.6.26/arch/powerpc/kernel/iommu.c @@ -473,7 +473,7 @@ struct iommu_table *iommu_init_table(str spin_lock_init(&tbl->it_lock); #ifdef CONFIG_CRASH_DUMP - if (ppc_md.tce_get) { + if (reloc_delta && ppc_md.tce_get) { unsigned long index; unsigned long tceval; unsigned long tcecount = 0; @@ -499,7 +499,10 @@ struct iommu_table *iommu_init_table(str index < tbl->it_size; index++) __clear_bit(index, tbl->it_map); } - } + } else + /* Clear the hardware table in case firmware left allocations + in it */ + ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); #else /* Clear the hardware table in case firmware left allocations in it */ ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); Index: linux-2.6.26/arch/powerpc/platforms/pseries/iommu.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/platforms/pseries/iommu.c +++ linux-2.6.26/arch/powerpc/platforms/pseries/iommu.c @@ -262,7 +262,10 @@ static void iommu_table_setparms(struct tbl->it_base = (unsigned long)__va(*basep); -#ifndef CONFIG_CRASH_DUMP +#ifdef CONFIG_CRASH_DUMP + if (!reloc_delta) + memset((void *)tbl->it_base, 0, *sizep); +#else memset((void *)tbl->it_base, 0, *sizep); #endif Index: linux-2.6.26/arch/powerpc/mm/hash_utils_64.c =================================================================== --- linux-2.6.26.orig/arch/powerpc/mm/hash_utils_64.c +++ linux-2.6.26/arch/powerpc/mm/hash_utils_64.c @@ -638,8 +638,9 @@ void __init htab_initialize(void) continue; } #endif /* CONFIG_U3_DART */ - BUG_ON(htab_bolt_mapping(base, base + size, __pa(base), - mode_rw, mmu_linear_psize, mmu_kernel_ssize)); + BUG_ON(htab_bolt_mapping(base + kernel_base, base + size, + __pa(base) + kernel_base, mode_rw, mmu_linear_psize, + mmu_kernel_ssize)); } /* ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 4/4] Relocation support 2008-07-17 18:48 ` [RFC v3 PATCH 4/4] Relocation support Mohan Kumar M @ 2008-07-18 17:48 ` Segher Boessenkool 2008-07-21 9:11 ` Mohan Kumar M 0 siblings, 1 reply; 22+ messages in thread From: Segher Boessenkool @ 2008-07-18 17:48 UTC (permalink / raw) To: mohan; +Cc: ppcdev, paulus, miltonm > This patch changes all LOAD_REG_ADDR macro calls to LOAD_REG_IMMEDIATE > to make sure that we load the correct address. Did you figure out _why_ LOAD_REG_ADDR doesn't work? Using LOAD_REG_IMMEDIATE is actually a step back, it makes the kernel binary non-PIC. And LOAD_REG_ADDR _should_ work just fine with your scheme. Segher ^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [RFC v3 PATCH 4/4] Relocation support 2008-07-18 17:48 ` Segher Boessenkool @ 2008-07-21 9:11 ` Mohan Kumar M 0 siblings, 0 replies; 22+ messages in thread From: Mohan Kumar M @ 2008-07-21 9:11 UTC (permalink / raw) To: Segher Boessenkool; +Cc: ppcdev, paulus, miltonm Segher Boessenkool wrote: >> This patch changes all LOAD_REG_ADDR macro calls to LOAD_REG_IMMEDIATE >> to make sure that we load the correct address. > > Did you figure out _why_ LOAD_REG_ADDR doesn't work? Using > LOAD_REG_IMMEDIATE is actually a step back, it makes the kernel > binary non-PIC. And LOAD_REG_ADDR _should_ work just fine with > your scheme. > Hi Segher, I was going through the output generated by objdump -D vmlinux and readelf -h vmlinux. <Snip objdump of vmlinux> Disassembly of section .got: c000000000805010 <__toc_start>: c000000000805010: c0 00 00 00 lfs f0,0(0) c000000000805014: 00 80 d0 10 .long 0x80d010 c000000000805018: c0 00 00 00 lfs f0,0(0) c00000000080501c: 00 00 83 58 .long 0x8358 c000000000805020: c0 00 00 00 lfs f0,0(0) c000000000805024: 00 85 1f e8 .long 0x851fe8 c000000000805028: c0 00 00 00 lfs f0,0(0) c00000000080502c: 00 00 8d 84 .long 0x8d84 c000000000805030: c0 00 00 00 lfs f0,0(0) c000000000805034: 00 85 03 38 .long 0x850338 c000000000805038: c0 00 00 00 lfs f0,0(0) c00000000080503c: 00 85 28 b8 .long 0x8528b8 c000000000805040: c0 00 00 00 lfs f0,0(0) c000000000805044: 00 85 28 b0 .long 0x8528b0 c000000000805048: c0 00 00 00 lfs f0,0(0) c00000000080504c: 00 6d ef 60 .long 0x6def60 All of the variables references through @got translated into relocation type R_PPC64_GOT16_DS entries. All these entries correspond to one of the above entries in the .got section. But none of the entries in .got section are relocated. For example the instruction with relocation type R_PPC64_GOT16_DS, c00000000000830c: e8 62 80 10 ld r3,-32752(r2) refers to current_set variable. r2 will be pointing to 0xc00000000280d010 (relocated __toc_start + 0x8000). So the instruction loads r3 with the content 0xc000000000851fe8 at location 0xc000000002805020, but which is not a relocated entry (0xc000000000851fe8) But when there is a relocation type of R_PPC64_ADDR16_HI, like c000000000008110: 64 84 00 00 oris r4,r4,0 we could easily get more info about this relocation from readelf like: c000000000008112 000100000005 R_PPC64_ADDR16_HI c000000000000000 .text + 8124 So from above output we can identify that instruction at address c000000000008112 needs to be patched with the relocation delta. Now I have two options left: 1. Check for R_PPC64_GOT16_DS entries and check whether the contents addressed by r2+offset is relocated or not and apply relocation if its not. 2. Change all LOAD_REG_ADDR macros to LOAD_REG_IMMEDIATE. This I have already done. Regards, Mohan. ^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2008-07-22 17:27 UTC | newest] Thread overview: 22+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-07-17 18:33 [RFC v3 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M 2008-07-17 18:40 ` [RFC v3 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M 2008-07-17 20:06 ` Benjamin Herrenschmidt 2008-07-18 5:32 ` Mohan Kumar M 2008-07-18 17:00 ` Milton Miller 2008-07-21 19:17 ` Mohan Kumar M 2008-07-22 6:29 ` Paul Mackerras 2008-07-22 7:58 ` Mohan Kumar M 2008-07-21 19:20 ` [RFC v3 PATCH 2/4] Build files needed for relocation Mohan Kumar M 2008-07-21 19:21 ` [RFC v3 PATCH 3/4] Apply relocation Mohan Kumar M 2008-07-21 19:23 ` [RFC v3 PATCH 4/4] Relocation support Mohan Kumar M 2008-07-21 19:25 ` [RFC v3 PATCH 5/4] Relocation support for kdump kernel Mohan Kumar M 2008-07-21 19:26 ` [RFC v3 PATCH 6/4] Use LOAD_REG_IMMEDIATE macros Mohan Kumar M 2008-07-22 2:03 ` Paul Mackerras 2008-07-22 4:37 ` Mohan Kumar M 2008-07-22 6:37 ` Paul Mackerras 2008-07-22 17:13 ` Segher Boessenkool 2008-07-17 18:42 ` [RFC v3 PATCH 2/4] Build files needed for relocation support Mohan Kumar M 2008-07-17 18:45 ` [RFC v3 PATCH 3/4] Apply relocation info to vmlinux Mohan Kumar M 2008-07-17 18:48 ` [RFC v3 PATCH 4/4] Relocation support Mohan Kumar M 2008-07-18 17:48 ` Segher Boessenkool 2008-07-21 9:11 ` Mohan Kumar M
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).