25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: emul.c,v 1.255 2006/06/24 19:52:27 debug Exp $ |
* $Id: emul.c,v 1.272 2006/10/31 08:26:56 debug Exp $ |
29 |
* |
* |
30 |
* Emulation startup and misc. routines. |
* Emulation startup and misc. routines. |
31 |
*/ |
*/ |
51 |
#include "mips_cpu_types.h" |
#include "mips_cpu_types.h" |
52 |
#include "misc.h" |
#include "misc.h" |
53 |
#include "net.h" |
#include "net.h" |
54 |
|
#include "settings.h" |
55 |
#include "sgi_arcbios.h" |
#include "sgi_arcbios.h" |
56 |
|
#include "timer.h" |
57 |
#include "x11.h" |
#include "x11.h" |
58 |
|
|
59 |
|
|
146 |
*/ |
*/ |
147 |
static void fix_console(void) |
static void fix_console(void) |
148 |
{ |
{ |
149 |
console_deinit(); |
console_deinit_main(); |
150 |
} |
} |
151 |
|
|
152 |
|
|
565 |
|
|
566 |
/* Convert loadaddr to uncached: */ |
/* Convert loadaddr to uncached: */ |
567 |
if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 && |
if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 && |
568 |
(bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000) |
(bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000) { |
569 |
fatal("\nWARNING! Weird load address 0x%08x.\n\n", |
fatal("\nWARNING! Weird load address 0x%08"PRIx32 |
570 |
(int)bootblock_loadaddr); |
" for SCSI id %i.\n\n", |
571 |
|
(uint32_t)bootblock_loadaddr, boot_disk_id); |
572 |
|
if (bootblock_loadaddr == 0) { |
573 |
|
fatal("I'm assuming that this is _not_ a " |
574 |
|
"DEC bootblock.\nAre you sure you are" |
575 |
|
" booting from the correct disk?\n"); |
576 |
|
exit(1); |
577 |
|
} |
578 |
|
} |
579 |
|
|
580 |
bootblock_loadaddr &= 0x0fffffffULL; |
bootblock_loadaddr &= 0x0fffffffULL; |
581 |
bootblock_loadaddr |= 0xffffffffa0000000ULL; |
bootblock_loadaddr |= 0xffffffffa0000000ULL; |
582 |
|
|
701 |
iso_type = 3; |
iso_type = 3; |
702 |
|
|
703 |
if (iso_type != 0) { |
if (iso_type != 0) { |
704 |
/* We can't load a kernel if the name |
/* |
705 |
isn't specified. */ |
* If the user specified a kernel name, then load it from |
706 |
|
* disk. |
707 |
|
*/ |
708 |
if (cpu->machine->boot_kernel_filename == NULL || |
if (cpu->machine->boot_kernel_filename == NULL || |
709 |
cpu->machine->boot_kernel_filename[0] == '\0') |
cpu->machine->boot_kernel_filename[0] == '\0') |
710 |
fatal("\nISO9660 filesystem, but no kernel " |
fatal("\nISO9660 filesystem, but no kernel " |
727 |
} |
} |
728 |
if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' && |
if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' && |
729 |
bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') { |
bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') { |
|
/* We can't load a kernel if the name |
|
|
isn't specified. */ |
|
730 |
if (cpu->machine->boot_kernel_filename == NULL || |
if (cpu->machine->boot_kernel_filename == NULL || |
731 |
cpu->machine->boot_kernel_filename[0] == '\0') |
cpu->machine->boot_kernel_filename[0] == '\0') |
732 |
fatal("\nApple partition table, but no kernel " |
fatal("\nApple partition table, but no kernel " |
758 |
|
|
759 |
memset(e, 0, sizeof(struct emul)); |
memset(e, 0, sizeof(struct emul)); |
760 |
|
|
761 |
|
e->settings = settings_new(); |
762 |
|
|
763 |
|
settings_add(e->settings, "n_machines", 0, |
764 |
|
SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL, |
765 |
|
(void *) &e->n_machines); |
766 |
|
|
767 |
|
/* TODO: More settings? */ |
768 |
|
|
769 |
/* Sane default values: */ |
/* Sane default values: */ |
770 |
e->n_machines = 0; |
e->n_machines = 0; |
771 |
e->next_serial_nr = 1; |
e->next_serial_nr = 1; |
776 |
fprintf(stderr, "out of memory in emul_new()\n"); |
fprintf(stderr, "out of memory in emul_new()\n"); |
777 |
exit(1); |
exit(1); |
778 |
} |
} |
779 |
|
|
780 |
|
settings_add(e->settings, "name", 0, |
781 |
|
SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING, |
782 |
|
(void *) &e->name); |
783 |
} |
} |
784 |
|
|
785 |
return e; |
return e; |
787 |
|
|
788 |
|
|
789 |
/* |
/* |
790 |
|
* emul_destroy(): |
791 |
|
* |
792 |
|
* Destroys a previously created emul object. |
793 |
|
*/ |
794 |
|
void emul_destroy(struct emul *emul) |
795 |
|
{ |
796 |
|
int i; |
797 |
|
|
798 |
|
if (emul->name != NULL) { |
799 |
|
settings_remove(emul->settings, "name"); |
800 |
|
free(emul->name); |
801 |
|
} |
802 |
|
|
803 |
|
for (i=0; i<emul->n_machines; i++) |
804 |
|
machine_destroy(emul->machines[i]); |
805 |
|
|
806 |
|
if (emul->machines != NULL) |
807 |
|
free(emul->machines); |
808 |
|
|
809 |
|
/* Remove any remaining level-1 settings: */ |
810 |
|
settings_remove_all(emul->settings); |
811 |
|
settings_destroy(emul->settings); |
812 |
|
|
813 |
|
free(emul); |
814 |
|
} |
815 |
|
|
816 |
|
|
817 |
|
/* |
818 |
* emul_add_machine(): |
* emul_add_machine(): |
819 |
* |
* |
820 |
* Calls machine_new(), adds the new machine into the emul struct, and |
* Calls machine_new(), adds the new machine into the emul struct, and |
825 |
struct machine *emul_add_machine(struct emul *e, char *name) |
struct machine *emul_add_machine(struct emul *e, char *name) |
826 |
{ |
{ |
827 |
struct machine *m; |
struct machine *m; |
828 |
|
char tmpstr[20]; |
829 |
|
int i; |
830 |
|
|
831 |
m = machine_new(name, e); |
m = machine_new(name, e); |
832 |
m->serial_nr = (e->next_serial_nr ++); |
m->serial_nr = (e->next_serial_nr ++); |
833 |
|
|
834 |
|
i = e->n_machines; |
835 |
|
|
836 |
e->n_machines ++; |
e->n_machines ++; |
837 |
e->machines = realloc(e->machines, |
e->machines = realloc(e->machines, |
838 |
sizeof(struct machine *) * e->n_machines); |
sizeof(struct machine *) * e->n_machines); |
841 |
exit(1); |
exit(1); |
842 |
} |
} |
843 |
|
|
844 |
e->machines[e->n_machines - 1] = m; |
e->machines[i] = m; |
845 |
|
|
846 |
|
snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i); |
847 |
|
settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0, |
848 |
|
e->machines[i]->settings); |
849 |
|
|
850 |
return m; |
return m; |
851 |
} |
} |
852 |
|
|
1297 |
} |
} |
1298 |
break; |
break; |
1299 |
|
|
1300 |
|
case ARCH_AVR32: |
1301 |
|
cpu->pc = (uint32_t) cpu->pc; |
1302 |
|
if (cpu->pc & 1) { |
1303 |
|
fatal("AVR32: lowest bit of pc set: TODO\n"); |
1304 |
|
exit(1); |
1305 |
|
} |
1306 |
|
break; |
1307 |
|
|
1308 |
|
case ARCH_RCA180X: |
1309 |
|
cpu->pc &= 0xffff; |
1310 |
|
break; |
1311 |
|
|
1312 |
case ARCH_HPPA: |
case ARCH_HPPA: |
1313 |
break; |
break; |
1314 |
|
|
1343 |
break; |
break; |
1344 |
|
|
1345 |
case ARCH_SH: |
case ARCH_SH: |
1346 |
if (cpu->cd.sh.bits == 32) |
if (cpu->cd.sh.cpu_type.bits == 32) |
1347 |
cpu->pc &= 0xffffffffULL; |
cpu->pc &= 0xffffffffULL; |
1348 |
cpu->pc &= ~1; |
cpu->pc &= ~1; |
1349 |
break; |
break; |
1351 |
case ARCH_SPARC: |
case ARCH_SPARC: |
1352 |
break; |
break; |
1353 |
|
|
1354 |
|
case ARCH_TRANSPUTER: |
1355 |
|
cpu->pc &= 0xffffffffULL; |
1356 |
|
break; |
1357 |
|
|
1358 |
case ARCH_X86: |
case ARCH_X86: |
1359 |
/* |
/* |
1360 |
* NOTE: The toc field is used to indicate an ELF32 |
* NOTE: The toc field is used to indicate an ELF32 |
1408 |
useremul_setup(cpu, n_load, load_names); |
useremul_setup(cpu, n_load, load_names); |
1409 |
|
|
1410 |
/* Startup the bootstrap CPU: */ |
/* Startup the bootstrap CPU: */ |
1411 |
cpu->bootstrap_cpu_flag = 1; |
cpu->running = 1; |
|
cpu->running = 1; |
|
1412 |
|
|
1413 |
/* ... or pause all CPUs, if start_paused is set: */ |
/* ... or pause all CPUs, if start_paused is set: */ |
1414 |
if (m->start_paused) { |
if (m->start_paused) { |
1538 |
|
|
1539 |
/* Create a simple network: */ |
/* Create a simple network: */ |
1540 |
emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY, |
emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY, |
1541 |
"10.0.0.0", 8, NULL, 0, 0); |
NET_DEFAULT_IPV4_MASK, |
1542 |
|
NET_DEFAULT_IPV4_LEN, |
1543 |
|
NULL, 0, 0, NULL); |
1544 |
} else { |
} else { |
1545 |
/* Userland pseudo-machine: */ |
/* Userland pseudo-machine: */ |
1546 |
debug("Syscall emulation (userland-only) setup...\n"); |
debug("Syscall emulation (userland-only) setup...\n"); |
1649 |
cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0], |
cpu_functioncall_trace(emuls[0]->machines[0]->cpus[0], |
1650 |
emuls[0]->machines[0]->cpus[0]->pc); |
emuls[0]->machines[0]->cpus[0]->pc); |
1651 |
|
|
1652 |
|
/* Start emulated clocks: */ |
1653 |
|
timer_start(); |
1654 |
|
|
1655 |
/* |
/* |
1656 |
* MAIN LOOP: |
* MAIN LOOP: |
1657 |
* |
* |
1662 |
go = 0; |
go = 0; |
1663 |
|
|
1664 |
/* Flush X11 and serial console output every now and then: */ |
/* Flush X11 and serial console output every now and then: */ |
1665 |
if (emuls[0]->machines[0]->ncycles > |
if (emuls[0]->machines[0]->ninstrs > |
1666 |
emuls[0]->machines[0]->ncycles_flush + (1<<18)) { |
emuls[0]->machines[0]->ninstrs_flush + (1<<19)) { |
1667 |
x11_check_event(emuls, n_emuls); |
x11_check_event(emuls, n_emuls); |
1668 |
console_flush(); |
console_flush(); |
1669 |
emuls[0]->machines[0]->ncycles_flush = |
emuls[0]->machines[0]->ninstrs_flush = |
1670 |
emuls[0]->machines[0]->ncycles; |
emuls[0]->machines[0]->ninstrs; |
1671 |
} |
} |
1672 |
|
|
1673 |
if (emuls[0]->machines[0]->ncycles > |
if (emuls[0]->machines[0]->ninstrs > |
1674 |
emuls[0]->machines[0]->ncycles_show + (1<<25)) { |
emuls[0]->machines[0]->ninstrs_show + (1<<25)) { |
1675 |
emuls[0]->machines[0]->ncycles_since_gettimeofday += |
emuls[0]->machines[0]->ninstrs_since_gettimeofday += |
1676 |
(emuls[0]->machines[0]->ncycles - |
(emuls[0]->machines[0]->ninstrs - |
1677 |
emuls[0]->machines[0]->ncycles_show); |
emuls[0]->machines[0]->ninstrs_show); |
1678 |
cpu_show_cycles(emuls[0]->machines[0], 0); |
cpu_show_cycles(emuls[0]->machines[0], 0); |
1679 |
emuls[0]->machines[0]->ncycles_show = |
emuls[0]->machines[0]->ninstrs_show = |
1680 |
emuls[0]->machines[0]->ncycles; |
emuls[0]->machines[0]->ninstrs; |
1681 |
} |
} |
1682 |
|
|
1683 |
if (single_step == ENTER_SINGLE_STEPPING) { |
if (single_step == ENTER_SINGLE_STEPPING) { |
1696 |
if (single_step == SINGLE_STEPPING) |
if (single_step == SINGLE_STEPPING) |
1697 |
debugger(); |
debugger(); |
1698 |
|
|
1699 |
e = emuls[0]; /* Note: Only 1 emul supported now. */ |
for (i=0; i<n_emuls; i++) { |
1700 |
|
e = emuls[i]; |
1701 |
|
|
1702 |
for (j=0; j<e->n_machines; j++) { |
for (j=0; j<e->n_machines; j++) { |
1703 |
if (e->machines[j]->gdb.port > 0) |
if (e->machines[j]->gdb.port > 0) |
1704 |
debugger_gdb_check_incoming(e->machines[j]); |
debugger_gdb_check_incoming( |
1705 |
|
e->machines[j]); |
1706 |
anything = machine_run(e->machines[j]); |
|
1707 |
if (anything) |
anything = machine_run(e->machines[j]); |
1708 |
go = 1; |
if (anything) |
1709 |
|
go = 1; |
1710 |
|
} |
1711 |
} |
} |
1712 |
} |
} |
1713 |
|
|
1714 |
|
/* Stop any running timers: */ |
1715 |
|
timer_stop(); |
1716 |
|
|
1717 |
/* Deinitialize all CPUs in all machines in all emulations: */ |
/* Deinitialize all CPUs in all machines in all emulations: */ |
1718 |
for (i=0; i<n_emuls; i++) { |
for (i=0; i<n_emuls; i++) { |
1719 |
e = emuls[i]; |
e = emuls[i]; |
1730 |
debugger(); |
debugger(); |
1731 |
} |
} |
1732 |
|
|
1733 |
/* Any machine using X11? Then we should wait before exiting: */ |
/* Any machine using X11? Then wait before exiting: */ |
1734 |
n = 0; |
n = 0; |
1735 |
for (i=0; i<n_emuls; i++) |
for (i=0; i<n_emuls; i++) |
1736 |
for (j=0; j<emuls[i]->n_machines; j++) |
for (j=0; j<emuls[i]->n_machines; j++) |
1740 |
printf("Press enter to quit.\n"); |
printf("Press enter to quit.\n"); |
1741 |
while (!console_charavail(MAIN_CONSOLE)) { |
while (!console_charavail(MAIN_CONSOLE)) { |
1742 |
x11_check_event(emuls, n_emuls); |
x11_check_event(emuls, n_emuls); |
1743 |
usleep(1); |
usleep(10000); |
1744 |
} |
} |
1745 |
console_readchar(MAIN_CONSOLE); |
console_readchar(MAIN_CONSOLE); |
1746 |
} |
} |
1747 |
|
|
1748 |
console_deinit(); |
console_deinit_main(); |
1749 |
} |
} |
1750 |
|
|