diff options
Diffstat (limited to 'qemu/roms/openbios/kernel/dict.c')
-rw-r--r-- | qemu/roms/openbios/kernel/dict.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/qemu/roms/openbios/kernel/dict.c b/qemu/roms/openbios/kernel/dict.c new file mode 100644 index 000000000..0986cb14f --- /dev/null +++ b/qemu/roms/openbios/kernel/dict.c @@ -0,0 +1,320 @@ +/* + * tag: dict management + * + * Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz + * + * See the file "COPYING" for further information about + * the copyright and warranty status of this work. + */ + +#include "config.h" +#include "kernel/kernel.h" +#include "dict.h" +#ifdef BOOTSTRAP +#include <string.h> +#else +#include "libc/string.h" +#endif +#include "cross.h" + + +unsigned char *dict = NULL; +ucell *last; +cell dicthead = 0; +cell dictlimit = 0; + +/* lfa2nfa + * converts a link field address to a name field address, + * i.e find pointer to a given words name + */ + +ucell lfa2nfa(ucell ilfa) +{ + /* get offset from dictionary start */ + ilfa = ilfa - (ucell)pointer2cell(dict); + ilfa--; /* skip status */ + while (dict[--ilfa] == 0); /* skip all pad bytes */ + ilfa -= (dict[ilfa] - 128); + return ilfa + (ucell)pointer2cell(dict); +} + +/* lfa2cfa + * converts a link field address to a code field address. + * in this forth implementation this is just a fixed offset + */ + +static xt_t lfa2cfa(ucell ilfa) +{ + return (xt_t)(ilfa + sizeof(cell)); +} + + +/* fstrlen - returns length of a forth string. */ + +ucell fstrlen(ucell fstr) +{ + fstr -= pointer2cell(dict)+1; + //fstr -= pointer2cell(dict); FIXME + while (dict[++fstr] < 128) + ; + return dict[fstr] - 128; +} + +/* to_lower - convert a character to lowecase */ + +static int to_lower(int c) +{ + return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c; +} + +/* fstrcmp - compare null terminated string with forth string. */ + +static int fstrcmp(const char *s1, ucell fstr) +{ + char *s2 = (char*)cell2pointer(fstr); + while (*s1) { + if ( to_lower(*(s1++)) != to_lower(*(s2++)) ) + return -1; + } + return 0; +} + +/* fstrncpy - copy a forth string to a destination (with NULL termination) */ + +void fstrncpy(char *dest, ucell src, unsigned int maxlen) +{ + int len = fstrlen(src); + + if (fstrlen(src) >= maxlen) len = maxlen - 1; + memcpy(dest, cell2pointer(src), len); + *(dest + len) = '\0'; +} + + +/* findword + * looks up a given word in the dictionary. This function + * is used by the c based interpreter and to find the "initialize" + * word. + */ + +xt_t findword(const char *s1) +{ + ucell tmplfa, len; + + if (!last) + return 0; + + tmplfa = read_ucell(last); + + len = strlen(s1); + + while (tmplfa) { + ucell nfa = lfa2nfa(tmplfa); + + if (len == fstrlen(nfa) && !fstrcmp(s1, nfa)) { + return lfa2cfa(tmplfa); + } + + tmplfa = read_ucell(cell2pointer(tmplfa)); + } + + return 0; +} + + +/* findsemis_wordlist + * Given a DOCOL xt and a wordlist, find the address of the semis + * word at the end of the word definition. We do this by finding + * the word before this in the dictionary, then counting back one + * from the NFA. + */ + +static ucell findsemis_wordlist(ucell xt, ucell wordlist) +{ + ucell tmplfa, nextlfa, nextcfa; + + if (!wordlist) + return 0; + + tmplfa = read_ucell(cell2pointer(wordlist)); + nextcfa = lfa2cfa(tmplfa); + + /* Catch the special case where the lfa of the word we + * want is the last word in the dictionary; in that case + * the end of the word is given by "here" - 1 */ + if (nextcfa == xt) + return pointer2cell(dict) + dicthead - sizeof(cell); + + while (tmplfa) { + + /* Peek ahead and see if the next CFA in the list is the + * one we are searching for */ + nextlfa = read_ucell(cell2pointer(tmplfa)); + nextcfa = lfa2cfa(nextlfa); + + /* If so, count back 1 cell from the current NFA */ + if (nextcfa == xt) + return lfa2nfa(tmplfa) - sizeof(cell); + + tmplfa = nextlfa; + } + + return 0; +} + + +/* findsemis + * Given a DOCOL xt, find the address of the semis word at the end + * of the word definition by searching all vocabularies */ + +ucell findsemis(ucell xt) +{ + ucell usesvocab = findword("vocabularies?") + sizeof(cell); + unsigned int i; + + if (read_ucell(cell2pointer(usesvocab))) { + /* Vocabularies are in use, so search each one in turn */ + ucell numvocabs = findword("#order") + sizeof(cell); + + for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) { + ucell vocabs = findword("vocabularies") + 2 * sizeof(cell); + ucell semis = findsemis_wordlist(xt, read_cell(cell2pointer(vocabs + (i * sizeof(cell))))); + + /* If we get a non-zero result, we found the xt in this vocab */ + if (semis) + return semis; + } + } else { + /* Vocabularies not in use */ + return findsemis_wordlist(xt, read_ucell(last)); + } + + return 0; +} + + +/* findxtfromcell_wordlist + * Given a cell and a wordlist, determine the CFA of the word containing + * the cell or 0 if we are unable to return a suitable CFA + */ + +ucell findxtfromcell_wordlist(ucell incell, ucell wordlist) +{ + ucell tmplfa; + + if (!wordlist) + return 0; + + tmplfa = read_ucell(cell2pointer(wordlist)); + while (tmplfa) { + if (tmplfa < incell) + return lfa2cfa(tmplfa); + + tmplfa = read_ucell(cell2pointer(tmplfa)); + } + + return 0; +} + + +/* findxtfromcell + * Given a cell, determine the CFA of the word containing + * the cell by searching all vocabularies + */ + +ucell findxtfromcell(ucell incell) +{ + ucell usesvocab = findword("vocabularies?") + sizeof(cell); + unsigned int i; + + if (read_ucell(cell2pointer(usesvocab))) { + /* Vocabularies are in use, so search each one in turn */ + ucell numvocabs = findword("#order") + sizeof(cell); + + for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) { + ucell vocabs = findword("vocabularies") + 2 * sizeof(cell); + ucell semis = findxtfromcell_wordlist(incell, read_cell(cell2pointer(vocabs + (i * sizeof(cell))))); + + /* If we get a non-zero result, we found the xt in this vocab */ + if (semis) + return semis; + } + } else { + /* Vocabularies not in use */ + return findxtfromcell_wordlist(incell, read_ucell(last)); + } + + return 0; +} + +void dump_header(dictionary_header_t *header) +{ + printk("OpenBIOS dictionary:\n"); + printk(" version: %d\n", header->version); + printk(" cellsize: %d\n", header->cellsize); + printk(" endianess: %s\n", header->endianess?"big":"little"); + printk(" compression: %s\n", header->compression?"yes":"no"); + printk(" relocation: %s\n", header->relocation?"yes":"no"); + printk(" checksum: %08x\n", target_long(header->checksum)); + printk(" length: %08x\n", target_long(header->length)); + printk(" last: %0" FMT_CELL_x "\n", target_cell(header->last)); +} + +ucell load_dictionary(const char *data, ucell len) +{ + u32 checksum=0; + const char *checksum_walk; + ucell *walk, *reloc_table; + dictionary_header_t *header=(dictionary_header_t *)data; + + /* assertions */ + if (len <= (sizeof(dictionary_header_t)) || strncmp(DICTID, data, 8)) + return 0; +#ifdef CONFIG_DEBUG_DICTIONARY + dump_header(header); +#endif + + checksum_walk=data; + while (checksum_walk<data+len) { + checksum+=read_long(checksum_walk); + checksum_walk+=sizeof(u32); + } + + if(checksum) { + printk("Checksum invalid (%08x)!\n", checksum); + return 0; + } + + data += sizeof(dictionary_header_t); + + dicthead = target_long(header->length); + + memcpy(dict, data, dicthead); + reloc_table=(ucell *)(data+dicthead); + +#ifdef CONFIG_DEBUG_DICTIONARY + printk("\nmoving dictionary (%x bytes) to %x\n", + (ucell)dicthead, (ucell)dict); + printk("\ndynamic relocation..."); +#endif + + for (walk = (ucell *) dict; walk < (ucell *) (dict + dicthead); + walk++) { + int pos, bit, l; + l=(walk-(ucell *)dict); + pos=l/BITS; + bit=l&~(-BITS); + if (reloc_table[pos] & target_ucell((ucell)1ULL << bit)) { + // printk("%lx, pos %x, bit %d\n",*walk, pos, bit); + write_ucell(walk, read_ucell(walk)+pointer2cell(dict)); + } + } + +#ifdef CONFIG_DEBUG_DICTIONARY + printk(" done.\n"); +#endif + + last = (ucell *)(dict + target_ucell(header->last)); + + return -1; +} |