+# Runs Bochs.
+sub run_bochs {
+ # Select Bochs binary based on the chosen debugger.
+ my ($bin);
+ if ($debug eq 'none') {
+ $bin = 'bochs';
+ } elsif ($debug eq 'monitor') {
+ $bin = 'bochs-dbg';
+ } elsif ($debug eq 'gdb') {
+ $bin = 'bochs-gdb';
+ }
+
+ # Write bochsrc.txt configuration file.
+ open (BOCHSRC, ">", "bochsrc.txt") or die "bochsrc.txt: create: $!\n";
+ print BOCHSRC <<EOF;
+romimage: file=\$BXSHARE/BIOS-bochs-latest, address=0xf0000
+vgaromimage: \$BXSHARE/VGABIOS-lgpl-latest
+boot: c
+ips: 1000000
+megs: $mem
+log: bochsout.txt
+EOF
+ print BOCHSRC "clock: sync=", $realtime ? 'realtime' : 'none', "time0=0\n";
+ print_bochs_disk_line ("ata0-master", 0);
+ print_bochs_disk_line ("ata0-slave", 1);
+ if (defined ($disks_by_iface[2]{FILENAME})
+ || defined ($disks_by_iface[3]{FILENAME})) {
+ print BOCHSRC "ata1: enabled=1, ioaddr1=0x170, ",
+ "ioaddr2=0x370, irq=15\n";
+ print_bochs_disk_line ("ata1-master", 2);
+ print_bochs_disk_line ("ata1-slave", 3);
+ }
+ if ($vga ne 'terminal') {
+ print BOCHSRC "com1: enabled=1, dev=/dev/stdout\n" if $serial_out;
+ print BOCHSRC "display_library: nogui\n" if $vga eq 'none';
+ } else {
+ print BOCHSRC "display_library: term\n";
+ }
+ close (BOCHSRC);
+
+ # Compose Bochs command line.
+ my (@cmd) = ($bin, '-q');
+ push (@cmd, '-j', $jitter) if defined $jitter;
+
+ # Run Bochs.
+ print join (' ', @cmd), "\n";
+ my ($exit) = xsystem (@cmd);
+ if (WIFEXITED ($exit)) {
+ # Bochs exited normally.
+ # Ignore the exit code; Bochs normally exits with status 1,
+ # which is weird.
+ } elsif (WIFSIGNALED ($exit)) {
+ die "Bochs died with signal ", WTERMSIG ($exit), "\n";
+ } else {
+ die "Bochs died: code $exit\n";
+ }
+}
+
+# print_bochs_disk_line($device, $iface)
+#
+# If IDE interface $iface has a disk attached, prints a bochsrc.txt
+# line for attaching it to $device.
+sub print_bochs_disk_line {
+ my ($device, $iface) = @_;
+ my ($file) = $disks_by_iface[$iface]{FILENAME};
+ if (defined $file) {
+ my (%geom) = disk_geometry ($file);
+ print BOCHSRC "$device: type=disk, path=$file, mode=flat, ";
+ print BOCHSRC "cylinders=$geom{C}, heads=$geom{H}, spt=$geom{S}, ";
+ print BOCHSRC "translation=none\n";
+ }
+}
+
+# Runs qemu.
+sub run_qemu {
+ print "warning: qemu doesn't support --terminal\n"
+ if $vga eq 'terminal';
+ print "warning: qemu doesn't support jitter\n"
+ if defined $jitter;
+ my (@cmd) = ('qemu');
+ for my $iface (0...3) {
+ my ($option) = ('-hda', '-hdb', '-hdc', '-hdd')[$iface];
+ push (@cmd, $option, $disks_by_iface[$iface]{FILENAME})
+ if defined $disks_by_iface[$iface]{FILENAME};
+ }
+ push (@cmd, '-m', $mem);
+ push (@cmd, '-nographic') if $vga eq 'none';
+ push (@cmd, '-serial', 'stdio') if $serial_out && $vga ne 'none';
+ push (@cmd, '-S') if $debug eq 'monitor';
+ push (@cmd, '-s', '-S') if $debug eq 'gdb';
+ push (@cmd, '-monitor', 'null') if $vga eq 'none' && $debug eq 'none';
+ run_command (@cmd);
+}
+
+# gsx_unsup($flag)
+#
+# Prints a message that $flag is unsupported by GSX Server.
+sub gsx_unsup {
+ my ($flag) = @_;
+ print "warning: no support for $flag with VMware GSX Server\n";