@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.browser.js
CHANGED
|
@@ -142,6 +142,7 @@ var V86Starter = (() => {
|
|
|
142
142
|
var FW_CFG_SIGNATURE_QEMU = 1431127377;
|
|
143
143
|
var WASM_TABLE_SIZE = 900;
|
|
144
144
|
var WASM_TABLE_OFFSET = 1024;
|
|
145
|
+
var WASM_PAGE_SIZE = 65536;
|
|
145
146
|
var MIXER_CHANNEL_LEFT = 0;
|
|
146
147
|
var MIXER_CHANNEL_RIGHT = 1;
|
|
147
148
|
var MIXER_CHANNEL_BOTH = 2;
|
|
@@ -5456,17 +5457,18 @@ var V86Starter = (() => {
|
|
|
5456
5457
|
LOG_VIRTIO
|
|
5457
5458
|
);
|
|
5458
5459
|
}
|
|
5459
|
-
if (data & ~this.device_status & VIRTIO_STATUS_DRIVER_OK && this.device_status & VIRTIO_STATUS_DEVICE_NEEDS_RESET) {
|
|
5460
|
-
this.notify_config_changes();
|
|
5461
|
-
}
|
|
5462
5460
|
if (!this.features_ok) {
|
|
5463
5461
|
if (false) {
|
|
5464
5462
|
dbg_log("Removing FEATURES_OK", LOG_VIRTIO);
|
|
5465
5463
|
}
|
|
5466
5464
|
data &= ~VIRTIO_STATUS_FEATURES_OK;
|
|
5467
5465
|
}
|
|
5466
|
+
const prev_status = this.device_status;
|
|
5468
5467
|
this.device_status = data;
|
|
5469
|
-
if (data & ~
|
|
5468
|
+
if (data & ~prev_status & VIRTIO_STATUS_DRIVER_OK) {
|
|
5469
|
+
if (prev_status & VIRTIO_STATUS_DEVICE_NEEDS_RESET) {
|
|
5470
|
+
this.notify_config_changes();
|
|
5471
|
+
}
|
|
5470
5472
|
options.on_driver_ok();
|
|
5471
5473
|
}
|
|
5472
5474
|
}
|
|
@@ -5703,7 +5705,7 @@ var V86Starter = (() => {
|
|
|
5703
5705
|
// Call only within constructor.
|
|
5704
5706
|
init_capabilities(capabilities) {
|
|
5705
5707
|
let cap_next = this.pci_space[52] = 64;
|
|
5706
|
-
let cap_ptr
|
|
5708
|
+
let cap_ptr;
|
|
5707
5709
|
for (const cap of capabilities) {
|
|
5708
5710
|
const cap_len2 = VIRTIO_PCI_CAP_LENGTH + cap.extra.length;
|
|
5709
5711
|
cap_ptr = cap_next;
|
|
@@ -6924,7 +6926,7 @@ var V86Starter = (() => {
|
|
|
6924
6926
|
(out_byte) => {
|
|
6925
6927
|
if ((this.pci_addr[1] & 6) === 2 && (out_byte & 6) === 6) {
|
|
6926
6928
|
dbg_log("CPU reboot via PCI");
|
|
6927
|
-
cpu.
|
|
6929
|
+
cpu.reboot();
|
|
6928
6930
|
return;
|
|
6929
6931
|
}
|
|
6930
6932
|
this.pci_addr[1] = out_byte;
|
|
@@ -7030,6 +7032,7 @@ var V86Starter = (() => {
|
|
|
7030
7032
|
0,
|
|
7031
7033
|
0,
|
|
7032
7034
|
0,
|
|
7035
|
+
0,
|
|
7033
7036
|
PAM0,
|
|
7034
7037
|
0,
|
|
7035
7038
|
0,
|
|
@@ -7342,7 +7345,11 @@ var V86Starter = (() => {
|
|
|
7342
7345
|
dbg_assert(device.pci_space.length >= 64);
|
|
7343
7346
|
dbg_assert(device_id < this.devices.length);
|
|
7344
7347
|
const space = new Int32Array(64);
|
|
7345
|
-
|
|
7348
|
+
const pci_bytes = new Uint8Array(device.pci_space);
|
|
7349
|
+
const aligned_len = pci_bytes.length & ~3;
|
|
7350
|
+
if (aligned_len > 0) {
|
|
7351
|
+
space.set(new Int32Array(pci_bytes.buffer, 0, aligned_len >> 2));
|
|
7352
|
+
}
|
|
7346
7353
|
this.device_spaces[device_id] = space;
|
|
7347
7354
|
this.devices[device_id] = device;
|
|
7348
7355
|
const bar_space = space.slice(4, 10);
|
|
@@ -7993,7 +8000,7 @@ var V86Starter = (() => {
|
|
|
7993
8000
|
break;
|
|
7994
8001
|
case 254:
|
|
7995
8002
|
dbg_log("CPU reboot via PS2");
|
|
7996
|
-
this.cpu.
|
|
8003
|
+
this.cpu.reboot();
|
|
7997
8004
|
break;
|
|
7998
8005
|
default:
|
|
7999
8006
|
dbg_log(
|
|
@@ -15138,12 +15145,930 @@ var V86Starter = (() => {
|
|
|
15138
15145
|
}
|
|
15139
15146
|
};
|
|
15140
15147
|
|
|
15148
|
+
// src/virtio_mem.ts
|
|
15149
|
+
var VIRTIO_MEM_REQ_PLUG = 0;
|
|
15150
|
+
var VIRTIO_MEM_REQ_UNPLUG = 1;
|
|
15151
|
+
var VIRTIO_MEM_REQ_STATE = 3;
|
|
15152
|
+
var VIRTIO_MEM_RESP_ACK = 0;
|
|
15153
|
+
var VIRTIO_MEM_RESP_NACK = 1;
|
|
15154
|
+
var VIRTIO_MEM_RESP_ERROR = 3;
|
|
15155
|
+
var DEFAULT_BLOCK_SIZE = 128 * 1024 * 1024;
|
|
15156
|
+
var VirtioMem = class {
|
|
15157
|
+
bus;
|
|
15158
|
+
cpu;
|
|
15159
|
+
virtio;
|
|
15160
|
+
block_size;
|
|
15161
|
+
region_addr;
|
|
15162
|
+
region_size;
|
|
15163
|
+
usable_region_size;
|
|
15164
|
+
plugged_size;
|
|
15165
|
+
requested_size;
|
|
15166
|
+
constructor(cpu, bus, region_addr, region_size, block_size) {
|
|
15167
|
+
this.bus = bus;
|
|
15168
|
+
this.cpu = cpu;
|
|
15169
|
+
this.block_size = block_size || DEFAULT_BLOCK_SIZE;
|
|
15170
|
+
this.region_addr = region_addr;
|
|
15171
|
+
this.region_size = region_size;
|
|
15172
|
+
this.usable_region_size = region_size;
|
|
15173
|
+
this.plugged_size = 0;
|
|
15174
|
+
this.requested_size = 0;
|
|
15175
|
+
const queues = [{ size_supported: 32, notify_offset: 0 }];
|
|
15176
|
+
this.virtio = new VirtIO(cpu, {
|
|
15177
|
+
name: "virtio-mem",
|
|
15178
|
+
pci_id: 13 << 3,
|
|
15179
|
+
device_id: 4184,
|
|
15180
|
+
subsystem_device_id: 24,
|
|
15181
|
+
common: {
|
|
15182
|
+
initial_port: 59392,
|
|
15183
|
+
queues,
|
|
15184
|
+
features: [VIRTIO_F_VERSION_1],
|
|
15185
|
+
on_driver_ok: () => {
|
|
15186
|
+
dbg_log("virtio-mem setup", LOG_PCI);
|
|
15187
|
+
}
|
|
15188
|
+
},
|
|
15189
|
+
notification: {
|
|
15190
|
+
initial_port: 59648,
|
|
15191
|
+
single_handler: false,
|
|
15192
|
+
handlers: [
|
|
15193
|
+
(queue_id) => {
|
|
15194
|
+
this.handle_request(queue_id);
|
|
15195
|
+
}
|
|
15196
|
+
]
|
|
15197
|
+
},
|
|
15198
|
+
isr_status: {
|
|
15199
|
+
initial_port: 59136
|
|
15200
|
+
},
|
|
15201
|
+
device_specific: {
|
|
15202
|
+
initial_port: 58880,
|
|
15203
|
+
struct: [
|
|
15204
|
+
// block_size low
|
|
15205
|
+
{
|
|
15206
|
+
bytes: 4,
|
|
15207
|
+
name: "block_size_low",
|
|
15208
|
+
read: () => this.block_size >>> 0,
|
|
15209
|
+
write: () => {
|
|
15210
|
+
}
|
|
15211
|
+
},
|
|
15212
|
+
// block_size high
|
|
15213
|
+
{
|
|
15214
|
+
bytes: 4,
|
|
15215
|
+
name: "block_size_high",
|
|
15216
|
+
read: () => 0,
|
|
15217
|
+
write: () => {
|
|
15218
|
+
}
|
|
15219
|
+
},
|
|
15220
|
+
// node_id (u16 padded to u32)
|
|
15221
|
+
{
|
|
15222
|
+
bytes: 2,
|
|
15223
|
+
name: "node_id",
|
|
15224
|
+
read: () => 0,
|
|
15225
|
+
write: () => {
|
|
15226
|
+
}
|
|
15227
|
+
},
|
|
15228
|
+
// padding (6 bytes as 2+4)
|
|
15229
|
+
{
|
|
15230
|
+
bytes: 2,
|
|
15231
|
+
name: "padding0",
|
|
15232
|
+
read: () => 0,
|
|
15233
|
+
write: () => {
|
|
15234
|
+
}
|
|
15235
|
+
},
|
|
15236
|
+
{
|
|
15237
|
+
bytes: 4,
|
|
15238
|
+
name: "padding1",
|
|
15239
|
+
read: () => 0,
|
|
15240
|
+
write: () => {
|
|
15241
|
+
}
|
|
15242
|
+
},
|
|
15243
|
+
// addr low
|
|
15244
|
+
{
|
|
15245
|
+
bytes: 4,
|
|
15246
|
+
name: "addr_low",
|
|
15247
|
+
read: () => this.region_addr >>> 0,
|
|
15248
|
+
write: () => {
|
|
15249
|
+
}
|
|
15250
|
+
},
|
|
15251
|
+
// addr high
|
|
15252
|
+
{
|
|
15253
|
+
bytes: 4,
|
|
15254
|
+
name: "addr_high",
|
|
15255
|
+
read: () => 0,
|
|
15256
|
+
write: () => {
|
|
15257
|
+
}
|
|
15258
|
+
},
|
|
15259
|
+
// region_size low
|
|
15260
|
+
{
|
|
15261
|
+
bytes: 4,
|
|
15262
|
+
name: "region_size_low",
|
|
15263
|
+
read: () => this.region_size >>> 0,
|
|
15264
|
+
write: () => {
|
|
15265
|
+
}
|
|
15266
|
+
},
|
|
15267
|
+
// region_size high
|
|
15268
|
+
{
|
|
15269
|
+
bytes: 4,
|
|
15270
|
+
name: "region_size_high",
|
|
15271
|
+
read: () => 0,
|
|
15272
|
+
write: () => {
|
|
15273
|
+
}
|
|
15274
|
+
},
|
|
15275
|
+
// usable_region_size low
|
|
15276
|
+
{
|
|
15277
|
+
bytes: 4,
|
|
15278
|
+
name: "usable_region_size_low",
|
|
15279
|
+
read: () => this.usable_region_size >>> 0,
|
|
15280
|
+
write: () => {
|
|
15281
|
+
}
|
|
15282
|
+
},
|
|
15283
|
+
// usable_region_size high
|
|
15284
|
+
{
|
|
15285
|
+
bytes: 4,
|
|
15286
|
+
name: "usable_region_size_high",
|
|
15287
|
+
read: () => 0,
|
|
15288
|
+
write: () => {
|
|
15289
|
+
}
|
|
15290
|
+
},
|
|
15291
|
+
// plugged_size low
|
|
15292
|
+
{
|
|
15293
|
+
bytes: 4,
|
|
15294
|
+
name: "plugged_size_low",
|
|
15295
|
+
read: () => this.plugged_size >>> 0,
|
|
15296
|
+
write: () => {
|
|
15297
|
+
}
|
|
15298
|
+
},
|
|
15299
|
+
// plugged_size high
|
|
15300
|
+
{
|
|
15301
|
+
bytes: 4,
|
|
15302
|
+
name: "plugged_size_high",
|
|
15303
|
+
read: () => 0,
|
|
15304
|
+
write: () => {
|
|
15305
|
+
}
|
|
15306
|
+
},
|
|
15307
|
+
// requested_size low
|
|
15308
|
+
{
|
|
15309
|
+
bytes: 4,
|
|
15310
|
+
name: "requested_size_low",
|
|
15311
|
+
read: () => this.requested_size >>> 0,
|
|
15312
|
+
write: () => {
|
|
15313
|
+
}
|
|
15314
|
+
},
|
|
15315
|
+
// requested_size high
|
|
15316
|
+
{
|
|
15317
|
+
bytes: 4,
|
|
15318
|
+
name: "requested_size_high",
|
|
15319
|
+
read: () => 0,
|
|
15320
|
+
write: () => {
|
|
15321
|
+
}
|
|
15322
|
+
}
|
|
15323
|
+
]
|
|
15324
|
+
}
|
|
15325
|
+
});
|
|
15326
|
+
}
|
|
15327
|
+
handle_request(queue_id) {
|
|
15328
|
+
const queue = this.virtio.queues[queue_id];
|
|
15329
|
+
while (queue.has_request()) {
|
|
15330
|
+
const bufchain = queue.pop_request();
|
|
15331
|
+
const request = new Uint8Array(bufchain.length_readable);
|
|
15332
|
+
bufchain.get_next_blob(request);
|
|
15333
|
+
const type = request[0] | request[1] << 8;
|
|
15334
|
+
const resp = new Uint8Array(8);
|
|
15335
|
+
let resp_type = VIRTIO_MEM_RESP_ERROR;
|
|
15336
|
+
switch (type) {
|
|
15337
|
+
case VIRTIO_MEM_REQ_PLUG:
|
|
15338
|
+
resp_type = this.handle_plug(request);
|
|
15339
|
+
break;
|
|
15340
|
+
case VIRTIO_MEM_REQ_UNPLUG:
|
|
15341
|
+
resp_type = VIRTIO_MEM_RESP_NACK;
|
|
15342
|
+
break;
|
|
15343
|
+
case VIRTIO_MEM_REQ_STATE:
|
|
15344
|
+
resp_type = this.handle_state(request, resp);
|
|
15345
|
+
break;
|
|
15346
|
+
default:
|
|
15347
|
+
dbg_log("virtio-mem: unknown request type " + type, LOG_PCI);
|
|
15348
|
+
}
|
|
15349
|
+
resp[0] = resp_type & 255;
|
|
15350
|
+
resp[1] = resp_type >> 8 & 255;
|
|
15351
|
+
bufchain.set_next_blob(resp);
|
|
15352
|
+
queue.push_reply(bufchain);
|
|
15353
|
+
}
|
|
15354
|
+
queue.flush_replies();
|
|
15355
|
+
}
|
|
15356
|
+
handle_plug(request) {
|
|
15357
|
+
const addr = (request[8] | request[9] << 8 | request[10] << 16 | request[11] << 24) >>> 0;
|
|
15358
|
+
const nb_blocks = request[16] | request[17] << 8;
|
|
15359
|
+
const size = nb_blocks * this.block_size;
|
|
15360
|
+
const new_plugged = this.plugged_size + size;
|
|
15361
|
+
if (new_plugged > this.usable_region_size) {
|
|
15362
|
+
return VIRTIO_MEM_RESP_NACK;
|
|
15363
|
+
}
|
|
15364
|
+
const new_memory_size = this.cpu.memory_size[0] + size;
|
|
15365
|
+
this.cpu.resize_memory(new_memory_size);
|
|
15366
|
+
this.cpu.full_clear_tlb();
|
|
15367
|
+
this.plugged_size = new_plugged;
|
|
15368
|
+
dbg_log(
|
|
15369
|
+
"virtio-mem: plugged " + nb_blocks + " blocks at 0x" + addr.toString(16) + " (" + (size >> 20) + "MB)",
|
|
15370
|
+
LOG_PCI
|
|
15371
|
+
);
|
|
15372
|
+
return VIRTIO_MEM_RESP_ACK;
|
|
15373
|
+
}
|
|
15374
|
+
handle_state(request, resp) {
|
|
15375
|
+
const addr = (request[8] | request[9] << 8 | request[10] << 16 | request[11] << 24) >>> 0;
|
|
15376
|
+
const nb_blocks = request[16] | request[17] << 8;
|
|
15377
|
+
const offset = addr - this.region_addr;
|
|
15378
|
+
const end = offset + nb_blocks * this.block_size;
|
|
15379
|
+
const all_plugged = end <= this.plugged_size ? 1 : 0;
|
|
15380
|
+
resp[8] = all_plugged & 255;
|
|
15381
|
+
resp[9] = all_plugged >> 8 & 255;
|
|
15382
|
+
return VIRTIO_MEM_RESP_ACK;
|
|
15383
|
+
}
|
|
15384
|
+
set_requested_size(size) {
|
|
15385
|
+
this.requested_size = size;
|
|
15386
|
+
if (this.virtio.device_status & 4) {
|
|
15387
|
+
this.virtio.notify_config_changes();
|
|
15388
|
+
}
|
|
15389
|
+
}
|
|
15390
|
+
get_state() {
|
|
15391
|
+
const state = [];
|
|
15392
|
+
state[0] = this.virtio;
|
|
15393
|
+
state[1] = this.block_size;
|
|
15394
|
+
state[2] = this.region_addr;
|
|
15395
|
+
state[3] = this.region_size;
|
|
15396
|
+
state[4] = this.usable_region_size;
|
|
15397
|
+
state[5] = this.plugged_size;
|
|
15398
|
+
state[6] = this.requested_size;
|
|
15399
|
+
return state;
|
|
15400
|
+
}
|
|
15401
|
+
set_state(state) {
|
|
15402
|
+
this.virtio.set_state(state[0]);
|
|
15403
|
+
this.block_size = state[1];
|
|
15404
|
+
this.region_addr = state[2];
|
|
15405
|
+
this.region_size = state[3];
|
|
15406
|
+
this.usable_region_size = state[4];
|
|
15407
|
+
this.plugged_size = state[5];
|
|
15408
|
+
this.requested_size = state[6];
|
|
15409
|
+
}
|
|
15410
|
+
};
|
|
15411
|
+
|
|
15412
|
+
// src/virtio_v86fs.ts
|
|
15413
|
+
var V86FS_MSG_MOUNT = 0;
|
|
15414
|
+
var V86FS_MSG_LOOKUP = 1;
|
|
15415
|
+
var V86FS_MSG_GETATTR = 2;
|
|
15416
|
+
var V86FS_MSG_READDIR = 3;
|
|
15417
|
+
var V86FS_MSG_OPEN = 4;
|
|
15418
|
+
var V86FS_MSG_CLOSE = 5;
|
|
15419
|
+
var V86FS_MSG_READ = 6;
|
|
15420
|
+
var V86FS_MSG_CREATE = 7;
|
|
15421
|
+
var V86FS_MSG_WRITE = 8;
|
|
15422
|
+
var V86FS_MSG_MKDIR = 9;
|
|
15423
|
+
var V86FS_MSG_SETATTR = 10;
|
|
15424
|
+
var V86FS_MSG_FSYNC = 11;
|
|
15425
|
+
var V86FS_MSG_UNLINK = 12;
|
|
15426
|
+
var V86FS_MSG_RENAME = 13;
|
|
15427
|
+
var V86FS_MSG_SYMLINK = 14;
|
|
15428
|
+
var V86FS_MSG_READLINK = 15;
|
|
15429
|
+
var V86FS_MSG_STATFS = 16;
|
|
15430
|
+
var V86FS_MSG_INVALIDATE = 32;
|
|
15431
|
+
var V86FS_MSG_INVALIDATE_DIR = 33;
|
|
15432
|
+
var V86FS_MSG_MOUNT_R = 128;
|
|
15433
|
+
var V86FS_MSG_LOOKUP_R = 129;
|
|
15434
|
+
var V86FS_MSG_GETATTR_R = 130;
|
|
15435
|
+
var V86FS_MSG_READDIR_R = 131;
|
|
15436
|
+
var V86FS_MSG_OPEN_R = 132;
|
|
15437
|
+
var V86FS_MSG_CLOSE_R = 133;
|
|
15438
|
+
var V86FS_MSG_READ_R = 134;
|
|
15439
|
+
var V86FS_MSG_CREATE_R = 135;
|
|
15440
|
+
var V86FS_MSG_WRITE_R = 136;
|
|
15441
|
+
var V86FS_MSG_MKDIR_R = 137;
|
|
15442
|
+
var V86FS_MSG_SETATTR_R = 138;
|
|
15443
|
+
var V86FS_MSG_FSYNC_R = 139;
|
|
15444
|
+
var V86FS_MSG_UNLINK_R = 140;
|
|
15445
|
+
var V86FS_MSG_RENAME_R = 141;
|
|
15446
|
+
var V86FS_MSG_SYMLINK_R = 142;
|
|
15447
|
+
var V86FS_MSG_READLINK_R = 143;
|
|
15448
|
+
var V86FS_MSG_STATFS_R = 144;
|
|
15449
|
+
var ATTR_MODE = 1;
|
|
15450
|
+
var ATTR_SIZE = 8;
|
|
15451
|
+
var V86FS_STATUS_OK = 0;
|
|
15452
|
+
var V86FS_STATUS_ENOENT = 2;
|
|
15453
|
+
var DT_DIR = 4;
|
|
15454
|
+
var DT_REG = 8;
|
|
15455
|
+
var DT_LNK = 10;
|
|
15456
|
+
var S_IFDIR = 16384;
|
|
15457
|
+
var S_IFREG = 32768;
|
|
15458
|
+
var S_IFLNK = 40960;
|
|
15459
|
+
var textDecoder = new TextDecoder();
|
|
15460
|
+
var textEncoder = new TextEncoder();
|
|
15461
|
+
var FS_ENTRIES = /* @__PURE__ */ new Map([
|
|
15462
|
+
[
|
|
15463
|
+
1,
|
|
15464
|
+
[
|
|
15465
|
+
{
|
|
15466
|
+
inode_id: 2,
|
|
15467
|
+
name: "hello.txt",
|
|
15468
|
+
mode: S_IFREG | 420,
|
|
15469
|
+
size: 12,
|
|
15470
|
+
dt_type: DT_REG,
|
|
15471
|
+
mtime_sec: 17115e5,
|
|
15472
|
+
mtime_nsec: 0,
|
|
15473
|
+
content: textEncoder.encode("hello world\n")
|
|
15474
|
+
},
|
|
15475
|
+
{
|
|
15476
|
+
inode_id: 3,
|
|
15477
|
+
name: "subdir",
|
|
15478
|
+
mode: S_IFDIR | 493,
|
|
15479
|
+
size: 0,
|
|
15480
|
+
dt_type: DT_DIR,
|
|
15481
|
+
mtime_sec: 17115e5,
|
|
15482
|
+
mtime_nsec: 0
|
|
15483
|
+
}
|
|
15484
|
+
]
|
|
15485
|
+
]
|
|
15486
|
+
]);
|
|
15487
|
+
var INODE_MAP = /* @__PURE__ */ new Map([
|
|
15488
|
+
[
|
|
15489
|
+
1,
|
|
15490
|
+
{
|
|
15491
|
+
inode_id: 1,
|
|
15492
|
+
name: "",
|
|
15493
|
+
mode: S_IFDIR | 493,
|
|
15494
|
+
size: 0,
|
|
15495
|
+
dt_type: DT_DIR,
|
|
15496
|
+
mtime_sec: 17115e5,
|
|
15497
|
+
mtime_nsec: 0
|
|
15498
|
+
}
|
|
15499
|
+
]
|
|
15500
|
+
]);
|
|
15501
|
+
for (const entries of FS_ENTRIES.values()) {
|
|
15502
|
+
for (const e of entries) {
|
|
15503
|
+
INODE_MAP.set(e.inode_id, e);
|
|
15504
|
+
}
|
|
15505
|
+
}
|
|
15506
|
+
var V86FS_HDR_SIZE = 7;
|
|
15507
|
+
function packU32(buf, offset, val) {
|
|
15508
|
+
buf[offset] = val & 255;
|
|
15509
|
+
buf[offset + 1] = val >>> 8 & 255;
|
|
15510
|
+
buf[offset + 2] = val >>> 16 & 255;
|
|
15511
|
+
buf[offset + 3] = val >>> 24 & 255;
|
|
15512
|
+
}
|
|
15513
|
+
function packU64(buf, offset, val) {
|
|
15514
|
+
packU32(buf, offset, val);
|
|
15515
|
+
packU32(buf, offset + 4, 0);
|
|
15516
|
+
}
|
|
15517
|
+
function packU16(buf, offset, val) {
|
|
15518
|
+
buf[offset] = val & 255;
|
|
15519
|
+
buf[offset + 1] = val >>> 8 & 255;
|
|
15520
|
+
}
|
|
15521
|
+
function makeResp(size, type, tag) {
|
|
15522
|
+
const resp = new Uint8Array(size);
|
|
15523
|
+
packU32(resp, 0, size);
|
|
15524
|
+
resp[4] = type;
|
|
15525
|
+
resp[5] = tag & 255;
|
|
15526
|
+
resp[6] = tag >> 8 & 255;
|
|
15527
|
+
return resp;
|
|
15528
|
+
}
|
|
15529
|
+
function readU32(buf, offset) {
|
|
15530
|
+
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16 | buf[offset + 3] << 24 >>> 0;
|
|
15531
|
+
}
|
|
15532
|
+
function readU16(buf, offset) {
|
|
15533
|
+
return buf[offset] | buf[offset + 1] << 8;
|
|
15534
|
+
}
|
|
15535
|
+
function readU64(buf, offset) {
|
|
15536
|
+
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;
|
|
15537
|
+
}
|
|
15538
|
+
var VirtioV86FS = class {
|
|
15539
|
+
bus;
|
|
15540
|
+
virtio;
|
|
15541
|
+
next_handle_id;
|
|
15542
|
+
next_inode_id;
|
|
15543
|
+
open_handles;
|
|
15544
|
+
// handle_id -> inode_id
|
|
15545
|
+
read_count;
|
|
15546
|
+
constructor(cpu, bus) {
|
|
15547
|
+
this.bus = bus;
|
|
15548
|
+
this.next_handle_id = 1;
|
|
15549
|
+
this.next_inode_id = 100;
|
|
15550
|
+
this.open_handles = /* @__PURE__ */ new Map();
|
|
15551
|
+
this.read_count = 0;
|
|
15552
|
+
const queues = [
|
|
15553
|
+
// Queue 0: hipriq - high-priority metadata (LOOKUP, GETATTR)
|
|
15554
|
+
{ size_supported: 128, notify_offset: 0 },
|
|
15555
|
+
// Queue 1: requestq - data requests (READ, WRITE, READDIR)
|
|
15556
|
+
{ size_supported: 128, notify_offset: 1 },
|
|
15557
|
+
// Queue 2: notifyq - host-to-guest push invalidation
|
|
15558
|
+
{ size_supported: 128, notify_offset: 2 }
|
|
15559
|
+
];
|
|
15560
|
+
this.virtio = new VirtIO(cpu, {
|
|
15561
|
+
name: "virtio-v86fs",
|
|
15562
|
+
pci_id: 14 << 3,
|
|
15563
|
+
device_id: 4223,
|
|
15564
|
+
subsystem_device_id: 63,
|
|
15565
|
+
common: {
|
|
15566
|
+
initial_port: 63488,
|
|
15567
|
+
queues,
|
|
15568
|
+
features: [VIRTIO_F_VERSION_1],
|
|
15569
|
+
on_driver_ok: () => {
|
|
15570
|
+
console.log("v86fs: driver ok");
|
|
15571
|
+
this.bus.send("virtio-v86fs-driver-ok");
|
|
15572
|
+
}
|
|
15573
|
+
},
|
|
15574
|
+
notification: {
|
|
15575
|
+
initial_port: 63744,
|
|
15576
|
+
single_handler: false,
|
|
15577
|
+
handlers: [
|
|
15578
|
+
// Queue 0: hipriq
|
|
15579
|
+
(queue_id) => {
|
|
15580
|
+
this.handle_queue(queue_id);
|
|
15581
|
+
},
|
|
15582
|
+
// Queue 1: requestq
|
|
15583
|
+
(queue_id) => {
|
|
15584
|
+
this.handle_queue(queue_id);
|
|
15585
|
+
},
|
|
15586
|
+
// Queue 2: notifyq
|
|
15587
|
+
(_queue_id) => {
|
|
15588
|
+
dbg_log("v86fs: notifyq notification", LOG_PCI);
|
|
15589
|
+
}
|
|
15590
|
+
]
|
|
15591
|
+
},
|
|
15592
|
+
isr_status: {
|
|
15593
|
+
initial_port: 63232
|
|
15594
|
+
}
|
|
15595
|
+
});
|
|
15596
|
+
}
|
|
15597
|
+
handle_queue(queue_id) {
|
|
15598
|
+
const queue = this.virtio.queues[queue_id];
|
|
15599
|
+
while (queue.has_request()) {
|
|
15600
|
+
const bufchain = queue.pop_request();
|
|
15601
|
+
const req = new Uint8Array(bufchain.length_readable);
|
|
15602
|
+
bufchain.get_next_blob(req);
|
|
15603
|
+
const resp = this.handle_message(req);
|
|
15604
|
+
if (resp && bufchain.length_writable > 0) {
|
|
15605
|
+
bufchain.set_next_blob(resp);
|
|
15606
|
+
}
|
|
15607
|
+
queue.push_reply(bufchain);
|
|
15608
|
+
}
|
|
15609
|
+
queue.flush_replies();
|
|
15610
|
+
}
|
|
15611
|
+
handle_message(req) {
|
|
15612
|
+
if (req.length < V86FS_HDR_SIZE) {
|
|
15613
|
+
console.warn("v86fs: message too short:", req.length);
|
|
15614
|
+
return null;
|
|
15615
|
+
}
|
|
15616
|
+
const type = req[4];
|
|
15617
|
+
const tag = readU16(req, 5);
|
|
15618
|
+
switch (type) {
|
|
15619
|
+
case V86FS_MSG_MOUNT:
|
|
15620
|
+
return this.handle_mount(req, tag);
|
|
15621
|
+
case V86FS_MSG_LOOKUP:
|
|
15622
|
+
return this.handle_lookup(req, tag);
|
|
15623
|
+
case V86FS_MSG_GETATTR:
|
|
15624
|
+
return this.handle_getattr(req, tag);
|
|
15625
|
+
case V86FS_MSG_READDIR:
|
|
15626
|
+
return this.handle_readdir(req, tag);
|
|
15627
|
+
case V86FS_MSG_OPEN:
|
|
15628
|
+
return this.handle_open(req, tag);
|
|
15629
|
+
case V86FS_MSG_CLOSE:
|
|
15630
|
+
return this.handle_close(req, tag);
|
|
15631
|
+
case V86FS_MSG_READ:
|
|
15632
|
+
return this.handle_read(req, tag);
|
|
15633
|
+
case V86FS_MSG_CREATE:
|
|
15634
|
+
return this.handle_create(req, tag);
|
|
15635
|
+
case V86FS_MSG_WRITE:
|
|
15636
|
+
return this.handle_write(req, tag);
|
|
15637
|
+
case V86FS_MSG_MKDIR:
|
|
15638
|
+
return this.handle_mkdir(req, tag);
|
|
15639
|
+
case V86FS_MSG_SETATTR:
|
|
15640
|
+
return this.handle_setattr(req, tag);
|
|
15641
|
+
case V86FS_MSG_FSYNC:
|
|
15642
|
+
return this.handle_fsync(req, tag);
|
|
15643
|
+
case V86FS_MSG_UNLINK:
|
|
15644
|
+
return this.handle_unlink(req, tag);
|
|
15645
|
+
case V86FS_MSG_RENAME:
|
|
15646
|
+
return this.handle_rename(req, tag);
|
|
15647
|
+
case V86FS_MSG_SYMLINK:
|
|
15648
|
+
return this.handle_symlink(req, tag);
|
|
15649
|
+
case V86FS_MSG_READLINK:
|
|
15650
|
+
return this.handle_readlink(req, tag);
|
|
15651
|
+
case V86FS_MSG_STATFS:
|
|
15652
|
+
return this.handle_statfs(tag);
|
|
15653
|
+
default:
|
|
15654
|
+
console.warn("v86fs: unknown message type:", type);
|
|
15655
|
+
return null;
|
|
15656
|
+
}
|
|
15657
|
+
}
|
|
15658
|
+
handle_mount(req, tag) {
|
|
15659
|
+
const name_len = readU16(req, 7);
|
|
15660
|
+
const name = name_len > 0 ? textDecoder.decode(req.subarray(9, 9 + name_len)) : "";
|
|
15661
|
+
console.log("v86fs: mount:", name || "(default)");
|
|
15662
|
+
this.bus.send("virtio-v86fs-mount", name);
|
|
15663
|
+
const resp = new Uint8Array(23);
|
|
15664
|
+
packU32(resp, 0, 23);
|
|
15665
|
+
resp[4] = V86FS_MSG_MOUNT_R;
|
|
15666
|
+
resp[5] = tag & 255;
|
|
15667
|
+
resp[6] = tag >> 8 & 255;
|
|
15668
|
+
packU32(resp, 7, 0);
|
|
15669
|
+
packU64(resp, 11, 1);
|
|
15670
|
+
packU32(resp, 19, 16877);
|
|
15671
|
+
return resp;
|
|
15672
|
+
}
|
|
15673
|
+
handle_getattr(req, tag) {
|
|
15674
|
+
const inode_id = readU64(req, 7);
|
|
15675
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15676
|
+
const resp = makeResp(35, V86FS_MSG_GETATTR_R, tag);
|
|
15677
|
+
if (!entry) {
|
|
15678
|
+
packU32(resp, 7, V86FS_STATUS_ENOENT);
|
|
15679
|
+
return resp;
|
|
15680
|
+
}
|
|
15681
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15682
|
+
packU32(resp, 11, entry.mode);
|
|
15683
|
+
packU64(resp, 15, entry.size);
|
|
15684
|
+
packU64(resp, 23, entry.mtime_sec);
|
|
15685
|
+
packU32(resp, 31, entry.mtime_nsec);
|
|
15686
|
+
return resp;
|
|
15687
|
+
}
|
|
15688
|
+
handle_lookup(req, tag) {
|
|
15689
|
+
const parent_id = readU64(req, 7);
|
|
15690
|
+
const name_len = readU16(req, 15);
|
|
15691
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15692
|
+
const entries = FS_ENTRIES.get(parent_id);
|
|
15693
|
+
const entry = entries?.find((e) => e.name === name);
|
|
15694
|
+
const resp = new Uint8Array(31);
|
|
15695
|
+
packU32(resp, 0, 31);
|
|
15696
|
+
resp[4] = V86FS_MSG_LOOKUP_R;
|
|
15697
|
+
resp[5] = tag & 255;
|
|
15698
|
+
resp[6] = tag >> 8 & 255;
|
|
15699
|
+
if (!entry) {
|
|
15700
|
+
packU32(resp, 7, V86FS_STATUS_ENOENT);
|
|
15701
|
+
return resp;
|
|
15702
|
+
}
|
|
15703
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15704
|
+
packU64(resp, 11, entry.inode_id);
|
|
15705
|
+
packU32(resp, 19, entry.mode);
|
|
15706
|
+
packU64(resp, 23, entry.size);
|
|
15707
|
+
return resp;
|
|
15708
|
+
}
|
|
15709
|
+
handle_readdir(req, tag) {
|
|
15710
|
+
const dir_id = readU64(req, 7);
|
|
15711
|
+
const entries = FS_ENTRIES.get(dir_id) || [];
|
|
15712
|
+
const encodedNames = entries.map((e) => textEncoder.encode(e.name));
|
|
15713
|
+
let size = 7 + 4 + 4;
|
|
15714
|
+
for (const nameBytes of encodedNames) {
|
|
15715
|
+
size += 8 + 1 + 2 + nameBytes.length;
|
|
15716
|
+
}
|
|
15717
|
+
const resp = makeResp(size, V86FS_MSG_READDIR_R, tag);
|
|
15718
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15719
|
+
packU32(resp, 11, entries.length);
|
|
15720
|
+
let off = 15;
|
|
15721
|
+
for (let i = 0; i < entries.length; i++) {
|
|
15722
|
+
const e = entries[i];
|
|
15723
|
+
const nameBytes = encodedNames[i];
|
|
15724
|
+
packU64(resp, off, e.inode_id);
|
|
15725
|
+
resp[off + 8] = e.dt_type;
|
|
15726
|
+
packU16(resp, off + 9, nameBytes.length);
|
|
15727
|
+
resp.set(nameBytes, off + 11);
|
|
15728
|
+
off += 11 + nameBytes.length;
|
|
15729
|
+
}
|
|
15730
|
+
return resp;
|
|
15731
|
+
}
|
|
15732
|
+
handle_open(req, tag) {
|
|
15733
|
+
const inode_id = readU64(req, 7);
|
|
15734
|
+
const handle_id = this.next_handle_id++;
|
|
15735
|
+
this.open_handles.set(handle_id, inode_id);
|
|
15736
|
+
this.bus.send("virtio-v86fs-open", inode_id);
|
|
15737
|
+
const resp = makeResp(19, V86FS_MSG_OPEN_R, tag);
|
|
15738
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15739
|
+
packU64(resp, 11, handle_id);
|
|
15740
|
+
return resp;
|
|
15741
|
+
}
|
|
15742
|
+
handle_close(req, tag) {
|
|
15743
|
+
const handle_id = readU64(req, 7);
|
|
15744
|
+
this.open_handles.delete(handle_id);
|
|
15745
|
+
this.bus.send("virtio-v86fs-close", handle_id);
|
|
15746
|
+
const resp = makeResp(11, V86FS_MSG_CLOSE_R, tag);
|
|
15747
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15748
|
+
return resp;
|
|
15749
|
+
}
|
|
15750
|
+
handle_read(req, tag) {
|
|
15751
|
+
const handle_id = readU64(req, 7);
|
|
15752
|
+
const offset = readU64(req, 15);
|
|
15753
|
+
const size = readU32(req, 23);
|
|
15754
|
+
const inode_id = this.open_handles.get(handle_id) ?? handle_id;
|
|
15755
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15756
|
+
const content = entry?.content;
|
|
15757
|
+
this.read_count++;
|
|
15758
|
+
this.bus.send("virtio-v86fs-read", {
|
|
15759
|
+
handle_id,
|
|
15760
|
+
inode_id,
|
|
15761
|
+
offset,
|
|
15762
|
+
size
|
|
15763
|
+
});
|
|
15764
|
+
if (!content || offset >= content.length) {
|
|
15765
|
+
const resp2 = makeResp(15, V86FS_MSG_READ_R, tag);
|
|
15766
|
+
packU32(resp2, 7, V86FS_STATUS_OK);
|
|
15767
|
+
packU32(resp2, 11, 0);
|
|
15768
|
+
return resp2;
|
|
15769
|
+
}
|
|
15770
|
+
const start = Math.min(offset, content.length);
|
|
15771
|
+
const end = Math.min(start + size, content.length);
|
|
15772
|
+
const data = content.subarray(start, end);
|
|
15773
|
+
const resp = new Uint8Array(15 + data.length);
|
|
15774
|
+
packU32(resp, 0, 15 + data.length);
|
|
15775
|
+
resp[4] = V86FS_MSG_READ_R;
|
|
15776
|
+
resp[5] = tag & 255;
|
|
15777
|
+
resp[6] = tag >> 8 & 255;
|
|
15778
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15779
|
+
packU32(resp, 11, data.length);
|
|
15780
|
+
resp.set(data, 15);
|
|
15781
|
+
return resp;
|
|
15782
|
+
}
|
|
15783
|
+
handle_create(req, tag) {
|
|
15784
|
+
const parent_id = readU64(req, 7);
|
|
15785
|
+
const name_len = readU16(req, 15);
|
|
15786
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15787
|
+
const mode = readU32(req, 17 + name_len);
|
|
15788
|
+
const inode_id = this.next_inode_id++;
|
|
15789
|
+
const entry = {
|
|
15790
|
+
inode_id,
|
|
15791
|
+
name,
|
|
15792
|
+
mode: mode | S_IFREG,
|
|
15793
|
+
size: 0,
|
|
15794
|
+
dt_type: DT_REG,
|
|
15795
|
+
mtime_sec: Math.floor(Date.now() / 1e3),
|
|
15796
|
+
mtime_nsec: 0,
|
|
15797
|
+
content: new Uint8Array(0)
|
|
15798
|
+
};
|
|
15799
|
+
let children = FS_ENTRIES.get(parent_id);
|
|
15800
|
+
if (!children) {
|
|
15801
|
+
children = [];
|
|
15802
|
+
FS_ENTRIES.set(parent_id, children);
|
|
15803
|
+
}
|
|
15804
|
+
children.push(entry);
|
|
15805
|
+
INODE_MAP.set(inode_id, entry);
|
|
15806
|
+
const resp = makeResp(23, V86FS_MSG_CREATE_R, tag);
|
|
15807
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15808
|
+
packU64(resp, 11, inode_id);
|
|
15809
|
+
packU32(resp, 19, entry.mode);
|
|
15810
|
+
return resp;
|
|
15811
|
+
}
|
|
15812
|
+
handle_write(req, tag) {
|
|
15813
|
+
const inode_id = readU64(req, 7);
|
|
15814
|
+
const offset = readU64(req, 15);
|
|
15815
|
+
const size = readU32(req, 23);
|
|
15816
|
+
const data = req.subarray(27, 27 + size);
|
|
15817
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15818
|
+
if (entry) {
|
|
15819
|
+
const needed = offset + size;
|
|
15820
|
+
if (!entry.content || entry.content.length < needed) {
|
|
15821
|
+
const newContent = new Uint8Array(needed);
|
|
15822
|
+
if (entry.content) {
|
|
15823
|
+
newContent.set(entry.content);
|
|
15824
|
+
}
|
|
15825
|
+
entry.content = newContent;
|
|
15826
|
+
}
|
|
15827
|
+
entry.content.set(data, offset);
|
|
15828
|
+
if (needed > entry.size) {
|
|
15829
|
+
entry.size = needed;
|
|
15830
|
+
}
|
|
15831
|
+
}
|
|
15832
|
+
const resp = makeResp(15, V86FS_MSG_WRITE_R, tag);
|
|
15833
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15834
|
+
packU32(resp, 11, size);
|
|
15835
|
+
return resp;
|
|
15836
|
+
}
|
|
15837
|
+
handle_mkdir(req, tag) {
|
|
15838
|
+
const parent_id = readU64(req, 7);
|
|
15839
|
+
const name_len = readU16(req, 15);
|
|
15840
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15841
|
+
const mode = readU32(req, 17 + name_len);
|
|
15842
|
+
const inode_id = this.next_inode_id++;
|
|
15843
|
+
const entry = {
|
|
15844
|
+
inode_id,
|
|
15845
|
+
name,
|
|
15846
|
+
mode: mode | S_IFDIR,
|
|
15847
|
+
size: 0,
|
|
15848
|
+
dt_type: DT_DIR,
|
|
15849
|
+
mtime_sec: Math.floor(Date.now() / 1e3),
|
|
15850
|
+
mtime_nsec: 0
|
|
15851
|
+
};
|
|
15852
|
+
let children = FS_ENTRIES.get(parent_id);
|
|
15853
|
+
if (!children) {
|
|
15854
|
+
children = [];
|
|
15855
|
+
FS_ENTRIES.set(parent_id, children);
|
|
15856
|
+
}
|
|
15857
|
+
children.push(entry);
|
|
15858
|
+
INODE_MAP.set(inode_id, entry);
|
|
15859
|
+
FS_ENTRIES.set(inode_id, []);
|
|
15860
|
+
const resp = makeResp(23, V86FS_MSG_MKDIR_R, tag);
|
|
15861
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15862
|
+
packU64(resp, 11, inode_id);
|
|
15863
|
+
packU32(resp, 19, entry.mode);
|
|
15864
|
+
return resp;
|
|
15865
|
+
}
|
|
15866
|
+
handle_setattr(req, tag) {
|
|
15867
|
+
const inode_id = readU64(req, 7);
|
|
15868
|
+
const valid = readU32(req, 15);
|
|
15869
|
+
const mode = readU32(req, 19);
|
|
15870
|
+
const size = readU64(req, 23);
|
|
15871
|
+
const entry = INODE_MAP.get(inode_id);
|
|
15872
|
+
if (entry) {
|
|
15873
|
+
if (valid & ATTR_MODE) {
|
|
15874
|
+
entry.mode = entry.mode & 61440 | mode & 4095;
|
|
15875
|
+
}
|
|
15876
|
+
if (valid & ATTR_SIZE) {
|
|
15877
|
+
entry.size = size;
|
|
15878
|
+
if (entry.content) {
|
|
15879
|
+
if (size === 0) {
|
|
15880
|
+
entry.content = new Uint8Array(0);
|
|
15881
|
+
} else if (size < entry.content.length) {
|
|
15882
|
+
entry.content = entry.content.subarray(0, size);
|
|
15883
|
+
}
|
|
15884
|
+
}
|
|
15885
|
+
}
|
|
15886
|
+
}
|
|
15887
|
+
const resp = makeResp(11, V86FS_MSG_SETATTR_R, tag);
|
|
15888
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15889
|
+
return resp;
|
|
15890
|
+
}
|
|
15891
|
+
handle_fsync(req, tag) {
|
|
15892
|
+
const resp = makeResp(11, V86FS_MSG_FSYNC_R, tag);
|
|
15893
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15894
|
+
return resp;
|
|
15895
|
+
}
|
|
15896
|
+
handle_unlink(req, tag) {
|
|
15897
|
+
const parent_id = readU64(req, 7);
|
|
15898
|
+
const name_len = readU16(req, 15);
|
|
15899
|
+
const name = textDecoder.decode(req.subarray(17, 17 + name_len));
|
|
15900
|
+
const children = FS_ENTRIES.get(parent_id);
|
|
15901
|
+
let status = V86FS_STATUS_ENOENT;
|
|
15902
|
+
if (children) {
|
|
15903
|
+
const idx = children.findIndex((e) => e.name === name);
|
|
15904
|
+
if (idx >= 0) {
|
|
15905
|
+
const entry = children[idx];
|
|
15906
|
+
INODE_MAP.delete(entry.inode_id);
|
|
15907
|
+
FS_ENTRIES.delete(entry.inode_id);
|
|
15908
|
+
children.splice(idx, 1);
|
|
15909
|
+
status = V86FS_STATUS_OK;
|
|
15910
|
+
}
|
|
15911
|
+
}
|
|
15912
|
+
const resp = makeResp(11, V86FS_MSG_UNLINK_R, tag);
|
|
15913
|
+
packU32(resp, 7, status);
|
|
15914
|
+
return resp;
|
|
15915
|
+
}
|
|
15916
|
+
handle_rename(req, tag) {
|
|
15917
|
+
let off = 7;
|
|
15918
|
+
const old_parent_id = readU64(req, off);
|
|
15919
|
+
off += 8;
|
|
15920
|
+
const old_name_len = readU16(req, off);
|
|
15921
|
+
off += 2;
|
|
15922
|
+
const old_name = textDecoder.decode(
|
|
15923
|
+
req.subarray(off, off + old_name_len)
|
|
15924
|
+
);
|
|
15925
|
+
off += old_name_len;
|
|
15926
|
+
const new_parent_id = readU64(req, off);
|
|
15927
|
+
off += 8;
|
|
15928
|
+
const new_name_len = readU16(req, off);
|
|
15929
|
+
off += 2;
|
|
15930
|
+
const new_name = textDecoder.decode(
|
|
15931
|
+
req.subarray(off, off + new_name_len)
|
|
15932
|
+
);
|
|
15933
|
+
let status = V86FS_STATUS_ENOENT;
|
|
15934
|
+
const old_children = FS_ENTRIES.get(old_parent_id);
|
|
15935
|
+
if (old_children) {
|
|
15936
|
+
const idx = old_children.findIndex((e) => e.name === old_name);
|
|
15937
|
+
if (idx >= 0) {
|
|
15938
|
+
const entry = old_children[idx];
|
|
15939
|
+
old_children.splice(idx, 1);
|
|
15940
|
+
entry.name = new_name;
|
|
15941
|
+
let new_children = FS_ENTRIES.get(new_parent_id);
|
|
15942
|
+
if (!new_children) {
|
|
15943
|
+
new_children = [];
|
|
15944
|
+
FS_ENTRIES.set(new_parent_id, new_children);
|
|
15945
|
+
}
|
|
15946
|
+
const existing = new_children.findIndex(
|
|
15947
|
+
(e) => e.name === new_name
|
|
15948
|
+
);
|
|
15949
|
+
if (existing >= 0) {
|
|
15950
|
+
const old_entry = new_children[existing];
|
|
15951
|
+
INODE_MAP.delete(old_entry.inode_id);
|
|
15952
|
+
new_children.splice(existing, 1);
|
|
15953
|
+
}
|
|
15954
|
+
new_children.push(entry);
|
|
15955
|
+
status = V86FS_STATUS_OK;
|
|
15956
|
+
}
|
|
15957
|
+
}
|
|
15958
|
+
const resp = makeResp(11, V86FS_MSG_RENAME_R, tag);
|
|
15959
|
+
packU32(resp, 7, status);
|
|
15960
|
+
return resp;
|
|
15961
|
+
}
|
|
15962
|
+
handle_symlink(req, tag) {
|
|
15963
|
+
let off = 7;
|
|
15964
|
+
const parent_id = readU64(req, off);
|
|
15965
|
+
off += 8;
|
|
15966
|
+
const name_len = readU16(req, off);
|
|
15967
|
+
off += 2;
|
|
15968
|
+
const name = textDecoder.decode(req.subarray(off, off + name_len));
|
|
15969
|
+
off += name_len;
|
|
15970
|
+
const target_len = readU16(req, off);
|
|
15971
|
+
off += 2;
|
|
15972
|
+
const target = textDecoder.decode(req.subarray(off, off + target_len));
|
|
15973
|
+
const inode_id = this.next_inode_id++;
|
|
15974
|
+
const entry = {
|
|
15975
|
+
inode_id,
|
|
15976
|
+
name,
|
|
15977
|
+
mode: S_IFLNK | 511,
|
|
15978
|
+
size: target.length,
|
|
15979
|
+
dt_type: DT_LNK,
|
|
15980
|
+
mtime_sec: Math.floor(Date.now() / 1e3),
|
|
15981
|
+
mtime_nsec: 0,
|
|
15982
|
+
symlink_target: target
|
|
15983
|
+
};
|
|
15984
|
+
let children = FS_ENTRIES.get(parent_id);
|
|
15985
|
+
if (!children) {
|
|
15986
|
+
children = [];
|
|
15987
|
+
FS_ENTRIES.set(parent_id, children);
|
|
15988
|
+
}
|
|
15989
|
+
children.push(entry);
|
|
15990
|
+
INODE_MAP.set(inode_id, entry);
|
|
15991
|
+
const resp = makeResp(23, V86FS_MSG_SYMLINK_R, tag);
|
|
15992
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
15993
|
+
packU64(resp, 11, inode_id);
|
|
15994
|
+
packU32(resp, 19, entry.mode);
|
|
15995
|
+
return resp;
|
|
15996
|
+
}
|
|
15997
|
+
handle_readlink(req, tag) {
|
|
15998
|
+
const inode_id = readU64(req, 7);
|
|
15999
|
+
const entry = INODE_MAP.get(inode_id);
|
|
16000
|
+
if (!entry || !entry.symlink_target) {
|
|
16001
|
+
const resp2 = makeResp(11, V86FS_MSG_READLINK_R, tag);
|
|
16002
|
+
packU32(resp2, 7, V86FS_STATUS_ENOENT);
|
|
16003
|
+
return resp2;
|
|
16004
|
+
}
|
|
16005
|
+
const target_bytes = textEncoder.encode(entry.symlink_target);
|
|
16006
|
+
const resp_len = 11 + 2 + target_bytes.length;
|
|
16007
|
+
const resp = makeResp(resp_len, V86FS_MSG_READLINK_R, tag);
|
|
16008
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
16009
|
+
packU16(resp, 11, target_bytes.length);
|
|
16010
|
+
resp.set(target_bytes, 13);
|
|
16011
|
+
return resp;
|
|
16012
|
+
}
|
|
16013
|
+
handle_statfs(tag) {
|
|
16014
|
+
const resp = makeResp(55, V86FS_MSG_STATFS_R, tag);
|
|
16015
|
+
packU32(resp, 7, V86FS_STATUS_OK);
|
|
16016
|
+
packU64(resp, 11, 1024 * 1024);
|
|
16017
|
+
packU64(resp, 19, 512 * 1024);
|
|
16018
|
+
packU64(resp, 27, 512 * 1024);
|
|
16019
|
+
packU64(resp, 35, 1024 * 1024);
|
|
16020
|
+
packU64(resp, 43, 512 * 1024);
|
|
16021
|
+
packU32(resp, 51, 4096);
|
|
16022
|
+
return resp;
|
|
16023
|
+
}
|
|
16024
|
+
/** Push an INVALIDATE notification to the guest via notifyq.
|
|
16025
|
+
* Guest kernel will invalidate page cache for the given inode. */
|
|
16026
|
+
invalidate_inode(inode_id) {
|
|
16027
|
+
const queue = this.virtio.queues[2];
|
|
16028
|
+
if (!queue.has_request()) return false;
|
|
16029
|
+
const bufchain = queue.pop_request();
|
|
16030
|
+
const msg = new Uint8Array(15);
|
|
16031
|
+
packU32(msg, 0, 15);
|
|
16032
|
+
msg[4] = V86FS_MSG_INVALIDATE;
|
|
16033
|
+
packU16(msg, 5, 0);
|
|
16034
|
+
packU64(msg, 7, inode_id);
|
|
16035
|
+
bufchain.set_next_blob(msg);
|
|
16036
|
+
queue.push_reply(bufchain);
|
|
16037
|
+
queue.flush_replies();
|
|
16038
|
+
return true;
|
|
16039
|
+
}
|
|
16040
|
+
/** Push an INVALIDATE_DIR notification to the guest via notifyq.
|
|
16041
|
+
* Guest kernel will invalidate dcache for the given directory inode. */
|
|
16042
|
+
invalidate_dir(inode_id) {
|
|
16043
|
+
const queue = this.virtio.queues[2];
|
|
16044
|
+
if (!queue.has_request()) return false;
|
|
16045
|
+
const bufchain = queue.pop_request();
|
|
16046
|
+
const msg = new Uint8Array(15);
|
|
16047
|
+
packU32(msg, 0, 15);
|
|
16048
|
+
msg[4] = V86FS_MSG_INVALIDATE_DIR;
|
|
16049
|
+
packU16(msg, 5, 0);
|
|
16050
|
+
packU64(msg, 7, inode_id);
|
|
16051
|
+
bufchain.set_next_blob(msg);
|
|
16052
|
+
queue.push_reply(bufchain);
|
|
16053
|
+
queue.flush_replies();
|
|
16054
|
+
return true;
|
|
16055
|
+
}
|
|
16056
|
+
get_state() {
|
|
16057
|
+
const state = [];
|
|
16058
|
+
state[0] = this.virtio;
|
|
16059
|
+
return state;
|
|
16060
|
+
}
|
|
16061
|
+
set_state(state) {
|
|
16062
|
+
this.virtio.set_state(state[0]);
|
|
16063
|
+
}
|
|
16064
|
+
};
|
|
16065
|
+
|
|
15141
16066
|
// lib/filesystem.ts
|
|
15142
16067
|
var S_IFMT = 61440;
|
|
15143
16068
|
var S_IFSOCK = 49152;
|
|
15144
|
-
var
|
|
15145
|
-
var
|
|
15146
|
-
var
|
|
16069
|
+
var S_IFLNK2 = 40960;
|
|
16070
|
+
var S_IFREG2 = 32768;
|
|
16071
|
+
var S_IFDIR2 = 16384;
|
|
15147
16072
|
var STATUS_INVALID = -1;
|
|
15148
16073
|
var STATUS_OK = 0;
|
|
15149
16074
|
var STATUS_ON_STORAGE = 2;
|
|
@@ -15236,11 +16161,11 @@ var V86Starter = (() => {
|
|
|
15236
16161
|
get_state() {
|
|
15237
16162
|
const state = [];
|
|
15238
16163
|
state[0] = this.mode;
|
|
15239
|
-
if ((this.mode & S_IFMT) ===
|
|
16164
|
+
if ((this.mode & S_IFMT) === S_IFDIR2) {
|
|
15240
16165
|
state[1] = [...this.direntries];
|
|
15241
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16166
|
+
} else if ((this.mode & S_IFMT) === S_IFREG2) {
|
|
15242
16167
|
state[1] = this.sha256sum;
|
|
15243
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16168
|
+
} else if ((this.mode & S_IFMT) === S_IFLNK2) {
|
|
15244
16169
|
state[1] = this.symlink;
|
|
15245
16170
|
} else if ((this.mode & S_IFMT) === S_IFSOCK) {
|
|
15246
16171
|
state[1] = [this.minor, this.major];
|
|
@@ -15263,14 +16188,14 @@ var V86Starter = (() => {
|
|
|
15263
16188
|
}
|
|
15264
16189
|
set_state(state) {
|
|
15265
16190
|
this.mode = state[0];
|
|
15266
|
-
if ((this.mode & S_IFMT) ===
|
|
16191
|
+
if ((this.mode & S_IFMT) === S_IFDIR2) {
|
|
15267
16192
|
this.direntries = /* @__PURE__ */ new Map();
|
|
15268
16193
|
for (const [name, entry] of state[1]) {
|
|
15269
16194
|
this.direntries.set(name, entry);
|
|
15270
16195
|
}
|
|
15271
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16196
|
+
} else if ((this.mode & S_IFMT) === S_IFREG2) {
|
|
15272
16197
|
this.sha256sum = state[1];
|
|
15273
|
-
} else if ((this.mode & S_IFMT) ===
|
|
16198
|
+
} else if ((this.mode & S_IFMT) === S_IFLNK2) {
|
|
15274
16199
|
this.symlink = state[1];
|
|
15275
16200
|
} else if ((this.mode & S_IFMT) === S_IFSOCK) {
|
|
15276
16201
|
;
|
|
@@ -15339,7 +16264,7 @@ var V86Starter = (() => {
|
|
|
15339
16264
|
state[1] = this.qidcounter.last_qidnumber;
|
|
15340
16265
|
state[2] = [];
|
|
15341
16266
|
for (const [id, data] of Object.entries(this.inodedata)) {
|
|
15342
|
-
if ((this.inodes[Number(id)].mode &
|
|
16267
|
+
if ((this.inodes[Number(id)].mode & S_IFDIR2) === 0) {
|
|
15343
16268
|
state[2].push([id, data]);
|
|
15344
16269
|
}
|
|
15345
16270
|
}
|
|
@@ -15390,15 +16315,15 @@ var V86Starter = (() => {
|
|
|
15390
16315
|
inode.uid = data[JSONFS_IDX_UID];
|
|
15391
16316
|
inode.gid = data[JSONFS_IDX_GID];
|
|
15392
16317
|
const ifmt = inode.mode & S_IFMT;
|
|
15393
|
-
if (ifmt ===
|
|
16318
|
+
if (ifmt === S_IFDIR2) {
|
|
15394
16319
|
this.PushInode(inode, parentid, name);
|
|
15395
16320
|
this.LoadDir(this.inodes.length - 1, data[JSONFS_IDX_TARGET]);
|
|
15396
|
-
} else if (ifmt ===
|
|
16321
|
+
} else if (ifmt === S_IFREG2) {
|
|
15397
16322
|
inode.status = STATUS_ON_STORAGE;
|
|
15398
16323
|
inode.sha256sum = data[JSONFS_IDX_SHA256];
|
|
15399
16324
|
dbg_assert(!!inode.sha256sum);
|
|
15400
16325
|
this.PushInode(inode, parentid, name);
|
|
15401
|
-
} else if (ifmt ===
|
|
16326
|
+
} else if (ifmt === S_IFLNK2) {
|
|
15402
16327
|
inode.symlink = data[JSONFS_IDX_TARGET];
|
|
15403
16328
|
this.PushInode(inode, parentid, name);
|
|
15404
16329
|
} else if (ifmt === S_IFSOCK) {
|
|
@@ -15570,13 +16495,13 @@ var V86Starter = (() => {
|
|
|
15570
16495
|
return this.create_forwarder(parent_inode.mount_id, foreign_id);
|
|
15571
16496
|
}
|
|
15572
16497
|
const x = this.CreateInode();
|
|
15573
|
-
x.mode = 511 |
|
|
16498
|
+
x.mode = 511 | S_IFDIR2;
|
|
15574
16499
|
if (parentid >= 0) {
|
|
15575
16500
|
x.uid = this.inodes[parentid].uid;
|
|
15576
16501
|
x.gid = this.inodes[parentid].gid;
|
|
15577
|
-
x.mode = this.inodes[parentid].mode & 511 |
|
|
16502
|
+
x.mode = this.inodes[parentid].mode & 511 | S_IFDIR2;
|
|
15578
16503
|
}
|
|
15579
|
-
x.qid.type =
|
|
16504
|
+
x.qid.type = S_IFDIR2 >> 8;
|
|
15580
16505
|
this.PushInode(x, parentid, name);
|
|
15581
16506
|
this.NotifyListeners(this.inodes.length - 1, "newdir");
|
|
15582
16507
|
return this.inodes.length - 1;
|
|
@@ -15594,8 +16519,8 @@ var V86Starter = (() => {
|
|
|
15594
16519
|
const x = this.CreateInode();
|
|
15595
16520
|
x.uid = this.inodes[parentid].uid;
|
|
15596
16521
|
x.gid = this.inodes[parentid].gid;
|
|
15597
|
-
x.qid.type =
|
|
15598
|
-
x.mode = this.inodes[parentid].mode & 438 |
|
|
16522
|
+
x.qid.type = S_IFREG2 >> 8;
|
|
16523
|
+
x.mode = this.inodes[parentid].mode & 438 | S_IFREG2;
|
|
15599
16524
|
this.PushInode(x, parentid, filename);
|
|
15600
16525
|
this.NotifyListeners(this.inodes.length - 1, "newfile");
|
|
15601
16526
|
return this.inodes.length - 1;
|
|
@@ -15636,9 +16561,9 @@ var V86Starter = (() => {
|
|
|
15636
16561
|
const x = this.CreateInode();
|
|
15637
16562
|
x.uid = this.inodes[parentid].uid;
|
|
15638
16563
|
x.gid = this.inodes[parentid].gid;
|
|
15639
|
-
x.qid.type =
|
|
16564
|
+
x.qid.type = S_IFLNK2 >> 8;
|
|
15640
16565
|
x.symlink = symlink;
|
|
15641
|
-
x.mode =
|
|
16566
|
+
x.mode = S_IFLNK2;
|
|
15642
16567
|
this.PushInode(x, parentid, filename);
|
|
15643
16568
|
return this.inodes.length - 1;
|
|
15644
16569
|
}
|
|
@@ -15683,7 +16608,7 @@ var V86Starter = (() => {
|
|
|
15683
16608
|
if (this.is_forwarder(inode)) {
|
|
15684
16609
|
return await this.follow_fs(inode).OpenInode(inode.foreign_id, mode);
|
|
15685
16610
|
}
|
|
15686
|
-
if ((inode.mode & S_IFMT) ===
|
|
16611
|
+
if ((inode.mode & S_IFMT) === S_IFDIR2) {
|
|
15687
16612
|
this.FillDirectory(id);
|
|
15688
16613
|
}
|
|
15689
16614
|
}
|
|
@@ -16038,7 +16963,7 @@ var V86Starter = (() => {
|
|
|
16038
16963
|
let parentid = -1;
|
|
16039
16964
|
let id = 0;
|
|
16040
16965
|
let forward_path = null;
|
|
16041
|
-
let i
|
|
16966
|
+
let i;
|
|
16042
16967
|
for (i = 0; i < n; i++) {
|
|
16043
16968
|
parentid = id;
|
|
16044
16969
|
id = this.Search(parentid, walk[i]);
|
|
@@ -16104,13 +17029,13 @@ var V86Starter = (() => {
|
|
|
16104
17029
|
DeleteNode(path) {
|
|
16105
17030
|
const ids = this.SearchPath(path);
|
|
16106
17031
|
if (ids.id === -1) return;
|
|
16107
|
-
if ((this.inodes[ids.id].mode & S_IFMT) ===
|
|
17032
|
+
if ((this.inodes[ids.id].mode & S_IFMT) === S_IFREG2) {
|
|
16108
17033
|
const ret = this.Unlink(ids.parentid, ids.name);
|
|
16109
17034
|
dbg_assert(
|
|
16110
17035
|
ret === 0,
|
|
16111
17036
|
"Filesystem DeleteNode failed with error code: " + -ret
|
|
16112
17037
|
);
|
|
16113
|
-
} else if ((this.inodes[ids.id].mode & S_IFMT) ===
|
|
17038
|
+
} else if ((this.inodes[ids.id].mode & S_IFMT) === S_IFDIR2) {
|
|
16114
17039
|
this.RecursiveDelete(path);
|
|
16115
17040
|
const ret = this.Unlink(ids.parentid, ids.name);
|
|
16116
17041
|
dbg_assert(
|
|
@@ -16214,7 +17139,7 @@ var V86Starter = (() => {
|
|
|
16214
17139
|
if (this.is_forwarder(inode)) {
|
|
16215
17140
|
return this.follow_fs(inode).IsDirectory(inode.foreign_id);
|
|
16216
17141
|
}
|
|
16217
|
-
return (inode.mode & S_IFMT) ===
|
|
17142
|
+
return (inode.mode & S_IFMT) === S_IFDIR2;
|
|
16218
17143
|
}
|
|
16219
17144
|
IsEmpty(idx) {
|
|
16220
17145
|
const inode = this.inodes[idx];
|
|
@@ -16744,7 +17669,7 @@ var V86Starter = (() => {
|
|
|
16744
17669
|
bufchain.get_next_blob(buffer);
|
|
16745
17670
|
const state = { offset: 0 };
|
|
16746
17671
|
const header = Unmarshall(["w", "b", "h"], buffer, state);
|
|
16747
|
-
let size
|
|
17672
|
+
let size;
|
|
16748
17673
|
const id = header[1];
|
|
16749
17674
|
const tag = header[2];
|
|
16750
17675
|
switch (id) {
|
|
@@ -16805,7 +17730,7 @@ var V86Starter = (() => {
|
|
|
16805
17730
|
name
|
|
16806
17731
|
);
|
|
16807
17732
|
if (ret < 0) {
|
|
16808
|
-
let error_message
|
|
17733
|
+
let error_message;
|
|
16809
17734
|
if (ret === -EPERM)
|
|
16810
17735
|
error_message = "Operation not permitted";
|
|
16811
17736
|
else {
|
|
@@ -16918,7 +17843,7 @@ var V86Starter = (() => {
|
|
|
16918
17843
|
this.fids[fid].inodeid
|
|
16919
17844
|
);
|
|
16920
17845
|
const inode = this.fs.GetInode(idx);
|
|
16921
|
-
inode.mode = mode |
|
|
17846
|
+
inode.mode = mode | S_IFDIR2;
|
|
16922
17847
|
inode.uid = this.fids[fid].uid;
|
|
16923
17848
|
inode.gid = gid;
|
|
16924
17849
|
Marshall(["Q"], [inode.qid], this.replybuffer, 7);
|
|
@@ -16949,7 +17874,7 @@ var V86Starter = (() => {
|
|
|
16949
17874
|
const inode = this.fs.GetInode(idx);
|
|
16950
17875
|
inode.uid = this.fids[fid].uid;
|
|
16951
17876
|
inode.gid = gid;
|
|
16952
|
-
inode.mode = mode |
|
|
17877
|
+
inode.mode = mode | S_IFREG2;
|
|
16953
17878
|
Marshall(
|
|
16954
17879
|
["Q", "w"],
|
|
16955
17880
|
[inode.qid, this.msize - 24],
|
|
@@ -17274,7 +18199,7 @@ var V86Starter = (() => {
|
|
|
17274
18199
|
newname
|
|
17275
18200
|
);
|
|
17276
18201
|
if (ret < 0) {
|
|
17277
|
-
let error_message
|
|
18202
|
+
let error_message;
|
|
17278
18203
|
if (ret === -ENOENT)
|
|
17279
18204
|
error_message = "No such file or directory";
|
|
17280
18205
|
else if (ret === -EPERM)
|
|
@@ -17323,7 +18248,7 @@ var V86Starter = (() => {
|
|
|
17323
18248
|
}
|
|
17324
18249
|
const ret = this.fs.Unlink(this.fids[dirfd].inodeid, name);
|
|
17325
18250
|
if (ret < 0) {
|
|
17326
|
-
let error_message
|
|
18251
|
+
let error_message;
|
|
17327
18252
|
if (ret === -ENOTEMPTY)
|
|
17328
18253
|
error_message = "Directory not empty";
|
|
17329
18254
|
else if (ret === -EPERM)
|
|
@@ -17897,6 +18822,7 @@ var V86Starter = (() => {
|
|
|
17897
18822
|
wasm_memory;
|
|
17898
18823
|
memory_size;
|
|
17899
18824
|
mem8;
|
|
18825
|
+
mem8_offset = 0;
|
|
17900
18826
|
mem32s;
|
|
17901
18827
|
segment_is_null;
|
|
17902
18828
|
segment_offsets;
|
|
@@ -17975,7 +18901,6 @@ var V86Starter = (() => {
|
|
|
17975
18901
|
get_eflags;
|
|
17976
18902
|
handle_irqs;
|
|
17977
18903
|
main_loop;
|
|
17978
|
-
reboot_internal;
|
|
17979
18904
|
set_jit_config;
|
|
17980
18905
|
read8;
|
|
17981
18906
|
read16;
|
|
@@ -18024,13 +18949,49 @@ var V86Starter = (() => {
|
|
|
18024
18949
|
this.name = "cpu";
|
|
18025
18950
|
this.stop_idling = stop_idling;
|
|
18026
18951
|
this.wm = wm;
|
|
18952
|
+
this.wasm_memory = wm.wasm_memory;
|
|
18027
18953
|
this.wasm_patch();
|
|
18028
18954
|
this.create_jit_imports();
|
|
18029
|
-
const memory = this.wm.exports["memory"];
|
|
18030
|
-
this.wasm_memory = memory;
|
|
18031
|
-
this.memory_size = view(Uint32Array, memory, 812, 1);
|
|
18032
18955
|
this.mem8 = new Uint8Array(0);
|
|
18033
18956
|
this.mem32s = new Int32Array(this.mem8.buffer);
|
|
18957
|
+
this.rebuild_wasm_views();
|
|
18958
|
+
this.devices = {};
|
|
18959
|
+
this.memory_map_read8 = [];
|
|
18960
|
+
this.memory_map_write8 = [];
|
|
18961
|
+
this.memory_map_read32 = [];
|
|
18962
|
+
this.memory_map_write32 = [];
|
|
18963
|
+
this.bios = {
|
|
18964
|
+
main: null,
|
|
18965
|
+
vga: null
|
|
18966
|
+
};
|
|
18967
|
+
this.fpu_stack_empty[0] = 255;
|
|
18968
|
+
this.fpu_stack_ptr[0] = 0;
|
|
18969
|
+
this.fpu_control_word[0] = 895;
|
|
18970
|
+
this.fpu_status_word[0] = 0;
|
|
18971
|
+
this.fpu_ip[0] = 0;
|
|
18972
|
+
this.fpu_ip_selector[0] = 0;
|
|
18973
|
+
this.fpu_opcode[0] = 0;
|
|
18974
|
+
this.fpu_dp[0] = 0;
|
|
18975
|
+
this.fpu_dp_selector[0] = 0;
|
|
18976
|
+
this.fw_value = [];
|
|
18977
|
+
this.fw_pointer = 0;
|
|
18978
|
+
this.option_roms = [];
|
|
18979
|
+
this.io = void 0;
|
|
18980
|
+
this.bus = bus;
|
|
18981
|
+
this.set_tsc(0, 0);
|
|
18982
|
+
if (false) {
|
|
18983
|
+
this.seen_code = {};
|
|
18984
|
+
this.seen_code_uncompiled = {};
|
|
18985
|
+
}
|
|
18986
|
+
}
|
|
18987
|
+
/**
|
|
18988
|
+
* Rebuild all TypedArray views into WASM linear memory.
|
|
18989
|
+
* Must be called after any wasm_memory.grow() since growth
|
|
18990
|
+
* detaches the old ArrayBuffer, invalidating all views.
|
|
18991
|
+
*/
|
|
18992
|
+
rebuild_wasm_views() {
|
|
18993
|
+
const memory = this.wasm_memory;
|
|
18994
|
+
this.memory_size = view(Uint32Array, memory, 812, 1);
|
|
18034
18995
|
this.segment_is_null = view(Uint8Array, memory, 724, 8);
|
|
18035
18996
|
this.segment_offsets = view(Int32Array, memory, 736, 8);
|
|
18036
18997
|
this.segment_limits = view(Uint32Array, memory, 768, 8);
|
|
@@ -18059,40 +19020,22 @@ var V86Starter = (() => {
|
|
|
18059
19020
|
this.last_op1 = view(Int32Array, memory, 104, 1);
|
|
18060
19021
|
this.last_result = view(Int32Array, memory, 112, 1);
|
|
18061
19022
|
this.current_tsc = view(Uint32Array, memory, 960, 2);
|
|
18062
|
-
this.devices = {};
|
|
18063
19023
|
this.instruction_pointer = view(Int32Array, memory, 556, 1);
|
|
18064
19024
|
this.previous_ip = view(Int32Array, memory, 560, 1);
|
|
18065
19025
|
this.apic_enabled = view(Uint8Array, memory, 548, 1);
|
|
18066
19026
|
this.acpi_enabled = view(Uint8Array, memory, 552, 1);
|
|
18067
|
-
this.memory_map_read8 = [];
|
|
18068
|
-
this.memory_map_write8 = [];
|
|
18069
|
-
this.memory_map_read32 = [];
|
|
18070
|
-
this.memory_map_write32 = [];
|
|
18071
|
-
this.bios = {
|
|
18072
|
-
main: null,
|
|
18073
|
-
vga: null
|
|
18074
|
-
};
|
|
18075
19027
|
this.instruction_counter = view(Uint32Array, memory, 664, 1);
|
|
18076
19028
|
this.reg32 = view(Int32Array, memory, 64, 8);
|
|
18077
19029
|
this.fpu_st = view(Int32Array, memory, 1152, 4 * 8);
|
|
18078
19030
|
this.fpu_stack_empty = view(Uint8Array, memory, 816, 1);
|
|
18079
|
-
this.fpu_stack_empty[0] = 255;
|
|
18080
19031
|
this.fpu_stack_ptr = view(Uint8Array, memory, 1032, 1);
|
|
18081
|
-
this.fpu_stack_ptr[0] = 0;
|
|
18082
19032
|
this.fpu_control_word = view(Uint16Array, memory, 1036, 1);
|
|
18083
|
-
this.fpu_control_word[0] = 895;
|
|
18084
19033
|
this.fpu_status_word = view(Uint16Array, memory, 1040, 1);
|
|
18085
|
-
this.fpu_status_word[0] = 0;
|
|
18086
19034
|
this.fpu_ip = view(Int32Array, memory, 1048, 1);
|
|
18087
|
-
this.fpu_ip[0] = 0;
|
|
18088
19035
|
this.fpu_ip_selector = view(Int32Array, memory, 1052, 1);
|
|
18089
|
-
this.fpu_ip_selector[0] = 0;
|
|
18090
19036
|
this.fpu_opcode = view(Int32Array, memory, 1044, 1);
|
|
18091
|
-
this.fpu_opcode[0] = 0;
|
|
18092
19037
|
this.fpu_dp = view(Int32Array, memory, 1056, 1);
|
|
18093
|
-
this.fpu_dp[0] = 0;
|
|
18094
19038
|
this.fpu_dp_selector = view(Int32Array, memory, 1060, 1);
|
|
18095
|
-
this.fpu_dp_selector[0] = 0;
|
|
18096
19039
|
this.reg_xmm32s = view(Int32Array, memory, 832, 8 * 4);
|
|
18097
19040
|
this.mxcsr = view(Int32Array, memory, 824, 1);
|
|
18098
19041
|
this.sreg = view(Uint16Array, memory, 668, 8);
|
|
@@ -18100,16 +19043,6 @@ var V86Starter = (() => {
|
|
|
18100
19043
|
this.reg_pdpte = view(Int32Array, memory, 968, 8);
|
|
18101
19044
|
this.svga_dirty_bitmap_min_offset = view(Uint32Array, memory, 716, 1);
|
|
18102
19045
|
this.svga_dirty_bitmap_max_offset = view(Uint32Array, memory, 720, 1);
|
|
18103
|
-
this.fw_value = [];
|
|
18104
|
-
this.fw_pointer = 0;
|
|
18105
|
-
this.option_roms = [];
|
|
18106
|
-
this.io = void 0;
|
|
18107
|
-
this.bus = bus;
|
|
18108
|
-
this.set_tsc(0, 0);
|
|
18109
|
-
if (false) {
|
|
18110
|
-
this.seen_code = {};
|
|
18111
|
-
this.seen_code_uncompiled = {};
|
|
18112
|
-
}
|
|
18113
19046
|
}
|
|
18114
19047
|
mmap_read8(addr) {
|
|
18115
19048
|
const value = this.memory_map_read8[addr >>> MMAP_BLOCK_BITS](addr);
|
|
@@ -18172,7 +19105,7 @@ var V86Starter = (() => {
|
|
|
18172
19105
|
}
|
|
18173
19106
|
create_jit_imports() {
|
|
18174
19107
|
const jit_imports = /* @__PURE__ */ Object.create(null);
|
|
18175
|
-
jit_imports["m"] = this.
|
|
19108
|
+
jit_imports["m"] = this.wasm_memory;
|
|
18176
19109
|
for (const name of Object.keys(this.wm.exports)) {
|
|
18177
19110
|
if (name.startsWith("_") || name.startsWith("zstd") || name.endsWith("_js")) {
|
|
18178
19111
|
continue;
|
|
@@ -18193,7 +19126,6 @@ var V86Starter = (() => {
|
|
|
18193
19126
|
this.get_eflags = get_import("get_eflags");
|
|
18194
19127
|
this.handle_irqs = get_import("handle_irqs");
|
|
18195
19128
|
this.main_loop = get_import("main_loop");
|
|
18196
|
-
this.reboot_internal = get_import("reboot_internal");
|
|
18197
19129
|
this.set_jit_config = get_import("set_jit_config");
|
|
18198
19130
|
this.read8 = get_import("read8");
|
|
18199
19131
|
this.read16 = get_import("read16");
|
|
@@ -18350,6 +19282,8 @@ var V86Starter = (() => {
|
|
|
18350
19282
|
state[86] = this.last_result;
|
|
18351
19283
|
state[87] = this.fpu_status_word;
|
|
18352
19284
|
state[88] = this.mxcsr;
|
|
19285
|
+
state[89] = this.devices.virtio_mem;
|
|
19286
|
+
state[90] = this.devices.virtio_v86fs;
|
|
18353
19287
|
return state;
|
|
18354
19288
|
}
|
|
18355
19289
|
get_state_pic() {
|
|
@@ -18410,8 +19344,33 @@ var V86Starter = (() => {
|
|
|
18410
19344
|
IOAPIC_STRUCT_SIZE
|
|
18411
19345
|
);
|
|
18412
19346
|
}
|
|
19347
|
+
resize_memory(new_size) {
|
|
19348
|
+
const mem8_offset = this.mem8_offset;
|
|
19349
|
+
const needed_total = mem8_offset + new_size;
|
|
19350
|
+
const current_buffer = this.wasm_memory.buffer.byteLength;
|
|
19351
|
+
if (needed_total > current_buffer) {
|
|
19352
|
+
const grow_pages = Math.ceil(
|
|
19353
|
+
(needed_total - current_buffer) / WASM_PAGE_SIZE
|
|
19354
|
+
);
|
|
19355
|
+
this.wasm_memory.grow(grow_pages);
|
|
19356
|
+
this.rebuild_wasm_views();
|
|
19357
|
+
}
|
|
19358
|
+
this.mem8 = view(Uint8Array, this.wasm_memory, mem8_offset, new_size);
|
|
19359
|
+
this.mem32s = view(
|
|
19360
|
+
Int32Array,
|
|
19361
|
+
this.wasm_memory,
|
|
19362
|
+
mem8_offset,
|
|
19363
|
+
new_size >> 2
|
|
19364
|
+
);
|
|
19365
|
+
this.memory_size[0] = new_size;
|
|
19366
|
+
}
|
|
18413
19367
|
set_state(state) {
|
|
18414
|
-
|
|
19368
|
+
const saved_memory_size = state[0];
|
|
19369
|
+
if (saved_memory_size > this.memory_size[0]) {
|
|
19370
|
+
this.resize_memory(saved_memory_size);
|
|
19371
|
+
} else {
|
|
19372
|
+
this.memory_size[0] = saved_memory_size;
|
|
19373
|
+
}
|
|
18415
19374
|
if (this.mem8.length !== this.memory_size[0]) {
|
|
18416
19375
|
console.warn(
|
|
18417
19376
|
"Note: Memory size mismatch. we=" + this.mem8.length + " state=" + this.memory_size[0]
|
|
@@ -18509,6 +19468,10 @@ var V86Starter = (() => {
|
|
|
18509
19468
|
this.devices.virtio_net.set_state(state[83]);
|
|
18510
19469
|
if (this.devices.virtio_balloon)
|
|
18511
19470
|
this.devices.virtio_balloon.set_state(state[84]);
|
|
19471
|
+
if (this.devices.virtio_mem && state[89])
|
|
19472
|
+
this.devices.virtio_mem.set_state(state[89]);
|
|
19473
|
+
if (this.devices.virtio_v86fs && state[90])
|
|
19474
|
+
this.devices.virtio_v86fs.set_state(state[90]);
|
|
18512
19475
|
this.fw_value = state[62];
|
|
18513
19476
|
if (state[63]) this.set_state_ioapic(state[63]);
|
|
18514
19477
|
this.tss_size_32[0] = state[64];
|
|
@@ -18707,8 +19670,10 @@ var V86Starter = (() => {
|
|
|
18707
19670
|
this.memory_size[0] === 0,
|
|
18708
19671
|
"Expected uninitialised memory"
|
|
18709
19672
|
);
|
|
18710
|
-
this.memory_size[0] = size;
|
|
18711
19673
|
const memory_offset = this.allocate_memory(size);
|
|
19674
|
+
this.rebuild_wasm_views();
|
|
19675
|
+
this.memory_size[0] = size;
|
|
19676
|
+
this.mem8_offset = memory_offset;
|
|
18712
19677
|
this.mem8 = view(Uint8Array, this.wasm_memory, memory_offset, size);
|
|
18713
19678
|
this.mem32s = view(
|
|
18714
19679
|
Uint32Array,
|
|
@@ -18919,6 +19884,19 @@ var V86Starter = (() => {
|
|
|
18919
19884
|
device_bus
|
|
18920
19885
|
);
|
|
18921
19886
|
}
|
|
19887
|
+
if (settings.virtio_mem) {
|
|
19888
|
+
const mem_cfg = settings.virtio_mem;
|
|
19889
|
+
this.devices.virtio_mem = new VirtioMem(
|
|
19890
|
+
this,
|
|
19891
|
+
device_bus,
|
|
19892
|
+
mem_cfg.region_addr,
|
|
19893
|
+
mem_cfg.region_size,
|
|
19894
|
+
mem_cfg.block_size
|
|
19895
|
+
);
|
|
19896
|
+
}
|
|
19897
|
+
if (settings.virtio_v86fs) {
|
|
19898
|
+
this.devices.virtio_v86fs = new VirtioV86FS(this, device_bus);
|
|
19899
|
+
}
|
|
18922
19900
|
this.devices.sb16 = new SB16(this, device_bus);
|
|
18923
19901
|
}
|
|
18924
19902
|
if (settings.multiboot) {
|
|
@@ -18939,6 +19917,21 @@ var V86Starter = (() => {
|
|
|
18939
19917
|
}
|
|
18940
19918
|
}
|
|
18941
19919
|
this.debug_init();
|
|
19920
|
+
this.rebuild_wasm_views();
|
|
19921
|
+
if (this.mem8_offset > 0) {
|
|
19922
|
+
this.mem8 = view(
|
|
19923
|
+
Uint8Array,
|
|
19924
|
+
this.wasm_memory,
|
|
19925
|
+
this.mem8_offset,
|
|
19926
|
+
this.memory_size[0]
|
|
19927
|
+
);
|
|
19928
|
+
this.mem32s = view(
|
|
19929
|
+
Uint32Array,
|
|
19930
|
+
this.wasm_memory,
|
|
19931
|
+
this.mem8_offset,
|
|
19932
|
+
this.memory_size[0] >> 2
|
|
19933
|
+
);
|
|
19934
|
+
}
|
|
18942
19935
|
}
|
|
18943
19936
|
load_multiboot(buffer) {
|
|
18944
19937
|
if (this.bios.main) {
|
|
@@ -19144,7 +20137,6 @@ var V86Starter = (() => {
|
|
|
19144
20137
|
cpu.write32(multiboot_data + 4, ramdisk_top);
|
|
19145
20138
|
cpu.write32(multiboot_data + 8, 0);
|
|
19146
20139
|
cpu.write32(multiboot_data + 12, 0);
|
|
19147
|
-
multiboot_data += 16;
|
|
19148
20140
|
dbg_assert(ramdisk_top < cpu.memory_size[0]);
|
|
19149
20141
|
cpu.write_blob(new Uint8Array(initrd), ramdisk_address);
|
|
19150
20142
|
}
|
|
@@ -25218,20 +26210,12 @@ ${e.stack || e.message}`
|
|
|
25218
26210
|
};
|
|
25219
26211
|
|
|
25220
26212
|
// src/browser/starter.ts
|
|
25221
|
-
var
|
|
25222
|
-
|
|
25223
|
-
constructor(message) {
|
|
25224
|
-
this.message = message || "File already exists";
|
|
25225
|
-
}
|
|
25226
|
-
};
|
|
25227
|
-
FileExistsError.prototype = Error.prototype;
|
|
25228
|
-
var FileNotFoundError = class {
|
|
25229
|
-
message;
|
|
26213
|
+
var import_meta = {};
|
|
26214
|
+
var FileNotFoundError = class extends Error {
|
|
25230
26215
|
constructor(message) {
|
|
25231
|
-
|
|
26216
|
+
super(message || "File not found");
|
|
25232
26217
|
}
|
|
25233
26218
|
};
|
|
25234
|
-
FileNotFoundError.prototype = Error.prototype;
|
|
25235
26219
|
var V86 = class {
|
|
25236
26220
|
cpu_is_running = false;
|
|
25237
26221
|
cpu_exception_hook = function(_n) {
|
|
@@ -25259,12 +26243,25 @@ ${e.stack || e.message}`
|
|
|
25259
26243
|
this.bus = bus[0];
|
|
25260
26244
|
this.emulator_bus = bus[1];
|
|
25261
26245
|
let cpu;
|
|
25262
|
-
|
|
26246
|
+
const memory_size = options.memory_size || 64 * 1024 * 1024;
|
|
26247
|
+
const vga_memory_size = options.vga_memory_size || 8 * 1024 * 1024;
|
|
26248
|
+
const memory_max = options.memory_max || (memory_size + vga_memory_size) * 4;
|
|
26249
|
+
const WASM_PAGE_SIZE2 = 65536;
|
|
26250
|
+
const wasm_initial_pages = 256;
|
|
26251
|
+
const wasm_max_pages = Math.max(
|
|
26252
|
+
wasm_initial_pages,
|
|
26253
|
+
Math.min(Math.ceil(memory_max / WASM_PAGE_SIZE2), 65536)
|
|
26254
|
+
);
|
|
26255
|
+
const wasm_memory = new WebAssembly.Memory({
|
|
26256
|
+
initial: wasm_initial_pages,
|
|
26257
|
+
maximum: wasm_max_pages
|
|
26258
|
+
});
|
|
25263
26259
|
const wasm_table = new WebAssembly.Table({
|
|
25264
26260
|
element: "anyfunc",
|
|
25265
26261
|
initial: WASM_TABLE_SIZE + WASM_TABLE_OFFSET
|
|
25266
26262
|
});
|
|
25267
26263
|
const wasm_shared_funcs = {
|
|
26264
|
+
memory: wasm_memory,
|
|
25268
26265
|
cpu_exception_hook: (n) => this.cpu_exception_hook(n),
|
|
25269
26266
|
run_hardware_timers: function(a, t) {
|
|
25270
26267
|
return cpu.run_hardware_timers(a, t);
|
|
@@ -25357,9 +26354,10 @@ ${e.stack || e.message}`
|
|
|
25357
26354
|
"v86.wasm",
|
|
25358
26355
|
"v86-fallback.wasm"
|
|
25359
26356
|
);
|
|
25360
|
-
} else if (typeof window === "undefined"
|
|
25361
|
-
|
|
25362
|
-
|
|
26357
|
+
} else if (typeof window === "undefined") {
|
|
26358
|
+
const root = new URL("../../", import_meta.url).pathname;
|
|
26359
|
+
v86_bin = root + "build/" + v86_bin;
|
|
26360
|
+
v86_bin_fallback = root + "build/" + v86_bin_fallback;
|
|
25363
26361
|
} else {
|
|
25364
26362
|
v86_bin = "build/" + v86_bin;
|
|
25365
26363
|
v86_bin_fallback = "build/" + v86_bin_fallback;
|
|
@@ -25398,11 +26396,11 @@ ${e.stack || e.message}`
|
|
|
25398
26396
|
};
|
|
25399
26397
|
}
|
|
25400
26398
|
wasm_fn({ env: wasm_shared_funcs }).then((exports) => {
|
|
25401
|
-
wasm_memory = exports.memory;
|
|
25402
26399
|
exports["rust_init"]();
|
|
25403
26400
|
const emulator = this.v86 = new v86(this.emulator_bus, {
|
|
25404
26401
|
exports,
|
|
25405
|
-
wasm_table
|
|
26402
|
+
wasm_table,
|
|
26403
|
+
wasm_memory
|
|
25406
26404
|
});
|
|
25407
26405
|
cpu = emulator.cpu;
|
|
25408
26406
|
this.continue_init(emulator, options);
|
|
@@ -25444,7 +26442,9 @@ ${e.stack || e.message}`
|
|
|
25444
26442
|
settings.mac_address_translation = options.mac_address_translation;
|
|
25445
26443
|
settings.cpuid_level = options.cpuid_level;
|
|
25446
26444
|
settings.virtio_balloon = options.virtio_balloon;
|
|
26445
|
+
settings.virtio_mem = options.virtio_mem;
|
|
25447
26446
|
settings.virtio_console = !!options.virtio_console;
|
|
26447
|
+
settings.virtio_v86fs = !!options.virtio_v86fs;
|
|
25448
26448
|
const relay_url = options.network_relay_url || options.net_device && options.net_device.relay_url;
|
|
25449
26449
|
if (relay_url) {
|
|
25450
26450
|
if (relay_url === "fetch") {
|
|
@@ -25922,6 +26922,26 @@ ${e.stack || e.message}`
|
|
|
25922
26922
|
async run() {
|
|
25923
26923
|
this.v86.run();
|
|
25924
26924
|
}
|
|
26925
|
+
/**
|
|
26926
|
+
* Grow guest memory to the specified size in bytes. Stops the VM,
|
|
26927
|
+
* grows WASM linear memory, updates memory_size, clears the TLB,
|
|
26928
|
+
* and resumes execution.
|
|
26929
|
+
*/
|
|
26930
|
+
async growMemory(newSizeBytes) {
|
|
26931
|
+
const cpu = this.v86.cpu;
|
|
26932
|
+
if (newSizeBytes <= cpu.memory_size[0]) {
|
|
26933
|
+
return;
|
|
26934
|
+
}
|
|
26935
|
+
const wasRunning = this.cpu_is_running;
|
|
26936
|
+
if (wasRunning) {
|
|
26937
|
+
await this.stop();
|
|
26938
|
+
}
|
|
26939
|
+
cpu.resize_memory(newSizeBytes);
|
|
26940
|
+
cpu.full_clear_tlb();
|
|
26941
|
+
if (wasRunning) {
|
|
26942
|
+
await this.run();
|
|
26943
|
+
}
|
|
26944
|
+
}
|
|
25925
26945
|
/**
|
|
25926
26946
|
* Stop emulation. Do nothing if emulator is not running. Can be asynchronous.
|
|
25927
26947
|
*/
|