[PATCH] iSeries build with newer assemblers and compilers

Stephen Rothwell sfr at canb.auug.org.au
Mon Aug 15 17:51:15 EST 2005


Hi all,

This patch makes iSeries build with the newer assemblers and compilers.
We had a hack to allow us to move xLparMap out of head.S but that
required a horrible bit of inline assembler in LparData.c.  When I
upgraded Debian unstable in order to use their biarch compiler, even that
hack broke.  This patch works around the whole compiler/assembler mess by
patching the address we care about into the vmlinux after it is built.

This should really go in before 2.6.13 if at all possible as we have
problematic build systems out there already.

Signed-off-by: Stephen Rothwell <sfr at canb.auug.org.au>
---
 arch/ppc64/Makefile          |    8 ++++
 arch/ppc64/kernel/LparData.c |   65 ++++---------------------------------
 scripts/Makefile             |    1
 scripts/fix_lparmap.c        |   74 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 90 insertions(+), 58 deletions(-)

-- 
Cheers,
Stephen Rothwell                    sfr at canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

diff -ruN linus/arch/ppc64/Makefile linus-lparmap/arch/ppc64/Makefile
--- linus/arch/ppc64/Makefile	2005-06-27 16:08:00.000000000 +1000
+++ linus-lparmap/arch/ppc64/Makefile	2005-08-15 17:33:09.000000000 +1000
@@ -129,3 +129,11 @@
 endef
 
 CLEAN_FILES += include/asm-ppc64/offsets.h
+
+ifeq ($(CONFIG_PPC_ISERIES),y)
+cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
+      -T $(vmlinux-lds) $(vmlinux-init)                          \
+      --start-group $(vmlinux-main) --end-group                  \
+      $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^); \
+      scripts/fix_lparmap `$(OBJDUMP) -t $@ | grep ' xLparMap' | cut -d' ' -f1` $@
+endif
diff -ruN linus/arch/ppc64/kernel/LparData.c linus-lparmap/arch/ppc64/kernel/LparData.c
--- linus/arch/ppc64/kernel/LparData.c	2005-07-28 11:23:11.000000000 +1000
+++ linus-lparmap/arch/ppc64/kernel/LparData.c	2005-08-15 15:17:00.000000000 +1000
@@ -32,32 +32,18 @@
 /* The HvReleaseData is the root of the information shared between 
  * the hypervisor and Linux.  
  */
-
-/*
- * WARNING - magic here
- *
- * Ok, this is a horrid hack below, but marginally better than the
- * alternatives.  What we really want is just to initialize
- * hvReleaseData in C as in the #if 0 section here.  However, gcc
- * refuses to believe that (u32)&x is a constant expression, so will
- * not allow the xMsNucDataOffset field to be properly initialized.
- * So, we declare hvReleaseData in inline asm instead.  We use inline
- * asm, rather than a .S file, because the assembler won't generate
- * the necessary relocation for the LparMap either, unless that symbol
- * is declared in the same source file.  Finally, we put the asm in a
- * dummy, attribute-used function, instead of at file scope, because
- * file scope asms don't allow contraints.  We want to use the "i"
- * constraints to put sizeof() and offsetof() expressions in there,
- * because including asm/offsets.h in C code then stringifying causes
- * all manner of warnings.
- */
-#if 0
 struct HvReleaseData hvReleaseData = {
 	.xDesc = 0xc8a5d9c4,	/* "HvRD" ebcdic */
 	.xSize = sizeof(struct HvReleaseData),
 	.xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),
 	.xSlicNacaAddr = &naca,		/* 64-bit Naca address */
-	.xMsNucDataOffset = (u32)((unsigned long)&xLparMap - KERNELBASE),
+	/*
+	 * This next field should be initialiased to
+	 * (u32)((unsigned long)&xLparMap - KERNELBASE) but the compiler
+	 * does not believe that that is a constant expression.  We
+	 * will fix this up using by post processing the vmlinux.
+	 */
+	.xMsNucDataOffset = 0,
 	.xFlags = HVREL_TAGSINACTIVE	/* tags inactive       */
 					/* 64 bit              */
 					/* shared processors   */
@@ -70,43 +56,6 @@
 		0xa7, 0x40, 0xf2, 0x4b,
 		0xf4, 0x4b, 0xf6, 0xf4 },
 };
-#endif
-
-
-extern struct HvReleaseData hvReleaseData;
-
-static void __attribute_used__ hvReleaseData_wrapper(void)
-{
-	/* This doesn't appear to need any alignment (even 4 byte) */
-	asm volatile (
-		"	lparMapPhys = xLparMap - %3\n"
-		"	.data\n"
-		"	.globl	hvReleaseData\n"
-		"hvReleaseData:\n"
-		"	.long	0xc8a5d9c4\n"	/* xDesc */
-						/* "HvRD" in ebcdic */
-		"	.short	%0\n"		/* xSize */
-		"	.short	%1\n"		/* xVpdAreasPtrOffset */
-		"	.llong	naca\n"		/* xSlicNacaAddr */
-		"	.long	lparMapPhys\n"	/* xMsNucDataOffset */
-		"	.long	0\n"		/* xRsvd1 */
-		"	.short	%2\n"		/* xFlags */
-		"	.short	4\n"	/* xVrmIndex  - v5r2m0 */
-		"	.short	3\n"	/* xMinSupportedPlicVrmIndex - v5r1m0 */
-		"	.short	3\n"	/* xMinCompatablePlicVrmIndex - v5r1m0 */
-		"	.long	0xd38995a4\n"	/* xVrmName */
-		"	.long	0xa740f24b\n"	/*   "Linux 2.4.64" ebcdic */
-		"	.long	0xf44bf6f4\n"
-		"	. = hvReleaseData + %0\n"
-		"	.previous\n"
-		: : "i"(sizeof(hvReleaseData)),
-		"i"(offsetof(struct naca_struct, xItVpdAreas)),
-		"i"(HVREL_TAGSINACTIVE /* tags inactive, 64 bit, */
-				       /* shared processors, HMT allowed */
-		    | 6), /* TEMP: This allows non-GA drivers */
-		"i"(KERNELBASE)
-		);
-}
 
 struct LparMap __attribute__((aligned (16))) xLparMap = {
 	.xNumberEsids = HvEsidsToMap,
diff -ruN linus/scripts/Makefile linus-lparmap/scripts/Makefile
--- linus/scripts/Makefile	2005-06-27 16:08:15.000000000 +1000
+++ linus-lparmap/scripts/Makefile	2005-08-15 16:47:44.000000000 +1000
@@ -12,6 +12,7 @@
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash
 hostprogs-$(CONFIG_IKCONFIG)     += bin2c
+hostprogs-$(CONFIG_PPC_ISERIES)  += fix_lparmap
 
 always		:= $(hostprogs-y)
 
diff -ruN linus/scripts/fix_lparmap.c linus-lparmap/scripts/fix_lparmap.c
--- linus/scripts/fix_lparmap.c	1970-01-01 10:00:00.000000000 +1000
+++ linus-lparmap/scripts/fix_lparmap.c	2005-08-15 17:28:09.000000000 +1000
@@ -0,0 +1,74 @@
+/*
+ * This program is just here to work around the fact that the
+ * compiler cannot emit (u32)(&xLparMap - KERNElBASE) as a constant.
+ *
+ * Copyright (C) 2005 Stephen Rothwell  IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+#define ElfHeaderSize  (64 * 1024)
+#define KERNELBASE (0xc000000000000000ULL)
+
+int main(int argc, char *argv[])
+{
+	FILE *vmlinux = NULL;
+	unsigned long long xLparMap_addr;
+	unsigned int hvReleaseData_addr;
+	unsigned int xDesc;
+	unsigned int short_lpar_map;
+
+	if ((argc < 2) || (sscanf(argv[1], "%Lx", &xLparMap_addr) != 1)) {
+		fprintf(stderr, "Address of xLparMap is missing.\n");
+		return 1;
+	}
+
+	if (argc < 3) {
+		fprintf(stderr, "Name of vmlinux file is missing.\n");
+		return 1;
+	}
+
+	vmlinux = fopen(argv[2], "r+");
+	if (vmlinux == NULL) {
+		fprintf(stderr, "Cannot open vmlinux file \"%s\".\n", argv[2]);
+		return 1;
+	}
+
+	/* fseek to the hvReleaseData pointer */
+	fseek(vmlinux, ElfHeaderSize + 0x24, SEEK_SET);
+	if (fread(&hvReleaseData_addr, 4, 1, vmlinux) != 1) {
+		fprintf(stderr, "Could not read hvReleaseData pointer\n");
+		return 1;
+	}
+	hvReleaseData_addr = ntohl(hvReleaseData_addr);
+
+	/* fseek to the hvReleaseData */
+	fseek(vmlinux, ElfHeaderSize + hvReleaseData_addr, SEEK_SET);
+	if (fread(&xDesc, sizeof(xDesc), 1, vmlinux) != 1) {
+		fprintf(stderr, "Could not read hvReleaseData.xDesc\n");
+		return 1;
+	}
+	/* Check hvReleaseData sanity */
+	if (xDesc != 0xc8a5d9c4) {
+		fprintf(stderr, "hvReleaseData is invalid\n");
+		return 1;
+	}
+
+	short_lpar_map = htonl((unsigned int)(xLparMap_addr - KERNELBASE));
+	fseek(vmlinux, ElfHeaderSize + hvReleaseData_addr + 16, SEEK_SET);
+	if (fwrite(&short_lpar_map, 4, 1, vmlinux) != 1) {
+		fprintf(stderr, "Could not write xLparMap address\n");
+		return 1;
+	}
+
+	fclose(vmlinux);
+
+	return 0;
+}



More information about the Linuxppc64-dev mailing list