From a1c58ddd7be300b9bc376e091c6e05a117ed1a40 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Fri, 18 Aug 2023 12:47:16 -0700 Subject: [PATCH 01/27] Fix booting from cd while hda present, booting from hda while cd present --- debug.html | 3 + index.html | 4 + src/browser/main.js | 43 ++++++++- src/config.js | 6 +- src/cpu.js | 5 +- src/ide.js | 224 ++++++++++++++++++++++++-------------------- src/pci.js | 20 ++-- 7 files changed, 187 insertions(+), 118 deletions(-) diff --git a/debug.html b/debug.html index b49d712f67..6d37a39367 100644 --- a/debug.html +++ b/debug.html @@ -77,6 +77,9 @@

Debugger

+ + +
diff --git a/index.html b/index.html index dbe38c75ed..e43f112dbc 100644 --- a/index.html +++ b/index.html @@ -35,6 +35,10 @@

Select profile

With Enhanced Tools, QBasic, vim, games and demos. FreeDOS 0.5 MB With nasm, vim, debug.com, Rogue, some games and demos. + FreeDOS Live 400 MB + With nasm, vim, debug.com, Rogue, some games and demos. + FreeDOS 13 2 GB + A full freedos install. FreeBSD 17 MB FreeBSD 12.0 base install. Restored from snapshot. diff --git a/src/browser/main.js b/src/browser/main.js index c7a1b3ba7f..1ecc778821 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -358,6 +358,32 @@ }, name: "Freedos with FreeGEM", }, + { + id: "freedos-live", + cdrom: { + url: host + "FD13LIVE.iso", + async: false, + }, + name: "FreeDOS-Live", + }, + { + id: "freedos-13", + hda: { + url: host + "freedos13.img", + async: false, + }, + name: "FreeDOS 13", + boot_order: 0x312 + }, + { + id: "debian-wheezy", + hda: { + url: host + "debian_wheezy.img", + async: false, + }, + name: "Debian Wheezy", + boot_order: 0x312 + }, { id: "psychdos", hda: { @@ -395,6 +421,10 @@ size: 6547456, async: false, }, + fda: { + url: host + "freedos722.img", + async: false, + }, name: "Linux", }, { @@ -616,7 +646,7 @@ hda: { url: host + "windows2k.img", size: 2 * 1024 * 1024 * 1024, - async: true, + async: false, fixed_chunk_size: 256 * 1024, use_parts: !ON_LOCALHOST, }, @@ -725,6 +755,12 @@ url: host + "Win30.iso", async: false, }, + hda: { + url: host + "win31.img", + async: false, + size: 34463744, + }, + boot_order: 0x213, name: "Windows 3.0", }, { @@ -735,7 +771,12 @@ async: false, size: 34463744, }, + cdrom: { + url: host + "Win30.iso", + async: false, + }, name: "Windows 3.1", + boot_order: 0x312 }, { id: "freebsd", diff --git a/src/config.js b/src/config.js index 1eca2b8008..8d75315025 100644 --- a/src/config.js +++ b/src/config.js @@ -34,9 +34,9 @@ var DUMP_UNCOMPILED_ASSEMBLY = false; */ var TRACK_FILENAMES = false; -var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & - ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; - +// var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & +// ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; +var LOG_LEVEL = LOG_PCI | LOG_IO | LOG_DISK; /** * @const * Draws entire buffer and visualizes the layers that would be drawn diff --git a/src/cpu.js b/src/cpu.js index d476dbeb88..b92c0e717b 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -873,10 +873,7 @@ CPU.prototype.init = function(settings, device_bus) this.devices.hda = new IDEDevice(this, settings.hda, settings.hdb, false, ide_device_count++, device_bus); } - if(settings.cdrom) - { - this.devices.cdrom = new IDEDevice(this, settings.cdrom, undefined, true, ide_device_count++, device_bus); - } + this.devices.cdrom = new IDEDevice(this, settings.cdrom, undefined, true, ide_device_count++, device_bus); this.devices.pit = new PIT(this, device_bus); diff --git a/src/ide.js b/src/ide.js index fde307e165..35d8571912 100644 --- a/src/ide.js +++ b/src/ide.js @@ -45,8 +45,7 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) /** @type {number} */ this.ata_port_high = this.ata_port | 0x204; - /** @type {number} */ - this.master_port = 0xB400; + var master_port = 0xB400 + nr * 0x100; this.pci_space = [ 0x86, 0x80, 0x10, 0x70, 0x05, 0x00, 0xA0, 0x02, @@ -55,7 +54,7 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) this.ata_port_high & 0xFF | 1, this.ata_port_high >> 8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // second device 0x00, 0x00, 0x00, 0x00, // second device - this.master_port & 0xFF | 1, this.master_port >> 8, 0x00, 0x00, + master_port & 0xFF | 1, master_port >> 8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x10, 0xD4, 0x82, @@ -97,7 +96,7 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) // status cpu.io.register_read(this.ata_port | 7, this, function() { - dbg_log("lower irq", LOG_DISK); + dbg_log("dev "+this.name+" lower irq", LOG_DISK); this.cpu.device_lower_irq(this.irq); return this.read_status(); }); @@ -117,34 +116,34 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) cpu.io.register_read(this.ata_port | 1, this, function() { - dbg_log("Read error: " + h(this.current_interface.error & 0xFF) + + dbg_log("dev "+this.name+" Read error: " + h(this.current_interface.error & 0xFF) + " slave=" + (this.current_interface === this.slave), LOG_DISK); return this.current_interface.error & 0xFF; }); cpu.io.register_read(this.ata_port | 2, this, function() { - dbg_log("Read bytecount: " + h(this.current_interface.bytecount & 0xFF), LOG_DISK); + dbg_log("dev "+this.name+" Read bytecount: " + h(this.current_interface.bytecount & 0xFF), LOG_DISK); return this.current_interface.bytecount & 0xFF; }); cpu.io.register_read(this.ata_port | 3, this, function() { - dbg_log("Read sector: " + h(this.current_interface.sector & 0xFF), LOG_DISK); + dbg_log("dev "+this.name+" Read sector: " + h(this.current_interface.sector & 0xFF), LOG_DISK); return this.current_interface.sector & 0xFF; }); cpu.io.register_read(this.ata_port | 4, this, function() { - dbg_log("Read 1F4: " + h(this.current_interface.cylinder_low & 0xFF), LOG_DISK); + dbg_log("dev "+this.name+" Read 1F4: " + h(this.current_interface.cylinder_low & 0xFF), LOG_DISK); return this.current_interface.cylinder_low & 0xFF; }); cpu.io.register_read(this.ata_port | 5, this, function() { - dbg_log("Read 1F5: " + h(this.current_interface.cylinder_high & 0xFF), LOG_DISK); + dbg_log("dev "+this.name+" Read 1F5: " + h(this.current_interface.cylinder_high & 0xFF), LOG_DISK); return this.current_interface.cylinder_high & 0xFF; }); cpu.io.register_read(this.ata_port | 6, this, function() { - dbg_log("Read 1F6", LOG_DISK); + dbg_log("dev "+this.name+" Read 1F6", LOG_DISK); return this.current_interface.drive_head & 0xFF; }); @@ -161,32 +160,32 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) cpu.io.register_write(this.ata_port | 1, this, function(data) { - dbg_log("1F1/lba_count: " + h(data), LOG_DISK); + dbg_log("dev "+this.name+" 1F1/lba_count: " + h(data), LOG_DISK); this.master.lba_count = (this.master.lba_count << 8 | data) & 0xFFFF; this.slave.lba_count = (this.slave.lba_count << 8 | data) & 0xFFFF; }); cpu.io.register_write(this.ata_port | 2, this, function(data) { - dbg_log("1F2/bytecount: " + h(data), LOG_DISK); + dbg_log("dev "+this.name+" 1F2/bytecount: " + h(data), LOG_DISK); this.master.bytecount = (this.master.bytecount << 8 | data) & 0xFFFF; this.slave.bytecount = (this.slave.bytecount << 8 | data) & 0xFFFF; }); cpu.io.register_write(this.ata_port | 3, this, function(data) { - dbg_log("1F3/sector: " + h(data), LOG_DISK); + dbg_log("dev "+this.name+" 1F3/sector: " + h(data), LOG_DISK); this.master.sector = (this.master.sector << 8 | data) & 0xFFFF; this.slave.sector = (this.slave.sector << 8 | data) & 0xFFFF; }); cpu.io.register_write(this.ata_port | 4, this, function(data) { - dbg_log("1F4/sector low: " + h(data), LOG_DISK); + dbg_log("dev "+this.name+" 1F4/sector low: " + h(data), LOG_DISK); this.master.cylinder_low = (this.master.cylinder_low << 8 | data) & 0xFFFF; this.slave.cylinder_low = (this.slave.cylinder_low << 8 | data) & 0xFFFF; }); cpu.io.register_write(this.ata_port | 5, this, function(data) { - dbg_log("1F5/sector high: " + h(data), LOG_DISK); + dbg_log("dev "+this.name+" 1F5/sector high: " + h(data), LOG_DISK); this.master.cylinder_high = (this.master.cylinder_high << 8 | data) & 0xFFFF; this.slave.cylinder_high = (this.slave.cylinder_high << 8 | data) & 0xFFFF; }); @@ -195,11 +194,11 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) var slave = data & 0x10; var mode = data & 0xE0; - dbg_log("1F6/drive: " + h(data, 2), LOG_DISK); + dbg_log("dev "+this.name+" 1F6/drive: " + h(data, 2), LOG_DISK); if(slave) { - dbg_log("Slave", LOG_DISK); + dbg_log("dev "+this.name+" Slave", LOG_DISK); this.current_interface = this.slave; } else @@ -224,30 +223,32 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) cpu.io.register_write(this.ata_port | 7, this, function(data) { - dbg_log("lower irq", LOG_DISK); + dbg_log("dev "+this.name+" lower irq", LOG_DISK); this.cpu.device_lower_irq(this.irq); this.current_interface.ata_command(data); }); - cpu.io.register_read(this.master_port | 4, this, undefined, undefined, this.dma_read_addr); - cpu.io.register_write(this.master_port | 4, this, undefined, undefined, this.dma_set_addr); + cpu.io.register_read(master_port | 4, this, undefined, undefined, this.dma_read_addr); + cpu.io.register_write(master_port | 4, this, undefined, undefined, this.dma_set_addr); - cpu.io.register_read(this.master_port, this, + cpu.io.register_read(master_port, this, this.dma_read_command8, undefined, this.dma_read_command); - cpu.io.register_write(this.master_port, this, + cpu.io.register_write(master_port, this, this.dma_write_command8, undefined, this.dma_write_command); - cpu.io.register_read(this.master_port | 2, this, this.dma_read_status); - cpu.io.register_write(this.master_port | 2, this, this.dma_write_status); + cpu.io.register_read(master_port | 2, this, this.dma_read_status); + cpu.io.register_write(master_port | 2, this, this.dma_write_status); - cpu.io.register_read(this.master_port | 0x8, this, function() { - dbg_log("DMA read 0x8", LOG_DISK); return 0; + cpu.io.register_read(master_port | 0x8, this, function() { + dbg_log("dev "+this.name+" DMA read 0x8 on "+h(master_port), LOG_DISK); return 0; }); - cpu.io.register_read(this.master_port | 0xA, this, function() { - dbg_log("DMA read 0xA", LOG_DISK); return 0; + cpu.io.register_read(master_port | 0xA, this, function() { + dbg_log("dev "+this.name+" DMA read 0xA on "+h(master_port), LOG_DISK); return 0; }); + dbg_log("pre-reg: device "+this.name+" space bar info "+this.pci_space.slice(16,40).map((x) => h(x)), LOG_DISK); cpu.devices.pci.register_device(this); + dbg_log("post-reg: device "+this.name+" space bar info "+this.pci_space.slice(16,40).map((x) => h(x)), LOG_DISK); DEBUG && Object.seal(this); } @@ -257,7 +258,7 @@ IDEDevice.prototype.read_status = function() if(this.current_interface.buffer) { var ret = this.current_interface.status; - dbg_log("ATA read status: " + h(ret, 2), LOG_DISK); + dbg_log("dev "+this.name+" ATA read status: " + h(ret, 2), LOG_DISK); return ret; } else @@ -268,12 +269,12 @@ IDEDevice.prototype.read_status = function() IDEDevice.prototype.write_control = function(data) { - dbg_log("set device control: " + h(data, 2) + " interrupts " + + dbg_log("dev "+this.name+" set device control: " + h(data, 2) + " interrupts " + ((data & 2) ? "disabled" : "enabled"), LOG_DISK); - if(data & 4) + if(data & 0x04) { - dbg_log("Reset via control port", LOG_DISK); + dbg_log("dev "+this.name+" Reset via control port", LOG_DISK); this.cpu.device_lower_irq(this.irq); @@ -286,42 +287,44 @@ IDEDevice.prototype.write_control = function(data) IDEDevice.prototype.dma_read_addr = function() { - dbg_log("dma get address: " + h(this.prdt_addr, 8), LOG_DISK); + dbg_log("dev "+this.name+" dma get address: " + h(this.prdt_addr, 8), LOG_DISK); return this.prdt_addr; }; IDEDevice.prototype.dma_set_addr = function(data) { - dbg_log("dma set address: " + h(data, 8), LOG_DISK); + dbg_log("dev "+this.name+" dma set address: " + h(data, 8), LOG_DISK); + this.prdt_addr = data; }; IDEDevice.prototype.dma_read_status = function() { - dbg_log("DMA read status: " + h(this.dma_status), LOG_DISK); + dbg_log("dev "+this.name+" DMA read status: " + h(this.dma_status), LOG_DISK); return this.dma_status; }; IDEDevice.prototype.dma_write_status = function(value) { - dbg_log("DMA set status: " + h(value), LOG_DISK); + dbg_log("dev "+this.name+" DMA set status: " + h(value), LOG_DISK); this.dma_status &= ~(value & 6); }; IDEDevice.prototype.dma_read_command = function() { + dbg_log("dev "+this.name+" DMA read command: " + h(this.dma_command), LOG_DISK); return this.dma_read_command8() | this.dma_read_status() << 16; }; IDEDevice.prototype.dma_read_command8 = function() { - dbg_log("DMA read command: " + h(this.dma_command), LOG_DISK); + dbg_log("dev "+this.name+" DMA read command8: " + h(this.dma_command), LOG_DISK); return this.dma_command; }; IDEDevice.prototype.dma_write_command = function(value) { - dbg_log("DMA write command: " + h(value), LOG_DISK); + dbg_log("dev "+this.name+" DMA write command: " + h(value), LOG_DISK); this.dma_write_command8(value & 0xFF); this.dma_write_status(value >> 16 & 0xFF); @@ -329,10 +332,10 @@ IDEDevice.prototype.dma_write_command = function(value) IDEDevice.prototype.dma_write_command8 = function(value) { - dbg_log("DMA write command8: " + h(value), LOG_DISK); + dbg_log("dev "+this.name+" DMA write command8: " + h(value), LOG_DISK); let old_command = this.dma_command; - this.dma_command = value & 0x9; + this.dma_command = value & 0x09; if((old_command & 1) === (value & 1)) { @@ -341,10 +344,12 @@ IDEDevice.prototype.dma_write_command8 = function(value) if((value & 1) === 0) { + dbg_log("dev "+this.name+" DMA clear status 1 bit", LOG_DISK); this.dma_status &= ~1; return; } + dbg_log("dev "+this.name+" DMA set status 1 bit", LOG_DISK); this.dma_status |= 1; switch(this.current_interface.current_command) @@ -364,9 +369,14 @@ IDEDevice.prototype.dma_write_command8 = function(value) break; default: - dbg_log("Spurious dma command write, current command: " + + dbg_log("dev "+this.name+" spurious dma command write, current command: " + h(this.current_interface.current_command), LOG_DISK); - dbg_assert(false); + dbg_log("dev "+this.name+" DMA clear status 1 bit, set status 2 bit", LOG_DISK); + this.dma_status &= ~1; + this.dma_status |= 2; + this.push_irq(); + break; +// dbg_assert(false); } }; @@ -374,7 +384,7 @@ IDEDevice.prototype.push_irq = function() { if((this.device_control & 2) === 0) { - dbg_log("push irq", LOG_DISK); + dbg_log("dev "+this.name+" push irq", LOG_DISK); this.dma_status |= 4; this.cpu.device_raise_irq(this.irq); } @@ -389,7 +399,7 @@ IDEDevice.prototype.get_state = function() state[3] = this.irq; state[4] = this.pci_id; state[5] = this.ata_port_high; - state[6] = this.master_port; + //state[6] = this.master_port; state[7] = this.name; state[8] = this.device_control; state[9] = this.prdt_addr; @@ -407,7 +417,7 @@ IDEDevice.prototype.set_state = function(state) this.irq = state[3]; this.pci_id = state[4]; this.ata_port_high = state[5]; - this.master_port = state[6]; + //this.master_port = state[6]; this.name = state[7]; this.device_control = state[8]; this.prdt_addr = state[9]; @@ -626,11 +636,11 @@ IDEInterface.prototype.push_irq = function() IDEInterface.prototype.ata_command = function(cmd) { - dbg_log("ATA Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); + dbg_log("ATA dev " + this.device.name + " Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); - if(!this.buffer) + if(!this.buffer && cmd != 0xA0 && cmd != 0xA1 && cmd != 0xEC) { - dbg_log("abort: No buffer", LOG_DISK); + dbg_log("dev "+this.device.name+" abort: No buffer", LOG_DISK); this.error = 4; this.status = 0x41; this.push_irq(); @@ -643,7 +653,7 @@ IDEInterface.prototype.ata_command = function(cmd) switch(cmd) { case 0x08: - dbg_log("ATA device reset", LOG_DISK); + dbg_log("dev "+this.device.name+" ATA device reset", LOG_DISK); this.data_pointer = 0; this.data_end = 0; this.data_length = 0; @@ -728,7 +738,7 @@ IDEInterface.prototype.ata_command = function(cmd) break; case 0xA1: - dbg_log("ATA identify packet device", LOG_DISK); + dbg_log("dev "+this.device.name+" ATA identify packet device", LOG_DISK); if(this.is_atapi) { @@ -750,7 +760,7 @@ IDEInterface.prototype.ata_command = function(cmd) case 0xC6: // set multiple mode // Logical sectors per DRQ Block in word 1 - dbg_log("Logical sectors per DRQ Block: " + h(this.bytecount & 0xFF), LOG_DISK); + dbg_log("dev "+this.device.name+" Logical sectors per DRQ Block: " + h(this.bytecount & 0xFF), LOG_DISK); this.sectors_per_drq = this.bytecount & 0xFF; this.status = 0x50; this.push_irq(); @@ -767,38 +777,38 @@ IDEInterface.prototype.ata_command = function(cmd) break; case 0x40: - dbg_log("read verify sectors", LOG_DISK); + dbg_log("dev "+this.device.name+" read verify sectors", LOG_DISK); this.status = 0x50; this.push_irq(); break; case 0xDA: - dbg_log("Unimplemented: get media status", LOG_DISK); + dbg_log("dev "+this.device.name+" Unimplemented: get media status", LOG_DISK); this.status = 0x41; this.error = 4; this.push_irq(); break; case 0xE0: - dbg_log("ATA standby immediate", LOG_DISK); + dbg_log("dev "+this.device.name+" ATA standby immediate", LOG_DISK); this.status = 0x50; this.push_irq(); break; case 0xE1: - dbg_log("ATA idle immediate", LOG_DISK); + dbg_log("dev "+this.device.name+" ATA idle immediate", LOG_DISK); this.status = 0x50; this.push_irq(); break; case 0xE7: - dbg_log("ATA flush cache", LOG_DISK); + dbg_log("dev "+this.device.name+" ATA flush cache", LOG_DISK); this.status = 0x50; this.push_irq(); break; case 0xEC: - dbg_log("ATA identify device", LOG_DISK); + dbg_log("dev "+this.device.name+" ATA identify device", LOG_DISK); if(this.is_atapi) { @@ -815,13 +825,13 @@ IDEInterface.prototype.ata_command = function(cmd) break; case 0xEA: - dbg_log("flush cache ext", LOG_DISK); + dbg_log("dev "+this.device.name+" flush cache ext", LOG_DISK); this.status = 0x50; this.push_irq(); break; case 0xEF: - dbg_log("set features: " + h(this.bytecount & 0xFF), LOG_DISK); + dbg_log("dev "+this.device.name+" set features: " + h(this.bytecount & 0xFF), LOG_DISK); this.status = 0x50; this.push_irq(); break; @@ -833,13 +843,13 @@ IDEInterface.prototype.ata_command = function(cmd) break; case 0xF5: - dbg_log("security freeze lock", LOG_DISK); + dbg_log("dev "+this.device.name+" security freeze lock", LOG_DISK); this.status = 0x50; this.push_irq(); break; case 0xF9: - dbg_log("Unimplemented: set max address", LOG_DISK); + dbg_log("dev "+this.device.name+" Unimplemented: set max address", LOG_DISK); this.status = 0x41; this.error = 4; break; @@ -855,7 +865,7 @@ IDEInterface.prototype.ata_command = function(cmd) IDEInterface.prototype.atapi_handle = function() { - dbg_log("ATAPI Command: " + h(this.data[0]) + + dbg_log("dev "+this.device.name+" ATAPI Command: " + h(this.data[0]) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); this.data_pointer = 0; @@ -864,7 +874,7 @@ IDEInterface.prototype.atapi_handle = function() switch(this.current_atapi_command) { case 0x00: - dbg_log("test unit ready", LOG_DISK); + dbg_log("dev "+this.device.name+" test unit ready", LOG_DISK); // test unit ready this.data_allocate(0); this.data_end = this.data_length; @@ -887,7 +897,7 @@ IDEInterface.prototype.atapi_handle = function() var length = this.data[4]; this.status = 0x58; - dbg_log("inquiry: " + h(this.data[1], 2) + " length=" + length, LOG_DISK); + dbg_log("dev "+this.device.name+" inquiry: " + h(this.data[1], 2) + " length=" + length, LOG_DISK); // http://www.t10.org/ftp/x3t9.2/document.87/87-106r0.txt //this.data_allocate(36); @@ -960,7 +970,7 @@ IDEInterface.prototype.atapi_handle = function() var length = this.data[8]; this.data_allocate(Math.min(8, length)); this.data_end = this.data_length; - dbg_log("read q subcode: length=" + length, LOG_DISK); + dbg_log("dev "+this.device.name+" read q subcode: length=" + length, LOG_DISK); this.status = 0x58; break; @@ -971,7 +981,7 @@ IDEInterface.prototype.atapi_handle = function() this.data_allocate(length); this.data_end = this.data_length; - dbg_log("read toc: " + h(format, 2) + + dbg_log("dev "+this.device.name+" read toc: " + h(format, 2) + " length=" + length + " " + (this.data[1] & 2) + " " + h(this.data[6]), LOG_DISK); @@ -1041,7 +1051,7 @@ IDEInterface.prototype.atapi_handle = function() break; case 0x52: - dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); + dbg_log("dev "+this.device.name+" Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); this.status = 0x51; this.data_length = 0; this.error = 5 << 4; @@ -1051,7 +1061,7 @@ IDEInterface.prototype.atapi_handle = function() // mode sense var length = this.data[8] | this.data[7] << 8; var page_code = this.data[2]; - dbg_log("mode sense: " + h(page_code) + " length=" + length, LOG_DISK); + dbg_log("dev "+this.device.name+" mode sense: " + h(page_code) + " length=" + length, LOG_DISK); if(page_code === 0x2A) { this.data_allocate(Math.min(30, length)); @@ -1072,12 +1082,12 @@ IDEInterface.prototype.atapi_handle = function() this.status = 0x51; this.data_length = 0; this.error = 5 << 4; - dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); + dbg_log("dev "+this.device.name+" Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); break; case 0xBE: // Hiren's boot CD - dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); + dbg_log("dev "+this.device.name+" Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); this.data_allocate(0); this.data_end = this.data_length; this.status = 0x50; @@ -1087,7 +1097,7 @@ IDEInterface.prototype.atapi_handle = function() this.status = 0x51; this.data_length = 0; this.error = 5 << 4; - dbg_log("Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); + dbg_log("dev "+this.device.name+" Unimplemented ATAPI command: " + h(this.data[0]), LOG_DISK); dbg_assert(false); } @@ -1133,14 +1143,14 @@ IDEInterface.prototype.atapi_read = function(cmd) var byte_count = count * this.sector_size; var start = lba * this.sector_size; - dbg_log("CD read lba=" + h(lba) + + dbg_log("dev "+this.device.name+" CD read lba=" + h(lba) + " lbacount=" + h(count) + " bytecount=" + h(byte_count) + " flags=" + h(flags), LOG_DISK); this.data_length = 0; var req_length = this.cylinder_high << 8 & 0xFF00 | this.cylinder_low & 0xFF; - dbg_log(h(this.cylinder_high, 2) + " " + h(this.cylinder_low, 2), LOG_DISK); + dbg_log("dev "+this.device.name+": "+h(this.cylinder_high, 2) + " " + h(this.cylinder_low, 2), LOG_DISK); this.cylinder_low = this.cylinder_high = 0; // oak technology driver (windows 3.0) if(req_length === 0xFFFF) @@ -1175,7 +1185,7 @@ IDEInterface.prototype.atapi_read = function(cmd) this.read_buffer(start, byte_count, (data) => { //setTimeout(() => { - dbg_log("cd read: data arrived", LOG_DISK); + dbg_log("dev "+this.device.name+" cd read: data arrived", LOG_DISK); this.data_set(data); this.status = 0x58; this.bytecount = this.bytecount & ~7 | 2; @@ -1207,7 +1217,7 @@ IDEInterface.prototype.atapi_read_dma = function(cmd) var byte_count = count * this.sector_size; var start = lba * this.sector_size; - dbg_log("CD read DMA lba=" + h(lba) + + dbg_log("dev "+this.device.name+" CD read DMA lba=" + h(lba) + " lbacount=" + h(count) + " bytecount=" + h(byte_count) + " flags=" + h(flags), LOG_DISK); @@ -1227,7 +1237,7 @@ IDEInterface.prototype.atapi_read_dma = function(cmd) this.read_buffer(start, byte_count, (data) => { - dbg_log("atapi_read_dma: Data arrived"); + dbg_log("dev "+this.device.name+" atapi_read_dma: Data arrived"); this.report_read_end(byte_count); this.status = 0x58; this.bytecount = this.bytecount & ~7 | 2; @@ -1242,17 +1252,25 @@ IDEInterface.prototype.do_atapi_dma = function() { if((this.device.dma_status & 1) === 0) { - dbg_log("do_atapi_dma: Status not set", LOG_DISK); + dbg_log("dev "+this.device.name+" do_atapi_dma: Status not set", LOG_DISK); + this.device.dma_status &= ~1; + this.device.dma_status |= 2; + this.status = 0x51; + this.push_irq(); return; } if((this.status & 0x8) === 0) { - dbg_log("do_atapi_dma: DRQ not set", LOG_DISK); + dbg_log("dev "+this.device.name+" do_atapi_dma: DRQ not set", LOG_DISK); + this.device.dma_status &= ~1; + this.device.dma_status |= 2; + this.status = 0x51; + this.push_irq(); return; } - dbg_log("atapi dma transfer len=" + this.data_length, LOG_DISK); + dbg_log("dev "+this.device.name+" atapi dma transfer len=" + this.data_length, LOG_DISK); var prdt_start = this.device.prdt_addr; var offset = 0; @@ -1269,7 +1287,7 @@ IDEInterface.prototype.do_atapi_dma = function() count = 0x10000; } - dbg_log("dma read dest=" + h(addr) + " count=" + h(count) + " datalen=" + h(this.data_length), LOG_DISK); + dbg_log("dev "+this.device.name+" dma read dest=" + h(addr) + " count=" + h(count) + " datalen=" + h(this.data_length), LOG_DISK); this.cpu.write_blob(data.subarray(offset, Math.min(offset + count, this.data_length)), addr); offset += count; @@ -1277,7 +1295,7 @@ IDEInterface.prototype.do_atapi_dma = function() if(offset >= this.data_length && !end) { - dbg_log("leave early end=" + (+end) + + dbg_log("dev "+this.device.name+" leave early end=" + (+end) + " offset=" + h(offset) + " data_length=" + h(this.data_length) + " cmd=" + h(this.current_command), LOG_DISK); @@ -1286,7 +1304,7 @@ IDEInterface.prototype.do_atapi_dma = function() } while(!end); - dbg_log("end offset=" + offset, LOG_DISK); + dbg_log("dev "+this.device.name+" end offset=" + offset, LOG_DISK); this.status = 0x50; this.device.dma_status &= ~1; @@ -1319,7 +1337,7 @@ IDEInterface.prototype.read_data = function(length) var align = (this.data_end & 0xFFF) === 0 ? 0xFFF : 0xFF; if((this.data_pointer & align) === 0) { - dbg_log("Read 1F0: " + h(this.data[this.data_pointer], 2) + + dbg_log("dev "+this.device.name+" Read 1F0: " + h(this.data[this.data_pointer], 2) + " cur=" + h(this.data_pointer) + " cnt=" + h(this.data_length), LOG_DISK); } @@ -1333,7 +1351,7 @@ IDEInterface.prototype.read_data = function(length) } else { - dbg_log("Read 1F0: empty", LOG_DISK); + dbg_log("dev "+this.device.name+" Read 1F0: empty", LOG_DISK); this.data_pointer += length; return 0; @@ -1342,7 +1360,7 @@ IDEInterface.prototype.read_data = function(length) IDEInterface.prototype.read_end = function() { - dbg_log("read_end cmd=" + h(this.current_command) + " data_pointer=" + h(this.data_pointer) + + dbg_log("dev "+this.device.name+" read_end cmd=" + h(this.current_command) + " data_pointer=" + h(this.data_pointer) + " end=" + h(this.data_end) + " length=" + h(this.data_length), LOG_DISK); if(this.current_command === 0xA0) @@ -1370,7 +1388,7 @@ IDEInterface.prototype.read_end = function() { this.data_end += byte_count; } - dbg_log("data_end=" + h(this.data_end), LOG_DISK); + dbg_log("dev "+this.device.name+" data_end=" + h(this.data_end), LOG_DISK); } } else @@ -1408,7 +1426,7 @@ IDEInterface.prototype.write_data_port = function(data, length) if(this.data_pointer >= this.data_end) { - dbg_log("Redundant write to data port: " + h(data) + " count=" + h(this.data_end) + + dbg_log("dev "+this.device.name+" Redundant write to data port: " + h(data) + " count=" + h(this.data_end) + " cur=" + h(this.data_pointer), LOG_DISK); } else @@ -1416,7 +1434,7 @@ IDEInterface.prototype.write_data_port = function(data, length) var align = (this.data_end & 0xFFF) === 0 ? 0xFFF : 0xFF; if((this.data_pointer + length & align) === 0 || this.data_end < 20) { - dbg_log("Data port: " + h(data >>> 0) + " count=" + h(this.data_end) + + dbg_log("dev "+this.device.name+" Data port: " + h(data >>> 0) + " count=" + h(this.data_end) + " cur=" + h(this.data_pointer), LOG_DISK); } @@ -1466,7 +1484,7 @@ IDEInterface.prototype.write_end = function() } else { - dbg_log("write_end data_pointer=" + h(this.data_pointer) + + dbg_log("dev "+this.device.name+" write_end data_pointer=" + h(this.data_pointer) + " data_length=" + h(this.data_length), LOG_DISK); if(this.data_pointer >= this.data_length) @@ -1491,7 +1509,7 @@ IDEInterface.prototype.write_end = function() IDEInterface.prototype.ata_advance = function(cmd, sectors) { - dbg_log("Advance sectors=" + sectors + " old_bytecount=" + this.bytecount, LOG_DISK); + dbg_log("dev "+this.device.name+" Advance sectors=" + sectors + " old_bytecount=" + this.bytecount, LOG_DISK); this.bytecount -= sectors; if(cmd === 0x24 || cmd === 0x29 || cmd === 0x34 || cmd === 0x39 || @@ -1535,7 +1553,7 @@ IDEInterface.prototype.ata_read_sectors = function(cmd) var byte_count = count * this.sector_size; var start = lba * this.sector_size; - dbg_log("ATA read cmd=" + h(cmd) + + dbg_log("dev "+this.device.name+" ATA read cmd=" + h(cmd) + " mode=" + (this.is_lba ? "lba" : "chs") + " lba=" + h(lba) + " lbacount=" + h(count) + @@ -1556,7 +1574,7 @@ IDEInterface.prototype.ata_read_sectors = function(cmd) this.read_buffer(start, byte_count, (data) => { //setTimeout(() => { - dbg_log("ata_read: Data arrived", LOG_DISK); + dbg_log("dev "+this.device.name+" ata_read: Data arrived", LOG_DISK); this.data_set(data); this.status = 0x58; @@ -1579,13 +1597,13 @@ IDEInterface.prototype.ata_read_sectors_dma = function(cmd) var byte_count = count * this.sector_size; var start = lba * this.sector_size; - dbg_log("ATA DMA read lba=" + h(lba) + + dbg_log("dev "+this.device.name+" dev "+this.device.name+" ATA DMA read lba=" + h(lba) + " lbacount=" + h(count) + " bytecount=" + h(byte_count), LOG_DISK); if(start + byte_count > this.buffer.byteLength) { - dbg_assert(false, "ATA read: Outside of disk", LOG_DISK); + dbg_assert(false, "dev "+this.device.name+" ATA read: Outside of disk", LOG_DISK); this.status = 0xFF; this.push_irq(); @@ -1616,7 +1634,7 @@ IDEInterface.prototype.do_ata_read_sectors_dma = function() this.read_buffer(start, byte_count, (data) => { //setTimeout(function() { - dbg_log("do_ata_read_sectors_dma: Data arrived", LOG_DISK); + dbg_log("dev "+this.device.name+" do_ata_read_sectors_dma: Data arrived", LOG_DISK); var prdt_start = this.device.prdt_addr; var offset = 0; @@ -1630,10 +1648,10 @@ IDEInterface.prototype.do_ata_read_sectors_dma = function() if(!prd_count) { prd_count = 0x10000; - dbg_log("dma: prd count was 0", LOG_DISK); + dbg_log("dev "+this.device.name+" dma: prd count was 0", LOG_DISK); } - dbg_log("dma read transfer dest=" + h(prd_addr) + + dbg_log("dev "+this.device.name+" dma read transfer dest=" + h(prd_addr) + " prd_count=" + h(prd_count), LOG_DISK); this.cpu.write_blob(data.subarray(offset, offset + prd_count), prd_addr); @@ -1647,11 +1665,13 @@ IDEInterface.prototype.do_ata_read_sectors_dma = function() this.ata_advance(this.current_command, count); this.status = 0x50; this.device.dma_status &= ~1; + dbg_log("dev "+this.device.name+" do_ata_read_sectors_dma completed", LOG_DISK); this.current_command = -1; + this.report_read_end(byte_count); + this.push_irq(); - this.report_read_end(byte_count); //}.bind(this), 10); }); }; @@ -1667,7 +1687,7 @@ IDEInterface.prototype.ata_write_sectors = function(cmd) var byte_count = count * this.sector_size; var start = lba * this.sector_size; - dbg_log("ATA write lba=" + h(lba) + + dbg_log("dev "+this.device.name+" ATA write lba=" + h(lba) + " mode=" + (this.is_lba ? "lba" : "chs") + " lbacount=" + h(count) + " bytecount=" + h(byte_count), LOG_DISK); @@ -1697,13 +1717,13 @@ IDEInterface.prototype.ata_write_sectors_dma = function(cmd) var byte_count = count * this.sector_size; var start = lba * this.sector_size; - dbg_log("ATA DMA write lba=" + h(lba) + + dbg_log("dev "+this.name+" ATA DMA write lba=" + h(lba) + " lbacount=" + h(count) + " bytecount=" + h(byte_count), LOG_DISK); if(start + byte_count > this.buffer.byteLength) { - dbg_assert(false, "ATA DMA write: Outside of disk", LOG_DISK); + dbg_assert(false, "dev "+this.name+" ATA DMA write: Outside of disk", LOG_DISK); this.status = 0xFF; this.push_irq(); @@ -1764,7 +1784,7 @@ IDEInterface.prototype.do_ata_write_sectors_dma = function() this.buffer.set(start, buffer, () => { - dbg_log("dma write completed", LOG_DISK); + dbg_log("dev "+this.device.name+" dma write completed", LOG_DISK); this.ata_advance(this.current_command, count); this.status = 0x50; this.push_irq(); diff --git a/src/pci.js b/src/pci.js index f708f7c79d..6985959cce 100644 --- a/src/pci.js +++ b/src/pci.js @@ -390,7 +390,7 @@ PCI.prototype.pci_write32 = function(address, written) var bar_nr = addr - 0x10 >> 2; var bar = device.pci_bars[bar_nr]; - dbg_log("BAR" + bar_nr + " exists=" + (bar ? "y" : "n") + " changed to " + + dbg_log("BAR" + bar_nr + " exists=" + (bar ? "y" : "n") + " changed from "+h(space[addr >> 2]) +" to " + h(written >>> 0) + " dev=" + h(bdf >> 3, 2) + " (" + device.name + ") ", LOG_PCI); if(bar) @@ -514,6 +514,7 @@ PCI.prototype.register_device = function(device) var bar_base = bar_space[i]; var type = bar_base & 1; + dbg_log("device "+ device.name +" register bar of size "+bar.size +" at " + h(bar_base), LOG_PCI); bar.original_bar = bar_base; bar.entries = []; @@ -561,6 +562,9 @@ PCI.prototype.set_io_bars = function(bar, from, to) old_entry.write32 === this.io.empty_port_write) { // happens when a device doesn't register its full range (currently ne2k and virtio) + // but it also happens when aligned reads/writes are set up, + // e.g. a 16-bit read registered at 0xB400 will show up as + // no source mapping at 0xB401. dbg_log("Warning: Bad IO bar: Source not mapped, port=" + h(from + i, 4), LOG_PCI); } @@ -573,16 +577,16 @@ PCI.prototype.set_io_bars = function(bar, from, to) ports[to + i] = entry; } - if(empty_entry.read8 === this.io.empty_port_read8 || - empty_entry.read16 === this.io.empty_port_read16 || - empty_entry.read32 === this.io.empty_port_read32 || - empty_entry.write8 === this.io.empty_port_write || - empty_entry.write16 === this.io.empty_port_write || - empty_entry.write32 === this.io.empty_port_write) + if(empty_entry.read8 !== this.io.empty_port_read8 || + empty_entry.read16 !== this.io.empty_port_read16 || + empty_entry.read32 !== this.io.empty_port_read32 || + empty_entry.write8 !== this.io.empty_port_write || + empty_entry.write16 !== this.io.empty_port_write || + empty_entry.write32 !== this.io.empty_port_write) { // These can fail if the os maps an io port in multiple bars (indicating a bug) // XXX: Fails during restore_state - dbg_log("Warning: Bad IO bar: Target already mapped, port=" + h(to + i, 4), LOG_PCI); + dbg_log("Warning: Bad IO bar: Target already mapped, port=" + h(to + i, 4)+" from device "+entry.device.name+" to device "+empty_entry.device.name, LOG_PCI); } } }; From 42ea08a119c6ad72b368ed447eae8423d3e4bd58 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Fri, 18 Aug 2023 13:24:35 -0700 Subject: [PATCH 02/27] fix wrong fields in log messages --- src/ide.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ide.js b/src/ide.js index 35d8571912..83013f98da 100644 --- a/src/ide.js +++ b/src/ide.js @@ -1717,13 +1717,13 @@ IDEInterface.prototype.ata_write_sectors_dma = function(cmd) var byte_count = count * this.sector_size; var start = lba * this.sector_size; - dbg_log("dev "+this.name+" ATA DMA write lba=" + h(lba) + + dbg_log("dev "+this.device.name+" ATA DMA write lba=" + h(lba) + " lbacount=" + h(count) + " bytecount=" + h(byte_count), LOG_DISK); if(start + byte_count > this.buffer.byteLength) { - dbg_assert(false, "dev "+this.name+" ATA DMA write: Outside of disk", LOG_DISK); + dbg_assert(false, "dev "+this.device.name+" ATA DMA write: Outside of disk", LOG_DISK); this.status = 0xFF; this.push_irq(); From 24af4dde83ef2d3249d948ca0ec333b4e93bb806 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Sat, 19 Aug 2023 07:09:43 -0700 Subject: [PATCH 03/27] revert changes to main, index, debug --- debug.html | 3 --- index.html | 4 ---- src/browser/main.js | 18 ++---------------- src/config.js | 6 +++--- 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/debug.html b/debug.html index 6d37a39367..b49d712f67 100644 --- a/debug.html +++ b/debug.html @@ -77,9 +77,6 @@

Debugger

- - -
diff --git a/index.html b/index.html index e43f112dbc..dbe38c75ed 100644 --- a/index.html +++ b/index.html @@ -35,10 +35,6 @@

Select profile

With Enhanced Tools, QBasic, vim, games and demos. FreeDOS 0.5 MB With nasm, vim, debug.com, Rogue, some games and demos. - FreeDOS Live 400 MB - With nasm, vim, debug.com, Rogue, some games and demos. - FreeDOS 13 2 GB - A full freedos install. FreeBSD 17 MB FreeBSD 12.0 base install. Restored from snapshot. diff --git a/src/browser/main.js b/src/browser/main.js index 1ecc778821..d7dc066c36 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -338,6 +338,7 @@ size: 8 * 1024 * 1024, async: false, }, + boot_order: 0x132, name: "MS-DOS", }, { @@ -421,10 +422,6 @@ size: 6547456, async: false, }, - fda: { - url: host + "freedos722.img", - async: false, - }, name: "Linux", }, { @@ -646,7 +643,7 @@ hda: { url: host + "windows2k.img", size: 2 * 1024 * 1024 * 1024, - async: false, + async: true, fixed_chunk_size: 256 * 1024, use_parts: !ON_LOCALHOST, }, @@ -755,12 +752,6 @@ url: host + "Win30.iso", async: false, }, - hda: { - url: host + "win31.img", - async: false, - size: 34463744, - }, - boot_order: 0x213, name: "Windows 3.0", }, { @@ -771,12 +762,7 @@ async: false, size: 34463744, }, - cdrom: { - url: host + "Win30.iso", - async: false, - }, name: "Windows 3.1", - boot_order: 0x312 }, { id: "freebsd", diff --git a/src/config.js b/src/config.js index 8d75315025..1eca2b8008 100644 --- a/src/config.js +++ b/src/config.js @@ -34,9 +34,9 @@ var DUMP_UNCOMPILED_ASSEMBLY = false; */ var TRACK_FILENAMES = false; -// var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & -// ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; -var LOG_LEVEL = LOG_PCI | LOG_IO | LOG_DISK; +var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & + ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; + /** * @const * Draws entire buffer and visualizes the layers that would be drawn From 775791801a64361ad2534af8097652ee7cecf582 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Sat, 19 Aug 2023 07:18:59 -0700 Subject: [PATCH 04/27] add wants_cdrom config flag to force presence of a cdrom even when no disk image is present --- src/browser/starter.js | 4 ++++ src/cpu.js | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/browser/starter.js b/src/browser/starter.js index 1f47f6d087..2479753324 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -39,6 +39,7 @@ * - `filesystem Object` (No 9p filesystem) - A 9p filesystem, see * [filesystem.md](filesystem.md). * + * - `want_cdrom bool` - Whether to set up a CD-ROM drive even with no CD present. Implied by the presence of a `cdrom` object. * - `serial_container HTMLTextAreaElement` (No serial terminal) - A textarea * that will receive and send data to the emulated serial terminal. * Alternatively the serial terminal can also be accessed programatically, @@ -261,6 +262,8 @@ V86Starter.prototype.continue_init = async function(emulator, options) options["fda"] ? BOOT_ORDER_FD_FIRST : options["hda"] ? BOOT_ORDER_HD_FIRST : BOOT_ORDER_CD_FIRST; + + settings.wants_cdrom = options["wants_cdrom"] || false; settings.acpi = options["acpi"]; settings.disable_jit = options["disable_jit"]; settings.load_devices = true; @@ -339,6 +342,7 @@ V86Starter.prototype.continue_init = async function(emulator, options) break; case "cdrom": settings.cdrom = this.disk_images["cdrom"] = buffer; + settings.wants_cdrom = true; break; case "fda": settings.fda = this.disk_images["fda"] = buffer; diff --git a/src/cpu.js b/src/cpu.js index b92c0e717b..330f4f688b 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -873,7 +873,10 @@ CPU.prototype.init = function(settings, device_bus) this.devices.hda = new IDEDevice(this, settings.hda, settings.hdb, false, ide_device_count++, device_bus); } - this.devices.cdrom = new IDEDevice(this, settings.cdrom, undefined, true, ide_device_count++, device_bus); + if(settings.cdrom || settings.want_cdrom) + { + this.devices.cdrom = new IDEDevice(this, settings.cdrom, undefined, true, ide_device_count++, device_bus); + } this.devices.pit = new PIT(this, device_bus); From c9621989d3c8ca2e2434c602e1a2747b3dcef568 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Sat, 19 Aug 2023 07:33:46 -0700 Subject: [PATCH 05/27] Expose wants_cdrom flag and fix a docstring. --- debug.html | 7 +++++++ index.html | 7 +++++++ src/browser/main.js | 3 +++ src/browser/starter.js | 2 +- 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/debug.html b/debug.html index b49d712f67..f4ab233048 100644 --- a/debug.html +++ b/debug.html @@ -143,6 +143,13 @@

Debugger

+ + + +
+ + +
diff --git a/index.html b/index.html index dbe38c75ed..f761018bcd 100644 --- a/index.html +++ b/index.html @@ -80,6 +80,13 @@

Setup

+ + + +
+ + +
diff --git a/src/browser/main.js b/src/browser/main.js index d7dc066c36..b3aa22fef9 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -1350,6 +1350,8 @@ const disable_audio = settings.audio === undefined ? $("disable_audio").checked : !settings.audio; const enable_acpi = settings.acpi === undefined ? $("enable_acpi").checked : settings.acpi; + const wants_cdrom = settings.wants_cdrom === undefined ? $("wants_cdrom").checked : settings.wants_cdrom; + /** @const */ var BIOSPATH = "bios/"; @@ -1396,6 +1398,7 @@ "hda": settings.hda, "hdb": settings.hdb, "cdrom": settings.cdrom, + "wants_cdrom": settings.wants_cdrom, "multiboot": settings.multiboot, "bzimage": settings.bzimage, diff --git a/src/browser/starter.js b/src/browser/starter.js index 2479753324..ecbd093c88 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -39,7 +39,7 @@ * - `filesystem Object` (No 9p filesystem) - A 9p filesystem, see * [filesystem.md](filesystem.md). * - * - `want_cdrom bool` - Whether to set up a CD-ROM drive even with no CD present. Implied by the presence of a `cdrom` object. + * - `wants_cdrom bool` - Whether to set up a CD-ROM drive even with no CD present. Implied by the presence of a `cdrom` object. * - `serial_container HTMLTextAreaElement` (No serial terminal) - A textarea * that will receive and send data to the emulated serial terminal. * Alternatively the serial terminal can also be accessed programatically, From 45945f75d4359ac0ed5ebcd515882630685532c2 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Sat, 19 Aug 2023 09:29:05 -0700 Subject: [PATCH 06/27] fix typo --- src/cpu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu.js b/src/cpu.js index 330f4f688b..9bf678bf70 100644 --- a/src/cpu.js +++ b/src/cpu.js @@ -873,7 +873,7 @@ CPU.prototype.init = function(settings, device_bus) this.devices.hda = new IDEDevice(this, settings.hda, settings.hdb, false, ide_device_count++, device_bus); } - if(settings.cdrom || settings.want_cdrom) + if(settings.cdrom || settings.wants_cdrom) { this.devices.cdrom = new IDEDevice(this, settings.cdrom, undefined, true, ide_device_count++, device_bus); } From 3500d3681243eee83c2653ff9e7c91e2f5993a02 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Sun, 20 Aug 2023 07:16:41 -0700 Subject: [PATCH 07/27] Fix hda+cdrom tests and tinycore hang, add a few more --- src/ide.js | 11 +--- tests/full/run.js | 159 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 10 deletions(-) diff --git a/src/ide.js b/src/ide.js index 83013f98da..1f7be64279 100644 --- a/src/ide.js +++ b/src/ide.js @@ -638,7 +638,8 @@ IDEInterface.prototype.ata_command = function(cmd) { dbg_log("ATA dev " + this.device.name + " Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); - if(!this.buffer && cmd != 0xA0 && cmd != 0xA1 && cmd != 0xEC) + // && cmd != 0xA0 && cmd != 0xA1 && cmd != 0xEC + if(!this.buffer) { dbg_log("dev "+this.device.name+" abort: No buffer", LOG_DISK); this.error = 4; @@ -1253,20 +1254,12 @@ IDEInterface.prototype.do_atapi_dma = function() if((this.device.dma_status & 1) === 0) { dbg_log("dev "+this.device.name+" do_atapi_dma: Status not set", LOG_DISK); - this.device.dma_status &= ~1; - this.device.dma_status |= 2; - this.status = 0x51; - this.push_irq(); return; } if((this.status & 0x8) === 0) { dbg_log("dev "+this.device.name+" do_atapi_dma: DRQ not set", LOG_DISK); - this.device.dma_status &= ~1; - this.device.dma_status |= 2; - this.status = 0x51; - this.push_irq(); return; } diff --git a/tests/full/run.js b/tests/full/run.js index 3dd07baef4..8690419edd 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -90,6 +90,37 @@ if(cluster.isMaster) "Welcome to FreeDOS", ], }, + { + name: "FreeDOS boot with cdrom present", + fda: root_path + "/images/freedos722.img", + cdrom: root_path + "/images/linux.iso", + boot_order:0x231, + timeout: 20, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with hda present", + fda: root_path + "/images/freedos722.img", + hda: root_path + "/images/msdos.img", + boot_order:0x231, + timeout: 20, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with cdrom and hda present", + fda: root_path + "/images/freedos722.img", + cdrom: root_path + "/images/linux.iso", + hda: root_path + "/images/msdos.img", + boot_order:0x321, + timeout: 30, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, { name: "FreeDOS boot with Bochs BIOS", fda: root_path + "/images/freedos722.img", @@ -99,6 +130,40 @@ if(cluster.isMaster) "Welcome to FreeDOS", ], }, + { + name: "FreeDOS boot with Bochs BIOS and cdrom present", + fda: root_path + "/images/freedos722.img", + cdrom: root_path + "/images/linux.iso", + boot_order:0x231, + timeout: 20, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and hda present", + fda: root_path + "/images/freedos722.img", + hda: root_path + "/images/msdos.img", + boot_order:0x231, + timeout: 20, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and cdrom and HDA present", + fda: root_path + "/images/freedos722.img", + cdrom: root_path + "/images/linux.iso", + hda: root_path + "/images/msdos.img", + boot_order:0x231, + timeout: 20, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, { name: "Windows 1.01 boot", fda: root_path + "/images/windows101.img", @@ -148,6 +213,23 @@ if(cluster.isMaster) }, ], }, + { + name: "Linux with HDA present", + cdrom: root_path + "/images/linux.iso", + hda: root_path + "/images/msdos.img", + boot_order: 0x123, + timeout: 90, + expected_texts: [ + "/root%", + "test passed", + ], + actions: [ + { + on_text: "/root%", + run: "cd tests; ./test-i386 > emu.test; diff emu.test reference.test && echo test pas''sed || echo failed\n", + }, + ], + }, { name: "Windows XP CD", skip_if_disk_image_missing: true, @@ -282,6 +364,24 @@ if(cluster.isMaster) }, ], }, + { + name: "Linux with Bochs BIOS and HDA present", + cdrom: root_path + "/images/linux.iso", + hda: root_path + "/images/msdos.img", + timeout: 90, + expected_texts: [ + "/root%", + "test passed", + ], + boot_order: 0x123, + alternative_bios: true, + actions: [ + { + on_text: "/root%", + run: "cd tests; ./test-i386 > emu.test; diff emu.test reference.test && echo test pas''sed || echo failed\n", + }, + ], + }, { name: "MS-DOS", skip_if_disk_image_missing: true, @@ -292,7 +392,7 @@ if(cluster.isMaster) ], }, { - name: "MS-DOS (hard disk + floppy disk)", + name: "MS-DOS (hard disk + floppy disk present)", skip_if_disk_image_missing: true, hda: root_path + "/images/msdos.img", fda: root_path + "/images/kolibri.img", @@ -305,6 +405,17 @@ if(cluster.isMaster) "A:\\>", ], }, + { + name: "MS-DOS (hard disk + cd-rom present)", + skip_if_disk_image_missing: true, + hda: root_path + "/images/msdos.img", + cdrom: root_path + "/images/linux.iso", + boot_order: 0x132, + timeout: 120, + expected_texts: [ + "C:\\>", + ], + }, { name: "Linux 4", skip_if_disk_image_missing: true, @@ -427,6 +538,38 @@ if(cluster.isMaster) }, ], }, + { + name: "Windows 3.0 (with hda present)", + slow: 1, + skip_if_disk_image_missing: true, + timeout: 10 * 60, + hda: root_path + "/images/win31.img", + cdrom: root_path + "/images/Win30.iso", + expected_texts: [ + "Press any key to continue", + " **************************************************", + ], + expect_graphical_mode: true, + expect_mouse_registered: true, + actions: [ + { + on_text: "Press any key to continue . . .", + after: 1000, + run: "x", + }, + { + on_text: " **************************************************", + after: 1000, + run: "x", + }, + { + on_text: "C> ", + after: 1000, + run: "win\n", + }, + ], + boot_order: 0x123 + }, { name: "Windows 3.1", skip_if_disk_image_missing: true, @@ -439,6 +582,20 @@ if(cluster.isMaster) "MODE prepare code page function completed", ], }, + { + name: "Windows 3.1 (with cdrom present)", + skip_if_disk_image_missing: true, + timeout: 2 * 60, + boot_order: 0x312, + hda: root_path + "/images/win31.img", + cdrom: root_path + "/images/Win30.iso", + expect_graphical_mode: true, + expect_graphical_size: [1024, 768], + expect_mouse_registered: true, + expected_texts: [ + "MODE prepare code page function completed", + ], + }, { name: "FreeBSD", skip_if_disk_image_missing: true, From 00bc200a588ee1916e342fa79425140a411d2a6c Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Mon, 21 Aug 2023 12:47:40 -0700 Subject: [PATCH 08/27] fixes towards empty cd-rom support for bochs bios --- src/browser/main.js | 1 + src/browser/starter.js | 3 +- src/ide.js | 92 ++++++++++++----------------- tests/full/run.js | 130 +++++++++++++++++++++++------------------ 4 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/browser/main.js b/src/browser/main.js index b3aa22fef9..26ea85e45b 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -1140,6 +1140,7 @@ settings.fda = infos.fda; settings.cdrom = infos.cdrom; + settings.wants_cdrom = infos.wants_cdrom; settings.hda = infos.hda; settings.multiboot = infos.multiboot; settings.bzimage = infos.bzimage; diff --git a/src/browser/starter.js b/src/browser/starter.js index ecbd093c88..b6028d9674 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -262,8 +262,7 @@ V86Starter.prototype.continue_init = async function(emulator, options) options["fda"] ? BOOT_ORDER_FD_FIRST : options["hda"] ? BOOT_ORDER_HD_FIRST : BOOT_ORDER_CD_FIRST; - - settings.wants_cdrom = options["wants_cdrom"] || false; + settings.wants_cdrom = options["wants_cdrom"] || ("cdrom" in options) || false; settings.acpi = options["acpi"]; settings.disable_jit = options["disable_jit"]; settings.load_devices = true; diff --git a/src/ide.js b/src/ide.js index 1f7be64279..2dab1ab9a1 100644 --- a/src/ide.js +++ b/src/ide.js @@ -96,7 +96,6 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) // status cpu.io.register_read(this.ata_port | 7, this, function() { - dbg_log("dev "+this.name+" lower irq", LOG_DISK); this.cpu.device_lower_irq(this.irq); return this.read_status(); }); @@ -203,6 +202,7 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) } else { + dbg_log("dev "+this.name+" Master", LOG_DISK); this.current_interface = this.master; } @@ -223,8 +223,10 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) cpu.io.register_write(this.ata_port | 7, this, function(data) { - dbg_log("dev "+this.name+" lower irq", LOG_DISK); + // dbg_log("dev "+this.name+" lower irq", LOG_DISK); this.cpu.device_lower_irq(this.irq); + // clear error and DF bits + this.current_interface.status &= ~(1 | (1 << 5)); this.current_interface.ata_command(data); }); @@ -255,16 +257,9 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) IDEDevice.prototype.read_status = function() { - if(this.current_interface.buffer) - { - var ret = this.current_interface.status; - dbg_log("dev "+this.name+" ATA read status: " + h(ret, 2), LOG_DISK); - return ret; - } - else - { - return 0; - } + var ret = this.current_interface.status; + dbg_log("dev "+this.name+" ATA read status: " + h(ret, 2), LOG_DISK); + return ret; }; IDEDevice.prototype.write_control = function(data) @@ -458,7 +453,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) this.sector_count = 0; /** @type {number} */ - this.head_count = 0; + this.head_count = this.is_atapi ? 1 : 0; /** @type {number} */ this.sectors_per_track = 0; @@ -476,12 +471,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) this.sector_count = Math.ceil(this.sector_count); } - if(is_cd) - { - this.head_count = 1; - this.sectors_per_track = 0; - } - else + if(!is_cd) { // "default" values: 16/63 // common: 255, 63 @@ -504,28 +494,6 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) //{ // this.cylinder_count = 16383; //} - - // disk translation: lba - var rtc = cpu.devices.rtc; - - // master - rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, - rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << this.nr * 4); - rtc.cmos_write(CMOS_DISK_DATA, rtc.cmos_read(CMOS_DISK_DATA) & 0x0F | 0xF0); - - var reg = CMOS_DISK_DRIVE1_CYL; - rtc.cmos_write(reg + 0, this.cylinder_count & 0xFF); - rtc.cmos_write(reg + 1, this.cylinder_count >> 8 & 0xFF); - rtc.cmos_write(reg + 2, this.head_count & 0xFF); - rtc.cmos_write(reg + 3, 0xFF); - rtc.cmos_write(reg + 4, 0xFF); - rtc.cmos_write(reg + 5, 0xC8); - rtc.cmos_write(reg + 6, this.cylinder_count & 0xFF); - rtc.cmos_write(reg + 7, this.cylinder_count >> 8 & 0xFF); - rtc.cmos_write(reg + 8, this.sectors_per_track & 0xFF); - - //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, - // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2)); // slave } /** @const */ @@ -638,8 +606,7 @@ IDEInterface.prototype.ata_command = function(cmd) { dbg_log("ATA dev " + this.device.name + " Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); - // && cmd != 0xA0 && cmd != 0xA1 && cmd != 0xEC - if(!this.buffer) + if(!this.buffer && cmd != 0xA1 && cmd != 0xEC && cmd != 0xA0) { dbg_log("dev "+this.device.name+" abort: No buffer", LOG_DISK); this.error = 4; @@ -742,7 +709,8 @@ IDEInterface.prototype.ata_command = function(cmd) dbg_log("dev "+this.device.name+" ATA identify packet device", LOG_DISK); if(this.is_atapi) - { + { + // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? this.create_identify_packet(); this.status = 0x58; @@ -819,6 +787,7 @@ IDEInterface.prototype.ata_command = function(cmd) return; } + // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? this.create_identify_packet(); this.status = 0x58; @@ -871,6 +840,21 @@ IDEInterface.prototype.atapi_handle = function() this.data_pointer = 0; this.current_atapi_command = this.data[0]; + if(!this.buffer && (this.current_atapi_command == 0x25 || + this.current_atapi_command == 0x28 || + this.current_atapi_command == 0x42 || + this.current_atapi_command == 0x43 || + this.current_atapi_command == 0x51)) + { + dbg_log("dev "+this.device.name+" CD read-related action: no buffer", LOG_DISK); + this.status = 0x51; + this.error = 0x21; + this.data_allocate(0); + this.data_end = this.data_length; + this.bytecount = this.bytecount & ~7 | 2 | 1; + this.push_irq(); + return; + } switch(this.current_atapi_command) { @@ -889,7 +873,7 @@ IDEInterface.prototype.atapi_handle = function() this.status = 0x58; this.data[0] = 0x80 | 0x70; - this.data[2] = 5; // illegal request + this.data[2] = this.error >> 4; this.data[7] = 8; break; @@ -1162,9 +1146,16 @@ IDEInterface.prototype.atapi_read = function(cmd) req_length = byte_count; } - if(start >= this.buffer.byteLength) + if(!this.buffer) { - dbg_assert(false, "CD read: Outside of disk end=" + h(start + byte_count) + + dbg_assert(false, "dev "+this.device.name+" CD read: no buffer", LOG_DISK); + this.status = 0xFF; + this.error = 0x41; + this.push_irq(); + } + else if(start >= this.buffer.byteLength) + { + dbg_assert(false, "dev "+this.device.name+" CD read: Outside of disk end=" + h(start + byte_count) + " size=" + h(this.buffer.byteLength), LOG_DISK); this.status = 0xFF; @@ -1852,13 +1843,6 @@ IDEInterface.prototype.create_identify_packet = function() { // http://bochs.sourceforge.net/cgi-bin/lxr/source/iodev/harddrv.cc#L2821 - if(this.drive_head & 0x10) - { - // slave - this.data_allocate(0); - return; - } - for(var i = 0; i < 512; i++) { this.data[i] = 0; diff --git a/tests/full/run.js b/tests/full/run.js index 8690419edd..7edf747f0d 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -85,7 +85,7 @@ if(cluster.isMaster) { name: "FreeDOS boot", fda: root_path + "/images/freedos722.img", - timeout: 20, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -95,7 +95,27 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 20, + timeout: 5, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with empty cdrom", + fda: root_path + "/images/freedos722.img", + wants_cdrom:true, + boot_order:0x231, + timeout: 5, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with empty cdrom (alternative boot order)", + fda: root_path + "/images/freedos722.img", + wants_cdrom:true, + boot_order:0x213, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -105,7 +125,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 20, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -116,7 +136,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x321, - timeout: 30, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -124,7 +144,29 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS", fda: root_path + "/images/freedos722.img", - timeout: 20, + timeout: 5, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and empty cdrom", + fda: root_path + "/images/freedos722.img", + timeout: 5, + wants_cdrom: true, + boot_order:0x312, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and empty cdrom (alternative boot order)", + fda: root_path + "/images/freedos722.img", + timeout: 5, + boot_order:0x321, + wants_cdrom: true, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -135,7 +177,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 20, + timeout: 5, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -146,7 +188,19 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 20, + timeout: 5, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and hda present and empty cdrom", + fda: root_path + "/images/freedos722.img", + hda: root_path + "/images/msdos.img", + wants_cdrom: true, + boot_order:0x231, + timeout: 5, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -158,7 +212,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 20, + timeout: 5, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -956,56 +1010,17 @@ if(cluster.isMaster) { on_text: "boot:", run: "\n" }, { on_text: "tc@box", run: "sudo mount /dev/fd0 /mnt && ls /mnt\n" }, ], - expected_texts: ["AUTOEXEC.BAT"], - }, - { - name: "Core 8", - skip_if_disk_image_missing: 1, - timeout: 5 * 60, - cdrom: root_path + "/images/experimental/os/Core-8.0.iso", - expected_texts: ["tc@box"], - actions: [{ on_text: "boot:", run: "\n" }], - }, - { - name: "Core 7", - skip_if_disk_image_missing: 1, - timeout: 5 * 60, - cdrom: root_path + "/images/experimental/os/Core-7.2.iso", - expected_texts: ["tc@box"], - actions: [{ on_text: "boot:", run: "\n" }], - }, - { - name: "Core 6", - skip_if_disk_image_missing: 1, - timeout: 5 * 60, - cdrom: root_path + "/images/experimental/os/Core-6.4.1.iso", - expected_texts: ["tc@box"], - actions: [{ on_text: "boot:", run: "\n" }], - }, - { - name: "Core 5", - skip_if_disk_image_missing: 1, - timeout: 5 * 60, - cdrom: root_path + "/images/experimental/os/Core-5.4.iso", - expected_texts: ["tc@box"], - actions: [{ on_text: "boot:", run: "\n" }], - }, - { - name: "Core 4", - skip_if_disk_image_missing: 1, - timeout: 5 * 60, - cdrom: root_path + "/images/experimental/os/Core-4.7.7.iso", - expected_texts: ["tc@box"], - actions: [{ on_text: "boot:", run: "\n" }], }, { - name: "Damn Small Linux", - skip_if_disk_image_missing: 1, - timeout: 5 * 60, - cdrom: root_path + "/images/dsl-4.11.rc2.iso", - expect_graphical_mode: true, - expect_graphical_size: [1024, 768], - expect_mouse_registered: true, + name: "FreeDOS boot with cdrom and HDA present (alternative boot order)", + fda: root_path + "/images/freedos722.img", + cdrom: root_path + "/images/linux.iso", + hda: root_path + "/images/msdos.img", + boot_order:0x321, + timeout: 5, + expected_texts: [ + "Welcome to FreeDOS", + ], }, ]; @@ -1123,7 +1138,7 @@ function run_test(test, done) vga_bios: { url: vga_bios }, autostart: true, memory_size: test.memory_size || 128 * 1024 * 1024, - log_level: 0, + log_level: 0x8000, cmdline: test.cmdline, }; @@ -1131,6 +1146,7 @@ function run_test(test, done) { settings.cdrom = { url: test.cdrom }; } + settings.wants_cdrom = test.wants_cdrom; if(test.fda) { settings.fda = { url: test.fda }; From dbc17b2fc0dce50c9ae5c8eaaca393acdf66d627 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Mon, 21 Aug 2023 13:20:39 -0700 Subject: [PATCH 09/27] Fix empty/missing device enumeration for bochs bios --- src/ide.js | 31 +++++++++++++++++++++++-------- tests/full/run.js | 30 +++++++++++++++--------------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/ide.js b/src/ide.js index 2dab1ab9a1..db2a6aeea3 100644 --- a/src/ide.js +++ b/src/ide.js @@ -167,26 +167,42 @@ function IDEDevice(cpu, master_buffer, slave_buffer, is_cd, nr, bus) { dbg_log("dev "+this.name+" 1F2/bytecount: " + h(data), LOG_DISK); this.master.bytecount = (this.master.bytecount << 8 | data) & 0xFFFF; - this.slave.bytecount = (this.slave.bytecount << 8 | data) & 0xFFFF; + // ignore writes to slave; bochs bios uses this to detect whether a slave is attached. + if(slave_buffer) + { + this.slave.bytecount = (this.slave.bytecount << 8 | data) & 0xFFFF; + } }); cpu.io.register_write(this.ata_port | 3, this, function(data) { dbg_log("dev "+this.name+" 1F3/sector: " + h(data), LOG_DISK); this.master.sector = (this.master.sector << 8 | data) & 0xFFFF; - this.slave.sector = (this.slave.sector << 8 | data) & 0xFFFF; + // ignore writes to slave; bochs bios uses this to detect whether a slave is attached. + if(slave_buffer) + { + this.slave.sector = (this.slave.sector << 8 | data) & 0xFFFF; + } }); cpu.io.register_write(this.ata_port | 4, this, function(data) { dbg_log("dev "+this.name+" 1F4/sector low: " + h(data), LOG_DISK); this.master.cylinder_low = (this.master.cylinder_low << 8 | data) & 0xFFFF; - this.slave.cylinder_low = (this.slave.cylinder_low << 8 | data) & 0xFFFF; + // ignore writes to slave; bochs bios uses this to detect whether a slave is attached. + if(slave_buffer) + { + this.slave.cylinder_low = (this.slave.cylinder_low << 8 | data) & 0xFFFF; + } }); cpu.io.register_write(this.ata_port | 5, this, function(data) { dbg_log("dev "+this.name+" 1F5/sector high: " + h(data), LOG_DISK); this.master.cylinder_high = (this.master.cylinder_high << 8 | data) & 0xFFFF; - this.slave.cylinder_high = (this.slave.cylinder_high << 8 | data) & 0xFFFF; + // ignore writes to slave; bochs bios uses this to detect whether a slave is attached. + if(slave_buffer) + { + this.slave.cylinder_high = (this.slave.cylinder_high << 8 | data) & 0xFFFF; + } }); cpu.io.register_write(this.ata_port | 6, this, function(data) { @@ -606,7 +622,7 @@ IDEInterface.prototype.ata_command = function(cmd) { dbg_log("ATA dev " + this.device.name + " Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); - if(!this.buffer && cmd != 0xA1 && cmd != 0xEC && cmd != 0xA0) + if((!this.buffer && cmd != 0xA1 && cmd != 0xEC && cmd != 0xA0)) { dbg_log("dev "+this.device.name+" abort: No buffer", LOG_DISK); this.error = 4; @@ -709,8 +725,7 @@ IDEInterface.prototype.ata_command = function(cmd) dbg_log("dev "+this.device.name+" ATA identify packet device", LOG_DISK); if(this.is_atapi) - { - // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? + { this.create_identify_packet(); this.status = 0x58; @@ -787,7 +802,6 @@ IDEInterface.prototype.ata_command = function(cmd) return; } - // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? this.create_identify_packet(); this.status = 0x58; @@ -1932,6 +1946,7 @@ IDEInterface.prototype.create_identify_packet = function() this.data_length = 512; this.data_end = 512; + }; IDEInterface.prototype.data_allocate = function(len) diff --git a/tests/full/run.js b/tests/full/run.js index 7edf747f0d..d55e7b8d2c 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -85,7 +85,7 @@ if(cluster.isMaster) { name: "FreeDOS boot", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -95,7 +95,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -105,7 +105,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", wants_cdrom:true, boot_order:0x231, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -115,7 +115,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", wants_cdrom:true, boot_order:0x213, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -125,7 +125,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -136,7 +136,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x321, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -144,7 +144,7 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -153,7 +153,7 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS and empty cdrom", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, wants_cdrom: true, boot_order:0x312, alternative_bios: true, @@ -164,7 +164,7 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS and empty cdrom (alternative boot order)", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, boot_order:0x321, wants_cdrom: true, alternative_bios: true, @@ -177,7 +177,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -188,7 +188,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -200,7 +200,7 @@ if(cluster.isMaster) hda: root_path + "/images/msdos.img", wants_cdrom: true, boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -212,7 +212,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -1017,7 +1017,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x321, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -1138,7 +1138,7 @@ function run_test(test, done) vga_bios: { url: vga_bios }, autostart: true, memory_size: test.memory_size || 128 * 1024 * 1024, - log_level: 0x8000, + log_level: 0, cmdline: test.cmdline, }; From 0389dfc6507ea6f5fb44b075a924f46ec3494310 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Tue, 22 Aug 2023 09:28:23 -0700 Subject: [PATCH 10/27] put back RTC CMOS writes, freedos13 seems to want them --- src/ide.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/ide.js b/src/ide.js index db2a6aeea3..8f0a3a273a 100644 --- a/src/ide.js +++ b/src/ide.js @@ -510,6 +510,23 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) //{ // this.cylinder_count = 16383; //} + var rtc = cpu.devices.rtc; + // master + rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, + rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << this.nr * 4); + rtc.cmos_write(CMOS_DISK_DATA, rtc.cmos_read(CMOS_DISK_DATA) & 0x0F | 0xF0); + + var reg = this.nr == 0 ? CMOS_DISK_DRIVE1_CYL : CMOS_DISK_DRIVE2_CYL; + rtc.cmos_write(reg + 0, this.cylinder_count & 0xFF); + rtc.cmos_write(reg + 1, this.cylinder_count >> 8 & 0xFF); + rtc.cmos_write(reg + 2, this.head_count & 0xFF); + rtc.cmos_write(reg + 3, 0xFF); + rtc.cmos_write(reg + 4, 0xFF); + rtc.cmos_write(reg + 5, 0xC8); + rtc.cmos_write(reg + 6, this.cylinder_count & 0xFF); + rtc.cmos_write(reg + 7, this.cylinder_count >> 8 & 0xFF); + //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, + // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2) } /** @const */ From b42912ae2158d0a8b00579a661e02a9b1aed441e Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Tue, 22 Aug 2023 11:44:46 -0700 Subject: [PATCH 11/27] set proper default sector count for cdrom --- src/ide.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ide.js b/src/ide.js index 8f0a3a273a..5bff7ecd6e 100644 --- a/src/ide.js +++ b/src/ide.js @@ -469,7 +469,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) this.sector_count = 0; /** @type {number} */ - this.head_count = this.is_atapi ? 1 : 0; + this.head_count = 0; /** @type {number} */ this.sectors_per_track = 0; @@ -487,7 +487,13 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) this.sector_count = Math.ceil(this.sector_count); } - if(!is_cd) + if(is_cd) + { + // default values: 1/2048 + this.head_count = 1; + this.sectors_per_track = 2048; + } + else { // "default" values: 16/63 // common: 255, 63 @@ -510,6 +516,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) //{ // this.cylinder_count = 16383; //} + var rtc = cpu.devices.rtc; // master rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, @@ -527,6 +534,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) rtc.cmos_write(reg + 7, this.cylinder_count >> 8 & 0xFF); //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2) + } /** @const */ From 79d4302167ba62b26a2740d3fa0abc1b7e067c33 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Wed, 16 Aug 2023 14:22:54 -0700 Subject: [PATCH 12/27] WIP floppy eject/insert; dos does not see re-insert yet --- src/floppy.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/floppy.js b/src/floppy.js index 914bd8be78..a212e6cdaa 100644 --- a/src/floppy.js +++ b/src/floppy.js @@ -56,6 +56,10 @@ function FloppyController(cpu, fda_image, fdb_image) { this.set_fda(fda_image); } + this.dir = 0x0; + cpu.devices.rtc.cmos_write(CMOS_FLOPPY_DRIVE_TYPE, this.floppy_type.type << 4); + + dbg_assert(!fdb_image, "FDB not supported"); dbg_assert(!fdb_image, "FDB not supported"); @@ -277,6 +281,9 @@ FloppyController.prototype.port3F5_write = function(reg_byte) case 0x05: case 0x45: case 0xC5: + // also format track?? + case 0x0D: + case 0x4D: this.next_command = function(args) { this.do_sector(true, args); }; this.bytes_expecting = 8; break; From 6c46de5a53daa136d013eb10d26473ae1536c7c8 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Wed, 16 Aug 2023 14:26:00 -0700 Subject: [PATCH 13/27] it seems to work for MSDOS --- src/floppy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/floppy.js b/src/floppy.js index a212e6cdaa..dddfa71d57 100644 --- a/src/floppy.js +++ b/src/floppy.js @@ -388,7 +388,7 @@ FloppyController.prototype.seek = function(args) // clear eject flag if seek takes us to a new cylinder if(new_cylinder !== this.last_cylinder) { - this.dir = 0x0; + this.dir = 0x80; } // do nothing if no fda if (this.fda_image) From 34ede09c939aea23a04ea173784965765a2219d9 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Wed, 16 Aug 2023 14:35:20 -0700 Subject: [PATCH 14/27] remove incorrect format command half-impl --- src/floppy.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/floppy.js b/src/floppy.js index dddfa71d57..2640c39d09 100644 --- a/src/floppy.js +++ b/src/floppy.js @@ -281,9 +281,6 @@ FloppyController.prototype.port3F5_write = function(reg_byte) case 0x05: case 0x45: case 0xC5: - // also format track?? - case 0x0D: - case 0x4D: this.next_command = function(args) { this.do_sector(true, args); }; this.bytes_expecting = 8; break; From b0824d81d7b5a4a3badf45a6eeb20671093e60ff Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Mon, 21 Aug 2023 09:41:43 -0700 Subject: [PATCH 15/27] Add extra_images config setting for V86Starter, extend test cases with floppy eject insert --- src/browser/starter.js | 24 ++++++++++++++++++++- src/floppy.js | 3 +-- tests/full/run.js | 48 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/browser/starter.js b/src/browser/starter.js index b6028d9674..17a3098915 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -373,7 +373,12 @@ V86Starter.prototype.continue_init = async function(emulator, options) settings.fs9p_json = buffer; break; default: - dbg_assert(false, name); + dbg_assert(name in this.extra_images, name); + if(name in this.extra_images) + { + this.extra_images[name].buffer = buffer; + } + break; } } @@ -426,6 +431,15 @@ V86Starter.prototype.continue_init = async function(emulator, options) console.warn("Warning: Unknown option 'state'. Did you mean 'initial_state'?"); } + if("extra_images" in options) + { + this.extra_images = options["extra_images"]; + } + else + { + this.extra_images = {}; + } + var image_names = [ "bios", "vga_bios", "cdrom", "hda", "hdb", "fda", "fdb", @@ -437,6 +451,14 @@ V86Starter.prototype.continue_init = async function(emulator, options) { add_file(image_names[i], options[image_names[i]]); } + for(let other_image in this.extra_images) + { + if(other_image in image_names) + { + throw new Error("Extra image name "+other_image+" overlaps with built-in image"); + } + add_file(other_image, this.extra_images[other_image]) + } if(options["filesystem"]) { diff --git a/src/floppy.js b/src/floppy.js index 2640c39d09..7b6c73e182 100644 --- a/src/floppy.js +++ b/src/floppy.js @@ -56,7 +56,6 @@ function FloppyController(cpu, fda_image, fdb_image) { this.set_fda(fda_image); } - this.dir = 0x0; cpu.devices.rtc.cmos_write(CMOS_FLOPPY_DRIVE_TYPE, this.floppy_type.type << 4); dbg_assert(!fdb_image, "FDB not supported"); @@ -385,7 +384,7 @@ FloppyController.prototype.seek = function(args) // clear eject flag if seek takes us to a new cylinder if(new_cylinder !== this.last_cylinder) { - this.dir = 0x80; + this.dir = 0x0; } // do nothing if no fda if (this.fda_image) diff --git a/tests/full/run.js b/tests/full/run.js index d55e7b8d2c..12381c57fd 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -9,7 +9,7 @@ var TEST_NAME = process.env.TEST_NAME; const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; const RUN_SLOW_TESTS = +process.env.RUN_SLOW_TESTS; -const VERBOSE = false; +const VERBOSE = +process.env.VERBOSE || false; const LOG_SCREEN = false; try @@ -79,6 +79,44 @@ function send_work_to_worker(worker, message) } } +function do_action(test, emulator, run_step) +{ + if(Array.isArray(run_step)) + { + for(let step of run_step) + { + do_action(test, emulator, step); + } + } + else if(typeof run_step == "string") + { + if(VERBOSE) console.error("Sending '%s'", run_step); + emulator.keyboard_send_text(run_step); + } + else if(typeof run_step == "function") + { + if(VERBOSE) console.error("Run fn ", run_step); + run_step(test, emulator); + } + else if(typeof run_step == "object") + { + if(VERBOSE) console.error("Trigger ", run_step); + switch(run_step.action) + { + case "eject_fda": + { + emulator.v86.cpu.devices.fdc.eject_fda(); + break; + } + case "insert_fda": + { + emulator.v86.cpu.devices.fdc.insert_fda(emulator.extra_images[run_step.image].buffer); + break; + } + } + } +} + if(cluster.isMaster) { var tests = [ @@ -1168,6 +1206,7 @@ function run_test(test, done) settings.acpi = test.acpi; settings.boot_order = test.boot_order; settings.cpuid_level = test.cpuid_level; + settings.extra_images = test.extra_images; if(test.expected_texts) { @@ -1182,7 +1221,6 @@ function run_test(test, done) { test.expected_serial_text = []; } - var emulator = new V86(settings); var screen = new Uint8Array(SCREEN_WIDTH * 25); @@ -1360,8 +1398,7 @@ function run_test(test, done) timeouts.push( setTimeout(() => { - if(VERBOSE) console.error("Sending '%s'", action.run); - emulator.keyboard_send_text(action.run); + do_action(test, emulator, action.run); }, action.after || 0) ); } @@ -1414,8 +1451,7 @@ function run_test(test, done) { timeouts.push( setTimeout(() => { - if(VERBOSE) console.error("Sending '%s'", action.run); - emulator.keyboard_send_text(action.run); + do_action(test, emulator, action.run); }, action.after || 0) ); } From 718fa0753189dabc0c1cbcbeee2054efa96fe8d5 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Mon, 21 Aug 2023 09:47:40 -0700 Subject: [PATCH 16/27] add semicolon --- src/browser/starter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/starter.js b/src/browser/starter.js index 17a3098915..2e9346544d 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -457,7 +457,7 @@ V86Starter.prototype.continue_init = async function(emulator, options) { throw new Error("Extra image name "+other_image+" overlaps with built-in image"); } - add_file(other_image, this.extra_images[other_image]) + add_file(other_image, this.extra_images[other_image]); } if(options["filesystem"]) From 276de392f608e28d4c1cac8f54940bac57d71793 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Wed, 23 Aug 2023 12:53:38 -0700 Subject: [PATCH 17/27] Remove extra_images, add V86.load_image load_image takes an image file descriptor (like you'd find in a V86 option like `hda` or `cdrom`) and returns a Promise which will resolve with a full image description (including a `buffer` field which is a buffer type from buffer.js). This currently duplicates a bunch of logic from starter's `continue_init` function, but I hope in the future that could be refactored out. The main sticking point is progress reporting, which would need to do something like add up the total sizes across all images and increment a counter as new bytes come in, but I wanted to keep this commit focused. --- src/browser/starter.js | 125 ++++++++++--- tests/full/run.js | 393 +++++++++++++++++++++-------------------- 2 files changed, 304 insertions(+), 214 deletions(-) diff --git a/src/browser/starter.js b/src/browser/starter.js index 2e9346544d..fa0fc21faa 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -373,11 +373,7 @@ V86Starter.prototype.continue_init = async function(emulator, options) settings.fs9p_json = buffer; break; default: - dbg_assert(name in this.extra_images, name); - if(name in this.extra_images) - { - this.extra_images[name].buffer = buffer; - } + dbg_assert(false, name); break; } } @@ -431,15 +427,6 @@ V86Starter.prototype.continue_init = async function(emulator, options) console.warn("Warning: Unknown option 'state'. Did you mean 'initial_state'?"); } - if("extra_images" in options) - { - this.extra_images = options["extra_images"]; - } - else - { - this.extra_images = {}; - } - var image_names = [ "bios", "vga_bios", "cdrom", "hda", "hdb", "fda", "fdb", @@ -451,14 +438,6 @@ V86Starter.prototype.continue_init = async function(emulator, options) { add_file(image_names[i], options[image_names[i]]); } - for(let other_image in this.extra_images) - { - if(other_image in image_names) - { - throw new Error("Extra image name "+other_image+" overlaps with built-in image"); - } - add_file(other_image, this.extra_images[other_image]); - } if(options["filesystem"]) { @@ -1433,6 +1412,108 @@ V86Starter.prototype.write_memory = function(blob, offset) this.v86.cpu.write_blob(blob, offset); }; +/** + * Loads an image buffer (e.g. a SyncBuffer, AsyncXHRBuffer, etc) from + * a buffer descriptor (as detailed in the documentation for the V86 + * constructor) asynchronously, yielding a buffer desc with an + * explicitly given buffer. + * + * @param {Object} file + * @return {Promise} + * @export + */ + +V86Starter.prototype.load_image = async function(file) +{ + if(file.buffer && file.buffer.get && file.buffer.set && file.buffer.load) + { + return file; + } + + let image = {}; + for(let fv in file) + { + image[fv] = file[fv]; + } + + if(file.buffer instanceof ArrayBuffer) + { + var buffer = new v86util.SyncBuffer(file.buffer); + image.buffer = await new Promise((resolve, reject) => { + image.buffer.onload = (e) => resolve(buffer); + image.buffer.load(); + }); + return image; + } + else if(typeof File !== "undefined" && file.buffer instanceof File) + { + // SyncFileBuffer: + // - loads the whole disk image into memory, impossible for large files (more than 1GB) + // - can later serve get/set operations fast and synchronously + // - takes some time for first load, neglectable for small files (up to 100Mb) + // + // AsyncFileBuffer: + // - loads slices of the file asynchronously as requested + // - slower get/set + + // Heuristics: If file is larger than or equal to 256M, use AsyncFileBuffer + if(file.async === undefined) + { + file.async = file.buffer.size >= 256 * 1024 * 1024; + } + + if(file.async) + { + var buffer = new v86util.AsyncFileBuffer(file.buffer); + } + else + { + var buffer = new v86util.SyncFileBuffer(file.buffer); + } + + image.buffer = await new Promise((resolve, reject) => { + image.buffer.onload = (e) => resolve(buffer); + image.buffer.load(); + }); + return image; + } + else if(file.url) + { + if(file.async) + { + let buffer; + + if(file.use_parts) + { + buffer = new v86util.AsyncXHRPartfileBuffer(file.url, file.size, file.fixed_chunk_size, false, this.zstd_decompress_worker.bind(this)); + } + else + { + buffer = new v86util.AsyncXHRBuffer(file.url, file.size, file.fixed_chunk_size); + } + image.buffer = await new Promise((resolve, reject) => { + image.buffer.onload = (e) => resolve(buffer); + image.buffer.load(); + }); + return image; + } + else + { + image.buffer = await new Promise((resolve, reject) => { + v86util.load_file(file.url, { + done: (result) => resolve(new v86util.SyncBuffer(result)) + }) + }); + return image; + } + } + else + { + dbg_log("Ignored file: url=" + file.url + " buffer=" + file.buffer); + return null; + } +}; + /** * @ignore * @constructor diff --git a/tests/full/run.js b/tests/full/run.js index 12381c57fd..aad4e833c5 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -110,7 +110,7 @@ function do_action(test, emulator, run_step) } case "insert_fda": { - emulator.v86.cpu.devices.fdc.insert_fda(emulator.extra_images[run_step.image].buffer); + emulator.v86.cpu.devices.fdc.insert_fda(test.extra_images[run_step.image].buffer); break; } } @@ -1206,7 +1206,6 @@ function run_test(test, done) settings.acpi = test.acpi; settings.boot_order = test.boot_order; settings.cpuid_level = test.cpuid_level; - settings.extra_images = test.extra_images; if(test.expected_texts) { @@ -1221,239 +1220,249 @@ function run_test(test, done) { test.expected_serial_text = []; } + var emulator = new V86(settings); var screen = new Uint8Array(SCREEN_WIDTH * 25); - function check_text_test_done() - { - return test.expected_texts.length === 0; - } - - function check_serial_test_done() - { - return test.expected_serial_text.length === 0; - } - - var mouse_test_done = false; - function check_mouse_test_done() + let extras = []; + for(let extra in test.extra_images) { - return !test.expect_mouse_registered || mouse_test_done; + extras.push(emulator.load_image(test.extra_images[extra]).then((img) => test.extra_images[extra] = img)); } + Promise.all(extras).then((_imgs) => { + function check_text_test_done() + { + return test.expected_texts.length === 0; + } - var graphical_test_done = false; - var size_test_done = false; - function check_graphical_test_done() - { - return !test.expect_graphical_mode || (graphical_test_done && (!test.expect_graphical_size || size_test_done)); - } - - var test_start = Date.now(); - - var timeout_seconds = test.timeout * TIMEOUT_EXTRA_FACTOR; - var timeout = setTimeout(check_test_done, (timeout_seconds + 1) * 1000); - var timeouts = [timeout]; - - var on_text = []; - var stopped = false; - - var screen_interval = null; + function check_serial_test_done() + { + return test.expected_serial_text.length === 0; + } - function check_test_done() - { - if(stopped) + var mouse_test_done = false; + function check_mouse_test_done() { - return; + return !test.expect_mouse_registered || mouse_test_done; } - if(check_text_test_done() && - check_mouse_test_done() && - check_graphical_test_done() && - check_serial_test_done()) + var graphical_test_done = false; + var size_test_done = false; + function check_graphical_test_done() { - var end = Date.now(); + return !test.expect_graphical_mode || (graphical_test_done && (!test.expect_graphical_size || size_test_done)); + } - for(let timeout of timeouts) clearTimeout(timeout); - stopped = true; + var test_start = Date.now(); - emulator.stop(); + var timeout_seconds = test.timeout * TIMEOUT_EXTRA_FACTOR; + var timeout = setTimeout(check_test_done, (timeout_seconds + 1) * 1000); + var timeouts = [timeout]; - if(screen_interval !== null) - { - clearInterval(screen_interval); - } + var on_text = []; + var stopped = false; - console.warn("Passed test: %s (took %ds)", test.name, (end - test_start) / 1000); - console.warn(); + var screen_interval = null; - done(); - } - else if(Date.now() >= test_start + timeout_seconds * 1000) + function check_test_done() { - for(let timeout of timeouts) clearTimeout(timeout); - stopped = true; - - if(screen_interval !== null) + if(stopped) { - clearInterval(screen_interval); + return; } - emulator.stop(); - emulator.destroy(); - - if(test.failure_allowed) + if(check_text_test_done() && + check_mouse_test_done() && + check_graphical_test_done() && + check_serial_test_done()) { - console.warn("Test failed: %s (failure allowed)\n", test.name); - } - else - { - console.warn(screen_to_text(screen)); - console.warn("Test failed: %s\n", test.name); - } + var end = Date.now(); - if(!check_text_test_done()) - { - console.warn('Expected text "%s" after %d seconds.', bytearray_to_string(test.expected_texts[0]), timeout_seconds); - } + for(let timeout of timeouts) clearTimeout(timeout); + stopped = true; - if(!check_graphical_test_done()) - { - console.warn("Expected graphical mode after %d seconds.", timeout_seconds); - } - - if(!check_mouse_test_done()) - { - console.warn("Expected mouse activation after %d seconds.", timeout_seconds); - } + emulator.stop(); - if(!check_serial_test_done()) - { - console.warn('Expected serial text "%s" after %d seconds.', test.expected_serial_text, timeout_seconds); - } + if(screen_interval !== null) + { + clearInterval(screen_interval); + } - if(on_text.length) - { - console.warn(`Note: Expected text "${bytearray_to_string(on_text[0].text)}" to run "${on_text[0].run}"`); - } + console.warn("Passed test: %s (took %ds)", test.name, (end - test_start) / 1000); + console.warn(); - if(!test.failure_allowed) - { - process.exit(1); - } - else - { done(); } - } - } - - emulator.add_listener("mouse-enable", function() - { - mouse_test_done = true; - check_test_done(); - }); - - emulator.add_listener("screen-set-mode", function(is_graphical) - { - graphical_test_done = is_graphical; - check_test_done(); - }); - - emulator.add_listener("screen-set-size-graphical", function(size) - { - if(test.expect_graphical_size) - { - size_test_done = size[0] === test.expect_graphical_size[0] && - size[1] === test.expect_graphical_size[1]; - check_test_done(); - } - }); + else if(Date.now() >= test_start + timeout_seconds * 1000) + { + for(let timeout of timeouts) clearTimeout(timeout); + stopped = true; - emulator.add_listener("screen-put-char", function(chr) - { - var y = chr[0]; - var x = chr[1]; - var code = chr[2]; - screen[x + SCREEN_WIDTH * y] = code; + if(screen_interval !== null) + { + clearInterval(screen_interval); + } - var line = get_line(screen, y); + emulator.stop(); + emulator.destroy(); - if(!check_text_test_done()) - { - let expected = test.expected_texts[0]; - if(x < expected.length && bytearray_starts_with(line, expected)) - { - test.expected_texts.shift(); - if(VERBOSE) console.log(`Passed: "${bytearray_to_string(expected)}" on screen (${test.name})`); - check_test_done(); - } - } - - if(on_text.length) - { - let expected = on_text[0].text; + if(test.failure_allowed) + { + console.warn("Test failed: %s (failure allowed)\n", test.name); + } + else + { + console.warn(screen_to_text(screen)); + console.warn("Test failed: %s\n", test.name); + } - if(x < expected.length && bytearray_starts_with(line, expected)) - { - var action = on_text.shift(); + if(!check_text_test_done()) + { + console.warn('Expected text "%s" after %d seconds.', bytearray_to_string(test.expected_texts[0]), timeout_seconds); + } - timeouts.push( - setTimeout(() => { - do_action(test, emulator, action.run); - }, action.after || 0) - ); - } - } - }); + if(!check_graphical_test_done()) + { + console.warn("Expected graphical mode after %d seconds.", timeout_seconds); + } - if(LOG_SCREEN) - { - screen_interval = setInterval(() => { - console.warn(screen_to_text(screen)); - }, 10000); - } + if(!check_mouse_test_done()) + { + console.warn("Expected mouse activation after %d seconds.", timeout_seconds); + } - let serial_line = ""; - emulator.add_listener("serial0-output-char", function(c) - { - if(c === "\n") - { - if(VERBOSE) + if(!check_serial_test_done()) { - console.log(`Serial (${test.name}):`, serial_line); + console.warn('Expected serial text "%s" after %d seconds.', test.expected_serial_text, timeout_seconds); } - if(test.expected_serial_text.length) + if(on_text.length) { - const expected = test.expected_serial_text[0]; - if(serial_line.includes(expected)) - { - test.expected_serial_text.shift(); - if(VERBOSE) console.log(`Passed: "${expected}" on serial (${test.name})`); - check_test_done(); - } + console.warn(`Note: Expected text "${bytearray_to_string(on_text[0].text)}" to run "${on_text[0].run}"`); } - serial_line = ""; - } - else if(c >= " " && c <= "~") - { - serial_line += c; + if(!test.failure_allowed) + { + process.exit(1); + } + else + { + done(); + } } - }); - - test.actions && test.actions.forEach(function(action) - { - if(action.on_text) - { - on_text.push({ text: string_to_bytearray(action.on_text), run: action.run, after: action.after }); } - else - { - timeouts.push( - setTimeout(() => { - do_action(test, emulator, action.run); - }, action.after || 0) - ); + + emulator.add_listener("mouse-enable", function() + { + mouse_test_done = true; + check_test_done(); + }); + + emulator.add_listener("screen-set-mode", function(is_graphical) + { + graphical_test_done = is_graphical; + check_test_done(); + }); + + emulator.add_listener("screen-set-size-graphical", function(size) + { + if(test.expect_graphical_size) + { + size_test_done = size[0] === test.expect_graphical_size[0] && + size[1] === test.expect_graphical_size[1]; + check_test_done(); + } + }); + + emulator.add_listener("screen-put-char", function(chr) + { + var y = chr[0]; + var x = chr[1]; + var code = chr[2]; + screen[x + SCREEN_WIDTH * y] = code; + + var line = get_line(screen, y); + + if(!check_text_test_done()) + { + let expected = test.expected_texts[0]; + if(x < expected.length && bytearray_starts_with(line, expected)) + { + test.expected_texts.shift(); + if(VERBOSE) console.log(`Passed: "${bytearray_to_string(expected)}" on screen (${test.name})`); + check_test_done(); + } + } + + if(on_text.length) + { + let expected = on_text[0].text; + + if(x < expected.length && bytearray_starts_with(line, expected)) + { + var action = on_text.shift(); + + timeouts.push( + setTimeout(() => { + do_action(test, emulator, action.run); + }, action.after || 0) + ); + } + } + }); + + if(LOG_SCREEN) + { + screen_interval = setInterval(() => { + console.warn(screen_to_text(screen)); + }, 10000); } + + let serial_line = ""; + emulator.add_listener("serial0-output-char", function(c) + { + if(c === "\n") + { + if(VERBOSE) + { + console.log(`Serial (${test.name}):`, serial_line); + } + + if(test.expected_serial_text.length) + { + const expected = test.expected_serial_text[0]; + if(serial_line.includes(expected)) + { + test.expected_serial_text.shift(); + if(VERBOSE) console.log(`Passed: "${expected}" on serial (${test.name})`); + check_test_done(); + } + } + + serial_line = ""; + } + else if(c >= " " && c <= "~") + { + serial_line += c; + } + }); + + test.actions && test.actions.forEach(function(action) + { + if(action.on_text) + { + on_text.push({ text: string_to_bytearray(action.on_text), run: action.run, after: action.after }); + } + else + { + timeouts.push( + setTimeout(() => { + do_action(test, emulator, action.run); + }, action.after || 0) + ); + } + }); + }); + } From 8f1b94de6213adbf096fc01718ddf2ab84ddf8d0 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Wed, 23 Aug 2023 14:39:42 -0700 Subject: [PATCH 18/27] Refactor starter to use load_image. Note that the progress indicator won't show the correct total number of files anymore. This should be fixed in the future by loading files in parallel and counting progress against the overall total number of bytes rather than the number of bytes in the current file. --- src/browser/starter.js | 151 ++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 76 deletions(-) diff --git a/src/browser/starter.js b/src/browser/starter.js index fa0fc21faa..418b356722 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -434,9 +434,58 @@ V86Starter.prototype.continue_init = async function(emulator, options) "bzimage", "initrd", ]; + var total = 0; + var current_file_index = 0; + var current_file_size = 0; + var current_file_name = null; + + function mk_progress(starter, index, size, url) + { + return function progress(e) + { + if(e.target.status === 200) + { + starter.emulator_bus.send("download-progress", { + file_index: index, + file_count: total, + file_name: url, + + lengthComputable: e.lengthComputable, + total: e.total || size, + loaded: e.loaded, + }); + } + else + { + starter.emulator_bus.send("download-error", { + file_index: index, + file_count: total, + file_name: url, + request: e.target, + }); + } + }; + } + for(var i = 0; i < image_names.length; i++) { - add_file(image_names[i], options[image_names[i]]); + let name = image_names[i]; + let file = options[image_names[i]]; + if(!file) { continue; } + if(name === "bios" || name === "vga_bios" || + name === "initial_state" || name === "multiboot" || + name === "bzimage" || name === "initrd") + { + // Ignore async for these because they must be available before boot. + // This should make result.buffer available after the object is loaded + file.async = false; + } + total += 1; + let img = await this.load_image(file, mk_progress(this, total-1, file.size, file.url || name)); + if(img) + { + put_on_settings.call(this, name, img.buffer); + } } if(options["filesystem"]) @@ -464,81 +513,18 @@ V86Starter.prototype.continue_init = async function(emulator, options) fs_url = fs_url.url; } dbg_assert(typeof fs_url === "string"); - - files_to_load.push({ + total += 1; + let img = await this.load_image({ name: "fs9p_json", url: fs_url, size: size, as_json: true, - }); + }, mk_progress(this, total-1, size, fs_url)); + put_on_settings.call(this, "fs9p_json", img.buffer); } } - var starter = this; - var total = files_to_load.length; - - var cont = function(index) - { - if(index === total) - { - setTimeout(done.bind(this), 0); - return; - } - - var f = files_to_load[index]; - - if(f.loadable) - { - f.loadable.onload = function(e) - { - put_on_settings.call(this, f.name, f.loadable); - cont(index + 1); - }.bind(this); - f.loadable.load(); - } - else - { - v86util.load_file(f.url, { - done: function(result) - { - if(f.url.endsWith(".zst") && f.name !== "initial_state") - { - dbg_assert(f.size, "A size must be provided for compressed images"); - result = this.zstd_decompress(f.size, new Uint8Array(result)); - } - - put_on_settings.call(this, f.name, f.as_json ? result : new v86util.SyncBuffer(result)); - cont(index + 1); - }.bind(this), - progress: function progress(e) - { - if(e.target.status === 200) - { - starter.emulator_bus.send("download-progress", { - file_index: index, - file_count: total, - file_name: f.url, - - lengthComputable: e.lengthComputable, - total: e.total || f.size, - loaded: e.loaded, - }); - } - else - { - starter.emulator_bus.send("download-error", { - file_index: index, - file_count: total, - file_name: f.url, - request: e.target, - }); - } - }, - as_json: f.as_json, - }); - } - }.bind(this); - cont(0); + setTimeout(done.bind(this), 0); async function done() { @@ -1419,11 +1405,12 @@ V86Starter.prototype.write_memory = function(blob, offset) * explicitly given buffer. * * @param {Object} file + * @param {function(*) | undefined} on_progress * @return {Promise} * @export */ -V86Starter.prototype.load_image = async function(file) +V86Starter.prototype.load_image = async function(file, on_progress) { if(file.buffer && file.buffer.get && file.buffer.set && file.buffer.load) { @@ -1438,8 +1425,8 @@ V86Starter.prototype.load_image = async function(file) if(file.buffer instanceof ArrayBuffer) { - var buffer = new v86util.SyncBuffer(file.buffer); - image.buffer = await new Promise((resolve, reject) => { + image.buffer = new v86util.SyncBuffer(file.buffer); + await new Promise((resolve, reject) => { image.buffer.onload = (e) => resolve(buffer); image.buffer.load(); }); @@ -1471,7 +1458,8 @@ V86Starter.prototype.load_image = async function(file) var buffer = new v86util.SyncFileBuffer(file.buffer); } - image.buffer = await new Promise((resolve, reject) => { + image.buffer = buffer; + await new Promise((resolve, reject) => { image.buffer.onload = (e) => resolve(buffer); image.buffer.load(); }); @@ -1491,7 +1479,8 @@ V86Starter.prototype.load_image = async function(file) { buffer = new v86util.AsyncXHRBuffer(file.url, file.size, file.fixed_chunk_size); } - image.buffer = await new Promise((resolve, reject) => { + image.buffer = buffer; + await new Promise((resolve, reject) => { image.buffer.onload = (e) => resolve(buffer); image.buffer.load(); }); @@ -1501,8 +1490,18 @@ V86Starter.prototype.load_image = async function(file) { image.buffer = await new Promise((resolve, reject) => { v86util.load_file(file.url, { - done: (result) => resolve(new v86util.SyncBuffer(result)) - }) + done: function(result) + { + if(file.url.endsWith(".zst") && file.name !== "initial_state") + { + dbg_assert(file.size, "A size must be provided for compressed images"); + result = this.zstd_decompress(file.size, new Uint8Array(result)); + } + resolve(file.as_json ? result : new v86util.SyncBuffer(result)); + }.bind(this), + progress: on_progress, + as_json: file.as_json, + }); }); return image; } From dd893efa7cbfb4b6b435ec05ff80fbd87a965cc7 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Mon, 21 Aug 2023 12:47:40 -0700 Subject: [PATCH 19/27] fixes towards empty cd-rom support for bochs bios --- src/ide.js | 9 ++++-- tests/full/run.js | 72 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/ide.js b/src/ide.js index 5bff7ecd6e..a37410fb23 100644 --- a/src/ide.js +++ b/src/ide.js @@ -469,7 +469,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) this.sector_count = 0; /** @type {number} */ - this.head_count = 0; + this.head_count = this.is_atapi ? 1 : 0; /** @type {number} */ this.sectors_per_track = 0; @@ -532,6 +532,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) rtc.cmos_write(reg + 5, 0xC8); rtc.cmos_write(reg + 6, this.cylinder_count & 0xFF); rtc.cmos_write(reg + 7, this.cylinder_count >> 8 & 0xFF); + rtc.cmos_write(reg + 8, this.sectors_per_track & 0xFF); //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2) @@ -647,7 +648,7 @@ IDEInterface.prototype.ata_command = function(cmd) { dbg_log("ATA dev " + this.device.name + " Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); - if((!this.buffer && cmd != 0xA1 && cmd != 0xEC && cmd != 0xA0)) + if(!this.buffer && cmd != 0xA1 && cmd != 0xEC && cmd != 0xA0) { dbg_log("dev "+this.device.name+" abort: No buffer", LOG_DISK); this.error = 4; @@ -750,7 +751,8 @@ IDEInterface.prototype.ata_command = function(cmd) dbg_log("dev "+this.device.name+" ATA identify packet device", LOG_DISK); if(this.is_atapi) - { + { + // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? this.create_identify_packet(); this.status = 0x58; @@ -827,6 +829,7 @@ IDEInterface.prototype.ata_command = function(cmd) return; } + // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? this.create_identify_packet(); this.status = 0x58; diff --git a/tests/full/run.js b/tests/full/run.js index aad4e833c5..40e046e555 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -123,7 +123,7 @@ if(cluster.isMaster) { name: "FreeDOS boot", fda: root_path + "/images/freedos722.img", - timeout: 20, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -133,7 +133,27 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 20, + timeout: 5, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with empty cdrom", + fda: root_path + "/images/freedos722.img", + wants_cdrom:true, + boot_order:0x231, + timeout: 5, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with empty cdrom (alternative boot order)", + fda: root_path + "/images/freedos722.img", + wants_cdrom:true, + boot_order:0x213, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -163,7 +183,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 20, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -174,7 +194,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x321, - timeout: 20, + timeout: 5, expected_texts: [ "Welcome to FreeDOS", ], @@ -182,7 +202,29 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS", fda: root_path + "/images/freedos722.img", - timeout: 20, + timeout: 5, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and empty cdrom", + fda: root_path + "/images/freedos722.img", + timeout: 5, + wants_cdrom: true, + boot_order:0x312, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and empty cdrom (alternative boot order)", + fda: root_path + "/images/freedos722.img", + timeout: 5, + boot_order:0x321, + wants_cdrom: true, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -215,7 +257,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 20, + timeout: 5, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -226,7 +268,19 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 20, + timeout: 5, + alternative_bios: true, + expected_texts: [ + "Welcome to FreeDOS", + ], + }, + { + name: "FreeDOS boot with Bochs BIOS and hda present and empty cdrom", + fda: root_path + "/images/freedos722.img", + hda: root_path + "/images/msdos.img", + wants_cdrom: true, + boot_order:0x231, + timeout: 5, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -250,7 +304,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 20, + timeout: 5, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -1176,7 +1230,7 @@ function run_test(test, done) vga_bios: { url: vga_bios }, autostart: true, memory_size: test.memory_size || 128 * 1024 * 1024, - log_level: 0, + log_level: 0x8000, cmdline: test.cmdline, }; From 02383c2a2eb901435e78d2b23276f4c6a2937634 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Mon, 21 Aug 2023 13:20:39 -0700 Subject: [PATCH 20/27] Fix empty/missing device enumeration for bochs bios --- src/ide.js | 6 ++---- tests/full/run.js | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/ide.js b/src/ide.js index a37410fb23..cb75ab9a95 100644 --- a/src/ide.js +++ b/src/ide.js @@ -648,7 +648,7 @@ IDEInterface.prototype.ata_command = function(cmd) { dbg_log("ATA dev " + this.device.name + " Command: " + h(cmd) + " slave=" + (this.drive_head >> 4 & 1), LOG_DISK); - if(!this.buffer && cmd != 0xA1 && cmd != 0xEC && cmd != 0xA0) + if((!this.buffer && cmd != 0xA1 && cmd != 0xEC && cmd != 0xA0)) { dbg_log("dev "+this.device.name+" abort: No buffer", LOG_DISK); this.error = 4; @@ -751,8 +751,7 @@ IDEInterface.prototype.ata_command = function(cmd) dbg_log("dev "+this.device.name+" ATA identify packet device", LOG_DISK); if(this.is_atapi) - { - // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? + { this.create_identify_packet(); this.status = 0x58; @@ -829,7 +828,6 @@ IDEInterface.prototype.ata_command = function(cmd) return; } - // TODO handle missing (slave) drive by setting status = 0x00 or 0xFF? this.create_identify_packet(); this.status = 0x58; diff --git a/tests/full/run.js b/tests/full/run.js index 40e046e555..439e7f3f64 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -123,7 +123,7 @@ if(cluster.isMaster) { name: "FreeDOS boot", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -133,7 +133,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -143,7 +143,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", wants_cdrom:true, boot_order:0x231, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -153,7 +153,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", wants_cdrom:true, boot_order:0x213, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -183,7 +183,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -194,7 +194,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x321, - timeout: 5, + timeout: 20, expected_texts: [ "Welcome to FreeDOS", ], @@ -202,7 +202,7 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -211,7 +211,7 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS and empty cdrom", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, wants_cdrom: true, boot_order:0x312, alternative_bios: true, @@ -222,7 +222,7 @@ if(cluster.isMaster) { name: "FreeDOS boot with Bochs BIOS and empty cdrom (alternative boot order)", fda: root_path + "/images/freedos722.img", - timeout: 5, + timeout: 20, boot_order:0x321, wants_cdrom: true, alternative_bios: true, @@ -257,7 +257,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", cdrom: root_path + "/images/linux.iso", boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -268,7 +268,7 @@ if(cluster.isMaster) fda: root_path + "/images/freedos722.img", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -280,7 +280,7 @@ if(cluster.isMaster) hda: root_path + "/images/msdos.img", wants_cdrom: true, boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -304,7 +304,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 5, + timeout: 20, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -1230,7 +1230,7 @@ function run_test(test, done) vga_bios: { url: vga_bios }, autostart: true, memory_size: test.memory_size || 128 * 1024 * 1024, - log_level: 0x8000, + log_level: 0, cmdline: test.cmdline, }; From 6e53a641f621f16a8fa5e7341a29714b8d261941 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Wed, 23 Aug 2023 07:17:02 -0700 Subject: [PATCH 21/27] WIP insert/eject --- src/browser/main.js | 69 ++++++++++++++++++++-- src/config.js | 5 +- src/ide.js | 141 ++++++++++++++++++++++++++------------------ tests/full/run.js | 36 ++++++++++- 4 files changed, 183 insertions(+), 68 deletions(-) diff --git a/src/browser/main.js b/src/browser/main.js index 26ea85e45b..20da0fa703 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -178,6 +178,44 @@ // Abandonware OS images are from https://winworldpc.com/library/operating-systems var oses = [ + { + id: "wheezy", + memory_size: 512 * 1024 * 1024, + vga_memory_size: 16 * 1024 * 1024, + hda: { + url: host + "debian_wheezy.img", + async: true, + }, + boot_order: 0x132, + name: "Debian Wheezy", + }, + { + id: "wheezy+empty", + memory_size: 512 * 1024 * 1024, + vga_memory_size: 16 * 1024 * 1024, + wants_cdrom: true, + hda: { + url: host + "debian_wheezy.img", + async: true, + }, + boot_order: 0x132, + name: "Debian Wheezy (empty cd)", + }, + { + id: "wheezy+cd", + memory_size: 512 * 1024 * 1024, + vga_memory_size: 16 * 1024 * 1024, + cdrom: { + url: host+"linux.iso", + async:false + }, + hda: { + url: host + "debian_wheezy.img", + async: true, + }, + boot_order: 0x132, + name: "Debian Wheezy (with cd)", + }, { id: "archlinux", name: "Arch Linux", @@ -736,14 +774,37 @@ { id: "windows95-boot", memory_size: 32 * 1024 * 1024, + boot_order:0x312, hda: { url: host + "w95.img", - size: 242049024, async: true, - fixed_chunk_size: 256 * 1024, - use_parts: !ON_LOCALHOST, }, - name: "Windows 95", + name: "Windows 95 (boot)", + }, + { + id: "windows95-boot-empty", + memory_size: 32 * 1024 * 1024, + boot_order:0x312, + wants_cdrom:true, + hda: { + url: host + "w95.img", + async: true, + }, + name: "Windows 95 (boot)", + }, + { + id: "windows95-boot-cdrom", + memory_size: 32 * 1024 * 1024, + boot_order:0x312, + cdrom: { + url: host + "Win30.iso", + async:false + }, + hda: { + url: host + "w95.img", + async: true, + }, + name: "Windows 95 (boot)", }, { id: "windows30", diff --git a/src/config.js b/src/config.js index 1eca2b8008..87d5251d0d 100644 --- a/src/config.js +++ b/src/config.js @@ -34,9 +34,10 @@ var DUMP_UNCOMPILED_ASSEMBLY = false; */ var TRACK_FILENAMES = false; -var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & - ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; +// var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & +// ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; +var LOG_LEVEL = LOG_DISK; /** * @const * Draws entire buffer and visualizes the layers that would be drawn diff --git a/src/ide.js b/src/ide.js index cb75ab9a95..5f4e2b49df 100644 --- a/src/ide.js +++ b/src/ide.js @@ -457,7 +457,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) /** @const @type {CPU} */ this.cpu = cpu; - this.buffer = buffer; + this.buffer = null; /** @type {number} */ this.sector_size = is_cd ? CDROM_SECTOR_SIZE : HD_SECTOR_SIZE; @@ -477,65 +477,9 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) /** @type {number} */ this.cylinder_count = 0; - if(this.buffer) + if(buffer) { - this.sector_count = this.buffer.byteLength / this.sector_size; - - if(this.sector_count !== (this.sector_count | 0)) - { - dbg_log("Warning: Disk size not aligned with sector size", LOG_DISK); - this.sector_count = Math.ceil(this.sector_count); - } - - if(is_cd) - { - // default values: 1/2048 - this.head_count = 1; - this.sectors_per_track = 2048; - } - else - { - // "default" values: 16/63 - // common: 255, 63 - this.head_count = 16; - this.sectors_per_track = 63; - } - - - this.cylinder_count = this.sector_count / this.head_count / this.sectors_per_track; - - if(this.cylinder_count !== (this.cylinder_count | 0)) - { - dbg_log("Warning: Rounding up cylinder count. Choose different head number", LOG_DISK); - this.cylinder_count = Math.floor(this.cylinder_count); - //this.sector_count = this.cylinder_count * this.head_count * - // this.sectors_per_track * this.sector_size; - } - - //if(this.cylinder_count > 16383) - //{ - // this.cylinder_count = 16383; - //} - - var rtc = cpu.devices.rtc; - // master - rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, - rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << this.nr * 4); - rtc.cmos_write(CMOS_DISK_DATA, rtc.cmos_read(CMOS_DISK_DATA) & 0x0F | 0xF0); - - var reg = this.nr == 0 ? CMOS_DISK_DRIVE1_CYL : CMOS_DISK_DRIVE2_CYL; - rtc.cmos_write(reg + 0, this.cylinder_count & 0xFF); - rtc.cmos_write(reg + 1, this.cylinder_count >> 8 & 0xFF); - rtc.cmos_write(reg + 2, this.head_count & 0xFF); - rtc.cmos_write(reg + 3, 0xFF); - rtc.cmos_write(reg + 4, 0xFF); - rtc.cmos_write(reg + 5, 0xC8); - rtc.cmos_write(reg + 6, this.cylinder_count & 0xFF); - rtc.cmos_write(reg + 7, this.cylinder_count >> 8 & 0xFF); - rtc.cmos_write(reg + 8, this.sectors_per_track & 0xFF); - //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, - // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2) - + this.insert(buffer); } /** @const */ @@ -613,6 +557,85 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) Object.seal(this); } +IDEInterface.prototype.eject = function() +{ + this.buffer = null; + if(this.is_atapi) + { + this.status = 0x59; + this.error = 0x60; + } +} + +IDEInterface.prototype.insert = function(buffer) +{ + if(buffer) + { + this.buffer = buffer; + if(this.is_atapi) + { + this.status = 0x59; + this.error = 0x60; + } + this.sector_count = this.buffer.byteLength / this.sector_size; + + if(this.sector_count !== (this.sector_count | 0)) + { + dbg_log("Warning: Disk size not aligned with sector size", LOG_DISK); + this.sector_count = Math.ceil(this.sector_count); + } + + if(this.is_atapi) + { + // default values: 1/2048 + this.head_count = 1; + this.sectors_per_track = 2048; + } + else + { + // "default" values: 16/63 + // common: 255, 63 + this.head_count = 16; + this.sectors_per_track = 63; + } + + + this.cylinder_count = this.sector_count / this.head_count / this.sectors_per_track; + + if(this.cylinder_count !== (this.cylinder_count | 0)) + { + dbg_log("Warning: Rounding up cylinder count. Choose different head number", LOG_DISK); + this.cylinder_count = Math.floor(this.cylinder_count); + //this.sector_count = this.cylinder_count * this.head_count * + // this.sectors_per_track * this.sector_size; + } + + //if(this.cylinder_count > 16383) + //{ + // this.cylinder_count = 16383; + //} + + var rtc = cpu.devices.rtc; + // master + rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, + rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << this.nr * 4); + rtc.cmos_write(CMOS_DISK_DATA, rtc.cmos_read(CMOS_DISK_DATA) & 0x0F | 0xF0); + + var reg = this.nr == 0 ? CMOS_DISK_DRIVE1_CYL : CMOS_DISK_DRIVE2_CYL; + rtc.cmos_write(reg + 0, this.cylinder_count & 0xFF); + rtc.cmos_write(reg + 1, this.cylinder_count >> 8 & 0xFF); + rtc.cmos_write(reg + 2, this.head_count & 0xFF); + rtc.cmos_write(reg + 3, 0xFF); + rtc.cmos_write(reg + 4, 0xFF); + rtc.cmos_write(reg + 5, 0xC8); + rtc.cmos_write(reg + 6, this.cylinder_count & 0xFF); + rtc.cmos_write(reg + 7, this.cylinder_count >> 8 & 0xFF); + rtc.cmos_write(reg + 8, this.sectors_per_track & 0xFF); + //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, + // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2) + } +} + IDEInterface.prototype.device_reset = function() { if(this.is_atapi) diff --git a/tests/full/run.js b/tests/full/run.js index 439e7f3f64..ccd5d9e340 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -120,6 +120,36 @@ function do_action(test, emulator, run_step) if(cluster.isMaster) { var tests = [ + { + name: "Wheezy boot", + hda: root_path + "/images/debian_wheezy.img", + timeout: 60, + expect_graphical_mode: true, + }, + { + name: "Wheezy boot with empty cdrom", + wants_cdrom: true, + hda: root_path + "/images/debian_wheezy.img", + timeout: 60, + boot_order:0x312, + expect_graphical_mode: true, + }, + { + name: "Wheezy boot with cdrom present", + wants_cdrom: true, + hda: root_path + "/images/debian_wheezy.img", + cdrom: root_path + "/images/linux.iso", + timeout: 60, + boot_order:0x312, + expect_graphical_mode: true, + }, + { + name: "Windows 1.01 boot", + fda: root_path + "/images/windows101.img", + timeout: 10, + expect_graphical_mode: true, + expect_mouse_registered: true, + }, { name: "FreeDOS boot", fda: root_path + "/images/freedos722.img", @@ -194,7 +224,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x321, - timeout: 20, + timeout: 40, expected_texts: [ "Welcome to FreeDOS", ], @@ -304,7 +334,7 @@ if(cluster.isMaster) cdrom: root_path + "/images/linux.iso", hda: root_path + "/images/msdos.img", boot_order:0x231, - timeout: 20, + timeout: 30, alternative_bios: true, expected_texts: [ "Welcome to FreeDOS", @@ -1230,7 +1260,7 @@ function run_test(test, done) vga_bios: { url: vga_bios }, autostart: true, memory_size: test.memory_size || 128 * 1024 * 1024, - log_level: 0, + log_level: 0x0, cmdline: test.cmdline, }; From 1df73ec9e91b528de2f99a88cec90202984d46d4 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Wed, 30 Aug 2023 11:47:41 -0700 Subject: [PATCH 22/27] clean up tests and code after rebase --- Makefile | 1 + src/browser/main.js | 70 +------ src/browser/starter.js | 279 +++++++++++----------------- src/config.js | 5 +- src/floppy.js | 3 - src/ide.js | 6 +- tests/full/run.js | 406 +++++++++++++++++++++-------------------- 7 files changed, 323 insertions(+), 447 deletions(-) diff --git a/Makefile b/Makefile index 1a158f4654..eb756ea431 100644 --- a/Makefile +++ b/Makefile @@ -314,6 +314,7 @@ api-tests: all-debug ./tests/api/reset.js ./tests/api/floppy-insert-eject.js ./tests/api/serial.js + ./tests/api/cdrom-insert-eject.js all-tests: jshint kvm-unit-test qemutests qemutests-release jitpagingtests api-tests nasmtests nasmtests-force-jit tests expect-tests # Skipping: diff --git a/src/browser/main.js b/src/browser/main.js index 20da0fa703..ca085c29eb 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -178,44 +178,6 @@ // Abandonware OS images are from https://winworldpc.com/library/operating-systems var oses = [ - { - id: "wheezy", - memory_size: 512 * 1024 * 1024, - vga_memory_size: 16 * 1024 * 1024, - hda: { - url: host + "debian_wheezy.img", - async: true, - }, - boot_order: 0x132, - name: "Debian Wheezy", - }, - { - id: "wheezy+empty", - memory_size: 512 * 1024 * 1024, - vga_memory_size: 16 * 1024 * 1024, - wants_cdrom: true, - hda: { - url: host + "debian_wheezy.img", - async: true, - }, - boot_order: 0x132, - name: "Debian Wheezy (empty cd)", - }, - { - id: "wheezy+cd", - memory_size: 512 * 1024 * 1024, - vga_memory_size: 16 * 1024 * 1024, - cdrom: { - url: host+"linux.iso", - async:false - }, - hda: { - url: host + "debian_wheezy.img", - async: true, - }, - boot_order: 0x132, - name: "Debian Wheezy (with cd)", - }, { id: "archlinux", name: "Arch Linux", @@ -376,7 +338,6 @@ size: 8 * 1024 * 1024, async: false, }, - boot_order: 0x132, name: "MS-DOS", }, { @@ -774,37 +735,14 @@ { id: "windows95-boot", memory_size: 32 * 1024 * 1024, - boot_order:0x312, - hda: { - url: host + "w95.img", - async: true, - }, - name: "Windows 95 (boot)", - }, - { - id: "windows95-boot-empty", - memory_size: 32 * 1024 * 1024, - boot_order:0x312, - wants_cdrom:true, - hda: { - url: host + "w95.img", - async: true, - }, - name: "Windows 95 (boot)", - }, - { - id: "windows95-boot-cdrom", - memory_size: 32 * 1024 * 1024, - boot_order:0x312, - cdrom: { - url: host + "Win30.iso", - async:false - }, hda: { url: host + "w95.img", + size: 242049024, async: true, + fixed_chunk_size: 256 * 1024, + use_parts: !ON_LOCALHOST, }, - name: "Windows 95 (boot)", + name: "Windows 95", }, { id: "windows30", diff --git a/src/browser/starter.js b/src/browser/starter.js index 418b356722..649672f152 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -434,58 +434,9 @@ V86Starter.prototype.continue_init = async function(emulator, options) "bzimage", "initrd", ]; - var total = 0; - var current_file_index = 0; - var current_file_size = 0; - var current_file_name = null; - - function mk_progress(starter, index, size, url) - { - return function progress(e) - { - if(e.target.status === 200) - { - starter.emulator_bus.send("download-progress", { - file_index: index, - file_count: total, - file_name: url, - - lengthComputable: e.lengthComputable, - total: e.total || size, - loaded: e.loaded, - }); - } - else - { - starter.emulator_bus.send("download-error", { - file_index: index, - file_count: total, - file_name: url, - request: e.target, - }); - } - }; - } - for(var i = 0; i < image_names.length; i++) { - let name = image_names[i]; - let file = options[image_names[i]]; - if(!file) { continue; } - if(name === "bios" || name === "vga_bios" || - name === "initial_state" || name === "multiboot" || - name === "bzimage" || name === "initrd") - { - // Ignore async for these because they must be available before boot. - // This should make result.buffer available after the object is loaded - file.async = false; - } - total += 1; - let img = await this.load_image(file, mk_progress(this, total-1, file.size, file.url || name)); - if(img) - { - put_on_settings.call(this, name, img.buffer); - } + add_file(image_names[i], options[image_names[i]]); } if(options["filesystem"]) @@ -513,18 +464,81 @@ V86Starter.prototype.continue_init = async function(emulator, options) fs_url = fs_url.url; } dbg_assert(typeof fs_url === "string"); - total += 1; - let img = await this.load_image({ + + files_to_load.push({ name: "fs9p_json", url: fs_url, size: size, as_json: true, - }, mk_progress(this, total-1, size, fs_url)); - put_on_settings.call(this, "fs9p_json", img.buffer); + }); } } - setTimeout(done.bind(this), 0); + var starter = this; + var total = files_to_load.length; + + var cont = function(index) + { + if(index === total) + { + setTimeout(done.bind(this), 0); + return; + } + + var f = files_to_load[index]; + + if(f.loadable) + { + f.loadable.onload = function(e) + { + put_on_settings.call(this, f.name, f.loadable); + cont(index + 1); + }.bind(this); + f.loadable.load(); + } + else + { + v86util.load_file(f.url, { + done: function(result) + { + if(f.url.endsWith(".zst") && f.name !== "initial_state") + { + dbg_assert(f.size, "A size must be provided for compressed images"); + result = this.zstd_decompress(f.size, new Uint8Array(result)); + } + + put_on_settings.call(this, f.name, f.as_json ? result : new v86util.SyncBuffer(result)); + cont(index + 1); + }.bind(this), + progress: function progress(e) + { + if(e.target.status === 200) + { + starter.emulator_bus.send("download-progress", { + file_index: index, + file_count: total, + file_name: f.url, + + lengthComputable: e.lengthComputable, + total: e.total || f.size, + loaded: e.loaded, + }); + } + else + { + starter.emulator_bus.send("download-error", { + file_index: index, + file_count: total, + file_name: f.url, + request: e.target, + }); + } + }, + as_json: f.as_json, + }); + } + }.bind(this); + cont(0); async function done() { @@ -998,6 +1012,42 @@ V86Starter.prototype.eject_fda = function() this.v86.cpu.devices.fdc.eject_fda(); }; +/** + * Set the image inserted in the CD-ROM drive. Can be changed at runtime, as + * when physically changing the CD-ROM. + * @export + */ +V86Starter.prototype.set_cdrom = async function(file) +{ + if(file.url && !file.async) + { + v86util.load_file(file.url, { + done: result => + { + this.v86.cpu.devices.cdrom.master.set_cdrom(new v86util.SyncBuffer(result)); + }, + }); + } + else + { + const image = v86util.buffer_from_object(file); + image.onload = () => + { + this.v86.cpu.devices.cdrom.master.set_cdrom(image); + }; + await image.load(); + } +}; + +/** + * Eject the CD-ROM. + * @export + */ +V86Starter.prototype.eject_cdrom = function() +{ + this.v86.cpu.devices.cdrom.master.eject_cdrom(); +}; + /** * Send a sequence of scan codes to the emulated PS2 controller. A list of * codes can be found at http://stanislavs.org/helppc/make_codes.html. @@ -1313,6 +1363,7 @@ V86Starter.prototype.automatically = function(steps) { const run = (steps) => { + console.log("do step",steps[0]); const step = steps[0]; if(!step) @@ -1332,8 +1383,10 @@ V86Starter.prototype.automatically = function(steps) { const screen = this.screen_adapter.get_text_screen(); + console.log("LOOKING FOR",step.vga_text); for(let line of screen) { + console.log(line); if(line.includes(step.vga_text)) { run(remaining_steps); @@ -1347,6 +1400,7 @@ V86Starter.prototype.automatically = function(steps) if(step.keyboard_send) { + console.log("SEND"); if(step.keyboard_send instanceof Array) { this.keyboard_send_scancodes(step.keyboard_send); @@ -1398,121 +1452,6 @@ V86Starter.prototype.write_memory = function(blob, offset) this.v86.cpu.write_blob(blob, offset); }; -/** - * Loads an image buffer (e.g. a SyncBuffer, AsyncXHRBuffer, etc) from - * a buffer descriptor (as detailed in the documentation for the V86 - * constructor) asynchronously, yielding a buffer desc with an - * explicitly given buffer. - * - * @param {Object} file - * @param {function(*) | undefined} on_progress - * @return {Promise} - * @export - */ - -V86Starter.prototype.load_image = async function(file, on_progress) -{ - if(file.buffer && file.buffer.get && file.buffer.set && file.buffer.load) - { - return file; - } - - let image = {}; - for(let fv in file) - { - image[fv] = file[fv]; - } - - if(file.buffer instanceof ArrayBuffer) - { - image.buffer = new v86util.SyncBuffer(file.buffer); - await new Promise((resolve, reject) => { - image.buffer.onload = (e) => resolve(buffer); - image.buffer.load(); - }); - return image; - } - else if(typeof File !== "undefined" && file.buffer instanceof File) - { - // SyncFileBuffer: - // - loads the whole disk image into memory, impossible for large files (more than 1GB) - // - can later serve get/set operations fast and synchronously - // - takes some time for first load, neglectable for small files (up to 100Mb) - // - // AsyncFileBuffer: - // - loads slices of the file asynchronously as requested - // - slower get/set - - // Heuristics: If file is larger than or equal to 256M, use AsyncFileBuffer - if(file.async === undefined) - { - file.async = file.buffer.size >= 256 * 1024 * 1024; - } - - if(file.async) - { - var buffer = new v86util.AsyncFileBuffer(file.buffer); - } - else - { - var buffer = new v86util.SyncFileBuffer(file.buffer); - } - - image.buffer = buffer; - await new Promise((resolve, reject) => { - image.buffer.onload = (e) => resolve(buffer); - image.buffer.load(); - }); - return image; - } - else if(file.url) - { - if(file.async) - { - let buffer; - - if(file.use_parts) - { - buffer = new v86util.AsyncXHRPartfileBuffer(file.url, file.size, file.fixed_chunk_size, false, this.zstd_decompress_worker.bind(this)); - } - else - { - buffer = new v86util.AsyncXHRBuffer(file.url, file.size, file.fixed_chunk_size); - } - image.buffer = buffer; - await new Promise((resolve, reject) => { - image.buffer.onload = (e) => resolve(buffer); - image.buffer.load(); - }); - return image; - } - else - { - image.buffer = await new Promise((resolve, reject) => { - v86util.load_file(file.url, { - done: function(result) - { - if(file.url.endsWith(".zst") && file.name !== "initial_state") - { - dbg_assert(file.size, "A size must be provided for compressed images"); - result = this.zstd_decompress(file.size, new Uint8Array(result)); - } - resolve(file.as_json ? result : new v86util.SyncBuffer(result)); - }.bind(this), - progress: on_progress, - as_json: file.as_json, - }); - }); - return image; - } - } - else - { - dbg_log("Ignored file: url=" + file.url + " buffer=" + file.buffer); - return null; - } -}; - /** * @ignore * @constructor diff --git a/src/config.js b/src/config.js index 87d5251d0d..1eca2b8008 100644 --- a/src/config.js +++ b/src/config.js @@ -34,10 +34,9 @@ var DUMP_UNCOMPILED_ASSEMBLY = false; */ var TRACK_FILENAMES = false; -// var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & -// ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; +var LOG_LEVEL = LOG_ALL & ~LOG_PS2 & ~LOG_PIT & ~LOG_VIRTIO & ~LOG_9P & ~LOG_PIC & + ~LOG_DMA & ~LOG_SERIAL & ~LOG_NET & ~LOG_FLOPPY & ~LOG_DISK & ~LOG_VGA & ~LOG_SB16; -var LOG_LEVEL = LOG_DISK; /** * @const * Draws entire buffer and visualizes the layers that would be drawn diff --git a/src/floppy.js b/src/floppy.js index 7b6c73e182..914bd8be78 100644 --- a/src/floppy.js +++ b/src/floppy.js @@ -56,9 +56,6 @@ function FloppyController(cpu, fda_image, fdb_image) { this.set_fda(fda_image); } - cpu.devices.rtc.cmos_write(CMOS_FLOPPY_DRIVE_TYPE, this.floppy_type.type << 4); - - dbg_assert(!fdb_image, "FDB not supported"); dbg_assert(!fdb_image, "FDB not supported"); diff --git a/src/ide.js b/src/ide.js index 5f4e2b49df..b7d759a781 100644 --- a/src/ide.js +++ b/src/ide.js @@ -479,7 +479,7 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) if(buffer) { - this.insert(buffer); + this.set_cdrom(buffer); } /** @const */ @@ -567,7 +567,7 @@ IDEInterface.prototype.eject = function() } } -IDEInterface.prototype.insert = function(buffer) +IDEInterface.prototype.set_cdrom = function(buffer) { if(buffer) { @@ -615,7 +615,7 @@ IDEInterface.prototype.insert = function(buffer) // this.cylinder_count = 16383; //} - var rtc = cpu.devices.rtc; + var rtc = this.cpu.devices.rtc; // master rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << this.nr * 4); diff --git a/tests/full/run.js b/tests/full/run.js index ccd5d9e340..cc1d3dd7d1 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -105,12 +105,22 @@ function do_action(test, emulator, run_step) { case "eject_fda": { - emulator.v86.cpu.devices.fdc.eject_fda(); + emulator.eject_fda(); break; } case "insert_fda": { - emulator.v86.cpu.devices.fdc.insert_fda(test.extra_images[run_step.image].buffer); + emulator.set_fda(test.extra_images[run_step.image]); + break; + } + case "eject_cdrom": + { + emulator.eject_cdrom(); + break; + } + case "insert_cdrom": + { + emulator.set_cdrom(test.extra_images[run_step.image]); break; } } @@ -1308,245 +1318,237 @@ function run_test(test, done) var emulator = new V86(settings); var screen = new Uint8Array(SCREEN_WIDTH * 25); - let extras = []; - for(let extra in test.extra_images) + function check_text_test_done() { - extras.push(emulator.load_image(test.extra_images[extra]).then((img) => test.extra_images[extra] = img)); + return test.expected_texts.length === 0; } - Promise.all(extras).then((_imgs) => { - function check_text_test_done() - { - return test.expected_texts.length === 0; - } - function check_serial_test_done() - { - return test.expected_serial_text.length === 0; - } + function check_serial_test_done() + { + return test.expected_serial_text.length === 0; + } + + var mouse_test_done = false; + function check_mouse_test_done() + { + return !test.expect_mouse_registered || mouse_test_done; + } - var mouse_test_done = false; - function check_mouse_test_done() + var graphical_test_done = false; + var size_test_done = false; + function check_graphical_test_done() + { + return !test.expect_graphical_mode || (graphical_test_done && (!test.expect_graphical_size || size_test_done)); + } + + var test_start = Date.now(); + + var timeout_seconds = test.timeout * TIMEOUT_EXTRA_FACTOR; + var timeout = setTimeout(check_test_done, (timeout_seconds + 1) * 1000); + var timeouts = [timeout]; + + var on_text = []; + var stopped = false; + + var screen_interval = null; + + function check_test_done() + { + if(stopped) { - return !test.expect_mouse_registered || mouse_test_done; + return; } - var graphical_test_done = false; - var size_test_done = false; - function check_graphical_test_done() + if(check_text_test_done() && + check_mouse_test_done() && + check_graphical_test_done() && + check_serial_test_done()) { - return !test.expect_graphical_mode || (graphical_test_done && (!test.expect_graphical_size || size_test_done)); - } + var end = Date.now(); - var test_start = Date.now(); + for(let timeout of timeouts) clearTimeout(timeout); + stopped = true; - var timeout_seconds = test.timeout * TIMEOUT_EXTRA_FACTOR; - var timeout = setTimeout(check_test_done, (timeout_seconds + 1) * 1000); - var timeouts = [timeout]; + emulator.stop(); - var on_text = []; - var stopped = false; + if(screen_interval !== null) + { + clearInterval(screen_interval); + } - var screen_interval = null; + console.warn("Passed test: %s (took %ds)", test.name, (end - test_start) / 1000); + console.warn(); - function check_test_done() + done(); + } + else if(Date.now() >= test_start + timeout_seconds * 1000) { - if(stopped) + for(let timeout of timeouts) clearTimeout(timeout); + stopped = true; + + if(screen_interval !== null) { - return; + clearInterval(screen_interval); } - if(check_text_test_done() && - check_mouse_test_done() && - check_graphical_test_done() && - check_serial_test_done()) + emulator.stop(); + emulator.destroy(); + + if(test.failure_allowed) { - var end = Date.now(); + console.warn("Test failed: %s (failure allowed)\n", test.name); + } + else + { + console.warn(screen_to_text(screen)); + console.warn("Test failed: %s\n", test.name); + } - for(let timeout of timeouts) clearTimeout(timeout); - stopped = true; + if(!check_text_test_done()) + { + console.warn('Expected text "%s" after %d seconds.', bytearray_to_string(test.expected_texts[0]), timeout_seconds); + } - emulator.stop(); + if(!check_graphical_test_done()) + { + console.warn("Expected graphical mode after %d seconds.", timeout_seconds); + } - if(screen_interval !== null) - { - clearInterval(screen_interval); - } + if(!check_mouse_test_done()) + { + console.warn("Expected mouse activation after %d seconds.", timeout_seconds); + } - console.warn("Passed test: %s (took %ds)", test.name, (end - test_start) / 1000); - console.warn(); + if(!check_serial_test_done()) + { + console.warn('Expected serial text "%s" after %d seconds.', test.expected_serial_text, timeout_seconds); + } - done(); + if(on_text.length) + { + console.warn(`Note: Expected text "${bytearray_to_string(on_text[0].text)}" to run "${on_text[0].run}"`); + } + + if(!test.failure_allowed) + { + process.exit(1); } - else if(Date.now() >= test_start + timeout_seconds * 1000) + else { - for(let timeout of timeouts) clearTimeout(timeout); - stopped = true; + done(); + } + } + } - if(screen_interval !== null) - { - clearInterval(screen_interval); - } + emulator.add_listener("mouse-enable", function() + { + mouse_test_done = true; + check_test_done(); + }); - emulator.stop(); - emulator.destroy(); + emulator.add_listener("screen-set-mode", function(is_graphical) + { + graphical_test_done = is_graphical; + check_test_done(); + }); - if(test.failure_allowed) - { - console.warn("Test failed: %s (failure allowed)\n", test.name); - } - else - { - console.warn(screen_to_text(screen)); - console.warn("Test failed: %s\n", test.name); - } + emulator.add_listener("screen-set-size-graphical", function(size) + { + if(test.expect_graphical_size) + { + size_test_done = size[0] === test.expect_graphical_size[0] && + size[1] === test.expect_graphical_size[1]; + check_test_done(); + } + }); - if(!check_text_test_done()) - { - console.warn('Expected text "%s" after %d seconds.', bytearray_to_string(test.expected_texts[0]), timeout_seconds); - } + emulator.add_listener("screen-put-char", function(chr) + { + var y = chr[0]; + var x = chr[1]; + var code = chr[2]; + screen[x + SCREEN_WIDTH * y] = code; - if(!check_graphical_test_done()) - { - console.warn("Expected graphical mode after %d seconds.", timeout_seconds); - } + var line = get_line(screen, y); - if(!check_mouse_test_done()) - { - console.warn("Expected mouse activation after %d seconds.", timeout_seconds); - } + if(!check_text_test_done()) + { + let expected = test.expected_texts[0]; + if(x < expected.length && bytearray_starts_with(line, expected)) + { + test.expected_texts.shift(); + if(VERBOSE) console.log(`Passed: "${bytearray_to_string(expected)}" on screen (${test.name})`); + check_test_done(); + } + } - if(!check_serial_test_done()) - { - console.warn('Expected serial text "%s" after %d seconds.', test.expected_serial_text, timeout_seconds); - } + if(on_text.length) + { + let expected = on_text[0].text; - if(on_text.length) - { - console.warn(`Note: Expected text "${bytearray_to_string(on_text[0].text)}" to run "${on_text[0].run}"`); - } + if(x < expected.length && bytearray_starts_with(line, expected)) + { + var action = on_text.shift(); - if(!test.failure_allowed) - { - process.exit(1); - } - else - { - done(); - } + timeouts.push( + setTimeout(() => { + do_action(test, emulator, action.run); + }, action.after || 0) + ); } } + }); - emulator.add_listener("mouse-enable", function() - { - mouse_test_done = true; - check_test_done(); - }); - - emulator.add_listener("screen-set-mode", function(is_graphical) - { - graphical_test_done = is_graphical; - check_test_done(); - }); - - emulator.add_listener("screen-set-size-graphical", function(size) - { - if(test.expect_graphical_size) - { - size_test_done = size[0] === test.expect_graphical_size[0] && - size[1] === test.expect_graphical_size[1]; - check_test_done(); - } - }); - - emulator.add_listener("screen-put-char", function(chr) - { - var y = chr[0]; - var x = chr[1]; - var code = chr[2]; - screen[x + SCREEN_WIDTH * y] = code; - - var line = get_line(screen, y); - - if(!check_text_test_done()) - { - let expected = test.expected_texts[0]; - if(x < expected.length && bytearray_starts_with(line, expected)) - { - test.expected_texts.shift(); - if(VERBOSE) console.log(`Passed: "${bytearray_to_string(expected)}" on screen (${test.name})`); - check_test_done(); - } - } - - if(on_text.length) - { - let expected = on_text[0].text; - - if(x < expected.length && bytearray_starts_with(line, expected)) - { - var action = on_text.shift(); - - timeouts.push( - setTimeout(() => { - do_action(test, emulator, action.run); - }, action.after || 0) - ); - } - } - }); - - if(LOG_SCREEN) - { - screen_interval = setInterval(() => { - console.warn(screen_to_text(screen)); - }, 10000); - } + if(LOG_SCREEN) + { + screen_interval = setInterval(() => { + console.warn(screen_to_text(screen)); + }, 10000); + } + + let serial_line = ""; + emulator.add_listener("serial0-output-char", function(c) + { + if(c === "\n") + { + if(VERBOSE) + { + console.log(`Serial (${test.name}):`, serial_line); + } - let serial_line = ""; - emulator.add_listener("serial0-output-char", function(c) - { - if(c === "\n") - { - if(VERBOSE) - { - console.log(`Serial (${test.name}):`, serial_line); - } - - if(test.expected_serial_text.length) - { - const expected = test.expected_serial_text[0]; - if(serial_line.includes(expected)) - { - test.expected_serial_text.shift(); - if(VERBOSE) console.log(`Passed: "${expected}" on serial (${test.name})`); - check_test_done(); - } - } - - serial_line = ""; - } - else if(c >= " " && c <= "~") - { - serial_line += c; - } - }); - - test.actions && test.actions.forEach(function(action) - { - if(action.on_text) - { - on_text.push({ text: string_to_bytearray(action.on_text), run: action.run, after: action.after }); - } - else - { - timeouts.push( - setTimeout(() => { - do_action(test, emulator, action.run); - }, action.after || 0) - ); - } - }); + if(test.expected_serial_text.length) + { + const expected = test.expected_serial_text[0]; + if(serial_line.includes(expected)) + { + test.expected_serial_text.shift(); + if(VERBOSE) console.log(`Passed: "${expected}" on serial (${test.name})`); + check_test_done(); + } + } + serial_line = ""; + } + else if(c >= " " && c <= "~") + { + serial_line += c; + } }); + test.actions && test.actions.forEach( + function(action) + { + if(action.on_text) + { + on_text.push({ text: string_to_bytearray(action.on_text), run: action.run, after: action.after }); + } + else + { + timeouts.push( + setTimeout(() => { + do_action(test, emulator, action.run); + }, action.after || 0) + ); + } + }); } From add76051832dc577bcf3accb45904d96a2f339be Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Fri, 1 Sep 2023 10:19:33 -0700 Subject: [PATCH 23/27] tweaks to ordering in initialization --- src/browser/starter.js | 2 +- src/ide.js | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/browser/starter.js b/src/browser/starter.js index 649672f152..eb9e607ad6 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -1045,7 +1045,7 @@ V86Starter.prototype.set_cdrom = async function(file) */ V86Starter.prototype.eject_cdrom = function() { - this.v86.cpu.devices.cdrom.master.eject_cdrom(); + this.v86.cpu.devices.cdrom.master.eject(); }; /** diff --git a/src/ide.js b/src/ide.js index b7d759a781..86327490f3 100644 --- a/src/ide.js +++ b/src/ide.js @@ -477,11 +477,6 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) /** @type {number} */ this.cylinder_count = 0; - if(buffer) - { - this.set_cdrom(buffer); - } - /** @const */ this.stats = { sectors_read: 0, @@ -554,6 +549,11 @@ function IDEInterface(device, cpu, buffer, is_cd, device_nr, interface_nr, bus) this.in_progress_io_ids = new Set(); this.cancelled_io_ids = new Set(); + if(buffer) + { + this.set_cdrom(buffer); + } + Object.seal(this); } @@ -564,6 +564,7 @@ IDEInterface.prototype.eject = function() { this.status = 0x59; this.error = 0x60; + this.push_irq(); } } @@ -633,6 +634,9 @@ IDEInterface.prototype.set_cdrom = function(buffer) rtc.cmos_write(reg + 8, this.sectors_per_track & 0xFF); //rtc.cmos_write(CMOS_BIOS_DISKTRANSFLAG, // rtc.cmos_read(CMOS_BIOS_DISKTRANSFLAG) | 1 << (nr * 4 + 2) + if(this.device.cpu) { + this.push_irq(); + } } } From c77dc1f4a4d40877c47c1f98b4357e404296ae54 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Fri, 1 Sep 2023 10:22:15 -0700 Subject: [PATCH 24/27] remove debug output --- src/browser/starter.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/browser/starter.js b/src/browser/starter.js index eb9e607ad6..d0688ce2db 100644 --- a/src/browser/starter.js +++ b/src/browser/starter.js @@ -1363,7 +1363,6 @@ V86Starter.prototype.automatically = function(steps) { const run = (steps) => { - console.log("do step",steps[0]); const step = steps[0]; if(!step) @@ -1383,10 +1382,8 @@ V86Starter.prototype.automatically = function(steps) { const screen = this.screen_adapter.get_text_screen(); - console.log("LOOKING FOR",step.vga_text); for(let line of screen) { - console.log(line); if(line.includes(step.vga_text)) { run(remaining_steps); @@ -1400,7 +1397,6 @@ V86Starter.prototype.automatically = function(steps) if(step.keyboard_send) { - console.log("SEND"); if(step.keyboard_send instanceof Array) { this.keyboard_send_scancodes(step.keyboard_send); From f6cf8615a550894e84d46d7a2d3cf45d52f80a3d Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Fri, 1 Sep 2023 10:30:26 -0700 Subject: [PATCH 25/27] add missing file --- tests/api/cdrom-insert-eject.js | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100755 tests/api/cdrom-insert-eject.js diff --git a/tests/api/cdrom-insert-eject.js b/tests/api/cdrom-insert-eject.js new file mode 100755 index 0000000000..b31b9e9c4e --- /dev/null +++ b/tests/api/cdrom-insert-eject.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node +"use strict"; + +const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; + +const fs = require("fs"); +var V86 = require(`../../build/${TEST_RELEASE_BUILD ? "libv86" : "libv86-debug"}.js`).V86; + +process.on("unhandledRejection", exn => { throw exn; }); + +const emulator = new V86({ + bios: { url: __dirname + "/../../bios/seabios.bin" }, + vga_bios: { url: __dirname + "/../../bios/vgabios.bin" }, + hda: { url: __dirname + "/../../images/freedos13.img" }, + wants_cdrom: true, + network_relay_url: "", + autostart: true, + memory_size: 32 * 1024 * 1024, + filesystem: {}, + log_level: 0, + screen_dummy: true, +}); + +emulator.automatically([ + { sleep: 1 }, + { vga_text: "JEMM386" }, + { sleep: 1 }, + { keyboard_send: "3" }, + { vga_text: "C:\\> " }, + { keyboard_send: "dir D:\n" }, + { vga_text: "(A)bort, (R)etry, (F)ail?" }, + { keyboard_send: "f" }, + { sleep: 10 }, + { vga_text: "(A)bort, (R)etry, (F)ail?" }, + { keyboard_send: "f" }, + { sleep: 10 }, + { vga_text: "(A)bort, (R)etry, (F)ail?" }, + { keyboard_send: "f" }, + { sleep: 10 }, + { call: () => { + emulator.set_cdrom({ url: __dirname + "/../../images/FD13LIVE.iso" }); + }, + }, + { sleep: 5 }, + { keyboard_send: "dir D:\n" }, + { vga_text: "Volume in drive D is FD13-LiveCD" }, + { call: () => { + console.log("Passed"); + emulator.stop(); + } + }, +]); From bdf6cce5669a0c136431706699991e2ec954cbd4 Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Fri, 1 Sep 2023 10:32:41 -0700 Subject: [PATCH 26/27] roll back main profiles, full-test changes --- src/browser/main.js | 26 --- tests/full/run.js | 482 ++++++++------------------------------------ 2 files changed, 89 insertions(+), 419 deletions(-) diff --git a/src/browser/main.js b/src/browser/main.js index ca085c29eb..301465b78c 100644 --- a/src/browser/main.js +++ b/src/browser/main.js @@ -358,32 +358,6 @@ }, name: "Freedos with FreeGEM", }, - { - id: "freedos-live", - cdrom: { - url: host + "FD13LIVE.iso", - async: false, - }, - name: "FreeDOS-Live", - }, - { - id: "freedos-13", - hda: { - url: host + "freedos13.img", - async: false, - }, - name: "FreeDOS 13", - boot_order: 0x312 - }, - { - id: "debian-wheezy", - hda: { - url: host + "debian_wheezy.img", - async: false, - }, - name: "Debian Wheezy", - boot_order: 0x312 - }, { id: "psychdos", hda: { diff --git a/tests/full/run.js b/tests/full/run.js index cc1d3dd7d1..3dd07baef4 100755 --- a/tests/full/run.js +++ b/tests/full/run.js @@ -9,7 +9,7 @@ var TEST_NAME = process.env.TEST_NAME; const TEST_RELEASE_BUILD = +process.env.TEST_RELEASE_BUILD; const RUN_SLOW_TESTS = +process.env.RUN_SLOW_TESTS; -const VERBOSE = +process.env.VERBOSE || false; +const VERBOSE = false; const LOG_SCREEN = false; try @@ -79,87 +79,9 @@ function send_work_to_worker(worker, message) } } -function do_action(test, emulator, run_step) -{ - if(Array.isArray(run_step)) - { - for(let step of run_step) - { - do_action(test, emulator, step); - } - } - else if(typeof run_step == "string") - { - if(VERBOSE) console.error("Sending '%s'", run_step); - emulator.keyboard_send_text(run_step); - } - else if(typeof run_step == "function") - { - if(VERBOSE) console.error("Run fn ", run_step); - run_step(test, emulator); - } - else if(typeof run_step == "object") - { - if(VERBOSE) console.error("Trigger ", run_step); - switch(run_step.action) - { - case "eject_fda": - { - emulator.eject_fda(); - break; - } - case "insert_fda": - { - emulator.set_fda(test.extra_images[run_step.image]); - break; - } - case "eject_cdrom": - { - emulator.eject_cdrom(); - break; - } - case "insert_cdrom": - { - emulator.set_cdrom(test.extra_images[run_step.image]); - break; - } - } - } -} - if(cluster.isMaster) { var tests = [ - { - name: "Wheezy boot", - hda: root_path + "/images/debian_wheezy.img", - timeout: 60, - expect_graphical_mode: true, - }, - { - name: "Wheezy boot with empty cdrom", - wants_cdrom: true, - hda: root_path + "/images/debian_wheezy.img", - timeout: 60, - boot_order:0x312, - expect_graphical_mode: true, - }, - { - name: "Wheezy boot with cdrom present", - wants_cdrom: true, - hda: root_path + "/images/debian_wheezy.img", - cdrom: root_path + "/images/linux.iso", - timeout: 60, - boot_order:0x312, - expect_graphical_mode: true, - }, - { - name: "Windows 1.01 boot", - fda: root_path + "/images/windows101.img", - timeout: 10, - expect_graphical_mode: true, - expect_mouse_registered: true, - }, { name: "FreeDOS boot", fda: root_path + "/images/freedos722.img", @@ -168,77 +90,6 @@ if(cluster.isMaster) "Welcome to FreeDOS", ], }, - { - name: "FreeDOS boot with cdrom present", - fda: root_path + "/images/freedos722.img", - cdrom: root_path + "/images/linux.iso", - boot_order:0x231, - timeout: 20, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with empty cdrom", - fda: root_path + "/images/freedos722.img", - wants_cdrom:true, - boot_order:0x231, - timeout: 20, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with empty cdrom (alternative boot order)", - fda: root_path + "/images/freedos722.img", - wants_cdrom:true, - boot_order:0x213, - timeout: 20, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with empty cdrom", - fda: root_path + "/images/freedos722.img", - wants_cdrom:true, - boot_order:0x231, - timeout: 20, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with empty cdrom (alternative boot order)", - fda: root_path + "/images/freedos722.img", - wants_cdrom:true, - boot_order:0x213, - timeout: 20, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with hda present", - fda: root_path + "/images/freedos722.img", - hda: root_path + "/images/msdos.img", - boot_order:0x231, - timeout: 20, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with cdrom and hda present", - fda: root_path + "/images/freedos722.img", - cdrom: root_path + "/images/linux.iso", - hda: root_path + "/images/msdos.img", - boot_order:0x321, - timeout: 40, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, { name: "FreeDOS boot with Bochs BIOS", fda: root_path + "/images/freedos722.img", @@ -248,108 +99,6 @@ if(cluster.isMaster) "Welcome to FreeDOS", ], }, - { - name: "FreeDOS boot with Bochs BIOS and empty cdrom", - fda: root_path + "/images/freedos722.img", - timeout: 20, - wants_cdrom: true, - boot_order:0x312, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and empty cdrom (alternative boot order)", - fda: root_path + "/images/freedos722.img", - timeout: 20, - boot_order:0x321, - wants_cdrom: true, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and empty cdrom", - fda: root_path + "/images/freedos722.img", - timeout: 20, - wants_cdrom: true, - boot_order:0x312, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and empty cdrom (alternative boot order)", - fda: root_path + "/images/freedos722.img", - timeout: 20, - boot_order:0x321, - wants_cdrom: true, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and cdrom present", - fda: root_path + "/images/freedos722.img", - cdrom: root_path + "/images/linux.iso", - boot_order:0x231, - timeout: 20, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and hda present", - fda: root_path + "/images/freedos722.img", - hda: root_path + "/images/msdos.img", - boot_order:0x231, - timeout: 20, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and hda present and empty cdrom", - fda: root_path + "/images/freedos722.img", - hda: root_path + "/images/msdos.img", - wants_cdrom: true, - boot_order:0x231, - timeout: 20, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and hda present and empty cdrom", - fda: root_path + "/images/freedos722.img", - hda: root_path + "/images/msdos.img", - wants_cdrom: true, - boot_order:0x231, - timeout: 20, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, - { - name: "FreeDOS boot with Bochs BIOS and cdrom and HDA present", - fda: root_path + "/images/freedos722.img", - cdrom: root_path + "/images/linux.iso", - hda: root_path + "/images/msdos.img", - boot_order:0x231, - timeout: 30, - alternative_bios: true, - expected_texts: [ - "Welcome to FreeDOS", - ], - }, { name: "Windows 1.01 boot", fda: root_path + "/images/windows101.img", @@ -399,23 +148,6 @@ if(cluster.isMaster) }, ], }, - { - name: "Linux with HDA present", - cdrom: root_path + "/images/linux.iso", - hda: root_path + "/images/msdos.img", - boot_order: 0x123, - timeout: 90, - expected_texts: [ - "/root%", - "test passed", - ], - actions: [ - { - on_text: "/root%", - run: "cd tests; ./test-i386 > emu.test; diff emu.test reference.test && echo test pas''sed || echo failed\n", - }, - ], - }, { name: "Windows XP CD", skip_if_disk_image_missing: true, @@ -550,24 +282,6 @@ if(cluster.isMaster) }, ], }, - { - name: "Linux with Bochs BIOS and HDA present", - cdrom: root_path + "/images/linux.iso", - hda: root_path + "/images/msdos.img", - timeout: 90, - expected_texts: [ - "/root%", - "test passed", - ], - boot_order: 0x123, - alternative_bios: true, - actions: [ - { - on_text: "/root%", - run: "cd tests; ./test-i386 > emu.test; diff emu.test reference.test && echo test pas''sed || echo failed\n", - }, - ], - }, { name: "MS-DOS", skip_if_disk_image_missing: true, @@ -578,7 +292,7 @@ if(cluster.isMaster) ], }, { - name: "MS-DOS (hard disk + floppy disk present)", + name: "MS-DOS (hard disk + floppy disk)", skip_if_disk_image_missing: true, hda: root_path + "/images/msdos.img", fda: root_path + "/images/kolibri.img", @@ -591,17 +305,6 @@ if(cluster.isMaster) "A:\\>", ], }, - { - name: "MS-DOS (hard disk + cd-rom present)", - skip_if_disk_image_missing: true, - hda: root_path + "/images/msdos.img", - cdrom: root_path + "/images/linux.iso", - boot_order: 0x132, - timeout: 120, - expected_texts: [ - "C:\\>", - ], - }, { name: "Linux 4", skip_if_disk_image_missing: true, @@ -724,38 +427,6 @@ if(cluster.isMaster) }, ], }, - { - name: "Windows 3.0 (with hda present)", - slow: 1, - skip_if_disk_image_missing: true, - timeout: 10 * 60, - hda: root_path + "/images/win31.img", - cdrom: root_path + "/images/Win30.iso", - expected_texts: [ - "Press any key to continue", - " **************************************************", - ], - expect_graphical_mode: true, - expect_mouse_registered: true, - actions: [ - { - on_text: "Press any key to continue . . .", - after: 1000, - run: "x", - }, - { - on_text: " **************************************************", - after: 1000, - run: "x", - }, - { - on_text: "C> ", - after: 1000, - run: "win\n", - }, - ], - boot_order: 0x123 - }, { name: "Windows 3.1", skip_if_disk_image_missing: true, @@ -768,20 +439,6 @@ if(cluster.isMaster) "MODE prepare code page function completed", ], }, - { - name: "Windows 3.1 (with cdrom present)", - skip_if_disk_image_missing: true, - timeout: 2 * 60, - boot_order: 0x312, - hda: root_path + "/images/win31.img", - cdrom: root_path + "/images/Win30.iso", - expect_graphical_mode: true, - expect_graphical_size: [1024, 768], - expect_mouse_registered: true, - expected_texts: [ - "MODE prepare code page function completed", - ], - }, { name: "FreeBSD", skip_if_disk_image_missing: true, @@ -1142,17 +799,56 @@ if(cluster.isMaster) { on_text: "boot:", run: "\n" }, { on_text: "tc@box", run: "sudo mount /dev/fd0 /mnt && ls /mnt\n" }, ], + expected_texts: ["AUTOEXEC.BAT"], }, { - name: "FreeDOS boot with cdrom and HDA present (alternative boot order)", - fda: root_path + "/images/freedos722.img", - cdrom: root_path + "/images/linux.iso", - hda: root_path + "/images/msdos.img", - boot_order:0x321, - timeout: 20, - expected_texts: [ - "Welcome to FreeDOS", - ], + name: "Core 8", + skip_if_disk_image_missing: 1, + timeout: 5 * 60, + cdrom: root_path + "/images/experimental/os/Core-8.0.iso", + expected_texts: ["tc@box"], + actions: [{ on_text: "boot:", run: "\n" }], + }, + { + name: "Core 7", + skip_if_disk_image_missing: 1, + timeout: 5 * 60, + cdrom: root_path + "/images/experimental/os/Core-7.2.iso", + expected_texts: ["tc@box"], + actions: [{ on_text: "boot:", run: "\n" }], + }, + { + name: "Core 6", + skip_if_disk_image_missing: 1, + timeout: 5 * 60, + cdrom: root_path + "/images/experimental/os/Core-6.4.1.iso", + expected_texts: ["tc@box"], + actions: [{ on_text: "boot:", run: "\n" }], + }, + { + name: "Core 5", + skip_if_disk_image_missing: 1, + timeout: 5 * 60, + cdrom: root_path + "/images/experimental/os/Core-5.4.iso", + expected_texts: ["tc@box"], + actions: [{ on_text: "boot:", run: "\n" }], + }, + { + name: "Core 4", + skip_if_disk_image_missing: 1, + timeout: 5 * 60, + cdrom: root_path + "/images/experimental/os/Core-4.7.7.iso", + expected_texts: ["tc@box"], + actions: [{ on_text: "boot:", run: "\n" }], + }, + { + name: "Damn Small Linux", + skip_if_disk_image_missing: 1, + timeout: 5 * 60, + cdrom: root_path + "/images/dsl-4.11.rc2.iso", + expect_graphical_mode: true, + expect_graphical_size: [1024, 768], + expect_mouse_registered: true, }, ]; @@ -1270,7 +966,7 @@ function run_test(test, done) vga_bios: { url: vga_bios }, autostart: true, memory_size: test.memory_size || 128 * 1024 * 1024, - log_level: 0x0, + log_level: 0, cmdline: test.cmdline, }; @@ -1278,7 +974,6 @@ function run_test(test, done) { settings.cdrom = { url: test.cdrom }; } - settings.wants_cdrom = test.wants_cdrom; if(test.fda) { settings.fda = { url: test.fda }; @@ -1360,9 +1055,9 @@ function run_test(test, done) } if(check_text_test_done() && - check_mouse_test_done() && - check_graphical_test_done() && - check_serial_test_done()) + check_mouse_test_done() && + check_graphical_test_done() && + check_serial_test_done()) { var end = Date.now(); @@ -1457,7 +1152,7 @@ function run_test(test, done) if(test.expect_graphical_size) { size_test_done = size[0] === test.expect_graphical_size[0] && - size[1] === test.expect_graphical_size[1]; + size[1] === test.expect_graphical_size[1]; check_test_done(); } }); @@ -1492,7 +1187,8 @@ function run_test(test, done) timeouts.push( setTimeout(() => { - do_action(test, emulator, action.run); + if(VERBOSE) console.error("Sending '%s'", action.run); + emulator.keyboard_send_text(action.run); }, action.after || 0) ); } @@ -1508,47 +1204,47 @@ function run_test(test, done) let serial_line = ""; emulator.add_listener("serial0-output-char", function(c) - { - if(c === "\n") { - if(VERBOSE) + if(c === "\n") { - console.log(`Serial (${test.name}):`, serial_line); - } + if(VERBOSE) + { + console.log(`Serial (${test.name}):`, serial_line); + } - if(test.expected_serial_text.length) - { - const expected = test.expected_serial_text[0]; - if(serial_line.includes(expected)) + if(test.expected_serial_text.length) { - test.expected_serial_text.shift(); - if(VERBOSE) console.log(`Passed: "${expected}" on serial (${test.name})`); - check_test_done(); + const expected = test.expected_serial_text[0]; + if(serial_line.includes(expected)) + { + test.expected_serial_text.shift(); + if(VERBOSE) console.log(`Passed: "${expected}" on serial (${test.name})`); + check_test_done(); + } } + + serial_line = ""; + } + else if(c >= " " && c <= "~") + { + serial_line += c; } + }); - serial_line = ""; + test.actions && test.actions.forEach(function(action) + { + if(action.on_text) + { + on_text.push({ text: string_to_bytearray(action.on_text), run: action.run, after: action.after }); } - else if(c >= " " && c <= "~") + else { - serial_line += c; + timeouts.push( + setTimeout(() => { + if(VERBOSE) console.error("Sending '%s'", action.run); + emulator.keyboard_send_text(action.run); + }, action.after || 0) + ); } }); - - test.actions && test.actions.forEach( - function(action) - { - if(action.on_text) - { - on_text.push({ text: string_to_bytearray(action.on_text), run: action.run, after: action.after }); - } - else - { - timeouts.push( - setTimeout(() => { - do_action(test, emulator, action.run); - }, action.after || 0) - ); - } - }); } From bf707ccbe4aadaa73276b3b3528454d915b2ef8c Mon Sep 17 00:00:00 2001 From: "Joseph C. Osborn" Date: Fri, 1 Sep 2023 10:34:27 -0700 Subject: [PATCH 27/27] add missing semicolons --- src/ide.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ide.js b/src/ide.js index 86327490f3..ec9f880809 100644 --- a/src/ide.js +++ b/src/ide.js @@ -566,7 +566,7 @@ IDEInterface.prototype.eject = function() this.error = 0x60; this.push_irq(); } -} +}; IDEInterface.prototype.set_cdrom = function(buffer) { @@ -638,7 +638,7 @@ IDEInterface.prototype.set_cdrom = function(buffer) this.push_irq(); } } -} +}; IDEInterface.prototype.device_reset = function() {