/[gxemul]/trunk/src/emul_parse.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/emul_parse.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22899 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


1 /*
2 * Copyright (C) 2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: emul_parse.c,v 1.33 2005/08/12 06:02:56 debug Exp $
29 *
30 * Set up an emulation by parsing a config file.
31 *
32 * TODO: This could be extended to support XML config files as well, but
33 * XML is ugly. It is ugly right now as well. The question is: which
34 * solution is the least ugly?
35 */
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "diskimage.h"
42 #include "emul.h"
43 #include "machine.h"
44 #include "misc.h"
45 #include "net.h"
46
47
48 #define is_word_char(ch) ( \
49 (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || \
50 ch == '_' || ch == '$' || (ch >= '0' && ch <= '9') )
51
52
53 #define EXPECT_WORD 1
54 #define EXPECT_LEFT_PARENTHESIS 2
55 #define EXPECT_RIGHT_PARENTHESIS 4
56
57
58 /*
59 * read_one_word():
60 *
61 * Reads the file f until it has read a complete word. Whitespace is ignored,
62 * and also any exclamation mark ('!') and anything following an exclamation
63 * mark on a line.
64 *
65 * Used internally by emul_parse_config().
66 */
67 static void read_one_word(FILE *f, char *buf, int buflen, int *line,
68 int expect)
69 {
70 int ch;
71 int done = 0;
72 int curlen = 0;
73 int in_word = 0;
74
75 while (!done) {
76 if (curlen >= buflen - 1)
77 break;
78
79 ch = fgetc(f);
80 if (ch == EOF)
81 break;
82
83 if (in_word) {
84 if (is_word_char(ch)) {
85 buf[curlen++] = ch;
86 if (curlen == buflen - 1)
87 done = 1;
88 continue;
89 } else {
90 if (ungetc(ch, f) == EOF) {
91 fatal("ungetc() failed?\n");
92 exit(1);
93 }
94 break;
95 }
96 }
97
98 if (ch == '\n') {
99 (*line) ++;
100 continue;
101 }
102
103 if (ch == '\r')
104 continue;
105
106 if (ch == '!') {
107 /* Skip until newline: */
108 while (ch != '\n' && ch != EOF)
109 ch = fgetc(f);
110 if (ch == '\n')
111 (*line) ++;
112 continue;
113 }
114
115 if (ch == '{') {
116 int depth = 1;
117
118 /* Skip until '}': */
119 while (depth > 0) {
120 ch = fgetc(f);
121 if (ch == '\n')
122 (*line) ++;
123 if (ch == '{')
124 depth ++;
125 if (ch == '}')
126 depth --;
127 if (ch == EOF) {
128 fatal("line %i: unexpected EOF inside"
129 " a nested comment\n", *line);
130 exit(1);
131 }
132 }
133 continue;
134 }
135
136 /* Whitespace? */
137 if (ch <= ' ')
138 continue;
139
140 if (ch == '"' || ch == '\'') {
141 /* This is a quoted word. */
142 int start_ch = ch;
143
144 if (expect & EXPECT_LEFT_PARENTHESIS) {
145 fatal("unexpected character '%c', line %i\n",
146 ch, *line);
147 exit(1);
148 }
149
150 while (curlen < buflen - 1) {
151 ch = fgetc(f);
152 if (ch == '\n') {
153 fatal("line %i: newline inside"
154 " quotes?\n", *line);
155 exit(1);
156 }
157 if (ch == EOF) {
158 fatal("line %i: EOF inside a quoted"
159 " string?\n", *line);
160 exit(1);
161 }
162 if (ch == start_ch)
163 break;
164 buf[curlen++] = ch;
165 }
166 break;
167 }
168
169 if ((expect & EXPECT_WORD) && is_word_char(ch)) {
170 buf[curlen++] = ch;
171 in_word = 1;
172 if (curlen == buflen - 1)
173 done = 1;
174 } else {
175 if ((expect & EXPECT_LEFT_PARENTHESIS) && ch == '(') {
176 buf[curlen++] = ch;
177 break;
178 }
179 if ((expect & EXPECT_RIGHT_PARENTHESIS) && ch == ')') {
180 buf[curlen++] = ch;
181 break;
182 }
183
184 fatal("unexpected character '%c', line %i\n",
185 ch, *line);
186 exit(1);
187 }
188 }
189
190 buf[curlen] = '\0';
191 }
192
193
194 #define PARSESTATE_NONE 0
195 #define PARSESTATE_EMUL 1
196 #define PARSESTATE_NET 2
197 #define PARSESTATE_MACHINE 3
198
199 static char cur_net_ipv4net[50];
200 static char cur_net_ipv4len[50];
201 static char cur_net_local_port[10];
202 #define MAX_N_REMOTE 20
203 #define MAX_REMOTE_LEN 100
204 static char *cur_net_remote[MAX_N_REMOTE];
205 static int cur_net_n_remote;
206
207 static char cur_machine_name[50];
208 static char cur_machine_cpu[50];
209 static char cur_machine_type[50];
210 static char cur_machine_subtype[50];
211 static char cur_machine_bootname[150];
212 static char cur_machine_bootarg[250];
213 static char cur_machine_slowsi[10];
214 static char cur_machine_debugger_on_badaddr[10];
215 static char cur_machine_prom_emulation[10];
216 static char cur_machine_use_x11[10];
217 static char cur_machine_x11_scaledown[10];
218 static char cur_machine_bintrans[10];
219 static char cur_machine_old_bintrans[10];
220 static char cur_machine_bintrans_size[10];
221 static char cur_machine_byte_order[20];
222 static char cur_machine_random_mem[10];
223 static char cur_machine_random_cpu[10];
224 static char cur_machine_force_netboot[10];
225 static char cur_machine_start_paused[10];
226 static char cur_machine_ncpus[10];
227 static char cur_machine_n_gfx_cards[10];
228 static char cur_machine_serial_nr[10];
229 static char cur_machine_emulated_hz[10];
230 static char cur_machine_memory[10];
231 static char cur_machine_max_random_cycles[10];
232 #define MAX_N_LOAD 15
233 #define MAX_LOAD_LEN 2000
234 static char *cur_machine_load[MAX_N_LOAD];
235 static int cur_machine_n_load;
236 #define MAX_N_DISK 10
237 #define MAX_DISK_LEN 2000
238 static char *cur_machine_disk[MAX_N_DISK];
239 static int cur_machine_n_disk;
240 #define MAX_N_DEVICE 20
241 #define MAX_DEVICE_LEN 400
242 static char *cur_machine_device[MAX_N_DISK];
243 static int cur_machine_n_device;
244 #define MAX_N_X11_DISP 5
245 #define MAX_X11_DISP_LEN 1000
246 static char *cur_machine_x11_disp[MAX_N_X11_DISP];
247 static int cur_machine_n_x11_disp;
248
249 #define WORD(w,var) { \
250 if (strcmp(word, w) == 0) { \
251 read_one_word(f, word, maxbuflen, \
252 line, EXPECT_LEFT_PARENTHESIS); \
253 read_one_word(f, var, sizeof(var), \
254 line, EXPECT_WORD); \
255 read_one_word(f, word, maxbuflen, \
256 line, EXPECT_RIGHT_PARENTHESIS); \
257 return; \
258 } \
259 }
260
261
262 /*
263 * parse_on_off():
264 *
265 * Returns 1 for "on", "yes", "enable", or "1".
266 * Returns 0 for "off", "no", "disable", or "0".
267 * Prints a fatal warning and exit()s for other values.
268 */
269 int parse_on_off(char *s)
270 {
271 if (strcasecmp(s, "on") == 0 || strcasecmp(s, "yes") == 0 ||
272 strcasecmp(s, "enable") == 0 || strcasecmp(s, "1") == 0)
273 return 1;
274 if (strcasecmp(s, "off") == 0 || strcasecmp(s, "no") == 0 ||
275 strcasecmp(s, "disable") == 0 || strcasecmp(s, "0") == 0)
276 return 0;
277
278 fatal("parse_on_off(): unknown value '%s'\n", s);
279 exit(1);
280 }
281
282
283 /*
284 * parse__none():
285 *
286 * emul ( [...] )
287 */
288 static void parse__none(struct emul *e, FILE *f, int *in_emul, int *line,
289 int *parsestate, char *word, size_t maxbuflen)
290 {
291 if (strcmp(word, "emul") == 0) {
292 if (*in_emul) {
293 fatal("line %i: only one emul per config "
294 "file is supported!\n", *line);
295 exit(1);
296 }
297 *parsestate = PARSESTATE_EMUL;
298 *in_emul = 1;
299 read_one_word(f, word, maxbuflen,
300 line, EXPECT_LEFT_PARENTHESIS);
301 return;
302 }
303
304 fatal("line %i: expecting 'emul', not '%s'\n", *line, word);
305 exit(1);
306 }
307
308
309 /*
310 * parse__emul():
311 *
312 * name, net, machine
313 */
314 static void parse__emul(struct emul *e, FILE *f, int *in_emul, int *line,
315 int *parsestate, char *word, size_t maxbuflen)
316 {
317 if (word[0] == ')') {
318 *parsestate = PARSESTATE_NONE;
319 return;
320 }
321
322 if (strcmp(word, "name") == 0) {
323 char tmp[200];
324 read_one_word(f, word, maxbuflen,
325 line, EXPECT_LEFT_PARENTHESIS);
326 read_one_word(f, tmp, sizeof(tmp), line, EXPECT_WORD);
327 read_one_word(f, word, maxbuflen,
328 line, EXPECT_RIGHT_PARENTHESIS);
329 if (e->name != NULL) {
330 free(e->name);
331 e->name = NULL;
332 }
333 e->name = strdup(tmp);
334 if (e->name == NULL) {
335 fprintf(stderr, "out of memory in parse__emul()\n");
336 exit(1);
337 }
338 debug("name: \"%s\"\n", e->name);
339 return;
340 }
341
342 if (strcmp(word, "net") == 0) {
343 *parsestate = PARSESTATE_NET;
344 read_one_word(f, word, maxbuflen,
345 line, EXPECT_LEFT_PARENTHESIS);
346
347 /* Default net: */
348 strlcpy(cur_net_ipv4net, "10.0.0.0", sizeof(cur_net_ipv4net));
349 strlcpy(cur_net_ipv4len, "8", sizeof(cur_net_ipv4len));
350 strlcpy(cur_net_local_port, "", sizeof(cur_net_local_port));
351 cur_net_n_remote = 0;
352 return;
353 }
354
355 if (strcmp(word, "machine") == 0) {
356 *parsestate = PARSESTATE_MACHINE;
357 read_one_word(f, word, maxbuflen,
358 line, EXPECT_LEFT_PARENTHESIS);
359
360 /* A "zero state": */
361 cur_machine_name[0] = '\0';
362 cur_machine_cpu[0] = '\0';
363 cur_machine_type[0] = '\0';
364 cur_machine_subtype[0] = '\0';
365 cur_machine_bootname[0] = '\0';
366 cur_machine_bootarg[0] = '\0';
367 cur_machine_n_load = 0;
368 cur_machine_n_disk = 0;
369 cur_machine_n_device = 0;
370 cur_machine_n_x11_disp = 0;
371 cur_machine_slowsi[0] = '\0';
372 cur_machine_debugger_on_badaddr[0] = '\0';
373 cur_machine_prom_emulation[0] = '\0';
374 cur_machine_use_x11[0] = '\0';
375 cur_machine_x11_scaledown[0] = '\0';
376 cur_machine_bintrans[0] = '\0';
377 cur_machine_old_bintrans[0] = '\0';
378 cur_machine_bintrans_size[0] = '\0';
379 cur_machine_byte_order[0] = '\0';
380 cur_machine_random_mem[0] = '\0';
381 cur_machine_random_cpu[0] = '\0';
382 cur_machine_force_netboot[0] = '\0';
383 cur_machine_start_paused[0] = '\0';
384 cur_machine_ncpus[0] = '\0';
385 cur_machine_n_gfx_cards[0] = '\0';
386 cur_machine_serial_nr[0] = '\0';
387 cur_machine_emulated_hz[0] = '\0';
388 cur_machine_memory[0] = '\0';
389 cur_machine_max_random_cycles[0] = '\0';
390 return;
391 }
392
393 fatal("line %i: not expecting '%s' in an 'emul' section\n",
394 *line, word);
395 exit(1);
396 }
397
398
399 /*
400 * parse__net():
401 *
402 * Simple words: ipv4net, ipv4len, local_port
403 *
404 * Complex: add_remote
405 *
406 * TODO: more words? for example an option to disable the gateway? that would
407 * have to be implemented correctly in src/net.c first.
408 */
409 static void parse__net(struct emul *e, FILE *f, int *in_emul, int *line,
410 int *parsestate, char *word, size_t maxbuflen)
411 {
412 int i;
413
414 if (word[0] == ')') {
415 /* Finished with the 'net' section. Let's create the net: */
416 if (e->net != NULL) {
417 fatal("line %i: more than one net isn't really "
418 "supported yet\n", *line);
419 exit(1);
420 }
421
422 if (!cur_net_local_port[0])
423 strlcpy(cur_net_local_port, "0",
424 sizeof(cur_net_local_port));
425
426 e->net = net_init(e, NET_INIT_FLAG_GATEWAY,
427 cur_net_ipv4net, atoi(cur_net_ipv4len),
428 cur_net_remote, cur_net_n_remote,
429 atoi(cur_net_local_port));
430
431 if (e->net == NULL) {
432 fatal("line %i: fatal error: could not create"
433 " the net (?)\n", *line);
434 exit(1);
435 }
436
437 for (i=0; i<cur_net_n_remote; i++) {
438 free(cur_net_remote[i]);
439 cur_net_remote[i] = NULL;
440 }
441
442 *parsestate = PARSESTATE_EMUL;
443 return;
444 }
445
446 WORD("ipv4net", cur_net_ipv4net);
447 WORD("ipv4len", cur_net_ipv4len);
448 WORD("local_port", cur_net_local_port);
449
450 if (strcmp(word, "add_remote") == 0) {
451 read_one_word(f, word, maxbuflen,
452 line, EXPECT_LEFT_PARENTHESIS);
453 if (cur_net_n_remote >= MAX_N_REMOTE) {
454 fprintf(stderr, "too many remote networks\n");
455 exit(1);
456 }
457 cur_net_remote[cur_net_n_remote] = malloc(MAX_REMOTE_LEN);
458 if (cur_net_remote[cur_net_n_remote] == NULL) {
459 fprintf(stderr, "out of memory\n");
460 exit(1);
461 }
462 read_one_word(f, cur_net_remote[cur_net_n_remote],
463 MAX_REMOTE_LEN, line, EXPECT_WORD);
464 cur_net_n_remote ++;
465 read_one_word(f, word, maxbuflen, line,
466 EXPECT_RIGHT_PARENTHESIS);
467 return;
468 }
469
470 fatal("line %i: not expecting '%s' in a 'net' section\n", *line, word);
471 exit(1);
472 }
473
474
475 /*
476 * parse__machine():
477 */
478 static void parse__machine(struct emul *e, FILE *f, int *in_emul, int *line,
479 int *parsestate, char *word, size_t maxbuflen)
480 {
481 int r, i;
482
483 if (word[0] == ')') {
484 /* Finished with the 'machine' section. */
485 struct machine *m;
486
487 if (!cur_machine_name[0])
488 strlcpy(cur_machine_name, "no_name",
489 sizeof(cur_machine_name));
490
491 m = emul_add_machine(e, cur_machine_name);
492
493 r = machine_name_to_type(cur_machine_type, cur_machine_subtype,
494 &m->machine_type, &m->machine_subtype, &m->arch);
495 if (!r)
496 exit(1);
497
498 if (cur_machine_cpu[0])
499 m->cpu_name = strdup(cur_machine_cpu);
500
501 if (!cur_machine_use_x11[0])
502 strlcpy(cur_machine_use_x11, "no",
503 sizeof(cur_machine_use_x11));
504 m->use_x11 = parse_on_off(cur_machine_use_x11);
505
506 if (!cur_machine_slowsi[0])
507 strlcpy(cur_machine_slowsi, "no",
508 sizeof(cur_machine_slowsi));
509 m->slow_serial_interrupts_hack_for_linux =
510 parse_on_off(cur_machine_slowsi);
511
512 if (!cur_machine_debugger_on_badaddr[0])
513 strlcpy(cur_machine_debugger_on_badaddr, "no",
514 sizeof(cur_machine_debugger_on_badaddr));
515 m->single_step_on_bad_addr =
516 parse_on_off(cur_machine_debugger_on_badaddr);
517
518 if (!cur_machine_prom_emulation[0])
519 strlcpy(cur_machine_prom_emulation, "yes",
520 sizeof(cur_machine_prom_emulation));
521 m->prom_emulation = parse_on_off(cur_machine_prom_emulation);
522
523 if (!cur_machine_random_mem[0])
524 strlcpy(cur_machine_random_mem, "no",
525 sizeof(cur_machine_random_mem));
526 m->random_mem_contents =
527 parse_on_off(cur_machine_random_mem);
528
529 if (!cur_machine_random_cpu[0])
530 strlcpy(cur_machine_random_cpu, "no",
531 sizeof(cur_machine_random_cpu));
532 m->use_random_bootstrap_cpu =
533 parse_on_off(cur_machine_random_cpu);
534
535 m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
536 if (cur_machine_byte_order[0]) {
537 if (strncasecmp(cur_machine_byte_order, "big", 3) == 0)
538 m->byte_order_override = EMUL_BIG_ENDIAN;
539 else if (strncasecmp(cur_machine_byte_order, "little",
540 6) == 0)
541 m->byte_order_override = EMUL_LITTLE_ENDIAN;
542 else {
543 fatal("Byte order must be big-endian or"
544 " little-endian\n");
545 exit(1);
546 }
547 }
548
549 if (!cur_machine_bintrans[0])
550 strlcpy(cur_machine_bintrans, "yes",
551 sizeof(cur_machine_bintrans));
552 m->bintrans_enable = m->bintrans_enabled_from_start =
553 parse_on_off(cur_machine_bintrans);
554
555 if (!cur_machine_old_bintrans[0])
556 strlcpy(cur_machine_old_bintrans, "yes",
557 sizeof(cur_machine_old_bintrans));
558 m->old_bintrans_enable = parse_on_off(cur_machine_old_bintrans);
559
560 if (!m->bintrans_enable && m->old_bintrans_enable)
561 m->old_bintrans_enable = 0;
562
563 /* TODO: Hm... */
564 if (m->bintrans_enable)
565 m->speed_tricks = 0;
566
567 if (cur_machine_bintrans_size[0])
568 m->bintrans_size = 1048576 *
569 atoi(cur_machine_bintrans_size);
570
571 if (!cur_machine_force_netboot[0])
572 strlcpy(cur_machine_force_netboot, "no",
573 sizeof(cur_machine_force_netboot));
574 m->force_netboot = parse_on_off(cur_machine_force_netboot);
575
576 if (!cur_machine_start_paused[0])
577 strlcpy(cur_machine_start_paused, "no",
578 sizeof(cur_machine_start_paused));
579 m->start_paused = parse_on_off(cur_machine_start_paused);
580
581 /* NOTE: Default nr of CPUs is 0: */
582 if (!cur_machine_ncpus[0])
583 strlcpy(cur_machine_ncpus, "0",
584 sizeof(cur_machine_ncpus));
585 m->ncpus = atoi(cur_machine_ncpus);
586
587 if (cur_machine_n_gfx_cards[0])
588 m->n_gfx_cards = atoi(cur_machine_n_gfx_cards);
589
590 if (cur_machine_serial_nr[0]) {
591 m->serial_nr = atoi(cur_machine_serial_nr);
592 e->next_serial_nr = m->serial_nr+1;
593 }
594
595 if (cur_machine_emulated_hz[0]) {
596 m->emulated_hz = mystrtoull(cur_machine_emulated_hz,
597 NULL, 0);
598 m->automatic_clock_adjustment = 0;
599 }
600
601 /* NOTE: Default nr of CPUs is 0: */
602 if (!cur_machine_memory[0])
603 strlcpy(cur_machine_memory, "0",
604 sizeof(cur_machine_memory));
605 m->physical_ram_in_mb = atoi(cur_machine_memory);
606
607 if (cur_machine_max_random_cycles[0]) {
608 if (m->bintrans_enable) {
609 fprintf(stderr, "max_random_cycles doesn't"
610 " work with bintrans\n");
611 exit(1);
612 }
613 m->max_random_cycles_per_chunk = atoi(
614 cur_machine_max_random_cycles);
615 }
616
617 if (!cur_machine_x11_scaledown[0])
618 m->x11_scaledown = 1;
619 else {
620 m->x11_scaledown = atoi(cur_machine_x11_scaledown);
621 if (m->x11_scaledown < 0) {
622 fprintf(stderr, "Invalid scaledown value"
623 " (%i)\n", m->x11_scaledown);
624 exit(1);
625 }
626 }
627
628 for (i=0; i<cur_machine_n_disk; i++) {
629 diskimage_add(m, cur_machine_disk[i]);
630 free(cur_machine_disk[i]);
631 cur_machine_disk[i] = NULL;
632 }
633
634 m->boot_kernel_filename = strdup(cur_machine_bootname);
635
636 if (cur_machine_bootarg[0])
637 m->boot_string_argument = strdup(cur_machine_bootarg);
638
639 for (i=0; i<cur_machine_n_x11_disp; i++) {
640 m->x11_n_display_names ++;
641 m->x11_display_names = realloc(
642 m->x11_display_names, m->x11_n_display_names
643 * sizeof(char *));
644 if (m->x11_display_names == NULL) {
645 printf("out of memory\n");
646 exit(1);
647 }
648 m->x11_display_names[m->x11_n_display_names-1] =
649 strdup(cur_machine_x11_disp[i]);
650 if (m->x11_display_names
651 [m->x11_n_display_names-1] == NULL) {
652 printf("out of memory\n");
653 exit(1);
654 }
655 free(cur_machine_x11_disp[i]);
656 cur_machine_x11_disp[i] = NULL;
657 }
658
659 emul_machine_setup(m,
660 cur_machine_n_load, cur_machine_load,
661 cur_machine_n_device, cur_machine_device);
662
663 for (i=0; i<cur_machine_n_device; i++) {
664 free(cur_machine_device[i]);
665 cur_machine_device[i] = NULL;
666 }
667
668 for (i=0; i<cur_machine_n_load; i++) {
669 free(cur_machine_load[i]);
670 cur_machine_load[i] = NULL;
671 }
672
673 *parsestate = PARSESTATE_EMUL;
674 return;
675 }
676
677 WORD("name", cur_machine_name);
678 WORD("cpu", cur_machine_cpu);
679 WORD("type", cur_machine_type);
680 WORD("subtype", cur_machine_subtype);
681 WORD("bootname", cur_machine_bootname);
682 WORD("bootarg", cur_machine_bootarg);
683 WORD("slow_serial_interrupts_hack_for_linux", cur_machine_slowsi);
684 WORD("debugger_on_badaddr", cur_machine_debugger_on_badaddr);
685 WORD("prom_emulation", cur_machine_prom_emulation);
686 WORD("use_x11", cur_machine_use_x11);
687 WORD("x11_scaledown", cur_machine_x11_scaledown);
688 WORD("bintrans", cur_machine_bintrans);
689 WORD("old_bintrans", cur_machine_old_bintrans);
690 WORD("bintrans_size", cur_machine_bintrans_size);
691 WORD("byte_order", cur_machine_byte_order);
692 WORD("random_mem_contents", cur_machine_random_mem);
693 WORD("use_random_bootstrap_cpu", cur_machine_random_cpu);
694 WORD("force_netboot", cur_machine_force_netboot);
695 WORD("ncpus", cur_machine_ncpus);
696 WORD("serial_nr", cur_machine_serial_nr);
697 WORD("n_gfx_cards", cur_machine_n_gfx_cards);
698 WORD("emulated_hz", cur_machine_emulated_hz);
699 WORD("memory", cur_machine_memory);
700 WORD("max_random_cycles", cur_machine_max_random_cycles);
701 WORD("start_paused", cur_machine_start_paused);
702
703 if (strcmp(word, "load") == 0) {
704 read_one_word(f, word, maxbuflen,
705 line, EXPECT_LEFT_PARENTHESIS);
706 if (cur_machine_n_load >= MAX_N_LOAD) {
707 fprintf(stderr, "too many loads\n");
708 exit(1);
709 }
710 cur_machine_load[cur_machine_n_load] = malloc(MAX_LOAD_LEN);
711 if (cur_machine_load[cur_machine_n_load] == NULL) {
712 fprintf(stderr, "out of memory\n");
713 exit(1);
714 }
715 read_one_word(f, cur_machine_load[cur_machine_n_load],
716 MAX_LOAD_LEN, line, EXPECT_WORD);
717 cur_machine_n_load ++;
718 read_one_word(f, word, maxbuflen,
719 line, EXPECT_RIGHT_PARENTHESIS);
720 return;
721 }
722
723 if (strcmp(word, "disk") == 0) {
724 read_one_word(f, word, maxbuflen,
725 line, EXPECT_LEFT_PARENTHESIS);
726 if (cur_machine_n_disk >= MAX_N_DISK) {
727 fprintf(stderr, "too many disks\n");
728 exit(1);
729 }
730 cur_machine_disk[cur_machine_n_disk] = malloc(MAX_DISK_LEN);
731 if (cur_machine_disk[cur_machine_n_disk] == NULL) {
732 fprintf(stderr, "out of memory\n");
733 exit(1);
734 }
735 read_one_word(f, cur_machine_disk[cur_machine_n_disk],
736 MAX_DISK_LEN, line, EXPECT_WORD);
737 cur_machine_n_disk ++;
738 read_one_word(f, word, maxbuflen,
739 line, EXPECT_RIGHT_PARENTHESIS);
740 return;
741 }
742
743 if (strcmp(word, "device") == 0) {
744 read_one_word(f, word, maxbuflen,
745 line, EXPECT_LEFT_PARENTHESIS);
746 if (cur_machine_n_device >= MAX_N_DEVICE) {
747 fprintf(stderr, "too many devices\n");
748 exit(1);
749 }
750 cur_machine_device[cur_machine_n_device] =
751 malloc(MAX_DEVICE_LEN);
752 if (cur_machine_device[cur_machine_n_device] == NULL) {
753 fprintf(stderr, "out of memory\n");
754 exit(1);
755 }
756 read_one_word(f, cur_machine_device[cur_machine_n_device],
757 MAX_DEVICE_LEN, line, EXPECT_WORD);
758 cur_machine_n_device ++;
759 read_one_word(f, word, maxbuflen,
760 line, EXPECT_RIGHT_PARENTHESIS);
761 return;
762 }
763
764 if (strcmp(word, "add_x11_display") == 0) {
765 read_one_word(f, word, maxbuflen,
766 line, EXPECT_LEFT_PARENTHESIS);
767 if (cur_machine_n_x11_disp >= MAX_N_X11_DISP) {
768 fprintf(stderr, "too many x11 displays\n");
769 exit(1);
770 }
771 cur_machine_x11_disp[cur_machine_n_x11_disp] =
772 malloc(MAX_X11_DISP_LEN);
773 if (cur_machine_x11_disp[cur_machine_n_x11_disp] == NULL) {
774 fprintf(stderr, "out of memory\n");
775 exit(1);
776 }
777 read_one_word(f, cur_machine_x11_disp[cur_machine_n_x11_disp],
778 MAX_X11_DISP_LEN, line, EXPECT_WORD);
779 cur_machine_n_x11_disp ++;
780 read_one_word(f, word, maxbuflen,
781 line, EXPECT_RIGHT_PARENTHESIS);
782 return;
783 }
784
785 fatal("line %i: not expecting '%s' in a 'machine' section\n",
786 *line, word);
787 exit(1);
788 }
789
790
791 /*
792 * emul_parse_config():
793 *
794 * Set up an emulation by parsing a config file.
795 */
796 void emul_parse_config(struct emul *e, FILE *f)
797 {
798 char word[500];
799 int in_emul = 0;
800 int line = 1;
801 int parsestate = PARSESTATE_NONE;
802
803 /* debug("emul_parse_config()\n"); */
804
805 while (!feof(f)) {
806 read_one_word(f, word, sizeof(word), &line,
807 EXPECT_WORD | EXPECT_RIGHT_PARENTHESIS);
808 if (!word[0])
809 break;
810
811 /* debug("word = '%s'\n", word); */
812
813 switch (parsestate) {
814 case PARSESTATE_NONE:
815 parse__none(e, f, &in_emul, &line, &parsestate,
816 word, sizeof(word));
817 break;
818 case PARSESTATE_EMUL:
819 parse__emul(e, f, &in_emul, &line, &parsestate,
820 word, sizeof(word));
821 break;
822 case PARSESTATE_NET:
823 parse__net(e, f, &in_emul, &line, &parsestate,
824 word, sizeof(word));
825 break;
826 case PARSESTATE_MACHINE:
827 parse__machine(e, f, &in_emul, &line, &parsestate,
828 word, sizeof(word));
829 break;
830 default:
831 fatal("INTERNAL ERROR in emul_parse.c ("
832 "parsestate %i is not imlemented yet?)\n",
833 parsestate);
834 exit(1);
835 }
836 }
837
838 if (parsestate != PARSESTATE_NONE) {
839 fatal("EOF but not enough right parentheses?\n");
840 exit(1);
841 }
842 }
843

  ViewVC Help
Powered by ViewVC 1.1.26