Spaces:
Runtime error
Runtime error
| // https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-2900003 | |
| import { LOG_PCI } from "./const.js"; | |
| import { dbg_log } from "./log.js"; | |
| import { VirtIO, VIRTIO_F_VERSION_1 } from "./virtio.js"; | |
| import * as marshall from "../lib/marshall.js"; | |
| // For Types Only | |
| import { CPU } from "./cpu.js"; | |
| import { BusConnector } from "./bus.js"; | |
| 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 | |
| */ | |
| export 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() { | |
| }; | |