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(a)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 {
--
1.6.2.4