@aptre/v86 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/v86.browser.js +1113 -93
- package/dist/v86.browser.js.map +4 -4
- package/dist/v86.js +1112 -93
- package/dist/v86.js.map +4 -4
- package/lib/9p.ts +4 -4
- package/lib/filesystem.ts +1 -1
- package/package.json +7 -7
- package/src/browser/starter.ts +53 -23
- package/src/const.ts +2 -0
- package/src/cpu.ts +128 -98
- package/src/pci.ts +8 -3
- package/src/ps2.ts +2 -2
- package/src/virtio.ts +10 -18
- package/src/virtio_mem.ts +349 -0
- package/src/virtio_v86fs.ts +873 -0
- package/src/rust/gen/analyzer.rs +0 -3807
- package/src/rust/gen/analyzer0f.rs +0 -3992
- package/src/rust/gen/interpreter.rs +0 -4447
- package/src/rust/gen/interpreter0f.rs +0 -5404
- package/src/rust/gen/jit.rs +0 -5080
- package/src/rust/gen/jit0f.rs +0 -5547
package/dist/v86.js
CHANGED
|
@@ -106,6 +106,7 @@ var FW_CFG_FILE_START = 49152;
|
|
|
106
106
|
var FW_CFG_SIGNATURE_QEMU = 1431127377;
|
|
107
107
|
var WASM_TABLE_SIZE = 900;
|
|
108
108
|
var WASM_TABLE_OFFSET = 1024;
|
|
109
|
+
var WASM_PAGE_SIZE = 65536;
|
|
109
110
|
var MIXER_CHANNEL_LEFT = 0;
|
|
110
111
|
var MIXER_CHANNEL_RIGHT = 1;
|
|
111
112
|
var MIXER_CHANNEL_BOTH = 2;
|
|
@@ -5420,17 +5421,18 @@ var VirtIO = class {
|
|
|
5420
5421
|
LOG_VIRTIO
|
|
5421
5422
|
);
|
|
5422
5423
|
}
|
|
5423
|
-
if (data & ~this.device_status & VIRTIO_STATUS_DRIVER_OK && this.device_status & VIRTIO_STATUS_DEVICE_NEEDS_RESET) {
|
|
5424
|
-
this.notify_config_changes();
|
|
5425
|
-
}
|
|
5426
5424
|
if (!this.features_ok) {
|
|
5427
5425
|
if (false) {
|
|
5428
5426
|
dbg_log("Removing FEATURES_OK", LOG_VIRTIO);
|
|
5429
5427
|
}
|
|
5430
5428
|
data &= ~VIRTIO_STATUS_FEATURES_OK;
|
|
5431
5429
|
}
|
|
5430
|
+
const prev_status = this.device_status;
|
|
5432
5431
|
this.device_status = data;
|
|
5433
|
-
if (data & ~
|
|
5432
|
+
if (data & ~prev_status & VIRTIO_STATUS_DRIVER_OK) {
|
|
5433
|
+
if (prev_status & VIRTIO_STATUS_DEVICE_NEEDS_RESET) {
|
|
5434
|
+
this.notify_config_changes();
|
|
5435
|
+
}
|
|
5434
5436
|
options.on_driver_ok();
|
|
5435
5437
|
}
|
|
5436
5438
|
}
|
|
@@ -5667,7 +5669,7 @@ var VirtIO = class {
|
|
|
5667
5669
|
// Call only within constructor.
|
|
5668
5670
|
init_capabilities(capabilities) {
|
|
5669
5671
|
let cap_next = this.pci_space[52] = 64;
|
|
5670
|
-
let cap_ptr
|
|
5672
|
+
let cap_ptr;
|
|
5671
5673
|
for (const cap of capabilities) {
|
|
5672
5674
|
const cap_len2 = VIRTIO_PCI_CAP_LENGTH + cap.extra.length;
|
|
5673
5675
|
cap_ptr = cap_next;
|
|
@@ -6888,7 +6890,7 @@ var PCI = class {
|
|
|
6888
6890
|
(out_byte) => {
|
|
6889
6891
|
if ((this.pci_addr[1] & 6) === 2 && (out_byte & 6) === 6) {
|
|
6890
6892
|
dbg_log("CPU reboot via PCI");
|
|
6891
|
-
cpu.
|
|
6893
|
+
cpu.reboot();
|
|
6892
6894
|
return;
|
|
6893
6895
|
}
|
|
6894
6896
|
this.pci_addr[1] = out_byte;
|
|
@@ -6994,6 +6996,7 @@ var PCI = class {
|
|
|
6994
6996
|
0,
|
|
6995
6997
|
0,
|
|
6996
6998
|
0,
|
|
6999
|
+
0,
|
|
6997
7000
|
PAM0,
|
|
6998
7001
|
0,
|
|
6999
7002
|
0,
|
|
@@ -7306,7 +7309,11 @@ var PCI = class {
|
|
|
7306
7309
|
dbg_assert(device.pci_space.length >= 64);
|
|
7307
7310
|
dbg_assert(device_id < this.devices.length);
|
|
7308
7311
|
const space = new Int32Array(64);
|
|
7309
|
-
|
|
7312
|
+
const pci_bytes = new Uint8Array(device.pci_space);
|
|
7313
|
+
const aligned_len = pci_bytes.length & ~3;
|
|
7314
|
+
if (aligned_len > 0) {
|
|
7315
|
+
space.set(new Int32Array(pci_bytes.buffer, 0, aligned_len >> 2));
|
|
7316
|
+
}
|
|
7310
7317
|
this.device_spaces[device_id] = space;
|
|
7311
7318
|
this.devices[device_id] = device;
|
|
7312
7319
|
const bar_space = space.slice(4, 10);
|
|
@@ -7957,7 +7964,7 @@ var PS2 = class {
|
|
|
7957
7964
|
break;
|
|
7958
7965
|
case 254:
|
|
7959
7966
|
dbg_log("CPU reboot via PS2");
|
|
7960
|
-
this.cpu.
|
|
7967
|
+
this.cpu.reboot();
|
|
7961
7968
|
break;
|
|
7962
7969
|
default:
|
|
7963
7970
|
dbg_log(
|
|
@@ -15102,12 +15109,930 @@ var VirtioBalloon = class {
|
|
|
15102
15109
|
}
|
|
15103
15110
|
};
|
|
15104
15111
|
|
|
15112
|
+
// src/virtio_mem.ts
|
|
15113
|
+
var VIRTIO_MEM_REQ_PLUG = 0;
|
|
15114
|
+
var VIRTIO_MEM_REQ_UNPLUG = 1;
|
|
15115
|
+
var VIRTIO_MEM_REQ_STATE = 3;
|
|
15116
|
+
var VIRTIO_MEM_RESP_ACK = 0;
|
|
15117
|
+
var VIRTIO_MEM_RESP_NACK = 1;
|
|
15118
|
+
var VIRTIO_MEM_RESP_ERROR = 3;
|
|
15119
|
+
var DEFAULT_BLOCK_SIZE = 128 * 1024 * 1024;
|
|
15120
|
+
var VirtioMem = class {
|
|
15121
|
+
bus;
|
|
15122
|
+
cpu;
|
|
15123
|
+
virtio;
|
|
15124
|
+
block_size;
|
|
15125
|
+
region_addr;
|
|
15126
|
+
region_size;
|
|
15127
|
+
usable_region_size;
|
|
15128
|
+
plugged_size;
|
|
15129
|
+
requested_size;
|
|
15130
|
+
constructor(cpu, bus, region_addr, region_size, block_size) {
|
|
15131
|
+
this.bus = bus;
|
|
15132
|
+
this.cpu = cpu;
|
|
15133
|
+
this.block_size = block_size || DEFAULT_BLOCK_SIZE;
|
|
15134
|
+
this.region_addr = region_addr;
|
|
15135
|
+
this.region_size = region_size;
|
|
15136
|
+
this.usable_region_size = region_size;
|
|
15137
|
+
this.plugged_size = 0;
|
|
15138
|
+
this.requested_size = 0;
|
|
15139
|
+
const queues = [{ size_supported: 32, notify_offset: 0 }];
|
|
15140
|
+
this.virtio = new VirtIO(cpu, {
|
|
15141
|
+
name: "virtio-mem",
|
|
15142
|
+
pci_id: 13 << 3,
|
|
15143
|
+
device_id: 4184,
|
|
15144
|
+
subsystem_device_id: 24,
|
|
15145
|
+
common: {
|
|
15146
|
+
initial_port: 59392,
|
|
15147
|
+
queues,
|
|
15148
|
+
features: [VIRTIO_F_VERSION_1],
|
|
15149
|
+
on_driver_ok: () => {
|
|
15150
|
+
dbg_log("virtio-mem setup", LOG_PCI);
|
|
15151
|
+
}
|
|
15152
|
+
},
|
|
15153
|
+
notification: {
|
|
15154
|
+
initial_port: 59648,
|
|
15155
|
+
single_handler: false,
|
|
15156
|
+
handlers: [
|
|
15157
|
+
(queue_id) => {
|
|
15158
|
+
this.handle_request(queue_id);
|
|
15159
|
+
}
|
|
15160
|
+
]
|
|
15161
|
+
},
|
|
15162
|
+
isr_status: {
|
|
15163
|
+
initial_port: 59136
|
|
15164
|
+
},
|
|
15165
|
+
device_specific: {
|
|
15166
|
+
initial_port: 58880,
|
|
15167
|
+
struct: [
|
|
15168
|
+
// block_size low
|
|
15169
|
+
{
|
|
15170
|
+
bytes: 4,
|
|
15171
|
+
name: "block_size_low",
|
|
15172
|
+
read: () => this.block_size >>> 0,
|
|
15173
|
+
write: () => {
|
|
15174
|
+
}
|
|
15175
|
+
},
|
|
15176
|
+
// block_size high
|
|
15177
|
+
{
|
|
15178
|
+
bytes: 4,
|
|
15179
|
+
name: "block_size_high",
|
|
15180
|
+
read: () => 0,
|
|
15181
|
+
write: () => {
|
|
15182
|
+
}
|
|
15183
|
+
},
|
|
15184
|
+
// node_id (u16 padded to u32)
|
|
15185
|
+
{
|
|
15186
|
+
bytes: 2,
|
|
15187
|
+
name: "node_id",
|
|
15188
|
+
read: () => 0,
|
|
15189
|
+
write: () => {
|
|
15190
|
+
}
|
|
15191
|
+
},
|
|
15192
|
+
// padding (6 bytes as 2+4)
|
|
15193
|
+
{
|
|
15194
|
+
bytes: 2,
|
|
15195
|
+
name: "padding0",
|
|
15196
|
+
read: () => 0,
|
|
15197
|
+
write: () => {
|
|
15198
|
+
}
|
|
15199
|
+
},
|
|
15200
|
+
{
|
|
15201
|
+
bytes: 4,
|
|
15202
|
+
name: "padding1",
|
|
15203
|
+
read: () => 0,
|
|
15204
|
+
write: () => {
|
|
15205
|
+
}
|
|
15206
|
+
},
|
|
15207
|
+
// addr low
|
|
15208
|
+
{
|
|
15209
|
+
bytes: 4,
|
|
15210
|
+
name: "addr_low",
|
|
15211
|
+
read: () => this.region_addr >>> 0,
|
|
15212
|
+
write: () => {
|
|
15213
|
+
}
|
|
15214
|
+
},
|
|
15215
|
+
// addr high
|
|
15216
|
+
{
|
|
15217
|
+
bytes: 4,
|
|
15218
|
+
name: "addr_high",
|
|
15219
|
+
read: () => 0,
|
|
15220
|
+
write: () => {
|
|
15221
|
+
}
|
|
15222
|
+
},
|
|
15223
|
+
// region_size low
|
|
15224
|
+
{
|
|
15225
|
+
bytes: 4,
|
|
15226
|
+
name: "region_size_low",
|
|
15227
|
+
read: () => this.region_size >>> 0,
|
|
15228
|
+
write: () => {
|
|
15229
|
+
}
|
|
15230
|
+
},
|
|
15231
|
+
// region_size high
|
|
15232
|
+
{
|
|
15233
|
+
bytes: 4,
|
|
15234
|
+
name: "region_size_high",
|
|
15235
|
+
read: () => 0,
|
|
15236
|
+
write: () => {
|
|
15237
|
+
}
|
|
15238
|
+
},
|
|
15239
|
+
// usable_region_size low
|
|
15240
|
+
{
|
|
15241
|
+
bytes: 4,
|
|
15242
|
+
name: "usable_region_size_low",
|
|
15243
|
+
read: () => this.usable_region_size >>> 0,
|
|
15244
|
+
write: () => {
|
|
15245
|
+
}
|
|
15246
|
+
},
|
|
15247
|
+
// usable_region_size high
|
|
15248
|
+
{
|
|
15249
|
+
bytes: 4,
|
|
15250
|
+
name: "usable_region_size_high",
|
|
15251
|
+
read: () => 0,
|
|
15252
|
+
write: () => {
|
|
15253
|
+
}
|
|
15254
|
+
},
|
|
15255
|
+
// plugged_size low
|
|
15256
|
+
{
|
|
15257
|
+
bytes: 4,
|
|
15258
|
+
name: "plugged_size_low",
|
|
15259
|
+
read: () => this.plugged_size >>> 0,
|
|
15260
|
+
write: () => {
|
|
15261
|
+
}
|
|
15262
|
+
},
|
|
15263
|
+
// plugged_size high
|
|
15264
|
+
{
|
|
15265
|
+
bytes: 4,
|
|
15266
|
+
name: "plugged_size_high",
|
|
15267
|
+
read: () => 0,
|
|
15268
|
+
write: () => {
|
|
15269
|
+
}
|
|
15270
|
+
},
|
|
15271
|
+
// requested_size low
|
|
15272
|
+
{
|
|
15273
|
+
bytes: 4,
|
|
15274
|
+
name: "requested_size_low",
|
|
15275
|
+
read: () => this.requested_size >>> 0,
|
|
15276
|
+
write: () => {
|
|
15277
|
+
}
|
|
15278
|
+
},
|
|
15279
|
+
// requested_size high
|
|
15280
|
+
{
|
|
15281
|
+
bytes: 4,
|
|
15282
|
+
name: "requested_size_high",
|
|
15283
|
+
read: () => 0,
|
|
15284
|
+
write: () => {
|
|
15285
|
+
}
|
|
15286
|
+
}
|
|
15287
|
+
]
|
|
15288
|
+
}
|
|
15289
|
+
});
|
|
15290
|
+
}
|
|
15291
|
+
handle_request(queue_id) {
|
|
15292
|
+
const queue = this.virtio.queues[queue_id];
|
|
15293
|
+
while (queue.has_request()) {
|
|
15294
|
+
const bufchain = queue.pop_request();
|
|
15295
|
+
const request = new Uint8Array(bufchain.length_readable);
|
|
15296
|
+
bufchain.get_next_blob(request);
|
|
15297
|
+
const type = request[0] | request[1] << 8;
|
|
15298
|
+
const resp = new Uint8Array(8);
|
|
15299
|
+
let resp_type = VIRTIO_MEM_RESP_ERROR;
|
|
15300
|
+
switch (type) {
|
|
15301
|
+
case VIRTIO_MEM_REQ_PLUG:
|
|
15302
|
+
resp_type = this.handle_plug(request);
|
|
15303
|
+
break;
|
|
15304
|
+
case VIRTIO_MEM_REQ_UNPLUG:
|
|
15305
|
+
resp_type = VIRTIO_MEM_RESP_NACK;
|
|
15306
|
+
break;
|
|
15307
|
+
case VIRTIO_MEM_REQ_STATE:
|
|
15308
|
+
resp_type = this.handle_state(request, resp);
|
|
15309
|
+
break;
|
|
15310
|
+
default:
|
|
15311
|
+
dbg_log("virtio-mem: unknown request type " + type, LOG_PCI);
|
|
15312
|
+
}
|
|
15313
|
+
resp[0] = resp_type & 255;
|
|
15314
|
+
resp[1] = resp_type >> 8 & 255;
|
|
15315
|
+
bufchain.set_next_blob(resp);
|
|
15316
|
+
queue.push_reply(bufchain);
|
|
15317
|
+
}
|
|
15318
|
+
queue.flush_replies();
|
|
15319
|
+
}
|
|
15320
|
+
handle_plug(request) {
|
|
15321
|
+
const addr = (request[8] | request[9] << 8 | request[10] << 16 | request[11] << 24) >>> 0;
|
|
15322
|
+
const nb_blocks = request[16] | request[17] << 8;
|
|
15323
|
+
const size = nb_blocks * this.block_size;
|
|
15324
|
+
const new_plugged = this.plugged_size + size;
|
|
15325
|
+
if (new_plugged > this.usable_region_size) {
|
|
15326
|
+
return VIRTIO_MEM_RESP_NACK;
|
|
15327
|
+
}
|
|
15328
|
+
const new_memory_size = this.cpu.memory_size[0] + size;
|
|
15329
|
+
this.cpu.resize_memory(new_memory_size);
|
|
15330
|
+
this.cpu.full_clear_tlb();
|
|
15331
|
+
this.plugged_size = new_plugged;
|
|
15332
|
+
dbg_log(
|
|
15333
|
+
"virtio-mem: plugged " + nb_blocks + " blocks at 0x" + addr.toString(16) + " (" + (size >> 20) + "MB)",
|
|
15334
|
+
LOG_PCI
|
|
15335
|
+
);
|
|
15336
|
+
return VIRTIO_MEM_RESP_ACK;
|
|
15337
|
+
}
|
|
15338
|
+
handle_state(request, resp) {
|
|
15339
|
+
const addr = (request[8] | request[9] << 8 | request[10] << 16 | request[11] << 24) >>> 0;
|
|
15340
|
+
const nb_blocks = request[16] | request[17] << 8;
|
|
15341
|
+
const offset = addr - this.region_addr;
|
|
15342
|
+
const end = offset + nb_blocks * this.block_size;
|
|
15343
|
+
const all_plugged = end <= this.plugged_size ? 1 : 0;
|
|
15344
|
+
resp[8] = all_plugged & 255;
|
|
15345
|
+
resp[9] = all_plugged >> 8 & 255;
|
|
15346
|
+
return VIRTIO_MEM_RESP_ACK;
|
|
15347
|
+
}
|
|
15348
|
+
set_requested_size(size) {
|
|
15349
|
+
this.requested_size = size;
|
|
15350
|
+
if (this.virtio.device_status & 4) {
|
|
15351
|
+
this.virtio.notify_config_changes();
|
|
15352
|
+
}
|
|
15353
|
+
}
|
|
15354
|
+
get_state() {
|
|
15355
|
+
const state = [];
|
|
15356
|
+
state[0] = this.virtio;
|
|
15357
|
+
state[1] = this.block_size;
|
|
15358
|
+
state[2] = this.region_addr;
|
|
15359
|
+
state[3] = this.region_size;
|
|
15360
|
+
state[4] = this.usable_region_size;
|
|
15361
|
+
state[5] = this.plugged_size;
|
|
15362
|
+
state[6] = this.requested_size;
|
|
15363
|
+
return state;
|
|
15364
|
+
}
|
|
15365
|
+
set_state(state) {
|
|
15366
|
+
this.virtio.set_state(state[0]);
|
|
15367
|
+
this.block_size = state[1];
|
|
15368
|
+
this.region_addr = state[2];
|
|
15369
|
+
this.region_size = state[3];
|
|
15370
|
+
this.usable_region_size = state[4];
|
|
15371
|
+
this.plugged_size = state[5];
|
|
15372
|
+
this.requested_size = state[6];
|
|
15373
|
+
}
|
|
15374
|
+
};
|
|
15375
|
+
|
|
15376
|
+
// src/virtio_v86fs.ts
|
|
15377
|
+
var V86FS_MSG_MOUNT = 0;
|
|
15378
|
+
var V86FS_MSG_LOOKUP = 1;
|
|
15379
|
+
var V86FS_MSG_GETATTR = 2;
|
|
15380
|
+
var V86FS_MSG_READDIR = 3;
|
|
15381
|
+
var V86FS_MSG_OPEN = 4;
|
|
15382
|
+
var V86FS_MSG_CLOSE = 5;
|
|
15383
|
+
var V86FS_MSG_READ = 6;
|
|
15384
|
+
var V86FS_MSG_CREATE = 7;
|
|
15385
|
+
var V86FS_MSG_WRITE = 8;
|
|
15386
|
+
var V86FS_MSG_MKDIR = 9;
|
|
15387
|
+
var V86FS_MSG_SETATTR = 10;
|
|
15388
|
+
var V86FS_MSG_FSYNC = 11;
|
|
15389
|
+
var V86FS_MSG_UNLINK = 12;
|
|
15390
|
+
var V86FS_MSG_RENAME = 13;
|
|
15391
|
+
var V86FS_MSG_SYMLINK = 14;
|
|
15392
|
+
var V86FS_MSG_READLINK = 15;
|
|
15393
|
+
var V86FS_MSG_STATFS = 16;
|
|
15394
|
+
var V86FS_MSG_INVALIDATE = 32;
|
|
15395
|
+
var V86FS_MSG_INVALIDATE_DIR = 33;
|
|
15396
|
+
var V86FS_MSG_MOUNT_R = 128;
|
|
15397
|
+
var V86FS_MSG_LOOKUP_R = 129;
|
|
15398
|
+
var V86FS_MSG_GETATTR_R = 130;
|
|
15399
|
+
var V86FS_MSG_READDIR_R = 131;
|
|
15400
|
+
var V86FS_MSG_OPEN_R = 132;
|
|
15401
|
+
var V86FS_MSG_CLOSE_R = 133;
|
|
15402
|
+
var V86FS_MSG_READ_R = 134;
|
|
15403
|
+
var V86FS_MSG_CREATE_R = 135;
|
|
15404
|
+
var V86FS_MSG_WRITE_R = 136;
|
|
15405
|
+
var V86FS_MSG_MKDIR_R = 137;
|
|
15406
|
+
var V86FS_MSG_SETATTR_R = 138;
|
|
15407
|
+
var V86FS_MSG_FSYNC_R = 139;
|
|
15408
|
+
var V86FS_MSG_UNLINK_R = 140;
|
|
15409
|
+
var V86FS_MSG_RENAME_R = 141;
|
|
15410
|
+
var V86FS_MSG_SYMLINK_R = 142;
|
|
15411
|
+
var V86FS_MSG_READLINK_R = 143;
|
|
15412
|
+
var V86FS_MSG_STATFS_R = 144;
|
|
15413
|
+
var ATTR_MODE = 1;
|
|
15414
|
+
var ATTR_SIZE = 8;
|
|
15415
|
+
var V86FS_STATUS_OK = 0;
|
|
15416
|
+
var V86FS_STATUS_ENOENT = 2;
|
|
15417
|
+
var DT_DIR = 4;
|
|
15418
|
+
var DT_REG = 8;
|
|
15419
|
+
var DT_LNK = 10;
|
|
15420
|
+
var S_IFDIR = 16384;
|
|
15421
|
+
var S_IFREG = 32768;
|
|
15422
|
+
var S_IFLNK = 40960;
|
|
15423
|
+
var textDecoder = new TextDecoder();
|
|
15424
|
+
var textEncoder = new TextEncoder();
|
|
15425
|
+
var FS_ENTRIES = /* @__PURE__ */ new Map([
|
|
15426
|
+
[
|
|
15427
|
+
1,
|
|
15428
|
+
[
|
|
15429
|
+
{
|
|
15430
|
+
inode_id: 2,
|
|
15431
|
+
name: "hello.txt",
|
|
15432
|
+
mode: S_IFREG | 420,
|
|
15433
|
+
size: 12,
|
|
15434
|
+
dt_type: DT_REG,
|
|
15435
|
+
mtime_sec: 17115e5,
|
|
15436
|
+
mtime_nsec: 0,
|
|
15437
|
+
content: textEncoder.encode("hello world\n")
|
|
15438
|
+
},
|
|
15439
|
+
{
|
|
15440
|
+
inode_id: 3,
|
|
15441
|
+
name: "subdir",
|
|
15442
|
+
mode: S_IFDIR | 493,
|
|
15443
|
+
size: 0,
|
|
15444
|
+
dt_type: DT_DIR,
|
|
15445
|
+
mtime_sec: 17115e5,
|
|
15446
|
+
mtime_nsec: 0
|
|
15447
|
+
}
|
|
15448
|
+
]
|
|
15449
|
+
]
|
|
15450
|
+
]);
|
|
15451
|
+
var INODE_MAP = /* @__PURE__ */ new Map([
|
|
15452
|
+
[
|
|
15453
|
+
1,
|
|
15454
|
+
{
|
|
15455
|
+
inode_id: 1,
|
|
15456
|
+
name: "",
|
|
15457
|
+
mode: S_IFDIR | 493,
|
|
15458
|
+
size: 0,
|
|
15459
|
+
dt_type: DT_DIR,
|
|
15460
|
+
mtime_sec: 17115e5,
|
|
15461
|
+
mtime_nsec: 0
|
|
15462
|
+
}
|
|
15463
|
+
]
|
|
15464
|
+
]);
|
|
15465
|
+
for (const entries of FS_ENTRIES.values()) {
|
|
15466
|
+
for (const e of entries) {
|
|
15467
|
+
INODE_MAP.set(e.inode_id, e);
|
|
15468
|
+
}
|
|
15469
|
+
}
|
|
15470
|
+
var V86FS_HDR_SIZE = 7;
|
|
15471
|
+
function packU32(buf, offset, val) {
|
|
15472
|
+
buf[offset] = val & 255;
|
|
15473
|
+
buf[offset + 1] = val >>> 8 & 255;
|
|
15474
|
+
buf[offset + 2] = val >>> 16 & 255;
|
|
15475
|
+
buf[offset + 3] = val >>> 24 & 255;
|
|
15476
|
+
}
|
|
15477
|
+
function packU64(buf, offset, val) {
|
|
15478
|
+
packU32(buf, offset, val);
|
|
15479
|
+
packU32(buf, offset + 4, 0);
|
|
15480
|
+
}
|
|
15481
|
+
function packU16(buf, offset, val) {
|
|
15482
|
+
buf[offset] = val & 255;
|
|
15483
|
+
buf[offset + 1] = val >>> 8 & 255;
|
|
15484
|
+
}
|
|
15485
|
+
function makeResp(size, type, tag) {
|
|
15486
|
+
const resp = new Uint8Array(size);
|
|
15487
|
+
packU32(resp, 0, size);
|
|
15488
|
+
resp[4] = type;
|
|
15489
|
+
resp[5] = tag & 255;
|
|
15490
|
+
resp[6] = tag >> 8 & 255;
|
|
15491
|
+
return resp;
|
|
15492
|
+
}
|
|
15493
|
+
function readU32(buf, offset) {
|
|
15494
|
+
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16 | buf[offset + 3] << 24 >>> 0;
|
|
15495
|
+
}
|
|
15496
|
+
function readU16(buf, offset) {
|
|
15497
|
+
return buf[offset] | buf[offset + 1] << 8;
|
|
15498
|
+
}
|
|
15499
|
+
function readU64(buf, offset) {
|
|
15500
|
+
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16 | (buf[offset + 3] << 24 >>> 0) + (buf[offset + 4] | buf[offset + 5] << 8 | buf[offset + 6] << 16 | buf[offset + 7] << 24 >>> 0) * 4294967296;
|
|
15501
|
+
}
|
|
15502
|
+
var VirtioV86FS = class {
|
|
15503
|
+
bus;
|
|
15504
|
+
virtio;
|
|
15505
|
+
next_handle_id;
|
|
15506
|
+
next_inode_id;
|
|
15507
|
+
open_handles;
|
|
15508
|
+
// handle_id -> inode_id
|
|
15509
|
+
read_count;
|
|
15510
|
+
constructor(cpu, bus) {
|
|
15511
|
+
this.bus = bus;
|
|
15512
|
+
this.next_handle_id = 1;
|
|
15513
|
+
this.next_inode_id = 100;
|
|
15514
|
+
this.open_handles = /* @__PURE__ */ new Map();
|
|
15515
|
+
this.read_count = 0;
|
|
15516
|
+
const queues = [
|
|
15517
|
+
// Queue 0: hipriq - high-priority metadata (LOOKUP, GETATTR)
|
|
15518
|
+
{ size_supported: 128, notify_offset: 0 },
|
|
15519
|
+
// Queue 1: requestq - data requests (READ, WRITE, READDIR)
|
|
15520
|
+
{ size_supported: 128, notify_offset: 1 },
|
|
15521
|
+
// Queue 2: notifyq - host-to-guest push invalidation
|
|
15522
|
+
{ size_supported: 128, notify_offset: 2 }
|
|
15523
|
+
];
|
|
15524
|
+
this.virtio = new VirtIO(cpu, {
|
|
15525
|
+
name: "virtio-v86fs",
|
|
15526
|
+
pci_id: 14 << 3,
|
|
15527
|
+
device_id: 4223,
|
|
15528
|
+
subsystem_device_id: 63,
|
|
15529
|
+
common: {
|
|
15530
|
+
initial_port: 63488,
|
|
15531
|
+
queues,
|
|
15532
|
+
features: [VIRTIO_F_VERSION_1],
|
|
15533
|
+
on_driver_ok: () => {
|
|
15534
|
+
console.log("v86fs: driver ok");
|
|
15535
|
+
this.bus.send("virtio-v86fs-driver-ok");
|
|
15536
|
+
}
|
|
15537
|
+
},
|
|
15538
|
+
notification: {
|
|
15539
|
+
initial_port: 63744,
|
|
15540
|
+
single_handler: false,
|
|
15541
|
+
handlers: [
|
|
15542
|
+
// Queue 0: hipriq
|
|
15543
|
+
(queue_id) => {
|
|
15544
|
+
this.handle_queue(queue_id);
|
|
15545
|
+
},
|
|
15546
|
+
// Queue 1: requestq
|
|
15547
|
+
(queue_id) => {
|
|
15548
|
+
this.handle_queue(queue_id);
|
|
15549
|
+
},
|
|
15550
|
+
// Queue 2: notifyq
|
|
15551
|
+
(_queue_id) => {
|
|
15552
|
+
dbg_log("v86fs: notifyq notification", LOG_PCI);
|
|
15553
|
+
}
|
|
15554
|
+
]
|
|
15555
|
+
},
|
|
15556
|
+
isr_status: {
|
|
15557
|
+
initial_port: 63232
|
|
15558
|
+
}
|
|
15559
|
+
});
|
|
15560
|
+
}
|
|
15561
|
+
handle_queue(queue_id) {
|
|
15562
|
+
const queue = this.virtio.queues[queue_id];
|
|
15563
|
+
while (queue.has_request()) {
|
|
15564
|
+
const bufchain = queue.pop_request();
|
|
15565
|
+
const req = new Uint8Array(bufchain.length_readable);
|
|
15566
|
+
bufchain.get_next_blob(req);
|
|
15567
|
+
const resp = this.handle_message(req);
|
|
15568
|
+
if (resp && bufchain.length_writable > 0) {
|
|
15569
|
+
bufchain.set_next_blob(resp);
|
|
15570
|
+
}
|
|
15571
|
+
queue.push_reply(bufchain);
|
|
15572
|
+
}
|
|
15573
|
+
queue.flush_replies();
|
|
15574
|
+
}
|
|
15575
|
+
handle_message(req) {
|
|
15576
|
+
if (req.length < V86FS_HDR_SIZE) {
|
|
15577
|
+
console.warn("v86fs: message too short:", req.length);
|
|
15578
|
+
return null;
|
|
15579
|
+
}
|
|
15580
|
+
const type = req[4];
|
|
15581
|
+
const tag = readU16(req, 5);
|
|
15582
|
+
switch (type) {
|
|
15583
|
+
case V86FS_MSG_MOUNT:
|
|
15584
|
+
return this.handle_mount(req, tag);
|
|
15585
|
+
case V86FS_MSG_LOOKUP:
|
|
15586
|
+
return this.handle_lookup(req, tag);
|
|
15587
|
+
case V86FS_MSG_GETATTR:
|
|
15588
|
+
return this.handle_getattr(req, tag);
|
|
15589
|
+
case V86FS_MSG_READDIR:
|
|
15590
|
+
return this.handle_readdir(req, tag);
|
|
15591
|
+
case V86FS_MSG_OPEN:
|
|
15592
|
+
return this.handle_open(req, tag);
|
|
15593
|
+
case V86FS_MSG_CLOSE:
|
|
15594
|
+
return this.handle_close(req, tag);
|
|
15595
|
+
case V86FS_MSG_READ:
|
|
15596
|
+
return this.handle_read(req, tag);
|
|
15597
|
+
case V86FS_MSG_CREATE:
|
|
15598
|
+
return this.handle_create(req, tag);
|
|
15599
|
+
case V86FS_MSG_WRITE:
|
|
15600
|
+
return this.handle_write(req, tag);
|
|
15601
|
+
case V86FS_MSG_MKDIR:
|
|
15602
|
+
return this.handle_mkdir(req, tag);
|
|
15603
|
+
case V86FS_MSG_SETATTR:
|
|
15604
|
+
return this.handle_setattr(req, tag);
|
|
15605
|
+
case V86FS_MSG_FSYNC:
|
|
15606
|
+
return this.handle_fsync(req, tag);
|
|
15607
|
+
case V86FS_MSG_UNLINK:
|
|
15608
|
+
return this.handle_unlink(req, tag);
|
|
15609
|
+
case V86FS_MSG_RENAME:
|
|
15610
|
+
return this.handle_rename(req, tag);
|
|
15611
|
+
case V86FS_MSG_SYMLINK:
|
|
15612
|
+
return this.handle_symlink(req, tag);
|
|
15613
|
+
case V86FS_MSG_READLINK:
|
|
15614
|
+
return this.handle_readlink(req, tag);
|
|
15615
|
+
case V86FS_MSG_STATFS:
|
|
15616
|
+
return this.handle_statfs(tag);
|
|
15617
|
+
default:
|
|
15618
|
+
console.warn("v86fs: unknown message type:", type);
|
|
15619
|
+
return null;
|
|
15620
|
+
}
|
|
15621
|
+
}
|
|
15622
|
+
handle_mount(req, tag) {
|
|
15623
|
+
const name_len = readU16(req, 7);
|
|
15624
|
+
const name = name_len > 0 ? textDecoder.decode(req.subarray(9, 9 + name_len)) : "";
|
|
15625
|
+
console.log("v86fs: mount:", name || "(default)");
|
|
15626
|
+
this.bus.send("virtio-v86fs-mount", name);
|
|
15627
|
+
const resp = new Uint8Array(23);
|
|
15628
|
+
packU32(resp, 0, 23);
|
|
15629
|
+
resp[4] = V86FS_MSG_MOUNT_R;
|
|
15630
|
+
resp[5] = tag & 255;
|
|
15631
|
+
resp[6] = tag >> 8 & 255;
|
|
15632
|
+
packU32(resp, 7, 0);
|
|
15633
|
+
packU64(resp, 11, 1);
|
|
15634
|
+
packU32(resp, 19, 16877);
|
|
15635
|
+
return resp;
|
|
15636
|
+
}
|
|
15637
|
+
handle_getattr(req, tag) {
|
|
15638
|
+
const inode_id = readU64(req, 7);
|
|
15639
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15640
|
+
const resp = makeResp(35, V86FS_MSG_GETATTR_R, tag);
|
|
15641
|
+
if (!entry) {
|
|
15642
|
+
packU32(resp, 7, V86FS_STATUS_ENOENT);
|
|
15643
|
+
return resp;
|
|
15644
|
+
}
|
|
15645
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15646
|
+
packU32(resp, 11, entry.mode);
|
|
15647
|
+
packU64(resp, 15, entry.size);
|
|
15648
|
+
packU64(resp, 23, entry.mtime_sec);
|
|
15649
|
+
packU32(resp, 31, entry.mtime_nsec);
|
|
15650
|
+
return resp;
|
|
15651
|
+
}
|
|
15652
|
+
handle_lookup(req, tag) {
|
|
15653
|
+
const parent_id = readU64(req, 7);
|
|
15654
|
+
const name_len = readU16(req, 15);
|
|
15655
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15656
|
+
const entries = FS_ENTRIES.get(parent_id);
|
|
15657
|
+
const entry = entries?.find((e) => e.name === name);
|
|
15658
|
+
const resp = new Uint8Array(31);
|
|
15659
|
+
packU32(resp, 0, 31);
|
|
15660
|
+
resp[4] = V86FS_MSG_LOOKUP_R;
|
|
15661
|
+
resp[5] = tag & 255;
|
|
15662
|
+
resp[6] = tag >> 8 & 255;
|
|
15663
|
+
if (!entry) {
|
|
15664
|
+
packU32(resp, 7, V86FS_STATUS_ENOENT);
|
|
15665
|
+
return resp;
|
|
15666
|
+
}
|
|
15667
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15668
|
+
packU64(resp, 11, entry.inode_id);
|
|
15669
|
+
packU32(resp, 19, entry.mode);
|
|
15670
|
+
packU64(resp, 23, entry.size);
|
|
15671
|
+
return resp;
|
|
15672
|
+
}
|
|
15673
|
+
handle_readdir(req, tag) {
|
|
15674
|
+
const dir_id = readU64(req, 7);
|
|
15675
|
+
const entries = FS_ENTRIES.get(dir_id) || [];
|
|
15676
|
+
const encodedNames = entries.map((e) => textEncoder.encode(e.name));
|
|
15677
|
+
let size = 7 + 4 + 4;
|
|
15678
|
+
for (const nameBytes of encodedNames) {
|
|
15679
|
+
size += 8 + 1 + 2 + nameBytes.length;
|
|
15680
|
+
}
|
|
15681
|
+
const resp = makeResp(size, V86FS_MSG_READDIR_R, tag);
|
|
15682
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15683
|
+
packU32(resp, 11, entries.length);
|
|
15684
|
+
let off = 15;
|
|
15685
|
+
for (let i = 0; i < entries.length; i++) {
|
|
15686
|
+
const e = entries[i];
|
|
15687
|
+
const nameBytes = encodedNames[i];
|
|
15688
|
+
packU64(resp, off, e.inode_id);
|
|
15689
|
+
resp[off + 8] = e.dt_type;
|
|
15690
|
+
packU16(resp, off + 9, nameBytes.length);
|
|
15691
|
+
resp.set(nameBytes, off + 11);
|
|
15692
|
+
off += 11 + nameBytes.length;
|
|
15693
|
+
}
|
|
15694
|
+
return resp;
|
|
15695
|
+
}
|
|
15696
|
+
handle_open(req, tag) {
|
|
15697
|
+
const inode_id = readU64(req, 7);
|
|
15698
|
+
const handle_id = this.next_handle_id++;
|
|
15699
|
+
this.open_handles.set(handle_id, inode_id);
|
|
15700
|
+
this.bus.send("virtio-v86fs-open", inode_id);
|
|
15701
|
+
const resp = makeResp(19, V86FS_MSG_OPEN_R, tag);
|
|
15702
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15703
|
+
packU64(resp, 11, handle_id);
|
|
15704
|
+
return resp;
|
|
15705
|
+
}
|
|
15706
|
+
handle_close(req, tag) {
|
|
15707
|
+
const handle_id = readU64(req, 7);
|
|
15708
|
+
this.open_handles.delete(handle_id);
|
|
15709
|
+
this.bus.send("virtio-v86fs-close", handle_id);
|
|
15710
|
+
const resp = makeResp(11, V86FS_MSG_CLOSE_R, tag);
|
|
15711
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15712
|
+
return resp;
|
|
15713
|
+
}
|
|
15714
|
+
handle_read(req, tag) {
|
|
15715
|
+
const handle_id = readU64(req, 7);
|
|
15716
|
+
const offset = readU64(req, 15);
|
|
15717
|
+
const size = readU32(req, 23);
|
|
15718
|
+
const inode_id = this.open_handles.get(handle_id) ?? handle_id;
|
|
15719
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15720
|
+
const content = entry?.content;
|
|
15721
|
+
this.read_count++;
|
|
15722
|
+
this.bus.send("virtio-v86fs-read", {
|
|
15723
|
+
handle_id,
|
|
15724
|
+
inode_id,
|
|
15725
|
+
offset,
|
|
15726
|
+
size
|
|
15727
|
+
});
|
|
15728
|
+
if (!content || offset >= content.length) {
|
|
15729
|
+
const resp2 = makeResp(15, V86FS_MSG_READ_R, tag);
|
|
15730
|
+
packU32(resp2, 7, V86FS_STATUS_OK);
|
|
15731
|
+
packU32(resp2, 11, 0);
|
|
15732
|
+
return resp2;
|
|
15733
|
+
}
|
|
15734
|
+
const start = Math.min(offset, content.length);
|
|
15735
|
+
const end = Math.min(start + size, content.length);
|
|
15736
|
+
const data = content.subarray(start, end);
|
|
15737
|
+
const resp = new Uint8Array(15 + data.length);
|
|
15738
|
+
packU32(resp, 0, 15 + data.length);
|
|
15739
|
+
resp[4] = V86FS_MSG_READ_R;
|
|
15740
|
+
resp[5] = tag & 255;
|
|
15741
|
+
resp[6] = tag >> 8 & 255;
|
|
15742
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15743
|
+
packU32(resp, 11, data.length);
|
|
15744
|
+
resp.set(data, 15);
|
|
15745
|
+
return resp;
|
|
15746
|
+
}
|
|
15747
|
+
handle_create(req, tag) {
|
|
15748
|
+
const parent_id = readU64(req, 7);
|
|
15749
|
+
const name_len = readU16(req, 15);
|
|
15750
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15751
|
+
const mode = readU32(req, 17 + name_len);
|
|
15752
|
+
const inode_id = this.next_inode_id++;
|
|
15753
|
+
const entry = {
|
|
15754
|
+
inode_id,
|
|
15755
|
+
name,
|
|
15756
|
+
mode: mode | S_IFREG,
|
|
15757
|
+
size: 0,
|
|
15758
|
+
dt_type: DT_REG,
|
|
15759
|
+
mtime_sec: Math.floor(Date.now() / 1e3),
|
|
15760
|
+
mtime_nsec: 0,
|
|
15761
|
+
content: new Uint8Array(0)
|
|
15762
|
+
};
|
|
15763
|
+
let children = FS_ENTRIES.get(parent_id);
|
|
15764
|
+
if (!children) {
|
|
15765
|
+
children = [];
|
|
15766
|
+
FS_ENTRIES.set(parent_id, children);
|
|
15767
|
+
}
|
|
15768
|
+
children.push(entry);
|
|
15769
|
+
INODE_MAP.set(inode_id, entry);
|
|
15770
|
+
const resp = makeResp(23, V86FS_MSG_CREATE_R, tag);
|
|
15771
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15772
|
+
packU64(resp, 11, inode_id);
|
|
15773
|
+
packU32(resp, 19, entry.mode);
|
|
15774
|
+
return resp;
|
|
15775
|
+
}
|
|
15776
|
+
handle_write(req, tag) {
|
|
15777
|
+
const inode_id = readU64(req, 7);
|
|
15778
|
+
const offset = readU64(req, 15);
|
|
15779
|
+
const size = readU32(req, 23);
|
|
15780
|
+
const data = req.subarray(27, 27 + size);
|
|
15781
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15782
|
+
if (entry) {
|
|
15783
|
+
const needed = offset + size;
|
|
15784
|
+
if (!entry.content || entry.content.length < needed) {
|
|
15785
|
+
const newContent = new Uint8Array(needed);
|
|
15786
|
+
if (entry.content) {
|
|
15787
|
+
newContent.set(entry.content);
|
|
15788
|
+
}
|
|
15789
|
+
entry.content = newContent;
|
|
15790
|
+
}
|
|
15791
|
+
entry.content.set(data, offset);
|
|
15792
|
+
if (needed > entry.size) {
|
|
15793
|
+
entry.size = needed;
|
|
15794
|
+
}
|
|
15795
|
+
}
|
|
15796
|
+
const resp = makeResp(15, V86FS_MSG_WRITE_R, tag);
|
|
15797
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15798
|
+
packU32(resp, 11, size);
|
|
15799
|
+
return resp;
|
|
15800
|
+
}
|
|
15801
|
+
handle_mkdir(req, tag) {
|
|
15802
|
+
const parent_id = readU64(req, 7);
|
|
15803
|
+
const name_len = readU16(req, 15);
|
|
15804
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15805
|
+
const mode = readU32(req, 17 + name_len);
|
|
15806
|
+
const inode_id = this.next_inode_id++;
|
|
15807
|
+
const entry = {
|
|
15808
|
+
inode_id,
|
|
15809
|
+
name,
|
|
15810
|
+
mode: mode | S_IFDIR,
|
|
15811
|
+
size: 0,
|
|
15812
|
+
dt_type: DT_DIR,
|
|
15813
|
+
mtime_sec: Math.floor(Date.now() / 1e3),
|
|
15814
|
+
mtime_nsec: 0
|
|
15815
|
+
};
|
|
15816
|
+
let children = FS_ENTRIES.get(parent_id);
|
|
15817
|
+
if (!children) {
|
|
15818
|
+
children = [];
|
|
15819
|
+
FS_ENTRIES.set(parent_id, children);
|
|
15820
|
+
}
|
|
15821
|
+
children.push(entry);
|
|
15822
|
+
INODE_MAP.set(inode_id, entry);
|
|
15823
|
+
FS_ENTRIES.set(inode_id, []);
|
|
15824
|
+
const resp = makeResp(23, V86FS_MSG_MKDIR_R, tag);
|
|
15825
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15826
|
+
packU64(resp, 11, inode_id);
|
|
15827
|
+
packU32(resp, 19, entry.mode);
|
|
15828
|
+
return resp;
|
|
15829
|
+
}
|
|
15830
|
+
handle_setattr(req, tag) {
|
|
15831
|
+
const inode_id = readU64(req, 7);
|
|
15832
|
+
const valid = readU32(req, 15);
|
|
15833
|
+
const mode = readU32(req, 19);
|
|
15834
|
+
const size = readU64(req, 23);
|
|
15835
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15836
|
+
if (entry) {
|
|
15837
|
+
if (valid & ATTR_MODE) {
|
|
15838
|
+
entry.mode = entry.mode & 61440 | mode & 4095;
|
|
15839
|
+
}
|
|
15840
|
+
if (valid & ATTR_SIZE) {
|
|
15841
|
+
entry.size = size;
|
|
15842
|
+
if (entry.content) {
|
|
15843
|
+
if (size === 0) {
|
|
15844
|
+
entry.content = new Uint8Array(0);
|
|
15845
|
+
} else if (size < entry.content.length) {
|
|
15846
|
+
entry.content = entry.content.subarray(0, size);
|
|
15847
|
+
}
|
|
15848
|
+
}
|
|
15849
|
+
}
|
|
15850
|
+
}
|
|
15851
|
+
const resp = makeResp(11, V86FS_MSG_SETATTR_R, tag);
|
|
15852
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15853
|
+
return resp;
|
|
15854
|
+
}
|
|
15855
|
+
handle_fsync(req, tag) {
|
|
15856
|
+
const resp = makeResp(11, V86FS_MSG_FSYNC_R, tag);
|
|
15857
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15858
|
+
return resp;
|
|
15859
|
+
}
|
|
15860
|
+
handle_unlink(req, tag) {
|
|
15861
|
+
const parent_id = readU64(req, 7);
|
|
15862
|
+
const name_len = readU16(req, 15);
|
|
15863
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15864
|
+
const children = FS_ENTRIES.get(parent_id);
|
|
15865
|
+
let status = V86FS_STATUS_ENOENT;
|
|
15866
|
+
if (children) {
|
|
15867
|
+
const idx = children.findIndex((e) => e.name === name);
|
|
15868
|
+
if (idx >= 0) {
|
|
15869
|
+
const entry = children[idx];
|
|
15870
|
+
INODE_MAP.delete(entry.inode_id);
|
|
15871
|
+
FS_ENTRIES.delete(entry.inode_id);
|
|
15872
|
+
children.splice(idx, 1);
|
|
15873
|
+
status = V86FS_STATUS_OK;
|
|
15874
|
+
}
|
|
15875
|
+
}
|
|
15876
|
+
const resp = makeResp(11, V86FS_MSG_UNLINK_R, tag);
|
|
15877
|
+
packU32(resp, 7, status);
|
|
15878
|
+
return resp;
|
|
15879
|
+
}
|
|
15880
|
+
handle_rename(req, tag) {
|
|
15881
|
+
let off = 7;
|
|
15882
|
+
const old_parent_id = readU64(req, off);
|
|
15883
|
+
off += 8;
|
|
15884
|
+
const old_name_len = readU16(req, off);
|
|
15885
|
+
off += 2;
|
|
15886
|
+
const old_name = textDecoder.decode(
|
|
15887
|
+
req.subarray(off, off + old_name_len)
|
|
15888
|
+
);
|
|
15889
|
+
off += old_name_len;
|
|
15890
|
+
const new_parent_id = readU64(req, off);
|
|
15891
|
+
off += 8;
|
|
15892
|
+
const new_name_len = readU16(req, off);
|
|
15893
|
+
off += 2;
|
|
15894
|
+
const new_name = textDecoder.decode(
|
|
15895
|
+
req.subarray(off, off + new_name_len)
|
|
15896
|
+
);
|
|
15897
|
+
let status = V86FS_STATUS_ENOENT;
|
|
15898
|
+
const old_children = FS_ENTRIES.get(old_parent_id);
|
|
15899
|
+
if (old_children) {
|
|
15900
|
+
const idx = old_children.findIndex((e) => e.name === old_name);
|
|
15901
|
+
if (idx >= 0) {
|
|
15902
|
+
const entry = old_children[idx];
|
|
15903
|
+
old_children.splice(idx, 1);
|
|
15904
|
+
entry.name = new_name;
|
|
15905
|
+
let new_children = FS_ENTRIES.get(new_parent_id);
|
|
15906
|
+
if (!new_children) {
|
|
15907
|
+
new_children = [];
|
|
15908
|
+
FS_ENTRIES.set(new_parent_id, new_children);
|
|
15909
|
+
}
|
|
15910
|
+
const existing = new_children.findIndex(
|
|
15911
|
+
(e) => e.name === new_name
|
|
15912
|
+
);
|
|
15913
|
+
if (existing >= 0) {
|
|
15914
|
+
const old_entry = new_children[existing];
|
|
15915
|
+
INODE_MAP.delete(old_entry.inode_id);
|
|
15916
|
+
new_children.splice(existing, 1);
|
|
15917
|
+
}
|
|
15918
|
+
new_children.push(entry);
|
|
15919
|
+
status = V86FS_STATUS_OK;
|
|
15920
|
+
}
|
|
15921
|
+
}
|
|
15922
|
+
const resp = makeResp(11, V86FS_MSG_RENAME_R, tag);
|
|
15923
|
+
packU32(resp, 7, status);
|
|
15924
|
+
return resp;
|
|
15925
|
+
}
|
|
15926
|
+
handle_symlink(req, tag) {
|
|
15927
|
+
let off = 7;
|
|
15928
|
+
const parent_id = readU64(req, off);
|
|
15929
|
+
off += 8;
|
|
15930
|
+
const name_len = readU16(req, off);
|
|
15931
|
+
off += 2;
|
|
15932
|
+
const name = textDecoder.decode(req.subarray(off, off + name_len));
|
|
15933
|
+
off += name_len;
|
|
15934
|
+
const target_len = readU16(req, off);
|
|
15935
|
+
off += 2;
|
|
15936
|
+
const target = textDecoder.decode(req.subarray(off, off + target_len));
|
|
15937
|
+
const inode_id = this.next_inode_id++;
|
|
15938
|
+
const entry = {
|
|
15939
|
+
inode_id,
|
|
15940
|
+
name,
|
|
15941
|
+
mode: S_IFLNK | 511,
|
|
15942
|
+
size: target.length,
|
|
15943
|
+
dt_type: DT_LNK,
|
|
15944
|
+
mtime_sec: Math.floor(Date.now() / 1e3),
|
|
15945
|
+
mtime_nsec: 0,
|
|
15946
|
+
symlink_target: target
|
|
15947
|
+
};
|
|
15948
|
+
let children = FS_ENTRIES.get(parent_id);
|
|
15949
|
+
if (!children) {
|
|
15950
|
+
children = [];
|
|
15951
|
+
FS_ENTRIES.set(parent_id, children);
|
|
15952
|
+
}
|
|
15953
|
+
children.push(entry);
|
|
15954
|
+
INODE_MAP.set(inode_id, entry);
|
|
15955
|
+
const resp = makeResp(23, V86FS_MSG_SYMLINK_R, tag);
|
|
15956
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15957
|
+
packU64(resp, 11, inode_id);
|
|
15958
|
+
packU32(resp, 19, entry.mode);
|
|
15959
|
+
return resp;
|
|
15960
|
+
}
|
|
15961
|
+
handle_readlink(req, tag) {
|
|
15962
|
+
const inode_id = readU64(req, 7);
|
|
15963
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15964
|
+
if (!entry || !entry.symlink_target) {
|
|
15965
|
+
const resp2 = makeResp(11, V86FS_MSG_READLINK_R, tag);
|
|
15966
|
+
packU32(resp2, 7, V86FS_STATUS_ENOENT);
|
|
15967
|
+
return resp2;
|
|
15968
|
+
}
|
|
15969
|
+
const target_bytes = textEncoder.encode(entry.symlink_target);
|
|
15970
|
+
const resp_len = 11 + 2 + target_bytes.length;
|
|
15971
|
+
const resp = makeResp(resp_len, V86FS_MSG_READLINK_R, tag);
|
|
15972
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15973
|
+
packU16(resp, 11, target_bytes.length);
|
|
15974
|
+
resp.set(target_bytes, 13);
|
|
15975
|
+
return resp;
|
|
15976
|
+
}
|
|
15977
|
+
handle_statfs(tag) {
|
|
15978
|
+
const resp = makeResp(55, V86FS_MSG_STATFS_R, tag);
|
|
15979
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15980
|
+
packU64(resp, 11, 1024 * 1024);
|
|
15981
|
+
packU64(resp, 19, 512 * 1024);
|
|
15982
|
+
packU64(resp, 27, 512 * 1024);
|
|
15983
|
+
packU64(resp, 35, 1024 * 1024);
|
|
15984
|
+
packU64(resp, 43, 512 * 1024);
|
|
15985
|
+
packU32(resp, 51, 4096);
|
|
15986
|
+
return resp;
|
|
15987
|
+
}
|
|
15988
|
+
/** Push an INVALIDATE notification to the guest via notifyq.
|
|
15989
|
+
* Guest kernel will invalidate page cache for the given inode. */
|
|
15990
|
+
invalidate_inode(inode_id) {
|
|
15991
|
+
const queue = this.virtio.queues[2];
|
|
15992
|
+
if (!queue.has_request()) return false;
|
|
15993
|
+
const bufchain = queue.pop_request();
|
|
15994
|
+
const msg = new Uint8Array(15);
|
|
15995
|
+
packU32(msg, 0, 15);
|
|
15996
|
+
msg[4] = V86FS_MSG_INVALIDATE;
|
|
15997
|
+
packU16(msg, 5, 0);
|
|
15998
|
+
packU64(msg, 7, inode_id);
|
|
15999
|
+
bufchain.set_next_blob(msg);
|
|
16000
|
+
queue.push_reply(bufchain);
|
|
16001
|
+
queue.flush_replies();
|
|
16002
|
+
return true;
|
|
16003
|
+
}
|
|
16004
|
+
/** Push an INVALIDATE_DIR notification to the guest via notifyq.
|
|
16005
|
+
* Guest kernel will invalidate dcache for the given directory inode. */
|
|
16006
|
+
invalidate_dir(inode_id) {
|
|
16007
|
+
const queue = this.virtio.queues[2];
|
|
16008
|
+
if (!queue.has_request()) return false;
|
|
16009
|
+
const bufchain = queue.pop_request();
|
|
16010
|
+
const msg = new Uint8Array(15);
|
|
16011
|
+
packU32(msg, 0, 15);
|
|
16012
|
+
msg[4] = V86FS_MSG_INVALIDATE_DIR;
|
|
16013
|
+
packU16(msg, 5, 0);
|
|
16014
|
+
packU64(msg, 7, inode_id);
|
|
16015
|
+
bufchain.set_next_blob(msg);
|
|
16016
|
+
queue.push_reply(bufchain);
|
|
16017
|
+
queue.flush_replies();
|
|
16018
|
+
return true;
|
|
16019
|
+
}
|
|
16020
|
+
get_state() {
|
|
16021
|
+
const state = [];
|
|
16022
|
+
state[0] = this.virtio;
|
|
16023
|
+
return state;
|
|
16024
|
+
}
|
|
16025
|
+
set_state(state) {
|
|
16026
|
+
this.virtio.set_state(state[0]);
|
|
16027
|
+
}
|
|
16028
|
+
};
|
|
16029
|
+
|
|
15105
16030
|
// lib/filesystem.ts
|
|
15106
16031
|
var S_IFMT = 61440;
|
|
15107
16032
|
var S_IFSOCK = 49152;
|
|
15108
|
-
var
|
|
15109
|
-
var
|
|
15110
|
-
var
|
|
16033
|
+
var S_IFLNK2 = 40960;
|
|
16034
|
+
var S_IFREG2 = 32768;
|
|
16035
|
+
var S_IFDIR2 = 16384;
|
|
15111
16036
|
var STATUS_INVALID = -1;
|
|
15112
16037
|
var STATUS_OK = 0;
|
|
15113
16038
|
var STATUS_ON_STORAGE = 2;
|
|
@@ -15200,11 +16125,11 @@ var Inode = class {
|
|
|
15200
16125
|
get_state() {
|
|
15201
16126
|
const state = [];
|
|
15202
16127
|
state[0] = this.mode;
|
|
15203
|
-
if ((this.mode & S_IFMT) ===
|
|
16128
|
+
if ((this.mode & S_IFMT) === S_IFDIR2) {
|
|
15204
16129
|
state[1] = [...this.direntries];
|
|
15205
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16130
|
+
} else if ((this.mode & S_IFMT) === S_IFREG2) {
|
|
15206
16131
|
state[1] = this.sha256sum;
|
|
15207
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16132
|
+
} else if ((this.mode & S_IFMT) === S_IFLNK2) {
|
|
15208
16133
|
state[1] = this.symlink;
|
|
15209
16134
|
} else if ((this.mode & S_IFMT) === S_IFSOCK) {
|
|
15210
16135
|
state[1] = [this.minor, this.major];
|
|
@@ -15227,14 +16152,14 @@ var Inode = class {
|
|
|
15227
16152
|
}
|
|
15228
16153
|
set_state(state) {
|
|
15229
16154
|
this.mode = state[0];
|
|
15230
|
-
if ((this.mode & S_IFMT) ===
|
|
16155
|
+
if ((this.mode & S_IFMT) === S_IFDIR2) {
|
|
15231
16156
|
this.direntries = /* @__PURE__ */ new Map();
|
|
15232
16157
|
for (const [name, entry] of state[1]) {
|
|
15233
16158
|
this.direntries.set(name, entry);
|
|
15234
16159
|
}
|
|
15235
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16160
|
+
} else if ((this.mode & S_IFMT) === S_IFREG2) {
|
|
15236
16161
|
this.sha256sum = state[1];
|
|
15237
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16162
|
+
} else if ((this.mode & S_IFMT) === S_IFLNK2) {
|
|
15238
16163
|
this.symlink = state[1];
|
|
15239
16164
|
} else if ((this.mode & S_IFMT) === S_IFSOCK) {
|
|
15240
16165
|
;
|
|
@@ -15303,7 +16228,7 @@ var FS = class {
|
|
|
15303
16228
|
state[1] = this.qidcounter.last_qidnumber;
|
|
15304
16229
|
state[2] = [];
|
|
15305
16230
|
for (const [id, data] of Object.entries(this.inodedata)) {
|
|
15306
|
-
if ((this.inodes[Number(id)].mode &
|
|
16231
|
+
if ((this.inodes[Number(id)].mode & S_IFDIR2) === 0) {
|
|
15307
16232
|
state[2].push([id, data]);
|
|
15308
16233
|
}
|
|
15309
16234
|
}
|
|
@@ -15354,15 +16279,15 @@ var FS = class {
|
|
|
15354
16279
|
inode.uid = data[JSONFS_IDX_UID];
|
|
15355
16280
|
inode.gid = data[JSONFS_IDX_GID];
|
|
15356
16281
|
const ifmt = inode.mode & S_IFMT;
|
|
15357
|
-
if (ifmt ===
|
|
16282
|
+
if (ifmt === S_IFDIR2) {
|
|
15358
16283
|
this.PushInode(inode, parentid, name);
|
|
15359
16284
|
this.LoadDir(this.inodes.length - 1, data[JSONFS_IDX_TARGET]);
|
|
15360
|
-
} else if (ifmt ===
|
|
16285
|
+
} else if (ifmt === S_IFREG2) {
|
|
15361
16286
|
inode.status = STATUS_ON_STORAGE;
|
|
15362
16287
|
inode.sha256sum = data[JSONFS_IDX_SHA256];
|
|
15363
16288
|
dbg_assert(!!inode.sha256sum);
|
|
15364
16289
|
this.PushInode(inode, parentid, name);
|
|
15365
|
-
} else if (ifmt ===
|
|
16290
|
+
} else if (ifmt === S_IFLNK2) {
|
|
15366
16291
|
inode.symlink = data[JSONFS_IDX_TARGET];
|
|
15367
16292
|
this.PushInode(inode, parentid, name);
|
|
15368
16293
|
} else if (ifmt === S_IFSOCK) {
|
|
@@ -15534,13 +16459,13 @@ var FS = class {
|
|
|
15534
16459
|
return this.create_forwarder(parent_inode.mount_id, foreign_id);
|
|
15535
16460
|
}
|
|
15536
16461
|
const x = this.CreateInode();
|
|
15537
|
-
x.mode = 511 |
|
|
16462
|
+
x.mode = 511 | S_IFDIR2;
|
|
15538
16463
|
if (parentid >= 0) {
|
|
15539
16464
|
x.uid = this.inodes[parentid].uid;
|
|
15540
16465
|
x.gid = this.inodes[parentid].gid;
|
|
15541
|
-
x.mode = this.inodes[parentid].mode & 511 |
|
|
16466
|
+
x.mode = this.inodes[parentid].mode & 511 | S_IFDIR2;
|
|
15542
16467
|
}
|
|
15543
|
-
x.qid.type =
|
|
16468
|
+
x.qid.type = S_IFDIR2 >> 8;
|
|
15544
16469
|
this.PushInode(x, parentid, name);
|
|
15545
16470
|
this.NotifyListeners(this.inodes.length - 1, "newdir");
|
|
15546
16471
|
return this.inodes.length - 1;
|
|
@@ -15558,8 +16483,8 @@ var FS = class {
|
|
|
15558
16483
|
const x = this.CreateInode();
|
|
15559
16484
|
x.uid = this.inodes[parentid].uid;
|
|
15560
16485
|
x.gid = this.inodes[parentid].gid;
|
|
15561
|
-
x.qid.type =
|
|
15562
|
-
x.mode = this.inodes[parentid].mode & 438 |
|
|
16486
|
+
x.qid.type = S_IFREG2 >> 8;
|
|
16487
|
+
x.mode = this.inodes[parentid].mode & 438 | S_IFREG2;
|
|
15563
16488
|
this.PushInode(x, parentid, filename);
|
|
15564
16489
|
this.NotifyListeners(this.inodes.length - 1, "newfile");
|
|
15565
16490
|
return this.inodes.length - 1;
|
|
@@ -15600,9 +16525,9 @@ var FS = class {
|
|
|
15600
16525
|
const x = this.CreateInode();
|
|
15601
16526
|
x.uid = this.inodes[parentid].uid;
|
|
15602
16527
|
x.gid = this.inodes[parentid].gid;
|
|
15603
|
-
x.qid.type =
|
|
16528
|
+
x.qid.type = S_IFLNK2 >> 8;
|
|
15604
16529
|
x.symlink = symlink;
|
|
15605
|
-
x.mode =
|
|
16530
|
+
x.mode = S_IFLNK2;
|
|
15606
16531
|
this.PushInode(x, parentid, filename);
|
|
15607
16532
|
return this.inodes.length - 1;
|
|
15608
16533
|
}
|
|
@@ -15647,7 +16572,7 @@ var FS = class {
|
|
|
15647
16572
|
if (this.is_forwarder(inode)) {
|
|
15648
16573
|
return await this.follow_fs(inode).OpenInode(inode.foreign_id, mode);
|
|
15649
16574
|
}
|
|
15650
|
-
if ((inode.mode & S_IFMT) ===
|
|
16575
|
+
if ((inode.mode & S_IFMT) === S_IFDIR2) {
|
|
15651
16576
|
this.FillDirectory(id);
|
|
15652
16577
|
}
|
|
15653
16578
|
}
|
|
@@ -16002,7 +16927,7 @@ var FS = class {
|
|
|
16002
16927
|
let parentid = -1;
|
|
16003
16928
|
let id = 0;
|
|
16004
16929
|
let forward_path = null;
|
|
16005
|
-
let i
|
|
16930
|
+
let i;
|
|
16006
16931
|
for (i = 0; i < n; i++) {
|
|
16007
16932
|
parentid = id;
|
|
16008
16933
|
id = this.Search(parentid, walk[i]);
|
|
@@ -16068,13 +16993,13 @@ var FS = class {
|
|
|
16068
16993
|
DeleteNode(path) {
|
|
16069
16994
|
const ids = this.SearchPath(path);
|
|
16070
16995
|
if (ids.id === -1) return;
|
|
16071
|
-
if ((this.inodes[ids.id].mode & S_IFMT) ===
|
|
16996
|
+
if ((this.inodes[ids.id].mode & S_IFMT) === S_IFREG2) {
|
|
16072
16997
|
const ret = this.Unlink(ids.parentid, ids.name);
|
|
16073
16998
|
dbg_assert(
|
|
16074
16999
|
ret === 0,
|
|
16075
17000
|
"Filesystem DeleteNode failed with error code: " + -ret
|
|
16076
17001
|
);
|
|
16077
|
-
} else if ((this.inodes[ids.id].mode & S_IFMT) ===
|
|
17002
|
+
} else if ((this.inodes[ids.id].mode & S_IFMT) === S_IFDIR2) {
|
|
16078
17003
|
this.RecursiveDelete(path);
|
|
16079
17004
|
const ret = this.Unlink(ids.parentid, ids.name);
|
|
16080
17005
|
dbg_assert(
|
|
@@ -16178,7 +17103,7 @@ var FS = class {
|
|
|
16178
17103
|
if (this.is_forwarder(inode)) {
|
|
16179
17104
|
return this.follow_fs(inode).IsDirectory(inode.foreign_id);
|
|
16180
17105
|
}
|
|
16181
|
-
return (inode.mode & S_IFMT) ===
|
|
17106
|
+
return (inode.mode & S_IFMT) === S_IFDIR2;
|
|
16182
17107
|
}
|
|
16183
17108
|
IsEmpty(idx) {
|
|
16184
17109
|
const inode = this.inodes[idx];
|
|
@@ -16708,7 +17633,7 @@ var Virtio9p = class {
|
|
|
16708
17633
|
bufchain.get_next_blob(buffer);
|
|
16709
17634
|
const state = { offset: 0 };
|
|
16710
17635
|
const header = Unmarshall(["w", "b", "h"], buffer, state);
|
|
16711
|
-
let size
|
|
17636
|
+
let size;
|
|
16712
17637
|
const id = header[1];
|
|
16713
17638
|
const tag = header[2];
|
|
16714
17639
|
switch (id) {
|
|
@@ -16769,7 +17694,7 @@ var Virtio9p = class {
|
|
|
16769
17694
|
name
|
|
16770
17695
|
);
|
|
16771
17696
|
if (ret < 0) {
|
|
16772
|
-
let error_message
|
|
17697
|
+
let error_message;
|
|
16773
17698
|
if (ret === -EPERM)
|
|
16774
17699
|
error_message = "Operation not permitted";
|
|
16775
17700
|
else {
|
|
@@ -16882,7 +17807,7 @@ var Virtio9p = class {
|
|
|
16882
17807
|
this.fids[fid].inodeid
|
|
16883
17808
|
);
|
|
16884
17809
|
const inode = this.fs.GetInode(idx);
|
|
16885
|
-
inode.mode = mode |
|
|
17810
|
+
inode.mode = mode | S_IFDIR2;
|
|
16886
17811
|
inode.uid = this.fids[fid].uid;
|
|
16887
17812
|
inode.gid = gid;
|
|
16888
17813
|
Marshall(["Q"], [inode.qid], this.replybuffer, 7);
|
|
@@ -16913,7 +17838,7 @@ var Virtio9p = class {
|
|
|
16913
17838
|
const inode = this.fs.GetInode(idx);
|
|
16914
17839
|
inode.uid = this.fids[fid].uid;
|
|
16915
17840
|
inode.gid = gid;
|
|
16916
|
-
inode.mode = mode |
|
|
17841
|
+
inode.mode = mode | S_IFREG2;
|
|
16917
17842
|
Marshall(
|
|
16918
17843
|
["Q", "w"],
|
|
16919
17844
|
[inode.qid, this.msize - 24],
|
|
@@ -17238,7 +18163,7 @@ var Virtio9p = class {
|
|
|
17238
18163
|
newname
|
|
17239
18164
|
);
|
|
17240
18165
|
if (ret < 0) {
|
|
17241
|
-
let error_message
|
|
18166
|
+
let error_message;
|
|
17242
18167
|
if (ret === -ENOENT)
|
|
17243
18168
|
error_message = "No such file or directory";
|
|
17244
18169
|
else if (ret === -EPERM)
|
|
@@ -17287,7 +18212,7 @@ var Virtio9p = class {
|
|
|
17287
18212
|
}
|
|
17288
18213
|
const ret = this.fs.Unlink(this.fids[dirfd].inodeid, name);
|
|
17289
18214
|
if (ret < 0) {
|
|
17290
|
-
let error_message
|
|
18215
|
+
let error_message;
|
|
17291
18216
|
if (ret === -ENOTEMPTY)
|
|
17292
18217
|
error_message = "Directory not empty";
|
|
17293
18218
|
else if (ret === -EPERM)
|
|
@@ -17861,6 +18786,7 @@ var CPU = class {
|
|
|
17861
18786
|
wasm_memory;
|
|
17862
18787
|
memory_size;
|
|
17863
18788
|
mem8;
|
|
18789
|
+
mem8_offset = 0;
|
|
17864
18790
|
mem32s;
|
|
17865
18791
|
segment_is_null;
|
|
17866
18792
|
segment_offsets;
|
|
@@ -17939,7 +18865,6 @@ var CPU = class {
|
|
|
17939
18865
|
get_eflags;
|
|
17940
18866
|
handle_irqs;
|
|
17941
18867
|
main_loop;
|
|
17942
|
-
reboot_internal;
|
|
17943
18868
|
set_jit_config;
|
|
17944
18869
|
read8;
|
|
17945
18870
|
read16;
|
|
@@ -17988,13 +18913,49 @@ var CPU = class {
|
|
|
17988
18913
|
this.name = "cpu";
|
|
17989
18914
|
this.stop_idling = stop_idling;
|
|
17990
18915
|
this.wm = wm;
|
|
18916
|
+
this.wasm_memory = wm.wasm_memory;
|
|
17991
18917
|
this.wasm_patch();
|
|
17992
18918
|
this.create_jit_imports();
|
|
17993
|
-
const memory = this.wm.exports["memory"];
|
|
17994
|
-
this.wasm_memory = memory;
|
|
17995
|
-
this.memory_size = view(Uint32Array, memory, 812, 1);
|
|
17996
18919
|
this.mem8 = new Uint8Array(0);
|
|
17997
18920
|
this.mem32s = new Int32Array(this.mem8.buffer);
|
|
18921
|
+
this.rebuild_wasm_views();
|
|
18922
|
+
this.devices = {};
|
|
18923
|
+
this.memory_map_read8 = [];
|
|
18924
|
+
this.memory_map_write8 = [];
|
|
18925
|
+
this.memory_map_read32 = [];
|
|
18926
|
+
this.memory_map_write32 = [];
|
|
18927
|
+
this.bios = {
|
|
18928
|
+
main: null,
|
|
18929
|
+
vga: null
|
|
18930
|
+
};
|
|
18931
|
+
this.fpu_stack_empty[0] = 255;
|
|
18932
|
+
this.fpu_stack_ptr[0] = 0;
|
|
18933
|
+
this.fpu_control_word[0] = 895;
|
|
18934
|
+
this.fpu_status_word[0] = 0;
|
|
18935
|
+
this.fpu_ip[0] = 0;
|
|
18936
|
+
this.fpu_ip_selector[0] = 0;
|
|
18937
|
+
this.fpu_opcode[0] = 0;
|
|
18938
|
+
this.fpu_dp[0] = 0;
|
|
18939
|
+
this.fpu_dp_selector[0] = 0;
|
|
18940
|
+
this.fw_value = [];
|
|
18941
|
+
this.fw_pointer = 0;
|
|
18942
|
+
this.option_roms = [];
|
|
18943
|
+
this.io = void 0;
|
|
18944
|
+
this.bus = bus;
|
|
18945
|
+
this.set_tsc(0, 0);
|
|
18946
|
+
if (false) {
|
|
18947
|
+
this.seen_code = {};
|
|
18948
|
+
this.seen_code_uncompiled = {};
|
|
18949
|
+
}
|
|
18950
|
+
}
|
|
18951
|
+
/**
|
|
18952
|
+
* Rebuild all TypedArray views into WASM linear memory.
|
|
18953
|
+
* Must be called after any wasm_memory.grow() since growth
|
|
18954
|
+
* detaches the old ArrayBuffer, invalidating all views.
|
|
18955
|
+
*/
|
|
18956
|
+
rebuild_wasm_views() {
|
|
18957
|
+
const memory = this.wasm_memory;
|
|
18958
|
+
this.memory_size = view(Uint32Array, memory, 812, 1);
|
|
17998
18959
|
this.segment_is_null = view(Uint8Array, memory, 724, 8);
|
|
17999
18960
|
this.segment_offsets = view(Int32Array, memory, 736, 8);
|
|
18000
18961
|
this.segment_limits = view(Uint32Array, memory, 768, 8);
|
|
@@ -18023,40 +18984,22 @@ var CPU = class {
|
|
|
18023
18984
|
this.last_op1 = view(Int32Array, memory, 104, 1);
|
|
18024
18985
|
this.last_result = view(Int32Array, memory, 112, 1);
|
|
18025
18986
|
this.current_tsc = view(Uint32Array, memory, 960, 2);
|
|
18026
|
-
this.devices = {};
|
|
18027
18987
|
this.instruction_pointer = view(Int32Array, memory, 556, 1);
|
|
18028
18988
|
this.previous_ip = view(Int32Array, memory, 560, 1);
|
|
18029
18989
|
this.apic_enabled = view(Uint8Array, memory, 548, 1);
|
|
18030
18990
|
this.acpi_enabled = view(Uint8Array, memory, 552, 1);
|
|
18031
|
-
this.memory_map_read8 = [];
|
|
18032
|
-
this.memory_map_write8 = [];
|
|
18033
|
-
this.memory_map_read32 = [];
|
|
18034
|
-
this.memory_map_write32 = [];
|
|
18035
|
-
this.bios = {
|
|
18036
|
-
main: null,
|
|
18037
|
-
vga: null
|
|
18038
|
-
};
|
|
18039
18991
|
this.instruction_counter = view(Uint32Array, memory, 664, 1);
|
|
18040
18992
|
this.reg32 = view(Int32Array, memory, 64, 8);
|
|
18041
18993
|
this.fpu_st = view(Int32Array, memory, 1152, 4 * 8);
|
|
18042
18994
|
this.fpu_stack_empty = view(Uint8Array, memory, 816, 1);
|
|
18043
|
-
this.fpu_stack_empty[0] = 255;
|
|
18044
18995
|
this.fpu_stack_ptr = view(Uint8Array, memory, 1032, 1);
|
|
18045
|
-
this.fpu_stack_ptr[0] = 0;
|
|
18046
18996
|
this.fpu_control_word = view(Uint16Array, memory, 1036, 1);
|
|
18047
|
-
this.fpu_control_word[0] = 895;
|
|
18048
18997
|
this.fpu_status_word = view(Uint16Array, memory, 1040, 1);
|
|
18049
|
-
this.fpu_status_word[0] = 0;
|
|
18050
18998
|
this.fpu_ip = view(Int32Array, memory, 1048, 1);
|
|
18051
|
-
this.fpu_ip[0] = 0;
|
|
18052
18999
|
this.fpu_ip_selector = view(Int32Array, memory, 1052, 1);
|
|
18053
|
-
this.fpu_ip_selector[0] = 0;
|
|
18054
19000
|
this.fpu_opcode = view(Int32Array, memory, 1044, 1);
|
|
18055
|
-
this.fpu_opcode[0] = 0;
|
|
18056
19001
|
this.fpu_dp = view(Int32Array, memory, 1056, 1);
|
|
18057
|
-
this.fpu_dp[0] = 0;
|
|
18058
19002
|
this.fpu_dp_selector = view(Int32Array, memory, 1060, 1);
|
|
18059
|
-
this.fpu_dp_selector[0] = 0;
|
|
18060
19003
|
this.reg_xmm32s = view(Int32Array, memory, 832, 8 * 4);
|
|
18061
19004
|
this.mxcsr = view(Int32Array, memory, 824, 1);
|
|
18062
19005
|
this.sreg = view(Uint16Array, memory, 668, 8);
|
|
@@ -18064,16 +19007,6 @@ var CPU = class {
|
|
|
18064
19007
|
this.reg_pdpte = view(Int32Array, memory, 968, 8);
|
|
18065
19008
|
this.svga_dirty_bitmap_min_offset = view(Uint32Array, memory, 716, 1);
|
|
18066
19009
|
this.svga_dirty_bitmap_max_offset = view(Uint32Array, memory, 720, 1);
|
|
18067
|
-
this.fw_value = [];
|
|
18068
|
-
this.fw_pointer = 0;
|
|
18069
|
-
this.option_roms = [];
|
|
18070
|
-
this.io = void 0;
|
|
18071
|
-
this.bus = bus;
|
|
18072
|
-
this.set_tsc(0, 0);
|
|
18073
|
-
if (false) {
|
|
18074
|
-
this.seen_code = {};
|
|
18075
|
-
this.seen_code_uncompiled = {};
|
|
18076
|
-
}
|
|
18077
19010
|
}
|
|
18078
19011
|
mmap_read8(addr) {
|
|
18079
19012
|
const value = this.memory_map_read8[addr >>> MMAP_BLOCK_BITS](addr);
|
|
@@ -18136,7 +19069,7 @@ var CPU = class {
|
|
|
18136
19069
|
}
|
|
18137
19070
|
create_jit_imports() {
|
|
18138
19071
|
const jit_imports = /* @__PURE__ */ Object.create(null);
|
|
18139
|
-
jit_imports["m"] = this.
|
|
19072
|
+
jit_imports["m"] = this.wasm_memory;
|
|
18140
19073
|
for (const name of Object.keys(this.wm.exports)) {
|
|
18141
19074
|
if (name.startsWith("_") || name.startsWith("zstd") || name.endsWith("_js")) {
|
|
18142
19075
|
continue;
|
|
@@ -18157,7 +19090,6 @@ var CPU = class {
|
|
|
18157
19090
|
this.get_eflags = get_import("get_eflags");
|
|
18158
19091
|
this.handle_irqs = get_import("handle_irqs");
|
|
18159
19092
|
this.main_loop = get_import("main_loop");
|
|
18160
|
-
this.reboot_internal = get_import("reboot_internal");
|
|
18161
19093
|
this.set_jit_config = get_import("set_jit_config");
|
|
18162
19094
|
this.read8 = get_import("read8");
|
|
18163
19095
|
this.read16 = get_import("read16");
|
|
@@ -18314,6 +19246,8 @@ var CPU = class {
|
|
|
18314
19246
|
state[86] = this.last_result;
|
|
18315
19247
|
state[87] = this.fpu_status_word;
|
|
18316
19248
|
state[88] = this.mxcsr;
|
|
19249
|
+
state[89] = this.devices.virtio_mem;
|
|
19250
|
+
state[90] = this.devices.virtio_v86fs;
|
|
18317
19251
|
return state;
|
|
18318
19252
|
}
|
|
18319
19253
|
get_state_pic() {
|
|
@@ -18374,8 +19308,33 @@ var CPU = class {
|
|
|
18374
19308
|
IOAPIC_STRUCT_SIZE
|
|
18375
19309
|
);
|
|
18376
19310
|
}
|
|
19311
|
+
resize_memory(new_size) {
|
|
19312
|
+
const mem8_offset = this.mem8_offset;
|
|
19313
|
+
const needed_total = mem8_offset + new_size;
|
|
19314
|
+
const current_buffer = this.wasm_memory.buffer.byteLength;
|
|
19315
|
+
if (needed_total > current_buffer) {
|
|
19316
|
+
const grow_pages = Math.ceil(
|
|
19317
|
+
(needed_total - current_buffer) / WASM_PAGE_SIZE
|
|
19318
|
+
);
|
|
19319
|
+
this.wasm_memory.grow(grow_pages);
|
|
19320
|
+
this.rebuild_wasm_views();
|
|
19321
|
+
}
|
|
19322
|
+
this.mem8 = view(Uint8Array, this.wasm_memory, mem8_offset, new_size);
|
|
19323
|
+
this.mem32s = view(
|
|
19324
|
+
Int32Array,
|
|
19325
|
+
this.wasm_memory,
|
|
19326
|
+
mem8_offset,
|
|
19327
|
+
new_size >> 2
|
|
19328
|
+
);
|
|
19329
|
+
this.memory_size[0] = new_size;
|
|
19330
|
+
}
|
|
18377
19331
|
set_state(state) {
|
|
18378
|
-
|
|
19332
|
+
const saved_memory_size = state[0];
|
|
19333
|
+
if (saved_memory_size > this.memory_size[0]) {
|
|
19334
|
+
this.resize_memory(saved_memory_size);
|
|
19335
|
+
} else {
|
|
19336
|
+
this.memory_size[0] = saved_memory_size;
|
|
19337
|
+
}
|
|
18379
19338
|
if (this.mem8.length !== this.memory_size[0]) {
|
|
18380
19339
|
console.warn(
|
|
18381
19340
|
"Note: Memory size mismatch. we=" + this.mem8.length + " state=" + this.memory_size[0]
|
|
@@ -18473,6 +19432,10 @@ var CPU = class {
|
|
|
18473
19432
|
this.devices.virtio_net.set_state(state[83]);
|
|
18474
19433
|
if (this.devices.virtio_balloon)
|
|
18475
19434
|
this.devices.virtio_balloon.set_state(state[84]);
|
|
19435
|
+
if (this.devices.virtio_mem && state[89])
|
|
19436
|
+
this.devices.virtio_mem.set_state(state[89]);
|
|
19437
|
+
if (this.devices.virtio_v86fs && state[90])
|
|
19438
|
+
this.devices.virtio_v86fs.set_state(state[90]);
|
|
18476
19439
|
this.fw_value = state[62];
|
|
18477
19440
|
if (state[63]) this.set_state_ioapic(state[63]);
|
|
18478
19441
|
this.tss_size_32[0] = state[64];
|
|
@@ -18671,8 +19634,10 @@ var CPU = class {
|
|
|
18671
19634
|
this.memory_size[0] === 0,
|
|
18672
19635
|
"Expected uninitialised memory"
|
|
18673
19636
|
);
|
|
18674
|
-
this.memory_size[0] = size;
|
|
18675
19637
|
const memory_offset = this.allocate_memory(size);
|
|
19638
|
+
this.rebuild_wasm_views();
|
|
19639
|
+
this.memory_size[0] = size;
|
|
19640
|
+
this.mem8_offset = memory_offset;
|
|
18676
19641
|
this.mem8 = view(Uint8Array, this.wasm_memory, memory_offset, size);
|
|
18677
19642
|
this.mem32s = view(
|
|
18678
19643
|
Uint32Array,
|
|
@@ -18883,6 +19848,19 @@ var CPU = class {
|
|
|
18883
19848
|
device_bus
|
|
18884
19849
|
);
|
|
18885
19850
|
}
|
|
19851
|
+
if (settings.virtio_mem) {
|
|
19852
|
+
const mem_cfg = settings.virtio_mem;
|
|
19853
|
+
this.devices.virtio_mem = new VirtioMem(
|
|
19854
|
+
this,
|
|
19855
|
+
device_bus,
|
|
19856
|
+
mem_cfg.region_addr,
|
|
19857
|
+
mem_cfg.region_size,
|
|
19858
|
+
mem_cfg.block_size
|
|
19859
|
+
);
|
|
19860
|
+
}
|
|
19861
|
+
if (settings.virtio_v86fs) {
|
|
19862
|
+
this.devices.virtio_v86fs = new VirtioV86FS(this, device_bus);
|
|
19863
|
+
}
|
|
18886
19864
|
this.devices.sb16 = new SB16(this, device_bus);
|
|
18887
19865
|
}
|
|
18888
19866
|
if (settings.multiboot) {
|
|
@@ -18903,6 +19881,21 @@ var CPU = class {
|
|
|
18903
19881
|
}
|
|
18904
19882
|
}
|
|
18905
19883
|
this.debug_init();
|
|
19884
|
+
this.rebuild_wasm_views();
|
|
19885
|
+
if (this.mem8_offset > 0) {
|
|
19886
|
+
this.mem8 = view(
|
|
19887
|
+
Uint8Array,
|
|
19888
|
+
this.wasm_memory,
|
|
19889
|
+
this.mem8_offset,
|
|
19890
|
+
this.memory_size[0]
|
|
19891
|
+
);
|
|
19892
|
+
this.mem32s = view(
|
|
19893
|
+
Uint32Array,
|
|
19894
|
+
this.wasm_memory,
|
|
19895
|
+
this.mem8_offset,
|
|
19896
|
+
this.memory_size[0] >> 2
|
|
19897
|
+
);
|
|
19898
|
+
}
|
|
18906
19899
|
}
|
|
18907
19900
|
load_multiboot(buffer) {
|
|
18908
19901
|
if (this.bios.main) {
|
|
@@ -19108,7 +20101,6 @@ var CPU = class {
|
|
|
19108
20101
|
cpu.write32(multiboot_data + 4, ramdisk_top);
|
|
19109
20102
|
cpu.write32(multiboot_data + 8, 0);
|
|
19110
20103
|
cpu.write32(multiboot_data + 12, 0);
|
|
19111
|
-
multiboot_data += 16;
|
|
19112
20104
|
dbg_assert(ramdisk_top < cpu.memory_size[0]);
|
|
19113
20105
|
cpu.write_blob(new Uint8Array(initrd), ramdisk_address);
|
|
19114
20106
|
}
|
|
@@ -25182,20 +26174,11 @@ var ServerFileStorageWrapper = class {
|
|
|
25182
26174
|
};
|
|
25183
26175
|
|
|
25184
26176
|
// src/browser/starter.ts
|
|
25185
|
-
var
|
|
25186
|
-
message;
|
|
25187
|
-
constructor(message) {
|
|
25188
|
-
this.message = message || "File already exists";
|
|
25189
|
-
}
|
|
25190
|
-
};
|
|
25191
|
-
FileExistsError.prototype = Error.prototype;
|
|
25192
|
-
var FileNotFoundError = class {
|
|
25193
|
-
message;
|
|
26177
|
+
var FileNotFoundError = class extends Error {
|
|
25194
26178
|
constructor(message) {
|
|
25195
|
-
|
|
26179
|
+
super(message || "File not found");
|
|
25196
26180
|
}
|
|
25197
26181
|
};
|
|
25198
|
-
FileNotFoundError.prototype = Error.prototype;
|
|
25199
26182
|
var V86 = class {
|
|
25200
26183
|
cpu_is_running = false;
|
|
25201
26184
|
cpu_exception_hook = function(_n) {
|
|
@@ -25223,12 +26206,25 @@ var V86 = class {
|
|
|
25223
26206
|
this.bus = bus[0];
|
|
25224
26207
|
this.emulator_bus = bus[1];
|
|
25225
26208
|
let cpu;
|
|
25226
|
-
|
|
26209
|
+
const memory_size = options.memory_size || 64 * 1024 * 1024;
|
|
26210
|
+
const vga_memory_size = options.vga_memory_size || 8 * 1024 * 1024;
|
|
26211
|
+
const memory_max = options.memory_max || (memory_size + vga_memory_size) * 4;
|
|
26212
|
+
const WASM_PAGE_SIZE2 = 65536;
|
|
26213
|
+
const wasm_initial_pages = 256;
|
|
26214
|
+
const wasm_max_pages = Math.max(
|
|
26215
|
+
wasm_initial_pages,
|
|
26216
|
+
Math.min(Math.ceil(memory_max / WASM_PAGE_SIZE2), 65536)
|
|
26217
|
+
);
|
|
26218
|
+
const wasm_memory = new WebAssembly.Memory({
|
|
26219
|
+
initial: wasm_initial_pages,
|
|
26220
|
+
maximum: wasm_max_pages
|
|
26221
|
+
});
|
|
25227
26222
|
const wasm_table = new WebAssembly.Table({
|
|
25228
26223
|
element: "anyfunc",
|
|
25229
26224
|
initial: WASM_TABLE_SIZE + WASM_TABLE_OFFSET
|
|
25230
26225
|
});
|
|
25231
26226
|
const wasm_shared_funcs = {
|
|
26227
|
+
memory: wasm_memory,
|
|
25232
26228
|
cpu_exception_hook: (n) => this.cpu_exception_hook(n),
|
|
25233
26229
|
run_hardware_timers: function(a, t) {
|
|
25234
26230
|
return cpu.run_hardware_timers(a, t);
|
|
@@ -25321,9 +26317,10 @@ var V86 = class {
|
|
|
25321
26317
|
"v86.wasm",
|
|
25322
26318
|
"v86-fallback.wasm"
|
|
25323
26319
|
);
|
|
25324
|
-
} else if (typeof window === "undefined"
|
|
25325
|
-
|
|
25326
|
-
|
|
26320
|
+
} else if (typeof window === "undefined") {
|
|
26321
|
+
const root = new URL("../../", import.meta.url).pathname;
|
|
26322
|
+
v86_bin = root + "build/" + v86_bin;
|
|
26323
|
+
v86_bin_fallback = root + "build/" + v86_bin_fallback;
|
|
25327
26324
|
} else {
|
|
25328
26325
|
v86_bin = "build/" + v86_bin;
|
|
25329
26326
|
v86_bin_fallback = "build/" + v86_bin_fallback;
|
|
@@ -25362,11 +26359,11 @@ var V86 = class {
|
|
|
25362
26359
|
};
|
|
25363
26360
|
}
|
|
25364
26361
|
wasm_fn({ env: wasm_shared_funcs }).then((exports) => {
|
|
25365
|
-
wasm_memory = exports.memory;
|
|
25366
26362
|
exports["rust_init"]();
|
|
25367
26363
|
const emulator = this.v86 = new v86(this.emulator_bus, {
|
|
25368
26364
|
exports,
|
|
25369
|
-
wasm_table
|
|
26365
|
+
wasm_table,
|
|
26366
|
+
wasm_memory
|
|
25370
26367
|
});
|
|
25371
26368
|
cpu = emulator.cpu;
|
|
25372
26369
|
this.continue_init(emulator, options);
|
|
@@ -25408,7 +26405,9 @@ var V86 = class {
|
|
|
25408
26405
|
settings.mac_address_translation = options.mac_address_translation;
|
|
25409
26406
|
settings.cpuid_level = options.cpuid_level;
|
|
25410
26407
|
settings.virtio_balloon = options.virtio_balloon;
|
|
26408
|
+
settings.virtio_mem = options.virtio_mem;
|
|
25411
26409
|
settings.virtio_console = !!options.virtio_console;
|
|
26410
|
+
settings.virtio_v86fs = !!options.virtio_v86fs;
|
|
25412
26411
|
const relay_url = options.network_relay_url || options.net_device && options.net_device.relay_url;
|
|
25413
26412
|
if (relay_url) {
|
|
25414
26413
|
if (relay_url === "fetch") {
|
|
@@ -25886,6 +26885,26 @@ var V86 = class {
|
|
|
25886
26885
|
async run() {
|
|
25887
26886
|
this.v86.run();
|
|
25888
26887
|
}
|
|
26888
|
+
/**
|
|
26889
|
+
* Grow guest memory to the specified size in bytes. Stops the VM,
|
|
26890
|
+
* grows WASM linear memory, updates memory_size, clears the TLB,
|
|
26891
|
+
* and resumes execution.
|
|
26892
|
+
*/
|
|
26893
|
+
async growMemory(newSizeBytes) {
|
|
26894
|
+
const cpu = this.v86.cpu;
|
|
26895
|
+
if (newSizeBytes <= cpu.memory_size[0]) {
|
|
26896
|
+
return;
|
|
26897
|
+
}
|
|
26898
|
+
const wasRunning = this.cpu_is_running;
|
|
26899
|
+
if (wasRunning) {
|
|
26900
|
+
await this.stop();
|
|
26901
|
+
}
|
|
26902
|
+
cpu.resize_memory(newSizeBytes);
|
|
26903
|
+
cpu.full_clear_tlb();
|
|
26904
|
+
if (wasRunning) {
|
|
26905
|
+
await this.run();
|
|
26906
|
+
}
|
|
26907
|
+
}
|
|
25889
26908
|
/**
|
|
25890
26909
|
* Stop emulation. Do nothing if emulator is not running. Can be asynchronous.
|
|
25891
26910
|
*/
|