1 /*
2  *  Copyright (C) 2003-2020  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  *  Machine registry.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 
38 #include "cpu.h"
39 #include "device.h"
40 #include "diskimage.h"
41 #include "emul.h"
42 #include "machine.h"
43 #include "memory.h"
44 #include "misc.h"
45 #include "settings.h"
46 #include "symbol.h"
47 
48 
49 /*  This is initialized by machine_init():  */
50 struct machine_entry *first_machine_entry = NULL;
51 
52 
53 /*
54  *  machine_new():
55  *
56  *  Returns a reasonably initialized struct machine.
57  */
machine_new(char * name,struct emul * emul,int id)58 struct machine *machine_new(char *name, struct emul *emul, int id)
59 {
60 	struct machine *m;
61 
62 	CHECK_ALLOCATION(m = (struct machine *) malloc(sizeof(struct machine)));
63 	memset(m, 0, sizeof(struct machine));
64 
65 	/*  Pointer back to the emul object that this machine belongs to:  */
66 	m->emul = emul;
67 
68 	if (name != NULL)
69 		CHECK_ALLOCATION(m->name = strdup(name));
70 
71 	/*  Full path, e.g. "machine[0]":  */
72 	CHECK_ALLOCATION(m->path = (char *) malloc(20));
73 	snprintf(m->path, 20, "machine[%i]", id);
74 
75 	/*  Sane default values:  */
76 	m->serial_nr = 1;
77 	m->machine_type = MACHINE_NONE;
78 	m->machine_subtype = MACHINE_NONE;
79 	m->arch_pagesize = 4096;	/*  Should be overriden in
80 					    emul.c for other pagesizes.  */
81 	m->prom_emulation = 1;
82 	m->allow_instruction_combinations = 1;
83 	m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
84 	m->boot_kernel_filename = strdup("");
85 	m->boot_string_argument = NULL;
86 	m->x11_md.scaledown = 1;
87 	m->x11_md.scaleup = 1;
88 	m->n_gfx_cards = 1;
89 	symbol_init(&m->symbol_context);
90 
91 	/*  Settings:  */
92 	m->settings = settings_new();
93 	settings_add(m->settings, "name", 0,
94 	    SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
95 	    (void *) &m->name);
96 	settings_add(m->settings, "serial_nr", 0,
97 	    SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
98 	    (void *) &m->serial_nr);
99 	settings_add(m->settings, "arch_pagesize", 0,
100 	    SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
101 	    (void *) &m->arch_pagesize);
102 	settings_add(m->settings, "prom_emulation", 0,
103 	    SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
104 	    (void *) &m->prom_emulation);
105 	settings_add(m->settings, "allow_instruction_combinations", 0,
106 	    SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
107 	    (void *) &m->allow_instruction_combinations);
108 	settings_add(m->settings, "n_gfx_cards", 0,
109 	    SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
110 	    (void *) &m->n_gfx_cards);
111 	settings_add(m->settings, "statistics_enabled", 1,
112 	    SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
113 	    (void *) &m->statistics.enabled);
114 
115 	return m;
116 }
117 
118 
119 /*
120  *  machine_destroy():
121  *
122  *  Destroys a machine object.
123  */
machine_destroy(struct machine * machine)124 void machine_destroy(struct machine *machine)
125 {
126 	int i;
127 
128 	for (i=0; i<machine->ncpus; i++)
129 		cpu_destroy(machine->cpus[i]);
130 
131 	// TODO: Memory leak; but it's ok, since the whole legacy thing should
132 	// be replaced anyway.
133 	// if (machine->name != NULL)
134 	// 	free(machine->name);
135 
136 	if (machine->path != NULL)
137 		free(machine->path);
138 
139 	/*  Remove any remaining level-1 settings:  */
140 	settings_remove_all(machine->settings);
141 	settings_destroy(machine->settings);
142 
143 	free(machine);
144 }
145 
146 
147 /*
148  *  machine_name_to_type():
149  *
150  *  Take a type and a subtype as strings, and convert them into numeric
151  *  values used internally throughout the code.
152  *
153  *  Return value is 1 on success, 0 if there was no match.
154  *  Also, any errors/warnings are printed using fatal()/debug().
155  */
machine_name_to_type(char * stype,char * ssubtype,int * type,int * subtype,int * arch)156 int machine_name_to_type(char *stype, char *ssubtype,
157 	int *type, int *subtype, int *arch)
158 {
159 	struct machine_entry *me;
160 	int i, j, k, nmatches = 0;
161 
162 	*type = MACHINE_NONE;
163 	*subtype = 0;
164 
165 	/*  Check stype, and optionally ssubtype:  */
166 	me = first_machine_entry;
167 	while (me != NULL) {
168 		for (i=0; i<me->n_aliases; i++)
169 			if (strcasecmp(me->aliases[i], stype) == 0) {
170 				/*  Found a type:  */
171 				*type = me->machine_type;
172 				*arch = me->arch;
173 
174 				if (me->n_subtypes == 0)
175 					return 1;
176 
177 				/*  Check for subtype:  */
178 				for (j=0; j<me->n_subtypes; j++)
179 					for (k=0; k<me->subtype[j]->n_aliases;
180 					    k++)
181 						if (strcasecmp(ssubtype,
182 						    me->subtype[j]->aliases[k]
183 						    ) == 0) {
184 							*subtype = me->subtype[
185 							    j]->machine_subtype;
186 							return 1;
187 						}
188 
189 				fatal("Unknown subtype '%s' for emulation"
190 				    " '%s'\n", ssubtype, stype);
191 				if (!ssubtype[0])
192 					fatal("(Maybe you forgot the -e"
193 					    " command line option?)\n");
194 				exit(1);
195 			}
196 
197 		me = me->next;
198 	}
199 
200 	/*  Not found? Then just check ssubtype:  */
201 	me = first_machine_entry;
202 	while (me != NULL) {
203 		if (me->n_subtypes == 0) {
204 			me = me->next;
205 			continue;
206 		}
207 
208 		/*  Check for subtype:  */
209 		for (j=0; j<me->n_subtypes; j++)
210 			for (k=0; k<me->subtype[j]->n_aliases; k++)
211 				if (strcasecmp(ssubtype, me->subtype[j]->
212 				    aliases[k]) == 0) {
213 					*type = me->machine_type;
214 					*arch = me->arch;
215 					*subtype = me->subtype[j]->
216 					    machine_subtype;
217 					nmatches ++;
218 				}
219 
220 		me = me->next;
221 	}
222 
223 	switch (nmatches) {
224 	case 0:	fatal("\nSorry, emulation \"%s\"", stype);
225 		if (ssubtype != NULL && ssubtype[0] != '\0')
226 			fatal(" (subtype \"%s\")", ssubtype);
227 		fatal(" is unknown.\n");
228 		break;
229 	case 1:	return 1;
230 	default:fatal("\nSorry, multiple matches for \"%s\"", stype);
231 		if (ssubtype != NULL && ssubtype[0] != '\0')
232 			fatal(" (subtype \"%s\")", ssubtype);
233 		fatal(".\n");
234 	}
235 
236 	*type = MACHINE_NONE;
237 	*subtype = 0;
238 
239 	fatal("Use the -H command line option to get a list of "
240 	    "available types and subtypes.\n\n");
241 
242 	return 0;
243 }
244 
245 
246 /*
247  *  machine_add_breakpoint_string():
248  *
249  *  Add a breakpoint string to the machine. Later (in emul.c) these will be
250  *  converted to actual breakpoints.
251  */
machine_add_breakpoint_string(struct machine * machine,char * str)252 void machine_add_breakpoint_string(struct machine *machine, char *str)
253 {
254 	int n = machine->breakpoints.n + 1;
255 
256 	CHECK_ALLOCATION(machine->breakpoints.string = (char **)
257 	    realloc(machine->breakpoints.string, n * sizeof(char *)));
258 	CHECK_ALLOCATION(machine->breakpoints.addr = (uint64_t *)
259 	    realloc(machine->breakpoints.addr, n * sizeof(uint64_t)));
260 	CHECK_ALLOCATION(machine->breakpoints.string[machine->breakpoints.n] =
261 	    strdup(optarg));
262 
263 	machine->breakpoints.addr[machine->breakpoints.n] = 0;
264 	machine->breakpoints.n ++;
265 }
266 
267 
268 /*
269  *  machine_add_tickfunction():
270  *
271  *  Adds a tick function (a function called every now and then, depending on
272  *  clock cycle count) to a machine.
273  *
274  *  If tickshift is non-zero, a tick will occur every (1 << tickshift) cycles.
275  *  This is used for the normal (fast dyntrans) emulation modes.
276  *
277  *  If tickshift is zero, then this is a cycle-accurate tick function.
278  *  The hz value is used in this case.
279  */
machine_add_tickfunction(struct machine * machine,void (* func)(struct cpu *,void *),void * extra,int tickshift)280 void machine_add_tickfunction(struct machine *machine, void (*func)
281 	(struct cpu *, void *), void *extra, int tickshift)
282 {
283 	int n = machine->tick_functions.n_entries;
284 
285 	CHECK_ALLOCATION(machine->tick_functions.ticks_till_next = (int *) realloc(
286 	    machine->tick_functions.ticks_till_next, (n+1) * sizeof(int)));
287 	CHECK_ALLOCATION(machine->tick_functions.ticks_reset_value = (int *) realloc(
288 	    machine->tick_functions.ticks_reset_value, (n+1) * sizeof(int)));
289 	CHECK_ALLOCATION(machine->tick_functions.f = (void (**)(cpu*,void*)) realloc(
290 	    machine->tick_functions.f, (n+1) * sizeof(void *)));
291 	CHECK_ALLOCATION(machine->tick_functions.extra = (void **) realloc(
292 	    machine->tick_functions.extra, (n+1) * sizeof(void *)));
293 
294 	/*
295 	 *  The dyntrans subsystem wants to run code in relatively
296 	 *  large chunks without checking for external interrupts;
297 	 *  too low tickshifts are not allowed.
298 	 */
299 	if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) {
300 		fatal("ERROR! tickshift = %i, less than "
301 		    "N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n",
302 		    tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT);
303 		exit(1);
304 	}
305 
306 	machine->tick_functions.ticks_till_next[n]   = 0;
307 	machine->tick_functions.ticks_reset_value[n] = 1 << tickshift;
308 	machine->tick_functions.f[n]                 = func;
309 	machine->tick_functions.extra[n]             = extra;
310 
311 	machine->tick_functions.n_entries = n + 1;
312 }
313 
314 
315 /*
316  *  machine_statistics_init():
317  *
318  *  Initialize the parts of a machine struct that deal with instruction
319  *  statistics gathering.
320  *
321  *  Note: The fname argument contains "flags:filename".
322  */
machine_statistics_init(struct machine * machine,char * fname)323 void machine_statistics_init(struct machine *machine, char *fname)
324 {
325 	int n_fields = 0;
326 	char *pcolon = fname;
327 	const char *mode = "a";	/*  Append by default  */
328 
329 	machine->allow_instruction_combinations = 0;
330 
331 	if (machine->statistics.fields != NULL) {
332 		fprintf(stderr, "Only one -s option is allowed.\n");
333 		exit(1);
334 	}
335 
336 	machine->statistics.enabled = 1;
337 	CHECK_ALLOCATION(machine->statistics.fields = (char *) malloc(1));
338 	machine->statistics.fields[0] = '\0';
339 
340 	while (*pcolon && *pcolon != ':')
341 		pcolon ++;
342 
343 	if (*pcolon != ':') {
344 		fprintf(stderr, "The syntax for the -s option is:    "
345 		    "-s flags:filename\nYou omitted the flags. Run g"
346 		    "xemul -h for a list of available flags.\n");
347 		exit(1);
348 	}
349 
350 	while (*fname != ':') {
351 		switch (*fname) {
352 
353 		/*  Type flags:  */
354 		case 'v':
355 		case 'i':
356 		case 'p':
357 			CHECK_ALLOCATION(machine->statistics.fields = (char *) realloc(
358 			    machine->statistics.fields, strlen(
359 			    machine->statistics.fields) + 2));
360 			machine->statistics.fields[n_fields ++] = *fname;
361 			machine->statistics.fields[n_fields] = '\0';
362 			break;
363 
364 		/*  Optional flags:  */
365 		case 'o':
366 			mode = "w";
367 			break;
368 		case 'd':
369 			machine->statistics.enabled = 0;
370 			break;
371 
372 		default:fprintf(stderr, "Unknown flag '%c' used with the"
373 			    " -s option. Aborting.\n", *fname);
374 			exit(1);
375 		}
376 		fname ++;
377 	}
378 
379 	fname ++;	/*  point to the filename after the colon  */
380 
381 	CHECK_ALLOCATION(machine->statistics.filename = strdup(fname));
382 	machine->statistics.file = fopen(machine->statistics.filename, mode);
383 }
384 
385 
386 /*
387  *  machine_dumpinfo():
388  *
389  *  Dumps info about a machine in some kind of readable format. (Used by
390  *  the 'machine' debugger command.)
391  */
machine_dumpinfo(struct machine * m)392 void machine_dumpinfo(struct machine *m)
393 {
394 	int i;
395 
396 	debug("serial nr: %i", m->serial_nr);
397 	if (m->nr_of_nics > 0)
398 		debug("  (nr of NICs: %i)", m->nr_of_nics);
399 	debug("\n");
400 
401 	debug("memory: %i MB", m->physical_ram_in_mb);
402 	if (m->memory_offset_in_mb != 0)
403 		debug(" (offset by %i MB)", m->memory_offset_in_mb);
404 	if (m->random_mem_contents)
405 		debug(", randomized contents");
406 	debug("\n");
407 
408 	if (!m->prom_emulation)
409 		debug("PROM emulation disabled\n");
410 
411 	for (i=0; i<m->ncpus; i++)
412 		cpu_dumpinfo(m, m->cpus[i]);
413 
414 	if (m->ncpus > 1)
415 		debug("Bootstrap cpu is nr %i\n", m->bootstrap_cpu);
416 
417 	if (m->slow_serial_interrupts_hack_for_linux)
418 		debug("Using slow_serial_interrupts_hack_for_linux\n");
419 
420 	if (m->x11_md.in_use) {
421 		debug("Using X11");
422 		if (m->x11_md.scaledown > 1)
423 			debug(", scaledown %i", m->x11_md.scaledown);
424 		if (m->x11_md.scaleup > 1)
425 			debug(", scaleup %i", m->x11_md.scaleup);
426 		if (m->x11_md.n_display_names > 0) {
427 			for (i=0; i<m->x11_md.n_display_names; i++) {
428 				debug(i? ", " : " (");
429 				debug("\"%s\"", m->x11_md.display_names[i]);
430 			}
431 			debug(")");
432 		}
433 		debug("\n");
434 	}
435 
436 	diskimage_dump_info(m);
437 
438 	if (m->force_netboot)
439 		debug("Forced netboot\n");
440 }
441 
442 
443 /*
444  *  machine_setup():
445  *
446  *  This function initializes memory, registers, and/or devices
447  *  required by specific machine emulations.
448  */
machine_setup(struct machine * machine)449 void machine_setup(struct machine *machine)
450 {
451 	struct machine_entry *me;
452 	struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
453 
454 	machine->bootdev_id = diskimage_bootdev(machine, &machine->bootdev_type);
455 	machine->machine_name = NULL;
456 
457 	/*  TODO: Move this somewhere else?  */
458 	if (machine->boot_string_argument == NULL) {
459 		switch (machine->machine_type) {
460 		case MACHINE_ARC:
461 			machine->boot_string_argument = strdup("-aN");
462 			break;
463 		case MACHINE_CATS:
464 			machine->boot_string_argument = strdup("-A");
465 			break;
466 		case MACHINE_PMAX:
467 			machine->boot_string_argument = strdup("-a");
468 			break;
469 		default:
470 			/*  Important, because boot_string_argument should
471 			    not be set to NULL:  */
472 			machine->boot_string_argument = strdup("");
473 		}
474 	}
475 
476 
477 	/*
478 	 *  If the machine has a setup function in src/machines/machine_*.c
479 	 *  then use that one, otherwise use the old hardcoded stuff here:
480 	 */
481 
482 	me = first_machine_entry;
483 	while (me != NULL) {
484 		if (machine->machine_type == me->machine_type &&
485 		    me->setup != NULL) {
486 			me->setup(machine, cpu);
487 			break;
488 		}
489 		me = me->next;
490 	}
491 
492 	if (me == NULL) {
493 		fatal("Unknown emulation type %i\n", machine->machine_type);
494 		exit(1);
495 	}
496 
497 	if (machine->machine_name != NULL)
498 		debug("machine: %s", machine->machine_name);
499 
500 	if (machine->emulated_hz > 0)
501 		debug(" (%.2f MHz)", (float)machine->emulated_hz / 1000000);
502 	debug("\n");
503 
504 	if (machine->bootstr != NULL) {
505 		debug("bootstring%s: %s", (machine->bootarg!=NULL &&
506 		    strlen(machine->bootarg) >= 1)? "(+bootarg)" : "",
507 		    machine->bootstr);
508 		if (machine->bootarg != NULL && strlen(machine->bootarg) >= 1)
509 			debug(" %s", machine->bootarg);
510 		debug("\n");
511 	}
512 }
513 
514 
515 /*
516  *  machine_memsize_fix():
517  *
518  *  Sets physical_ram_in_mb (if not already set), and memory_offset_in_mb,
519  *  depending on machine type.
520  */
machine_memsize_fix(struct machine * m)521 void machine_memsize_fix(struct machine *m)
522 {
523 	if (m == NULL) {
524 		fatal("machine_defaultmemsize(): m == NULL?\n");
525 		exit(1);
526 	}
527 
528 	if (m->physical_ram_in_mb == 0) {
529 		struct machine_entry *me = first_machine_entry;
530 		while (me != NULL) {
531 			if (m->machine_type == me->machine_type &&
532 			    me->set_default_ram != NULL) {
533 				me->set_default_ram(m);
534 				break;
535 			}
536 			me = me->next;
537 		}
538 	}
539 
540 	/*  Special SGI memory offsets:  (TODO: move this somewhere else)  */
541 	if (m->machine_type == MACHINE_SGI) {
542 		switch (m->machine_subtype) {
543 		case 20:
544 		case 22:
545 		case 24:
546 		case 26:
547 			m->memory_offset_in_mb = 128;
548 			break;
549 		case 28:
550 		case 30:
551 			m->memory_offset_in_mb = 512;
552 			break;
553 		}
554 	}
555 
556 	if (m->physical_ram_in_mb == 0)
557 		m->physical_ram_in_mb = DEFAULT_RAM_IN_MB;
558 }
559 
560 
561 /*
562  *  machine_default_cputype():
563  *
564  *  Sets m->cpu_name, if it isn't already set, depending on the machine type.
565  */
machine_default_cputype(struct machine * m)566 void machine_default_cputype(struct machine *m)
567 {
568 	struct machine_entry *me;
569 
570 	if (m == NULL) {
571 		fatal("machine_default_cputype(): m == NULL?\n");
572 		exit(1);
573 	}
574 
575 	/*  Already set? Then return.  */
576 	if (m->cpu_name != NULL)
577 		return;
578 
579 	me = first_machine_entry;
580 	while (me != NULL) {
581 		if (m->machine_type == me->machine_type &&
582 		    me->set_default_cpu != NULL) {
583 			me->set_default_cpu(m);
584 			break;
585 		}
586 		me = me->next;
587 	}
588 
589 	if (m->cpu_name == NULL) {
590 		fprintf(stderr, "machine_default_cputype(): no default"
591 		    " cpu for machine type %i subtype %i\n",
592 		    m->machine_type, m->machine_subtype);
593 		exit(1);
594 	}
595 }
596 
597 
598 /*****************************************************************************/
599 
600 
601 /*
602  *  machine_run():
603  *
604  *  Run one or more instructions on all CPUs in this machine. (Usually,
605  *  around N_SAFE_DYNTRANS_LIMIT instructions will be run by the dyntrans
606  *  system.)
607  *
608  *  Return value is 1 if any CPU in this machine is still running,
609  *  or 0 if all CPUs are stopped.
610  */
machine_run(struct machine * machine)611 int machine_run(struct machine *machine)
612 {
613 	struct cpu **cpus = machine->cpus;
614 	int ncpus = machine->ncpus, cpu0instrs = 0, i, te;
615 
616 	for (i=0; i<ncpus; i++) {
617 		if (cpus[i]->running) {
618 			int instrs_run = cpus[i]->run_instr(cpus[i]);
619 			if (i == 0)
620 				cpu0instrs += instrs_run;
621 		}
622 	}
623 
624 	/*
625 	 *  Hardware 'ticks':  (clocks, interrupt sources...)
626 	 *
627 	 *  Here, cpu0instrs is the number of instructions executed on cpu0.
628 	 *
629 	 *  TODO: This should be redesigned into some "mainbus" stuff instead!
630 	 */
631 
632 	for (te=0; te<machine->tick_functions.n_entries; te++) {
633 		machine->tick_functions.ticks_till_next[te] -= cpu0instrs;
634 		if (machine->tick_functions.ticks_till_next[te] <= 0) {
635 			while (machine->tick_functions.ticks_till_next[te]<=0) {
636 				machine->tick_functions.ticks_till_next[te] +=
637 				    machine->tick_functions.
638 				    ticks_reset_value[te];
639 			}
640 
641 			machine->tick_functions.f[te](cpus[0],
642 			    machine->tick_functions.extra[te]);
643 		}
644 	}
645 
646 	/*  Is any CPU still alive?  */
647 	for (i=0; i<ncpus; i++)
648 		if (cpus[i]->running)
649 			return 1;
650 
651 	return 0;
652 }
653 
654 
655 /*****************************************************************************/
656 
657 
658 /*
659  *  machine_entry_new():
660  *
661  *  This function creates a new machine_entry struct, and fills it with some
662  *  valid data; it is up to the caller to add additional data that weren't
663  *  passed as arguments to this function, such as alias names and machine
664  *  subtypes.
665  */
machine_entry_new(const char * name,int arch,int oldstyle_type)666 struct machine_entry *machine_entry_new(const char *name, int arch,
667 	int oldstyle_type)
668 {
669 	struct machine_entry *me;
670 
671 	CHECK_ALLOCATION(me = (struct machine_entry *) malloc(sizeof(struct machine_entry)));
672 	memset(me, 0, sizeof(struct machine_entry));
673 
674 	me->name = name;
675 	me->arch = arch;
676 	me->machine_type = oldstyle_type;
677 	me->n_aliases = 0;
678 	me->aliases = NULL;
679 	me->n_subtypes = 0;
680 	me->setup = NULL;
681 
682 	return me;
683 }
684 
685 
686 /*
687  *  machine_entry_add_alias():
688  *
689  *  This function adds an "alias" to a machine entry.
690  */
machine_entry_add_alias(struct machine_entry * me,const char * name)691 void machine_entry_add_alias(struct machine_entry *me, const char *name)
692 {
693 	me->n_aliases ++;
694 
695 	CHECK_ALLOCATION(me->aliases = (char **) realloc(me->aliases,
696 	    sizeof(char *) * me->n_aliases));
697 
698 	me->aliases[me->n_aliases - 1] = strdup(name);
699 }
700 
701 
702 /*
703  *  machine_entry_add_subtype():
704  *
705  *  This function adds a subtype to a machine entry. The argument list after
706  *  oldstyle_subtype is a list of one or more char *, followed by NULL. E.g.:
707  *
708  *	machine_entry_add_subtype(me, "Machine X", MACHINE_X,
709  *	    "machine-x", "x", NULL);
710  */
machine_entry_add_subtype(struct machine_entry * me,const char * name,int oldstyle_subtype,...)711 void machine_entry_add_subtype(struct machine_entry *me, const char *name,
712 	int oldstyle_subtype, ...)
713 {
714 	va_list argp;
715 	struct machine_entry_subtype *mes;
716 
717 	/*  Allocate a new subtype struct:  */
718 	CHECK_ALLOCATION(mes = (struct machine_entry_subtype *)
719 	    malloc(sizeof(struct machine_entry_subtype)));
720 
721 	/*  Add the subtype to the machine entry:  */
722 	me->n_subtypes ++;
723 	CHECK_ALLOCATION(me->subtype = (struct
724 	    machine_entry_subtype **) realloc(me->subtype, sizeof(struct
725 	    machine_entry_subtype *) * me->n_subtypes));
726 	me->subtype[me->n_subtypes - 1] = mes;
727 
728 	/*  Fill the struct with subtype data:  */
729 	memset(mes, 0, sizeof(struct machine_entry_subtype));
730 	mes->name = name;
731 	mes->machine_subtype = oldstyle_subtype;
732 
733 	/*  ... and all aliases:  */
734 	mes->n_aliases = 0;
735 	mes->aliases = NULL;
736 
737 	va_start(argp, oldstyle_subtype);
738 
739 	for (;;) {
740 		char *s = va_arg(argp, char *);
741 		if (s == NULL)
742 			break;
743 
744 		mes->n_aliases ++;
745 		CHECK_ALLOCATION(mes->aliases = (char **)
746 		    realloc(mes->aliases, sizeof(char *) * mes->n_aliases));
747 
748 		mes->aliases[mes->n_aliases - 1] = s;
749 	}
750 
751 	va_end(argp);
752 }
753 
754 
755 /*
756  *  machine_entry_register():
757  *
758  *  Inserts a new machine_entry into the machine entries list.
759  */
machine_entry_register(struct machine_entry * me,int arch)760 void machine_entry_register(struct machine_entry *me, int arch)
761 {
762 	struct machine_entry *prev, *next;
763 
764 	/*  Only insert it if the architecture is implemented in this
765 	    emulator configuration:  */
766 	if (cpu_family_ptr_by_number(arch) == NULL)
767 		return;
768 
769 	prev = NULL;
770 	next = first_machine_entry;
771 
772 	for (;;) {
773 		if (next == NULL)
774 			break;
775 		if (strcasecmp(me->name, next->name) < 0)
776 			break;
777 
778 		prev = next;
779 		next = next->next;
780 	}
781 
782 	if (prev != NULL)
783 		prev->next = me;
784 	else
785 		first_machine_entry = me;
786 	me->next = next;
787 }
788 
789 
790 /*
791  *  machine_list_available_types_and_cpus():
792  *
793  *  List all available machine types (for example when running the emulator
794  *  with just -H as command line argument).
795  */
machine_list_available_types_and_cpus(void)796 void machine_list_available_types_and_cpus(void)
797 {
798 	struct machine_entry *me;
799 	int iadd = DEBUG_INDENTATION * 2;
800 
801 	debug("Available CPU types:\n\n");
802 
803 	debug_indentation(iadd);
804 	cpu_list_available_types();
805 	debug_indentation(-iadd);
806 
807 	debug("\nMost of the CPU types are bogus, and not really implemented."
808 	    " The main effect of\nselecting a specific CPU type is to choose "
809 	    "what kind of 'id' it will have.\n\nAvailable machine types (with "
810 	    "aliases) and their subtypes:\n\n");
811 
812 	debug_indentation(iadd);
813 	me = first_machine_entry;
814 
815 	if (me == NULL)
816 		fatal("No machines defined!\n");
817 
818 	while (me != NULL) {
819 		int i, j, iadd2 = DEBUG_INDENTATION;
820 
821 		debug("%s [%s] (", me->name,
822 		    cpu_family_ptr_by_number(me->arch)->name);
823 		for (i=0; i<me->n_aliases; i++)
824 			debug("%s\"%s\"", i? ", " : "", me->aliases[i]);
825 		debug(")\n");
826 
827 		debug_indentation(iadd2);
828 		for (i=0; i<me->n_subtypes; i++) {
829 			struct machine_entry_subtype *mes;
830 			mes = me->subtype[i];
831 			debug("- %s", mes->name);
832 			debug(" (");
833 			for (j=0; j<mes->n_aliases; j++)
834 				debug("%s\"%s\"", j? ", " : "",
835 				    mes->aliases[j]);
836 			debug(")\n");
837 		}
838 		debug_indentation(-iadd2);
839 
840 		me = me->next;
841 	}
842 	debug_indentation(-iadd);
843 
844 	debug("\nMost of the machine types are bogus too. Please read the "
845 	    "GXemul documentation\nfor information about which machine types "
846 	    "that actually work. Use the alias\nwhen selecting a machine type "
847 	    "or subtype, not the real name.\n");
848 
849 	debug("\n");
850 }
851 
852 
853 /*
854  *  machine_init():
855  *
856  *  This function should be called before any other machine_*() function
857  *  is used.  automachine_init() registers all machines in src/machines/.
858  */
machine_init(void)859 void machine_init(void)
860 {
861 	if (first_machine_entry != NULL) {
862 		fatal("machine_init(): already called?\n");
863 		exit(1);
864 	}
865 
866 	automachine_init();
867 }
868 
869