Because the sizes of cells and pointers do not match on PPC64, relocations can't be computed in an ucell array by the linker.
Introduce a method to relocate the dictionary to a fixed address by forthstrap.
Signed-off-by: Blue Swirl blauwirbel@gmail.com --- arch/ppc/build.xml | 6 +----- arch/ppc/qemu/kernel.c | 18 +++++++++++++----- arch/ppc/qemu/ldscript | 7 +++++++ arch/ppc/qemu/ofmem.c | 2 +- arch/ppc64/qemu/ldscript | 7 +++++++ kernel/bootstrap.c | 44 ++++++++++++++++++++++++++++++++++++-------- 6 files changed, 65 insertions(+), 19 deletions(-)
diff --git a/arch/ppc/build.xml b/arch/ppc/build.xml index 4aec62f..2b7b605 100644 --- a/arch/ppc/build.xml +++ b/arch/ppc/build.xml @@ -60,11 +60,7 @@
<executable name="target/include/qemu-dict.h" target="target" condition="QEMU"> <rule><![CDATA[ - $(call quiet-command,true, " GEN $(TARGET_DIR)$@") - @echo "static const char forth_dictionary[] = {" > $@ - @cat $< | hexdump -ve '1/0 "\t" 8/1 "0x%02x, " 1/0 "\n"' \ - | sed 's/0x ,//g' >> $@ - @echo "};" >> $@]]></rule> + $(call quiet-command,$(ODIR)/forthstrap -x -a 0xfff08000 -D $@ -d $< </dev/null, " GEN $(TARGET_DIR)$@")]]></rule> <external-object source="openbios-qemu.dict"/> </executable>
diff --git a/arch/ppc/qemu/kernel.c b/arch/ppc/qemu/kernel.c index 4cae525..fbb5925 100644 --- a/arch/ppc/qemu/kernel.c +++ b/arch/ppc/qemu/kernel.c @@ -17,7 +17,6 @@ * */
-#include "qemu-dict.h" #include "config.h" #include "dict.h" #include "libopenbios/bindings.h" @@ -27,7 +26,14 @@ #include "kernel.h"
#define MEMORY_SIZE (256*1024) /* 256K ram for hosted system */ -#define DICTIONARY_SIZE (512*1024) /* 512K for the dictionary */ +/* 512K for the dictionary */ +#define DICTIONARY_SIZE (512 * 1024 / sizeof(ucell)) + +/* + * wrap an array around the hex'ed dictionary file + */ + +#include "qemu-dict.h"
static ucell *memory;
@@ -82,10 +88,12 @@ init_memory( void ) int initialize_forth( void ) { - dict = malloc(DICTIONARY_SIZE); - dictlimit = DICTIONARY_SIZE; + dict = (unsigned char *)forth_dictionary; + dicthead = (ucell)FORTH_DICTIONARY_END; + last = (ucell *)((unsigned char *)forth_dictionary + + FORTH_DICTIONARY_LAST); + dictlimit = sizeof(forth_dictionary);
- load_dictionary( forth_dictionary, sizeof(forth_dictionary) ); forth_init();
PUSH_xt( bind_noname_func(arch_of_init) ); diff --git a/arch/ppc/qemu/ldscript b/arch/ppc/qemu/ldscript index 840b498..3b1855a 100644 --- a/arch/ppc/qemu/ldscript +++ b/arch/ppc/qemu/ldscript @@ -6,6 +6,7 @@ OUTPUT_ARCH(powerpc) BASE_ADDR = 0xfff00000;
/* As NVRAM is at 0xfff04000, the .text needs to be after that + * The value in arch/ppc/build.xml must match this value! */ TEXT_ADDR = 0xfff08000;
@@ -26,6 +27,12 @@ SECTIONS
. = TEXT_ADDR; /* Normal sections */ + .data.dict ALIGN(4096): { + _dict_start = .; + *(.data.dict) + _dict_end = .; + } + .text ALIGN(4096): { *(.text) *(.text.*) diff --git a/arch/ppc/qemu/ofmem.c b/arch/ppc/qemu/ofmem.c index 4c6825e..f6cf8cd 100644 --- a/arch/ppc/qemu/ofmem.c +++ b/arch/ppc/qemu/ofmem.c @@ -55,7 +55,7 @@ extern void setup_mmu(unsigned long code_base); #define HASH_BITS 15 #endif #define HASH_SIZE (2 << HASH_BITS) -#define OFMEM_SIZE (2 * 1024 * 1024) +#define OFMEM_SIZE (1 * 1024 * 1024 + 512 * 1024)
#define SEGR_USER BIT(2) #define SEGR_BASE 0x0400 diff --git a/arch/ppc64/qemu/ldscript b/arch/ppc64/qemu/ldscript index 7a22903..0bb2157 100644 --- a/arch/ppc64/qemu/ldscript +++ b/arch/ppc64/qemu/ldscript @@ -6,6 +6,7 @@ OUTPUT_ARCH(powerpc:common64) BASE_ADDR = 0xfff00000;
/* As NVRAM is at 0xfff04000, the .text needs to be after that + * The value in arch/ppc/build.xml must match this value! */ TEXT_ADDR = 0xfff08000;
@@ -26,6 +27,12 @@ SECTIONS
. = TEXT_ADDR; /* Normal sections */ + .data.dict ALIGN(4096): { + _dict_start = .; + *(.data.dict) + _dict_end = .; + } + .text ALIGN(4096): { *(.text) *(.text.*) diff --git a/kernel/bootstrap.c b/kernel/bootstrap.c index 68fe5dd..b19c5c4 100644 --- a/kernel/bootstrap.c +++ b/kernel/bootstrap.c @@ -96,7 +96,15 @@ static const char *wordnames[] = { * dictionary related functions. */
-static void relocation_table(unsigned char * dict_one, unsigned char *dict_two, int length) +/* + * Compare two dictionaries constructed at different addresses. When + * the cells don't match, a need for relocation is detected and the + * corresponding bit in reloc_table bitmap is set. + * + * If offset is nonzero, add the offset to the cell instead. + */ +static void relocation_table(unsigned char * dict_one, unsigned char *dict_two, + int length, ucell offset) { ucell *d1=(ucell *)dict_one, *d2=(ucell *)dict_two; ucell *reloc_table; @@ -122,8 +130,12 @@ static void relocation_table(unsigned char * dict_one, unsigned char *dict_two, // printk("\nWARNING: inconsistent relocation (%x:%x)!\n", d1[i], d2[i]); } else { /* This is a pointer, it needs relocation, d2==dict */ - reloc_table[pos] |= target_ucell((ucell)1ULL << bit); - d2[i] = target_ucell(target_ucell(d2[i]) - pointer2cell(d2)); + if (!offset) { + reloc_table[pos] |= target_ucell((ucell)1ULL + << bit); + } + d2[i] = target_ucell(target_ucell(d2[i]) - + pointer2cell(d2) + offset); } }
@@ -237,6 +249,11 @@ static void write_dictionary(const char *filename) #endif }
+/* + * Write dictionary as a C array of ucells to filename. + * Put the array to special section so that its address can be fixed. + * Define some helpful constants. + */ static void write_dictionary_hex(const char *filename) { FILE *f; @@ -248,7 +265,8 @@ static void write_dictionary_hex(const char *filename) exit(1); }
- fprintf(f, "static ucell forth_dictionary[DICTIONARY_SIZE] = {\n"); + fprintf(f, "static ucell forth_dictionary[DICTIONARY_SIZE] " + "__attribute__((section(".data.dict"))) = {\n"); for (walk = (ucell *)dict; walk < (ucell *)(dict + dicthead); walk++) { int pos, bit, l; ucell val; @@ -1075,7 +1093,10 @@ static void new_dictionary(const char *source) " -s|--segfault install segfault handler\n" \ " -M|--dependency-dump file\n" \ " dump dependencies in Makefile format\n\n" \ - " -x|--hexdump output format is C language hex dump\n" + " -x|--hexdump output format is C language hex dump\n" \ + " -a|--fixed-address base\n" \ + " relocate output to base\n" + #else #define USAGE "Usage: %s [options] [dictionary file|source file]\n\n" \ " -h show this help\n" \ @@ -1090,7 +1111,8 @@ static void new_dictionary(const char *source) " write kernel console output to log file\n" \ " -s install segfault handler\n\n" \ " -M file dump dependencies in Makefile format\n\n" \ - " -x output format is C language hex dump\n" + " -x output format is C language hex dump\n" \ + " -a base relocate output to base\n" #endif
int main(int argc, char *argv[]) @@ -1105,8 +1127,9 @@ int main(int argc, char *argv[])
unsigned char *bootstrapdict[2]; int c, cnt, hexdump = 0; + ucell relocation_offset = 0;
- const char *optstring = "VvhsI:d:D:c:M:x?"; + const char *optstring = "a:VvhsI:d:D:c:M:x?";
while (1) { #ifdef __GLIBC__ @@ -1122,6 +1145,7 @@ int main(int argc, char *argv[]) {"console", 1, NULL, 'c'}, {"dependency-dump", 1, NULL, 'M'}, {"hexdump", 0, NULL, 'x'}, + {"fixed-address", 1, NULL, 'a'}, };
/* @@ -1180,6 +1204,9 @@ int main(int argc, char *argv[]) case 'x': hexdump = 1; break; + case 'a': + relocation_offset = strtoll(optarg, NULL, 0); + break; default: return 1; } @@ -1293,7 +1320,8 @@ int main(int argc, char *argv[]) else #endif { - relocation_table( bootstrapdict[0], bootstrapdict[1], dicthead); + relocation_table(bootstrapdict[0], bootstrapdict[1], dicthead, + relocation_offset); if (hexdump) { write_dictionary_hex(dictname); } else {