Skip to content

Commit

Permalink
Virtio balloon
Browse files Browse the repository at this point in the history
  • Loading branch information
basicer authored and copy committed Feb 2, 2025
1 parent 368efb0 commit 2b162b1
Show file tree
Hide file tree
Showing 8 changed files with 445 additions and 4 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ 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 virtio_net.js \
state.js ne2k.js sb16.js virtio.js virtio_console.js virtio_net.js virtio_balloon.js \
bus.js log.js cpu.js debug.js \
elf.js kernel.js
LIB_FILES=9p.js filesystem.js jor1k.js marshall.js
Expand Down Expand Up @@ -327,6 +327,7 @@ devices-test: all-debug
./tests/devices/fetch_network.js
USE_VIRTIO=1 ./tests/devices/fetch_network.js
./tests/devices/wisp_network.js
./tests/devices/virtio_balloon.js

rust-test: $(RUST_FILES)
env RUSTFLAGS="-D warnings" RUST_BACKTRACE=full RUST_TEST_THREADS=1 cargo test -- --nocapture
Expand Down
1 change: 1 addition & 0 deletions debug.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
<script src="src/ne2k.js"></script>
<script src="src/state.js"></script>
<script src="src/virtio.js"></script>
<script src="src/virtio_balloon.js"></script>
<script src="src/virtio_console.js"></script>
<script src="src/virtio_net.js"></script>
<script src="src/bus.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion nodejs-loader.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ let files = [
"src/virtio.js",
"src/virtio_console.js",
"src/virtio_net.js",
//"src/virtio_balloon.js",
"src/virtio_balloon.js",
"src/bus.js",

"src/debug.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.preserve_mac_from_state_image = options.preserve_mac_from_state_image;
settings.mac_address_translation = options.mac_address_translation;
settings.cpuid_level = options.cpuid_level;
settings.virtio_balloon = options.virtio_balloon;
settings.virtio_console = options.virtio_console;
settings.virtio_net = options.virtio_net;
settings.screen_options = options.screen_options;
Expand Down
7 changes: 6 additions & 1 deletion src/cpu.js
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ CPU.prototype.get_state = function()
state[81] = this.devices.uart3;
state[82] = this.devices.virtio_console;
state[83] = this.devices.virtio_net;
state[84] = this.devices.virtio_balloon;

return state;
};
Expand Down Expand Up @@ -552,6 +553,7 @@ CPU.prototype.set_state = function(state)
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.devices.virtio_balloon && this.devices.virtio_balloon.set_state(state[84]);

this.fw_value = state[62];

Expand Down Expand Up @@ -651,7 +653,7 @@ CPU.prototype.pack_memory = function()

CPU.prototype.unpack_memory = function(bitmap, packed_memory)
{
this.zero_memory(this.memory_size[0]);
this.zero_memory(0, this.memory_size[0]);

const page_count = this.memory_size[0] >> 12;
let packed_page = 0;
Expand Down Expand Up @@ -979,6 +981,9 @@ CPU.prototype.init = function(settings, device_bus)
{
this.devices.virtio_console = new VirtioConsole(this, device_bus);
}
if(settings.virtio_balloon) {
this.devices.virtio_balloon = new VirtioBalloon(this, device_bus);
}

if(true)
{
Expand Down
4 changes: 3 additions & 1 deletion src/rust/cpu/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ pub fn allocate_memory(size: u32) -> u32 {
}

#[no_mangle]
pub unsafe fn zero_memory(size: u32) { ptr::write_bytes(mem8, 0, size as usize); }
pub unsafe fn zero_memory(addr: u32, size: u32) {
ptr::write_bytes(mem8.offset(addr as isize), 0, size as usize);
}

#[allow(non_upper_case_globals)]
pub static mut vga_mem8: *mut u8 = ptr::null_mut();
Expand Down
218 changes: 218 additions & 0 deletions src/virtio_balloon.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
"use strict";

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

const VIRTIO_BALLOON_F_MUST_TELL_HOST = 0;
const VIRTIO_BALLOON_F_STATS_VQ = 1;
const VIRTIO_BALLOON_F_DEFLATE_ON_OOM = 2;
const VIRTIO_BALLOON_F_FREE_PAGE_HINT = 3;

const STAT_NAMES = [
"SWAP_IN",
"SWAP_OUT",
"MAJFLT",
"MINFLT",
"MEMFREE",
"MEMTOT",
"AVAIL",
"CACHES",
"HTLB_PGALLOC",
"HTLB_PGFAIL",
];

/**
* @constructor
* @param {CPU} cpu
* @param {BusConnector} bus
*/
function VirtioBalloon(cpu, bus)
{
/** @const @type {BusConnector} */
this.bus = bus;
this.num_pages = 0;
this.actual = 0;
this.fp_cmd = 0;
this.zeroed = 0;

const queues = [
{size_supported: 32, notify_offset: 0},
{size_supported: 32, notify_offset: 0},
{size_supported: 2, notify_offset: 1},
{size_supported: 64, notify_offset: 2},
];

//setInterval(() => this.GetStats(console.log.bind(console, "STATS")), 10000);

/** @type {VirtIO} */
this.virtio = new VirtIO(cpu,
{
name: "virtio-balloon",
pci_id: 0x0B << 3,
device_id: 0x1045,
subsystem_device_id: 5,
common:
{
initial_port: 0xD800,
queues: queues,
features:
[
VIRTIO_BALLOON_F_STATS_VQ,
VIRTIO_BALLOON_F_FREE_PAGE_HINT,
VIRTIO_F_VERSION_1,
],
on_driver_ok: () => {
dbg_log("Balloon setup", LOG_PCI);
},
},
notification:
{
initial_port: 0xD900,
single_handler: false,
handlers:
[
(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.virtio.queues[queue_id].push_reply(bufchain);
let n = buffer.byteLength / 4;
this.actual += (queue_id === 0 ? n : -n);
//console.log(queue_id === 0 ? "Inflate" : "Deflate", this.num_pages, this.actual, bufchain.read_buffers);
}
this.virtio.queues[queue_id].flush_replies();
},
(queue_id) =>
{
const queue = this.virtio.queues[queue_id];
if(queue.has_request())
{
const bufchain = queue.pop_request();
const buffer = new Uint8Array(bufchain.length_readable);
bufchain.get_next_blob(buffer);
let result = {};
for(let i = 0; i < bufchain.length_readable; i += 10) {
let [cat, value] = marshall.Unmarshall(["h", "d"], buffer, { offset : i });
result[STAT_NAMES[cat]] = value;
}
this.virtio.queues[queue_id].push_reply(bufchain);
if(this.stats_cb) this.stats_cb(result);
}
},
(queue_id) =>
{
const queue = this.virtio.queues[queue_id];
while(queue.has_request())
{
const bufchain = queue.pop_request();
if(bufchain.length_readable > 0) {
const buffer = new Uint8Array(bufchain.length_readable);
bufchain.get_next_blob(buffer);
let [cmd] = marshall.Unmarshall(["w"], buffer, { offset : 0 });
if(cmd === 0) {
if(this.free_cb) this.free_cb(this.zeroed);
if(this.fp_cmd > 1) this.fp_cmd = 1; // Signal done
this.virtio.notify_config_changes();
}
}
if(bufchain.length_writable > 0) {
// console.log("Free pages hinted", bufchain.read_buffers, bufchain.write_buffers);
let zeros = new Uint8Array(0);
for(let i = 0; i < bufchain.write_buffers.length; ++i) {
let b = bufchain.write_buffers[i];
this.zeroed += b.len;
this.virtio.cpu.zero_memory(b.addr_low, b.len);
}
}
this.virtio.queues[queue_id].push_reply(bufchain);
}
this.virtio.queues[queue_id].flush_replies();
},
],
},
isr_status:
{
initial_port: 0xD700,
},
device_specific:
{
initial_port: 0xD600,
struct:
[
{
bytes: 4,
name: "num_pages",
read: () => this.num_pages,
write: data => { /* read only */ },
},
{
bytes: 4,
name: "actual",
read: () => {
return this.actual;
},
write: data => { /* read only */ },
},
{
bytes: 4,
name: "free_page_hint_cmd_id",
read: () => this.fp_cmd,
write: data => { /* read only */ },
}
]
},
});
}

VirtioBalloon.prototype.Inflate = function(amount) {
this.num_pages += amount;
this.virtio.notify_config_changes();
};

VirtioBalloon.prototype.Deflate = function(amount) {
this.num_pages -= amount;
this.virtio.notify_config_changes();
};

VirtioBalloon.prototype.Cleanup = function(cb) {
this.fp_cmd = 2;
this.free_cb = cb;
this.zeroed = 0;
this.virtio.notify_config_changes();
};


VirtioBalloon.prototype.get_state = function()
{
const state = [];
state[0] = this.virtio;
state[1] = this.num_pages;
state[2] = this.actual;
return state;
};

VirtioBalloon.prototype.set_state = function(state)
{
this.virtio.set_state(state[0]);
this.num_pages = state[1];
this.actual = state[2];
};

VirtioBalloon.prototype.GetStats = function(data)
{
this.stats_cb = data;
const queue = this.virtio.queues[2];
while(queue.has_request())
{
const bufchain = queue.pop_request();
this.virtio.queues[2].push_reply(bufchain);
}
this.virtio.queues[2].flush_replies();
};

VirtioBalloon.prototype.Reset = function() {

};
Loading

0 comments on commit 2b162b1

Please sign in to comment.