linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [RFC v2 PATCH 0/4] Relocatable kernel support for PPC64
@ 2008-07-07 17:26 Mohan Kumar M
  2008-07-07 17:34 ` [RFC v2 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Mohan Kumar M @ 2008-07-07 17:26 UTC (permalink / raw)
  To: ppcdev; +Cc: paulus, michaele, 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.

Issues:
* During kdump kernel boot, all secondary processors are stuck up. But
  during yaboot all secondary processors are brought online.
* Relocatable kernel build process is not yet integrated with the kernel
  build.
* Kdump kernel boot fails on some specific systems because exception vectors
  are overwritten (When I tested the same kernel binary on an another
  machine kdump kernel boots). No issues in OpenPower and Power6 machines. I
  have faced exception overwritten problem in one Power5 lpar.

Building relocatable kernel support:
Enable "Build a kdump crash kernel" option and "Build relocatable
kernel"
options to build the kernel as relocatable.

After the kernel build, build the relocatable kernel by running
        make -f make.reloc

Copy the vmlinux.reloc to /boot, build initrd and update yaboot.conf to
include the entry for 'vmlinux.reloc' and corresponding initrd

Please give me your comments and suggestions to fix the above issues and
improve this feature.

Regards,
Mohan.

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

* [RFC v2 PATCH 1/4] Extract list of relocation offsets
  2008-07-07 17:26 [RFC v2 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M
@ 2008-07-07 17:34 ` Mohan Kumar M
  2008-07-07 17:34 ` [RFC v2 PATCH 2/4] Build files needed for relocation support Mohan Kumar M
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Mohan Kumar M @ 2008-07-07 17:34 UTC (permalink / raw)
  To: ppcdev; +Cc: paulus, miltonm, michaele

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/relocs.c |  865 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 865 insertions(+)

Index: linux-2.6.26-rc9/arch/powerpc/relocs.c
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9/arch/powerpc/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] 5+ messages in thread

* [RFC v2 PATCH 2/4] Build files needed for relocation support
  2008-07-07 17:26 [RFC v2 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M
  2008-07-07 17:34 ` [RFC v2 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M
@ 2008-07-07 17:34 ` Mohan Kumar M
  2008-07-07 17:35 ` [RFC v2 PATCH 3/4] Apply relocation info to vmlinux Mohan Kumar M
  2008-07-07 17:36 ` [RFC v2 PATCH 4/4] Relocation support Mohan Kumar M
  3 siblings, 0 replies; 5+ messages in thread
From: Mohan Kumar M @ 2008-07-07 17:34 UTC (permalink / raw)
  To: ppcdev; +Cc: paulus, miltonm, michaele

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.

File make.reloc is used to build the relocatable kernel "vmlinux.reloc".

TODO:
I have not yet integrated building relocatable kernel with kernel
Makefile. I need help to integrate this into kernel build process.

Signed-off-by: Mohan Kumar M <mohan@in.ibm.com>
---
 arch/powerpc/Kconfig             |   15 ++++++++++++---
 arch/powerpc/Makefile            |    2 +-
 arch/powerpc/vmlinux.reloc.lds.S |   29 +++++++++++++++++++++++++++++
 arch/powerpc/vmlinux.reloc.scr   |    8 ++++++++
 make.reloc                       |   35 +++++++++++++++++++++++++++++++++++
 5 files changed, 85 insertions(+), 4 deletions(-)

Index: linux-2.6.26-rc9/arch/powerpc/Kconfig
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/Kconfig
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/Makefile
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/Makefile
+++ linux-2.6.26-rc9/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
Index: linux-2.6.26-rc9/arch/powerpc/vmlinux.reloc.lds.S
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9/arch/powerpc/vmlinux.reloc.lds.S
@@ -0,0 +1,29 @@
+#include <asm/page.h>
+#include <asm-generic/vmlinux.lds.h>
+
+ENTRY(start_wrap)
+
+OUTPUT_ARCH(powerpc:common64)
+/* OUTPUT_ARCH(elf64ppc) */
+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 = .;
+	}
+}
Index: linux-2.6.26-rc9/arch/powerpc/vmlinux.reloc.scr
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9/arch/powerpc/vmlinux.reloc.scr
@@ -0,0 +1,8 @@
+SECTIONS
+{
+  .vmlinux : {
+	input_len = .;
+	*(.data)
+	output_len = . - 8;
+	}
+}
Index: linux-2.6.26-rc9/make.reloc
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9/make.reloc
@@ -0,0 +1,35 @@
+#Makefile for building vmlinux with relocatable information and code.
+
+all: vmlinux.reloc
+
+obj 	:= arch/powerpc
+
+AS	= as
+LD	= ld
+CC	= gcc
+CPP	= $(CC) -E
+
+
+$(obj)/relocs : $(obj)/relocs.c
+	$(CC) $(obj)/relocs.c -o $(obj)/relocs
+
+$(obj)/vmlinux.reloc.bin : vmlinux $(obj)/relocs
+	$(obj)/relocs vmlinux > $(obj)/vmlinux.reloc.bin 2>/dev/null
+
+$(obj)/vmlinux.bin: vmlinux
+	objcopy -O binary -R .note -R .comment -S vmlinux $(obj)/vmlinux.bin
+
+$(obj)/vmlinux.bin.all : $(obj)/vmlinux.bin $(obj)/vmlinux.reloc.bin
+	cat $(obj)/vmlinux.bin $(obj)/vmlinux.reloc.bin > $(obj)/vmlinux.bin.all
+
+$(obj)/vmlinux.new : $(obj)/vmlinux.reloc.scr $(obj)/vmlinux.bin.all
+	$(LD) -m elf64ppc -r --format binary --oformat elf64-powerpc -T $(obj)/vmlinux.reloc.scr $(obj)/vmlinux.bin.all -o $(obj)/vmlinux.new
+
+$(obj)/kernel/reloc_apply.o : $(obj)/kernel/reloc_apply.S
+	$(CC) -m64 -Wp,-MD,arch/powerpc/kernel/.reloc_apply.o.d  -nostdinc -isystem /usr/lib/gcc/powerpc64-suse-linux/4.1.2/include -D__KERNEL__ -Iinclude  -include include/linux/autoconf.h  -D__ASSEMBLY__  -Wa,-maltivec     -c -o arch/powerpc/kernel/reloc_apply.o arch/powerpc/kernel/reloc_apply.S
+
+$(obj)/vmlinux.reloc.lds : $(obj)/vmlinux.reloc.lds.S
+	$(CC) -m64 -E -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Os -msoft-float -pipe -mminimal-toc -mtraceback=none  -mcall-aixdesc -mtune=power4 -mno-altivec -mno-spe -funit-at-a-time -mno-string -Wa,-maltivec -fomit-frame-pointer  -fno-stack-protector -Wdeclaration-after-statement -Wno-pointer-sign -Wp,-MD,arch/powerpc/.vmlinux.reloc.lds.d  -nostdinc -isystem /usr/lib/gcc/powerpc64-suse-linux/4.1.2/include -D__KERNEL__ -Iinclude  -include include/linux/autoconf.h    -Upowerpc -P -C -Upowerpc -D__ASSEMBLY__ -o arch/powerpc/vmlinux.reloc.lds arch/powerpc/vmlinux.reloc.lds.S
+
+vmlinux.reloc : $(obj)/vmlinux.reloc.lds $(obj)/vmlinux.new $(obj)/kernel/reloc_apply.o
+	$(LD) -m elf64ppc -T $(obj)/vmlinux.reloc.lds $(obj)/vmlinux.new $(obj)/kernel/reloc_apply.o -o vmlinux.reloc

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

* [RFC v2 PATCH 3/4] Apply relocation info to vmlinux
  2008-07-07 17:26 [RFC v2 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M
  2008-07-07 17:34 ` [RFC v2 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M
  2008-07-07 17:34 ` [RFC v2 PATCH 2/4] Build files needed for relocation support Mohan Kumar M
@ 2008-07-07 17:35 ` Mohan Kumar M
  2008-07-07 17:36 ` [RFC v2 PATCH 4/4] Relocation support Mohan Kumar M
  3 siblings, 0 replies; 5+ messages in thread
From: Mohan Kumar M @ 2008-07-07 17:35 UTC (permalink / raw)
  To: ppcdev; +Cc: paulus, miltonm, michaele

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/kernel/reloc_apply.S |  229 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 229 insertions(+)

Index: linux-2.6.26-rc9/arch/powerpc/kernel/reloc_apply.S
===================================================================
--- /dev/null
+++ linux-2.6.26-rc9/arch/powerpc/kernel/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] 5+ messages in thread

* [RFC v2 PATCH 4/4] Relocation support
  2008-07-07 17:26 [RFC v2 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M
                   ` (2 preceding siblings ...)
  2008-07-07 17:35 ` [RFC v2 PATCH 3/4] Apply relocation info to vmlinux Mohan Kumar M
@ 2008-07-07 17:36 ` Mohan Kumar M
  3 siblings, 0 replies; 5+ messages in thread
From: Mohan Kumar M @ 2008-07-07 17:36 UTC (permalink / raw)
  To: ppcdev; +Cc: paulus, miltonm, michaele

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        |   22 +++++++++++
 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              |   14 ++++++-
 arch/powerpc/kernel/prom_init.c         |   32 +++++++++++++---
 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/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 ++
 21 files changed, 194 insertions(+), 48 deletions(-)

Index: linux-2.6.26-rc9/arch/powerpc/kernel/crash_dump.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/crash_dump.c
+++ linux-2.6.26-rc9/arch/powerpc/kernel/crash_dump.c
@@ -28,7 +28,15 @@
 
 void __init reserve_kdump_trampoline(void)
 {
+#ifdef CONFIG_RELOCATABLE_PPC64
+	if (RELOC(reloc_delta)) {
+		lmb_reserve(0, KDUMP_RESERVE_LIMIT);
+		printk("Reserving from 0 of size %lx\n", KDUMP_RESERVE_LIMIT);
+	}
+#else
 	lmb_reserve(0, KDUMP_RESERVE_LIMIT);
+	printk("Reserving from 0 of size %lx\n", KDUMP_RESERVE_LIMIT);
+#endif
 }
 
 static void __init create_trampoline(unsigned long addr)
@@ -42,7 +50,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 +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");
Index: linux-2.6.26-rc9/arch/powerpc/kernel/entry_64.S
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/entry_64.S
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/kernel/head_64.S
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/head_64.S
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/kernel/machine_kexec.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/machine_kexec.c
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/kernel/machine_kexec_64.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/machine_kexec_64.c
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/kernel/misc.S
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/misc.S
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/kernel/prom.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/prom.c
+++ linux-2.6.26-rc9/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;
@@ -1125,7 +1128,6 @@ static void __init phyp_dump_reserve_mem
 static inline void __init phyp_dump_reserve_mem(void) {}
 #endif /* CONFIG_PHYP_DUMP  && CONFIG_PPC_RTAS */
 
-
 void __init early_init_devtree(void *params)
 {
 	DBG(" -> early_init_devtree(%p)\n", params);
@@ -1159,8 +1161,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-rc9/arch/powerpc/kernel/prom_init.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/prom_init.c
+++ linux-2.6.26-rc9/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;
@@ -110,6 +108,9 @@ int of_workarounds;
         __asm__ __volatile__(".long " BUG_ILLEGAL_INSTR);	\
 } while (0)
 
+
+#define DEBUG_PROM
+
 #ifdef DEBUG_PROM
 #define prom_debug(x...)	prom_printf(x)
 #else
@@ -1070,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
@@ -1321,7 +1327,7 @@ extern unsigned long __secondary_hold_ac
  * We want to reference the copy of __secondary_hold_* in the
  * 0 - 0x100 address range
  */
-#define LOW_ADDR(x)	(((unsigned long) &(x)) & 0xff)
+#define LOW_ADDR(x)    (((unsigned long) &(x)) & 0xff)
 
 static void __init prom_hold_cpus(void)
 {
@@ -1334,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
@@ -2399,8 +2414,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-rc9/arch/powerpc/kernel/prom_init_check.sh
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/prom_init_check.sh
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/setup_64.c
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/mm/hash_low_64.S
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/mm/hash_low_64.S
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/mm/init_64.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/mm/init_64.c
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/mm/mem.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/mm/mem.c
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/mm/slb_low.S
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/mm/slb_low.S
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/platforms/pseries/hvCall.S
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/platforms/pseries/hvCall.S
+++ linux-2.6.26-rc9/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-rc9/include/asm-powerpc/exception.h
===================================================================
--- linux-2.6.26-rc9.orig/include/asm-powerpc/exception.h
+++ linux-2.6.26-rc9/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-rc9/include/asm-powerpc/system.h
===================================================================
--- linux-2.6.26-rc9.orig/include/asm-powerpc/system.h
+++ linux-2.6.26-rc9/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-rc9/include/asm-powerpc/sections.h
===================================================================
--- linux-2.6.26-rc9.orig/include/asm-powerpc/sections.h
+++ linux-2.6.26-rc9/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-rc9/include/asm-powerpc/prom.h
===================================================================
--- linux-2.6.26-rc9.orig/include/asm-powerpc/prom.h
+++ linux-2.6.26-rc9/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-rc9/arch/powerpc/kernel/iommu.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/kernel/iommu.c
+++ linux-2.6.26-rc9/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,6 +499,11 @@ 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);
+		printk("Called ppc_md.tce_free()\n");
 	}
 #else
 	/* Clear the hardware table in case firmware left allocations in it */
Index: linux-2.6.26-rc9/arch/powerpc/platforms/pseries/iommu.c
===================================================================
--- linux-2.6.26-rc9.orig/arch/powerpc/platforms/pseries/iommu.c
+++ linux-2.6.26-rc9/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
 

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

end of thread, other threads:[~2008-07-07 17:36 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-07 17:26 [RFC v2 PATCH 0/4] Relocatable kernel support for PPC64 Mohan Kumar M
2008-07-07 17:34 ` [RFC v2 PATCH 1/4] Extract list of relocation offsets Mohan Kumar M
2008-07-07 17:34 ` [RFC v2 PATCH 2/4] Build files needed for relocation support Mohan Kumar M
2008-07-07 17:35 ` [RFC v2 PATCH 3/4] Apply relocation info to vmlinux Mohan Kumar M
2008-07-07 17:36 ` [RFC v2 PATCH 4/4] Relocation support 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).