#! /usr/bin/perl
-$sim = "bochs";
-$debug = "";
$mem = 4;
-$headless = 0;
+$serial_out = 1;
while (@ARGV) {
my ($arg) = shift (@ARGV);
- if ($arg =~ /--(bochs|qemu|vmware)$/) {
+ if ($arg =~ /--(bochs|qemu|gsx)$/) {
+ die "$arg conflicts with --$sim\n" if defined $sim;
$sim = $1;
- } elsif ($arg =~ /--(monitor|gdb)$/) {
+ } elsif ($arg =~ /--(no-debug|monitor|gdb)$/) {
+ die "$debug conflicts with --$debug" if defined $debug;
$debug = $1;
} elsif ($arg eq 'run') {
run_vm (@ARGV);
exit 0;
- } elsif ($arg =~ /^mem(?:ory)?=(\d+)/) {
+ } elsif ($arg =~ /^--mem(?:ory)?=(\d+)/) {
$mem = $1;
- } elsif ($arg eq '--headless') {
- $headless = 1;
+ } elsif ($arg eq '-m') {
+ die "-m needs integer argument\n" if !@ARGV || $ARGV[0] !~ /^-?\d+$/;
+ $mem = shift (@ARGV);
+ } elsif ($arg eq '-j') {
+ die "-j need random seed argument\n" if !@ARGV;
+ die "-j need integer argument\n" if $ARGV[0] !~ /^-?\d+$/;
+ $jitter = shift (@ARGV);
+ } elsif ($arg =~ /--jitter=(-?\d+)$/) {
+ $jitter = $1;
+ } elsif ($arg eq '--no-vga' || $arg eq '-v') {
+ print "warning: --no-vga conflicts with --terminal\n"
+ if $vga eq 'terminal';
+ $vga = 'none';
+ } elsif ($arg eq '--no-serial' || $arg eq '-s') {
+ $serial_out = 0;
+ } elsif ($arg eq '--terminal' || $arg eq '-t') {
+ print "warning: --terminal conflicts with --no-vga\n"
+ if $vga eq 'none';
+ $vga = 'terminal';
} elsif ($arg eq 'make-disk') {
- my ($force) = @ARGV > 0 && $ARGV[0] eq '--force';
- shift @ARGV if $force;
usage () if @ARGV != 2;
my ($file, $mb) = @ARGV;
- usage () if $mb !~ /^\d+$/;
+ usage () if $mb !~ /^\d+(\.\d+)?|\.\d+$/;
die "$file: already exists\n" if -e $file;
- if ($mb != .5 && $mb != 1 && $mb != 1.5 && $mb != 2) {
- print "$file: recommended sizes are .5, 1, 1.5, or 2 MB\n";
- die "use --force to override\n" if !$force;
- }
-
- create_disk ($file, $mb * 1008);
+ create_disk ($file, int ($mb * 1008));
exit 0;
} elsif ($arg eq 'put') {
usage () if @ARGV != 1 && @ARGV != 2;
copy_pad ($hostfn, "scratch.dsk", 512);
# Do copy.
- run_vm ("-ci", $hostfn, $size, "-q");
+ run_vm ("-ci", $guestfn, $size, "-q");
exit 0;
} elsif ($arg eq 'get') {
usage () if @ARGV != 1 && @ARGV != 2;
close (SRC);
exit 0;
+ } elsif ($arg eq 'help' || $arg eq '--help') {
+ usage (0);
+ } else {
+ die "unknown option `$arg'\n";
}
}
usage ();
print " put HOSTFN [GUESTFN] copy HOSTFN into VM (as GUESTFN)\n";
print " get GUESTFN [HOSTFN] copy GUESTFN out of VM (to HOSTFN)\n";
print " help print this help message and exit\n";
- print "Available options:\n";
- print " --bochs Use Bochs as simulator (default)\n";
- print " --qemu Use qemu as simulator\n";
- print " --vmware Use VMware Workstation as simulator\n";
- print " --monitor Debug with simulator's monitor\n";
- print " --gdb Debug with gdb\n";
- print " --mem=MB Run VM with MB megabytes of physical memory\n";
- print " --headless No VGA display. Send VM output to stdout\n";
+ print "Simulator options:\n";
+ print " --bochs (default) Use Bochs as simulator\n";
+ print " --qemu Use qemu as simulator\n";
+ print " --gsx Use VMware GSX Server 3.x as simulator\n";
+ print "Debugger options:\n";
+ print " --no-debug (default) No debugger\n";
+ print " --monitor Debug with simulator's monitor\n";
+ print " --gdb Debug with gdb\n";
+ print "Display options: (default is VGA + serial)\n";
+ print " -v, --no-vga No VGA display\n";
+ print " -s, --no-serial No serial output\n";
+ print " -t, --terminal Display VGA in terminal (Bochs only)\n";
+ print "VM options:\n";
+ print " -j SEED Randomize timer interrupts (Bochs only)\n";
+ print " -m, --mem=MB Run VM with MB megabytes of physical memory\n";
exit $exitcode;
}
sub run_vm {
my (@disks) = (undef, undef, undef, undef);
+ $sim = "bochs" if !defined $sim;
+ $debug = "no-debug" if !defined $debug;
+ $vga = "window" if !defined $vga;
+
$disks[0] = "os.dsk";
$disks[1] = "fs.dsk" if -e "fs.dsk";
$disks[2] = "scratch.dsk" if -e "scratch.dsk";
write_cmd_line ($disks[0], @_);
if ($sim eq 'bochs') {
- if ($debug eq '') {
+ if ($debug eq 'no-debug') {
$bin = 'bochs';
} elsif ($debug eq 'monitor') {
$bin = 'bochs-dbg';
print BOCHSRC "vgaromimage: $vgaromimage\n";
print BOCHSRC bochs_disk_line ("ata0-master", $disks[0]);
print BOCHSRC bochs_disk_line ("ata0-slave", $disks[1]);
+ print BOCHSRC "ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15\n"
+ if defined ($disks[2]) || defined ($disks[3]);
print BOCHSRC bochs_disk_line ("ata1-master", $disks[2]);
print BOCHSRC bochs_disk_line ("ata1-slave", $disks[3]);
print BOCHSRC "boot: c\n";
print BOCHSRC "ips: 1000000\n";
print BOCHSRC "clock: sync=none, time0=0\n";
print BOCHSRC "megs: $mem\n";
- print BOCHSRC "com1: dev=/dev/tty\n" if $headless;
+ print BOCHSRC "log: bochsout.txt\n";
+ 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);
- run_command ($bin, '-q');
+ @cmd = ($bin, '-q');
+ push (@cmd, '-j', $jitter) if defined $jitter;
+ run_command_no_die (@cmd);
} elsif ($sim eq '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');
push (@cmd, '-hda', $disks[0]) if defined $disks[0];
push (@cmd, '-hdb', $disks[1]) if defined $disks[1];
push (@cmd, '-hdc', $disks[2]) if defined $disks[2];
push (@cmd, '-hdd', $disks[3]) if defined $disks[3];
push (@cmd, '-m', $mem);
- push (@cmd, '-nographic') if $headless;
+ 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') if $debug eq 'gdb';
run_command (@cmd);
- }
+ } elsif ($sim eq 'gsx') {
+ print "warning: VMware GSX Server doesn't support --$debug\n"
+ if $debug ne 'no-debug';
+ print "warning: VMware GSX Server doesn't support --no-vga\n"
+ if $vga eq 'none';
+ print "warning: VMware GSX Server doesn't support --terminal\n"
+ if $vga eq 'terminal';
+ print "warning: VMware GSX Server doesn't support jitter\n"
+ if defined $jitter;
+
+ open (VMX, ">pintos.vmx") or die "pintos.vmx: create: $!\n";
+ chmod 0777 & ~umask, "pintos.vmx";
+ print VMX "#! /usr/bin/vmware -G\n";
+ print VMX "config.version = 6\n";
+ print VMX "guestOS = \"linux\"\n";
+ print VMX "floppy0.present = FALSE\n";
+
+ if (! -e 'null.bin') {
+ open (NULL, ">null.bin") or die "null.bin: create: $!\n";
+ close (NULL);
+ }
+
+ for (my ($i) = 0; $i < 4; $i++) {
+ my ($dsk) = $disks[$i];
+ next if !defined $dsk;
+ $device = "ide" . int ($i / 2) . ":" . ($i % 2);
+
+ my ($pln) = $dsk;
+ $pln =~ s/\.dsk//;
+ $pln .= ".pln";
+
+ print VMX "\n$device.present = TRUE\n";
+ print VMX "$device.deviceType = \"plainDisk\"\n";
+ print VMX "$device.fileName = \"$pln\"\n";
+
+ my (%geom) = disk_geometry ($dsk);
+ open (PLN, ">$pln") or die "$pln: create: $!\n";
+ print PLN "DRIVETYPE ide\n";
+ print PLN "#vm|VERSION 2\n";
+ print PLN "#vm|TOOLSVERSION 2\n";
+ print PLN "CYLINDERS $geom{C}\n";
+ print PLN "HEADS $geom{H}\n";
+ print PLN "SECTORS $geom{S}\n";
+ print PLN "#vm|CAPACITY $geom{CAPACITY}\n";
+ print PLN "ACCESS \"$dsk\" 0 $geom{CAPACITY}\n";
+ close (PLN);
+ }
+ close (VMX);
+
+ use Cwd;
+ $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");
+ }
}
sub write_cmd_line {
die "command failed\n" if system (@_);
}
+sub run_command_no_die {
+ print join (' ', @_), "\n";
+ system (@_);
+}
+
sub search_path {
my ($target) = @_;
for $dir (split (':', $ENV{PATH})) {
sub bochs_disk_line {
my ($device, $file) = @_;
return "" if !defined $file;
+ my (%geom) = disk_geometry ($file);
+ return "$device: type=disk, path=$file, mode=flat, "
+ . "cylinders=$geom{C}, heads=$geom{H}, spt=$geom{S}, "
+ . "translation=none\n";
+}
+
+sub disk_geometry {
+ my ($file) = @_;
my ($size) = -s $file;
die "$file: stat: $!\n" if !defined $size;
die "$file: size not a multiple of 512 bytes\n" if $size % 512;
$cylinders = int ($size / (512 * 16 * 63));
$cylinders++ if $size % (512 * 16 * 63);
- return "$device: type=disk, path=$file, mode=flat, cylinders=$cylinders, "
- . "heads=16, spt=63, translation=none\n";
+
+ return (CAPACITY => $size / 512,
+ C => $cylinders,
+ H => 16,
+ S => 63);
}