+ 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 ($disk) = $disks_by_iface[$iface];
+ my ($file) = $disk->{FILE_NAME};
+ if (defined $file) {
+ my (%geom) = disk_geometry ($disk);
+ 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]{FILE_NAME})
+ if defined $disks_by_iface[$iface]{FILE_NAME};
+ }
+ 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";
+}
+
+# Runs VMware GSX Server.
+sub run_gsx {
+ gsx_unsup ("--$debug") if $debug ne 'none';
+ gsx_unsup ("--no-vga") if $vga eq 'none';
+ gsx_unsup ("--terminal") if $vga eq 'terminal';
+ gsx_unsup ("--jitter") if defined $jitter;
+
+ unlink ("pintos.out");
+
+ open (VMX, ">", "pintos.vmx") or die "pintos.vmx: create: $!\n";
+ chmod 0777 & ~umask, "pintos.vmx";
+ print VMX <<EOF;
+#! /usr/bin/vmware -G
+config.version = 6
+guestOS = "linux"
+floppy0.present = FALSE
+memsize = $mem
+
+serial0.present = TRUE
+serial0.fileType = "file"
+serial0.fileName = "pintos.out"
+EOF
+
+ for (my ($i) = 0; $i < 4; $i++) {
+ my ($disk) = $disks_by_iface[$i];
+ my ($dsk) = $disk->{FILE_NAME};
+ next if !defined $dsk;
+
+ my ($pln) = $dsk;
+ $pln =~ s/\.dsk//;
+ $pln .= ".pln";
+
+ my ($device) = "ide" . int ($i / 2) . ":" . ($i % 2);
+ print VMX <<EOF;
+
+$device.present = TRUE
+$device.deviceType = "plainDisk"
+$device.fileName = "$pln"
+EOF
+
+ my (%geom) = disk_geometry ($disk);
+ open (PLN, ">", $pln) or die "$pln: create: $!\n";
+ print PLN <<EOF;
+DRIVETYPE ide
+#vm|VERSION 2
+#vm|TOOLSVERSION 2
+CYLINDERS $geom{C}
+HEADS $geom{H}
+SECTORS $geom{S}
+#vm|CAPACITY $geom{CAPACITY}
+ACCESS "$dsk" 0 $geom{CAPACITY}
+EOF
+ close (PLN);
+ }
+ close (VMX);
+
+ my ($vmx) = getcwd () . "/pintos.vmx";
+ system ("vmware-cmd -s register $vmx >&/dev/null");
+ system ("vmware-cmd $vmx stop hard >&/dev/null");
+ system ("vmware -l -G -x -q $vmx");
+ system ("vmware-cmd $vmx stop hard >&/dev/null");
+ system ("vmware-cmd -s unregister $vmx >&/dev/null");
+}
+\f
+# Disk utilities.
+
+# open_disk($disk)
+#
+# Opens $disk, if it is not already open, and returns its file handle
+# and file name.
+sub open_disk {
+ my ($disk) = @_;
+ if (!defined ($disk->{HANDLE})) {
+ if ($disk->{FILE_NAME}) {
+ sysopen ($disk->{HANDLE}, $disk->{FILE_NAME}, O_RDWR)
+ or die "$disk->{FILE_NAME}: open: $!\n";
+ } else {
+ ($disk->{HANDLE}, $disk->{FILE_NAME}) = tempfile (UNLINK => 1,
+ SUFFIX => '.dsk');
+ }
+ }
+ return ($disk->{HANDLE}, $disk->{FILE_NAME});