Skip to content

Commit

Permalink
virtio_net device
Browse files Browse the repository at this point in the history
  • Loading branch information
basicer authored and copy committed Sep 15, 2024
1 parent cf9f088 commit c1db615
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 10 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ CARGO_FLAGS=$(CARGO_FLAGS_SAFE) -C target-feature=+bulk-memory -C target-feature
CORE_FILES=const.js config.js io.js main.js lib.js buffer.js ide.js pci.js floppy.js \
memory.js dma.js pit.js vga.js ps2.js rtc.js uart.js \
acpi.js apic.js ioapic.js \
state.js ne2k.js sb16.js virtio.js virtio_console.js bus.js log.js \
cpu.js debug.js \
state.js ne2k.js sb16.js virtio.js virtio_console.js virtio_net.js \
bus.js log.js cpu.js debug.js \
elf.js kernel.js
LIB_FILES=9p.js filesystem.js jor1k.js marshall.js
BROWSER_FILES=screen.js keyboard.js mouse.js speaker.js serial.js \
Expand Down Expand Up @@ -306,6 +306,7 @@ devices-test: all-debug
./tests/devices/virtio_9p.js
./tests/devices/virtio_console.js
./tests/devices/fetch_network.js
USE_VIRTIO=1 ./tests/devices/fetch_network.js
./tests/devices/wisp_network.js

rust-test: $(RUST_FILES)
Expand Down
2 changes: 1 addition & 1 deletion debug.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"const.js config.js log.js lib.js buffer.js cpu.js debug.js " +
"io.js main.js ide.js pci.js floppy.js " +
"memory.js dma.js pit.js vga.js ps2.js rtc.js uart.js acpi.js apic.js ioapic.js sb16.js " +
"ne2k.js state.js virtio.js virtio_console.js bus.js elf.js kernel.js";
"ne2k.js state.js virtio.js virtio_console.js virtio_net.js bus.js elf.js kernel.js";

var BROWSER_FILES = "main.js screen.js keyboard.js mouse.js speaker.js serial.js network.js fake_network.js fetch_network.js wisp_network.js starter.js worker_bus.js print_stats.js filestorage.js";
var LIB_FILES = "";
Expand Down
2 changes: 1 addition & 1 deletion nodejs-loader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ let files = [
"src/sb16.js",
"src/virtio.js",
"src/virtio_console.js",
//"src/virtio_net.js",
"src/virtio_net.js",
//"src/virtio_balloon.js",
"src/bus.js",

Expand Down
1 change: 1 addition & 0 deletions src/browser/starter.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ V86.prototype.continue_init = async function(emulator, options)
settings.mac_address_translation = options.mac_address_translation;
settings.cpuid_level = options.cpuid_level;
settings.virtio_console = options.virtio_console;
settings.virtio_net = options.virtio_net;

const relay_url = options.network_relay_url || options.net_device && options.net_device.relay_url;
if(relay_url)
Expand Down
14 changes: 12 additions & 2 deletions src/cpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ CPU.prototype.get_state = function()
state[80] = this.devices.uart2;
state[81] = this.devices.uart3;
state[82] = this.devices.virtio_console;
state[83] = this.devices.virtio_net;

return state;
};
Expand Down Expand Up @@ -549,6 +550,7 @@ CPU.prototype.set_state = function(state)
this.devices.uart2 && this.devices.uart2.set_state(state[80]);
this.devices.uart3 && this.devices.uart3.set_state(state[81]);
this.devices.virtio_console && this.devices.virtio_console.set_state(state[82]);
this.devices.virtio_net && this.devices.virtio_net.set_state(state[83]);

this.fw_value = state[62];

Expand Down Expand Up @@ -687,11 +689,15 @@ CPU.prototype.reboot_internal = function()

if(this.devices.virtio_9p)
{
this.devices.virtio_9p.reset();
this.devices.virtio_9p.Reset();
}
if(this.devices.virtio_console)
{
this.devices.virtio_console.reset();
this.devices.virtio_console.Reset();
}
if(this.devices.virtio_net)
{
this.devices.virtio_net.Reset();
}

this.load_bios();
Expand Down Expand Up @@ -973,6 +979,10 @@ CPU.prototype.init = function(settings, device_bus)
{
this.devices.net = new Ne2k(this, device_bus, settings.preserve_mac_from_state_image, settings.mac_address_translation);
}
else if(settings.net_device.type === "virtio")
{
this.devices.virtio_net = new VirtioNet(this, device_bus, settings.preserve_mac_from_state_image);
}

if(settings.fs9p)
{
Expand Down
6 changes: 3 additions & 3 deletions src/virtio.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ VirtIO.prototype.create_common_capability = function(options)
read: () => 0,
write: data =>
{
dbg_log("Warning: High dword of 64 bit queue_desc ignored", LOG_VIRTIO);
if(data !== 0) dbg_log("Warning: High dword of 64 bit queue_desc ignored:" + data, LOG_VIRTIO);
},
},
{
Expand All @@ -571,7 +571,7 @@ VirtIO.prototype.create_common_capability = function(options)
read: () => 0,
write: data =>
{
dbg_log("Warning: High dword of 64 bit queue_avail ignored", LOG_VIRTIO);
if(data !== 0) dbg_log("Warning: High dword of 64 bit queue_avail ignored:" + data, LOG_VIRTIO);
},
},
{
Expand All @@ -589,7 +589,7 @@ VirtIO.prototype.create_common_capability = function(options)
read: () => 0,
write: data =>
{
dbg_log("Warning: High dword of 64 bit queue_used ignored", LOG_VIRTIO);
if(data !== 0) dbg_log("Warning: High dword of 64 bit queue_used ignored:" + data, LOG_VIRTIO);
},
},
],
Expand Down
246 changes: 246 additions & 0 deletions src/virtio_net.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
"use strict";

// https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-2900003


const VIRTIO_NET_F_MAC = 5;
const VIRTIO_NET_F_CTRL_VQ = 17;
const VIRTIO_NET_F_STATUS = 16;
const VIRTIO_NET_F_MQ = 22;
const VIRTIO_NET_F_CTRL_MAC_ADDR = 23;
const VIRTIO_NET_F_MTU = 3;

const VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET = 0;
const VIRTIO_NET_CTRL_MAC_ADDR_SET = 1;

/**
* @constructor
* @param {CPU} cpu
* @param {BusConnector} bus
* @param {Boolean} preserve_mac_from_state_image
*/
function VirtioNet(cpu, bus, preserve_mac_from_state_image)
{
/** @const @type {BusConnector} */
this.bus = bus;
this.id = cpu.devices.net ? 1 : 0;
this.pairs = 1;
this.status = 1;
this.preserve_mac_from_state_image = preserve_mac_from_state_image;
this.mac = new Uint8Array([
0x00, 0x22, 0x15,
Math.random() * 255 | 0,
Math.random() * 255 | 0,
Math.random() * 255 | 0,
]);

this.bus.send("net" + this.id + "-mac", format_mac(this.mac));

const queues = [];

for(let i = 0; i < this.pairs; ++i)
{
queues.push({size_supported: 32, notify_offset: 0});
queues.push({size_supported: 32, notify_offset: 1});
}
queues.push({
size_supported: 16,
notify_offset: 2,
});

/** @type {VirtIO} */
this.virtio = new VirtIO(cpu,
{
name: "virtio-net",
pci_id: 0x0A << 3,
device_id: 0x1041,
subsystem_device_id: 1,
common:
{
initial_port: 0xC800,
queues: queues,
features:
[
VIRTIO_NET_F_MAC,
VIRTIO_NET_F_STATUS,
VIRTIO_NET_F_MQ,
VIRTIO_NET_F_MTU,
VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_MAC_ADDR,
VIRTIO_F_VERSION_1,
],
on_driver_ok: () => {},
},
notification:
{
initial_port: 0xC900,
single_handler: false,
handlers:
[
(queue_id) =>
{
// TODO: Full buffer looks like an empty buffer so prevent it from filling
// The kernel gives us a prefilled one, so throw the first bufchain so
// it doesnt look filled.

const queue = this.virtio.queues[queue_id];

const desc_idx = queue.avail_get_entry(queue.avail_last_idx);
const bufchain = new VirtQueueBufferChain(queue, desc_idx);
queue.avail_last_idx = queue.avail_last_idx + 1 & queue.mask;
this.virtio.queues[0].push_reply(bufchain);
this.virtio.queues[0].flush_replies();
},
(queue_id) =>
{
const queue = this.virtio.queues[queue_id];

while(queue.has_request())
{
const bufchain = queue.pop_request();
const buffer = new Uint8Array(bufchain.length_readable);
bufchain.get_next_blob(buffer);
this.bus.send("net" + this.id + "-send", buffer.subarray(12));
this.virtio.queues[queue_id].push_reply(bufchain);
}
this.virtio.queues[queue_id].flush_replies();
},
(queue_id) =>
{
if(queue_id !== this.pairs * 2)
{
dbg_assert(false, "VirtioConsole Notified for wrong queue: " + queue_id +
" (expected queue_id of 3)");
return;
}
const queue = this.virtio.queues[queue_id];

while(queue.has_request())
{
const bufchain = queue.pop_request();
const buffer = new Uint8Array(bufchain.length_readable);
bufchain.get_next_blob(buffer);


const parts = marshall.Unmarshall(["b", "b"], buffer, { offset : 0 });
const xclass = parts[0];
const command = parts[1];


//this.Ack(queue_id, bufchain);

switch(xclass << 8 | command) {
case 4 << 8 | VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET:
const data = marshall.Unmarshall(["h"], buffer, { offset : 2 });
dbg_assert(data[0] === 1);
this.Send(queue_id, bufchain, new Uint8Array([0]));
break;
case 1 << 8 | VIRTIO_NET_CTRL_MAC_ADDR_SET:
this.mac = buffer.subarray(2, 8);
this.Send(queue_id, bufchain, new Uint8Array([0]));
this.bus.send("net" + this.id + "-mac", format_mac(this.mac));
break;
default:
dbg_assert(false," VirtioConsole received unknown command: " + xclass + ":" + command);
this.Send(queue_id, bufchain, new Uint8Array([1]));
return;

}
}
},
],
},
isr_status:
{
initial_port: 0xC700,
},
device_specific:
{
initial_port: 0xC600,
struct:
[0,1,2,3,4,5].map((v,k) => ({
bytes: 1,
name: "mac_" + k,
read: () => this.mac[k],
write: data => { /* read only */ },
})).concat(
[
{
bytes: 2,
name: "status",
read: () => this.status,
write: data => { /* read only */ },
},
{
bytes: 2,
name: "max_pairs",
read: () => this.pairs,
write: data => { /* read only */ },
},
{
bytes: 2,
name: "mtu",
read: () => 1500,
write: data => {},
}
])
},
});

this.bus.register("net" + this.id + "-receive", data => {
const with_header = new Uint8Array(12 + data.byteLength);
const view = new DataView(with_header.buffer, with_header.byteOffset, with_header.byteLength);
view.setInt16(10, 1);
with_header.set(data, 12);

const queue = this.virtio.queues[0];
if(queue.has_request()) {
const bufchain = queue.pop_request();
bufchain.set_next_blob(with_header);
this.virtio.queues[0].push_reply(bufchain);
this.virtio.queues[0].flush_replies();
} else {
console.log("No buffer to write into!");
}
}, this);

}


VirtioNet.prototype.get_state = function()
{
const state = [];
state[0] = this.virtio;
state[1] = this.id;

if(this.preserve_mac_from_state_image)
{
this.mac = state[2];
this.bus.send("net" + this.id + "-mac", format_mac(this.mac));
}

return state;
};

VirtioNet.prototype.set_state = function(state)
{
this.virtio.set_state(state[0]);
};

VirtioNet.prototype.Reset = function() {

};

VirtioNet.prototype.Send = function (queue_id, bufchain, blob)
{
bufchain.set_next_blob(blob);
this.virtio.queues[queue_id].push_reply(bufchain);
this.virtio.queues[queue_id].flush_replies();
};

VirtioNet.prototype.Ack = function (queue_id, bufchain)
{
//bufchain.set_next_blob(new Uint8Array(0));
this.virtio.queues[queue_id].push_reply(bufchain);
this.virtio.queues[queue_id].flush_replies();
};
Loading

0 comments on commit c1db615

Please sign in to comment.