1 /*
2  * tag: dict management
3  *
4  * Copyright (C) 2003-2005 Stefan Reinauer, Patrick Mauritz
5  *
6  * See the file "COPYING" for further information about
7  * the copyright and warranty status of this work.
8  */
9 
10 #include "config.h"
11 #include "kernel/kernel.h"
12 #include "dict.h"
13 #ifdef BOOTSTRAP
14 #include <string.h>
15 #else
16 #include "libc/string.h"
17 #endif
18 #include "cross.h"
19 
20 
21 unsigned char *dict = NULL;
22 ucell *last;
23 cell dicthead = 0;
24 cell dictlimit = 0;
25 
26 /* lfa2nfa
27  * converts a link field address to a name field address,
28  * i.e find pointer to a given words name
29  */
30 
lfa2nfa(ucell ilfa)31 ucell lfa2nfa(ucell ilfa)
32 {
33 	/* get offset from dictionary start */
34 	ilfa = ilfa - (ucell)pointer2cell(dict);
35 	ilfa--;				/* skip status        */
36 	while (dict[--ilfa] == 0);	/* skip all pad bytes */
37 	ilfa -= (dict[ilfa] - 128);
38 	return ilfa + (ucell)pointer2cell(dict);
39 }
40 
41 /* lfa2cfa
42  * converts a link field address to a code field address.
43  * in this forth implementation this is just a fixed offset
44  */
45 
lfa2cfa(ucell ilfa)46 static xt_t lfa2cfa(ucell ilfa)
47 {
48 	return (xt_t)(ilfa + sizeof(cell));
49 }
50 
51 
52 /* fstrlen - returns length of a forth string. */
53 
fstrlen(ucell fstr)54 ucell fstrlen(ucell fstr)
55 {
56 	fstr -= pointer2cell(dict)+1;
57 	//fstr -= pointer2cell(dict); FIXME
58 	while (dict[++fstr] < 128)
59 		;
60 	return dict[fstr] - 128;
61 }
62 
63 /* to_lower - convert a character to lowecase */
64 
to_lower(int c)65 static int to_lower(int c)
66 {
67 	return ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 'a') : c;
68 }
69 
70 /* fstrcmp - compare null terminated string with forth string. */
71 
fstrcmp(const char * s1,ucell fstr)72 static int fstrcmp(const char *s1, ucell fstr)
73 {
74 	char *s2 = (char*)cell2pointer(fstr);
75 	while (*s1) {
76 		if ( to_lower(*(s1++)) != to_lower(*(s2++)) )
77 			return -1;
78 	}
79 	return 0;
80 }
81 
82 /* fstrncpy - copy a forth string to a destination (with NULL termination) */
83 
fstrncpy(char * dest,ucell src,unsigned int maxlen)84 void fstrncpy(char *dest, ucell src, unsigned int maxlen)
85 {
86 	int len = fstrlen(src);
87 
88 	if (fstrlen(src) >= maxlen) len = maxlen - 1;
89 	memcpy(dest, cell2pointer(src), len);
90 	*(dest + len) = '\0';
91 }
92 
93 
94 /* findword
95  * looks up a given word in the dictionary. This function
96  * is used by the c based interpreter and to find the "initialize"
97  * word.
98  */
99 
findword(const char * s1)100 xt_t findword(const char *s1)
101 {
102 	ucell tmplfa, len;
103 
104 	if (!last)
105 		return 0;
106 
107 	tmplfa = read_ucell(last);
108 
109 	len = strlen(s1);
110 
111 	while (tmplfa) {
112 		ucell nfa = lfa2nfa(tmplfa);
113 
114 		if (len == fstrlen(nfa) && !fstrcmp(s1, nfa)) {
115 			return lfa2cfa(tmplfa);
116 		}
117 
118 		tmplfa = read_ucell(cell2pointer(tmplfa));
119 	}
120 
121 	return 0;
122 }
123 
124 
125 /* findsemis_wordlist
126  * Given a DOCOL xt and a wordlist, find the address of the semis
127  * word at the end of the word definition. We do this by finding
128  * the word before this in the dictionary, then counting back one
129  * from the NFA.
130  */
131 
findsemis_wordlist(ucell xt,ucell wordlist)132 static ucell findsemis_wordlist(ucell xt, ucell wordlist)
133 {
134 	ucell tmplfa, nextlfa, nextcfa;
135 
136 	if (!wordlist)
137 		return 0;
138 
139 	tmplfa = read_ucell(cell2pointer(wordlist));
140 	nextcfa = lfa2cfa(tmplfa);
141 
142 	/* Catch the special case where the lfa of the word we
143 	 * want is the last word in the dictionary; in that case
144 	 * the end of the word is given by "here" - 1 */
145 	if (nextcfa == xt)
146 		return pointer2cell(dict) + dicthead - sizeof(cell);
147 
148 	while (tmplfa) {
149 
150 		/* Peek ahead and see if the next CFA in the list is the
151 		 * one we are searching for */
152 		nextlfa = read_ucell(cell2pointer(tmplfa));
153 		nextcfa = lfa2cfa(nextlfa);
154 
155 		/* If so, count back 1 cell from the current NFA */
156 		if (nextcfa == xt)
157 			return lfa2nfa(tmplfa) - sizeof(cell);
158 
159 		tmplfa = nextlfa;
160 	}
161 
162 	return 0;
163 }
164 
165 
166 /* findsemis
167  * Given a DOCOL xt, find the address of the semis word at the end
168  * of the word definition by searching all vocabularies */
169 
findsemis(ucell xt)170 ucell findsemis(ucell xt)
171 {
172 	ucell usesvocab = findword("vocabularies?") + sizeof(cell);
173 	unsigned int i;
174 
175 	if (read_ucell(cell2pointer(usesvocab))) {
176 		/* Vocabularies are in use, so search each one in turn */
177 		ucell numvocabs = findword("#order") + sizeof(cell);
178 
179 		for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) {
180 			ucell vocabs = findword("vocabularies") + 2 * sizeof(cell);
181 			ucell semis = findsemis_wordlist(xt, read_cell(cell2pointer(vocabs + (i * sizeof(cell)))));
182 
183 			/* If we get a non-zero result, we found the xt in this vocab */
184 			if (semis)
185 				return semis;
186 		}
187 	} else {
188 		/* Vocabularies not in use */
189 		return findsemis_wordlist(xt, read_ucell(last));
190 	}
191 
192 	return 0;
193 }
194 
195 
196 /* findxtfromcell_wordlist
197  * Given a cell and a wordlist, determine the CFA of the word containing
198  * the cell or 0 if we are unable to return a suitable CFA
199  */
200 
findxtfromcell_wordlist(ucell incell,ucell wordlist)201 ucell findxtfromcell_wordlist(ucell incell, ucell wordlist)
202 {
203 	ucell tmplfa;
204 
205 	if (!wordlist)
206 		return 0;
207 
208 	tmplfa = read_ucell(cell2pointer(wordlist));
209 	while (tmplfa) {
210 		if (tmplfa < incell)
211 			return lfa2cfa(tmplfa);
212 
213 		tmplfa = read_ucell(cell2pointer(tmplfa));
214 	}
215 
216 	return 0;
217 }
218 
219 
220 /* findxtfromcell
221  * Given a cell, determine the CFA of the word containing
222  * the cell by searching all vocabularies
223  */
224 
findxtfromcell(ucell incell)225 ucell findxtfromcell(ucell incell)
226 {
227 	ucell usesvocab = findword("vocabularies?") + sizeof(cell);
228 	unsigned int i;
229 
230 	if (read_ucell(cell2pointer(usesvocab))) {
231 		/* Vocabularies are in use, so search each one in turn */
232 		ucell numvocabs = findword("#order") + sizeof(cell);
233 
234 		for (i = 0; i < read_ucell(cell2pointer(numvocabs)); i++) {
235 			ucell vocabs = findword("vocabularies") + 2 * sizeof(cell);
236 			ucell semis = findxtfromcell_wordlist(incell, read_cell(cell2pointer(vocabs + (i * sizeof(cell)))));
237 
238 			/* If we get a non-zero result, we found the xt in this vocab */
239 			if (semis)
240 				return semis;
241 		}
242 	} else {
243 		/* Vocabularies not in use */
244 		return findxtfromcell_wordlist(incell, read_ucell(last));
245 	}
246 
247 	return 0;
248 }
249 
dump_header(dictionary_header_t * header)250 void dump_header(dictionary_header_t *header)
251 {
252 	printk("OpenBIOS dictionary:\n");
253 	printk("  version:     %d\n", header->version);
254 	printk("  cellsize:    %d\n", header->cellsize);
255 	printk("  endianess:   %s\n", header->endianess?"big":"little");
256 	printk("  compression: %s\n", header->compression?"yes":"no");
257 	printk("  relocation:  %s\n", header->relocation?"yes":"no");
258 	printk("  checksum:    %08x\n", target_long(header->checksum));
259 	printk("  length:      %08x\n", target_long(header->length));
260 	printk("  last:        %0" FMT_CELL_x "\n", target_cell(header->last));
261 }
262 
load_dictionary(const char * data,ucell len)263 ucell load_dictionary(const char *data, ucell len)
264 {
265 	u32 checksum=0;
266 	const char *checksum_walk;
267 	ucell *walk, *reloc_table;
268 	dictionary_header_t *header=(dictionary_header_t *)data;
269 
270 	/* assertions */
271 	if (len <= (sizeof(dictionary_header_t)) || strncmp(DICTID, data, 8))
272 		return 0;
273 #ifdef CONFIG_DEBUG_DICTIONARY
274 	dump_header(header);
275 #endif
276 
277 	checksum_walk=data;
278 	while (checksum_walk<data+len) {
279 		checksum+=read_long(checksum_walk);
280 		checksum_walk+=sizeof(u32);
281 	}
282 
283 	if(checksum) {
284 		printk("Checksum invalid (%08x)!\n", checksum);
285 		return 0;
286 	}
287 
288 	data += sizeof(dictionary_header_t);
289 
290 	dicthead = target_long(header->length);
291 
292 	memcpy(dict, data, dicthead);
293 	reloc_table=(ucell *)(data+dicthead);
294 
295 #ifdef CONFIG_DEBUG_DICTIONARY
296 	printk("\nmoving dictionary (%x bytes) to %x\n",
297 			(ucell)dicthead, (ucell)dict);
298 	printk("\ndynamic relocation...");
299 #endif
300 
301 	for (walk = (ucell *) dict; walk < (ucell *) (dict + dicthead);
302 	     walk++) {
303 		int pos, bit, l;
304 		l=(walk-(ucell *)dict);
305 		pos=l/BITS;
306 		bit=l&~(-BITS);
307                 if (reloc_table[pos] & target_ucell((ucell)1ULL << bit)) {
308 			// printk("%lx, pos %x, bit %d\n",*walk, pos, bit);
309 			write_ucell(walk, read_ucell(walk)+pointer2cell(dict));
310 		}
311 	}
312 
313 #ifdef CONFIG_DEBUG_DICTIONARY
314 	printk(" done.\n");
315 #endif
316 
317 	last = (ucell *)(dict + target_ucell(header->last));
318 
319 	return -1;
320 }
321