mirror of
https://github.com/copy/v86.git
synced 2025-12-31 04:23:15 +00:00
clean up
This commit is contained in:
parent
88aff1091f
commit
318003f117
3 changed files with 122 additions and 105 deletions
|
|
@ -1,9 +1,9 @@
|
|||
A 9p filesystem is supported by v86, using a virtio transport. There are several
|
||||
ways it can be set up.
|
||||
ways it can be set up.
|
||||
|
||||
### Guest mount
|
||||
|
||||
In all cases, the filesystem is mounted in the guest system using the `9p`
|
||||
In all cases, the filesystem is mounted in the guest system using the `9p`
|
||||
filesystem type and the `host9p` device tag. Typically you want to be specific
|
||||
with the version and transport options:
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ Here are kernel arguments you can use to boot directly off the 9p filesystem:
|
|||
rw root=host9p rootfstype=9p rootflags=trans=virtio,version=9p2000.L
|
||||
```
|
||||
|
||||
The `aname` option can be used to pick the directory from 9p to mount. The `rw`
|
||||
The `aname` option can be used to pick the directory from 9p to mount. The `rw`
|
||||
argument makes this a read-write root filesystem.
|
||||
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ argument makes this a read-write root filesystem.
|
|||
|
||||
This is the standard way to setup the 9p filesystem. It loads files over
|
||||
HTTP on-demand into an in-memory filesystem in JS. This allows files to be
|
||||
exchanged with the guest OS. See `create_file` and `read_file` in
|
||||
exchanged with the guest OS. See `create_file` and `read_file` in
|
||||
[`starter.js`](https://github.com/copy/v86/blob/master/src/browser/starter.js).
|
||||
|
||||
This mode is enabled by passing the following options to `V86`:
|
||||
|
|
@ -41,7 +41,7 @@ Here, `basefs` is a json file created using
|
|||
[fs2json](https://github.com/copy/fs2json). The base url is the prefix of a url
|
||||
from which the files are available. For instance, if the 9p filesystem has a
|
||||
file `/bin/sh`, that file must be accessible from
|
||||
`http://localhost/9p/base/bin/sh`.
|
||||
`http://localhost/9p/base/bin/sh`.
|
||||
|
||||
If `basefs` and `baseurl` are omitted, an empty 9p filesystem is created. Unless
|
||||
you configure one of the alternative modes.
|
||||
|
|
@ -84,16 +84,16 @@ Simlar to using `handle9p`, this filesystem will not be available in JS and
|
|||
will need to be re-mounted after restoring state.
|
||||
|
||||
The WS proxy just needs to hand off messages with a connection to a normal 9p
|
||||
server. Each binary WebSocket message is the full buffer of a request or a
|
||||
reply.
|
||||
server. Each binary WebSocket message is the full buffer of a request or a
|
||||
reply.
|
||||
|
||||
To implement, request message bytes can just be sent directly to the 9p
|
||||
To implement, request message bytes can just be sent directly to the 9p
|
||||
connection, but the 9p reply stream needs to be buffered into a single binary
|
||||
WebSocket message. The proxy must at least parse the first 4 bytes to get the
|
||||
message size and use it to buffer a full message before sending over WebSocket.
|
||||
WebSocket message. The proxy must at least parse the first 4 bytes to get the
|
||||
message size and use it to buffer a full message before sending over WebSocket.
|
||||
|
||||
The [wanix](https://github.com/tractordev/wanix) CLI has a `serve` command that
|
||||
not only serves a directory over HTTP, but also over 9P via WebSocket. You can
|
||||
see how it [implements a proxy][1] in Go.
|
||||
|
||||
[1]: https://github.com/tractordev/wanix/blob/main/cmd/wanix/serve.go#L117-L177
|
||||
[1]: https://github.com/tractordev/wanix/blob/main/cmd/wanix/serve.go#L117-L177
|
||||
|
|
|
|||
199
lib/9p.js
199
lib/9p.js
|
|
@ -88,19 +88,12 @@ function range(size)
|
|||
}
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*
|
||||
* @param {CPU} cpu
|
||||
* @param {Function} receive
|
||||
*/
|
||||
function Virtio9pDevice(cpu, receive) {
|
||||
//this.configspace = [0x0, 0x4, 0x68, 0x6F, 0x73, 0x74]; // length of string and "host" string
|
||||
//this.configspace = [0x0, 0x9, 0x2F, 0x64, 0x65, 0x76, 0x2F, 0x72, 0x6F, 0x6F, 0x74 ]; // length of string and "/dev/root" string
|
||||
this.configspace_tagname = [0x68, 0x6F, 0x73, 0x74, 0x39, 0x70]; // "host9p" string
|
||||
this.configspace_taglen = this.configspace_tagname.length; // num bytes
|
||||
|
||||
/** @type {VirtIO} */
|
||||
this.virtio = new VirtIO(cpu,
|
||||
function init_virtio(cpu, configspace_taglen, configspace_tagname, receive)
|
||||
{
|
||||
const virtio = new VirtIO(cpu,
|
||||
{
|
||||
name: "virtio-9p",
|
||||
pci_id: 0x06 << 3,
|
||||
|
|
@ -139,12 +132,13 @@ function Virtio9pDevice(cpu, receive) {
|
|||
" (expected queue_id of 0)");
|
||||
return;
|
||||
}
|
||||
while(this.virtqueue.has_request())
|
||||
const virtqueue = virtio.queues[0];
|
||||
while(virtqueue.has_request())
|
||||
{
|
||||
const bufchain = this.virtqueue.pop_request();
|
||||
const bufchain = virtqueue.pop_request();
|
||||
receive(bufchain);
|
||||
}
|
||||
this.virtqueue.notify_me_after(0);
|
||||
virtqueue.notify_me_after(0);
|
||||
// Don't flush replies here: async replies are not completed yet.
|
||||
},
|
||||
],
|
||||
|
|
@ -161,7 +155,7 @@ function Virtio9pDevice(cpu, receive) {
|
|||
{
|
||||
bytes: 2,
|
||||
name: "mount tag length",
|
||||
read: () => this.configspace_taglen,
|
||||
read: () => configspace_taglen,
|
||||
write: data => { /* read only */ },
|
||||
},
|
||||
].concat(range(VIRTIO_9P_MAX_TAGLEN).map(index =>
|
||||
|
|
@ -169,13 +163,13 @@ function Virtio9pDevice(cpu, receive) {
|
|||
bytes: 1,
|
||||
name: "mount tag name " + index,
|
||||
// Note: configspace_tagname may have changed after set_state
|
||||
read: () => this.configspace_tagname[index] || 0,
|
||||
read: () => configspace_tagname[index] || 0,
|
||||
write: data => { /* read only */ },
|
||||
})
|
||||
)),
|
||||
},
|
||||
});
|
||||
this.virtqueue = this.virtio.queues[0];
|
||||
return virtio;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -191,24 +185,27 @@ export function Virtio9p(filesystem, cpu, bus) {
|
|||
/** @const @type {BusConnector} */
|
||||
this.bus = bus;
|
||||
|
||||
|
||||
this.configspace_tagname = [0x68, 0x6F, 0x73, 0x74, 0x39, 0x70]; // "host9p" string
|
||||
this.configspace_taglen = this.configspace_tagname.length; // num bytes
|
||||
|
||||
this.virtio = init_virtio(cpu, this.configspace_taglen, this.configspace_tagname, this.ReceiveRequest.bind(this));
|
||||
this.virtqueue = this.virtio.queues[0];
|
||||
|
||||
this.VERSION = "9P2000.L";
|
||||
this.BLOCKSIZE = 8192; // Let's define one page.
|
||||
this.msize = 8192; // maximum message size
|
||||
this.replybuffer = new Uint8Array(this.msize*2); // Twice the msize to stay on the safe site
|
||||
this.replybuffersize = 0;
|
||||
this.fids = [];
|
||||
|
||||
this.device = new Virtio9pDevice(cpu, this.ReceiveRequest.bind(this));
|
||||
}
|
||||
|
||||
Virtio9p.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.device.configspace_tagname;
|
||||
state[1] = this.device.configspace_taglen;
|
||||
state[2] = this.device.virtio;
|
||||
state[0] = this.configspace_tagname;
|
||||
state[1] = this.configspace_taglen;
|
||||
state[2] = this.virtio;
|
||||
state[3] = this.VERSION;
|
||||
state[4] = this.BLOCKSIZE;
|
||||
state[5] = this.msize;
|
||||
|
|
@ -222,10 +219,10 @@ Virtio9p.prototype.get_state = function()
|
|||
|
||||
Virtio9p.prototype.set_state = function(state)
|
||||
{
|
||||
this.device.configspace_tagname = state[0];
|
||||
this.device.configspace_taglen = state[1];
|
||||
this.device.virtio.set_state(state[2]);
|
||||
this.device.virtqueue = this.device.virtio.queues[0];
|
||||
this.configspace_tagname = state[0];
|
||||
this.configspace_taglen = state[1];
|
||||
this.virtio.set_state(state[2]);
|
||||
this.virtqueue = this.virtio.queues[0];
|
||||
this.VERSION = state[3];
|
||||
this.BLOCKSIZE = state[4];
|
||||
this.msize = state[5];
|
||||
|
|
@ -254,12 +251,12 @@ Virtio9p.prototype.update_dbg_name = function(idx, newname)
|
|||
}
|
||||
};
|
||||
|
||||
Virtio9p.prototype.reset = function() {
|
||||
Virtio9p.prototype.reset = function()
|
||||
{
|
||||
this.fids = [];
|
||||
this.device.virtio.reset();
|
||||
this.virtio.reset();
|
||||
};
|
||||
|
||||
|
||||
Virtio9p.prototype.BuildReply = function(id, tag, payloadsize) {
|
||||
dbg_assert(payloadsize >= 0, "9P: Negative payload size");
|
||||
marshall.Marshall(["w", "b", "h"], [payloadsize+7, id+1, tag], this.replybuffer, 0);
|
||||
|
|
@ -280,8 +277,8 @@ Virtio9p.prototype.SendError = function (tag, errormsg, errorcode) {
|
|||
Virtio9p.prototype.SendReply = function (bufchain) {
|
||||
dbg_assert(this.replybuffersize >= 0, "9P: Negative replybuffersize");
|
||||
bufchain.set_next_blob(this.replybuffer.subarray(0, this.replybuffersize));
|
||||
this.device.virtqueue.push_reply(bufchain);
|
||||
this.device.virtqueue.flush_replies();
|
||||
this.virtqueue.push_reply(bufchain);
|
||||
this.virtqueue.flush_replies();
|
||||
};
|
||||
|
||||
Virtio9p.prototype.ReceiveRequest = async function (bufchain) {
|
||||
|
|
@ -894,7 +891,7 @@ Virtio9p.prototype.ReceiveRequest = async function (bufchain) {
|
|||
};
|
||||
|
||||
/** @typedef {function(Uint8Array, function(Uint8Array):void):void} */
|
||||
export let P9Handler;
|
||||
let P9Handler;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
|
|
@ -906,41 +903,52 @@ export function Virtio9pHandler(handle_fn, cpu) {
|
|||
/** @type {P9Handler} */
|
||||
this.handle_fn = handle_fn;
|
||||
this.tag_bufchain = new Map();
|
||||
this.device = new Virtio9pDevice(cpu, async (bufchain) => {
|
||||
// TODO: split into header + data blobs to avoid unnecessary copying.
|
||||
const reqbuf = new Uint8Array(bufchain.length_readable);
|
||||
bufchain.get_next_blob(reqbuf);
|
||||
|
||||
var reqheader = marshall.Unmarshall(["w", "b", "h"], reqbuf, { offset : 0 });
|
||||
var reqtag = reqheader[2];
|
||||
|
||||
this.tag_bufchain.set(reqtag, bufchain);
|
||||
this.handle_fn(reqbuf, (replybuf) => {
|
||||
var replyheader = marshall.Unmarshall(["w", "b", "h"], replybuf, { offset: 0 });
|
||||
var replytag = replyheader[2];
|
||||
|
||||
const bufchain = this.tag_bufchain.get(replytag);
|
||||
if (!bufchain) {
|
||||
console.error("No bufchain found for tag: " + replytag);
|
||||
return;
|
||||
}
|
||||
|
||||
bufchain.set_next_blob(replybuf);
|
||||
this.device.virtqueue.push_reply(bufchain);
|
||||
this.device.virtqueue.flush_replies();
|
||||
|
||||
this.tag_bufchain.delete(replytag);
|
||||
});
|
||||
});
|
||||
|
||||
this.configspace_tagname = [0x68, 0x6F, 0x73, 0x74, 0x39, 0x70]; // "host9p" string
|
||||
this.configspace_taglen = this.configspace_tagname.length; // num bytes
|
||||
|
||||
this.virtio = init_virtio(
|
||||
cpu,
|
||||
this.configspace_taglen,
|
||||
this.configspace_tagname,
|
||||
async (bufchain) => {
|
||||
// TODO: split into header + data blobs to avoid unnecessary copying.
|
||||
const reqbuf = new Uint8Array(bufchain.length_readable);
|
||||
bufchain.get_next_blob(reqbuf);
|
||||
|
||||
var reqheader = marshall.Unmarshall(["w", "b", "h"], reqbuf, { offset : 0 });
|
||||
var reqtag = reqheader[2];
|
||||
|
||||
this.tag_bufchain.set(reqtag, bufchain);
|
||||
this.handle_fn(reqbuf, (replybuf) => {
|
||||
var replyheader = marshall.Unmarshall(["w", "b", "h"], replybuf, { offset: 0 });
|
||||
var replytag = replyheader[2];
|
||||
|
||||
const bufchain = this.tag_bufchain.get(replytag);
|
||||
if(!bufchain)
|
||||
{
|
||||
console.error("No bufchain found for tag: " + replytag);
|
||||
return;
|
||||
}
|
||||
|
||||
bufchain.set_next_blob(replybuf);
|
||||
this.virtqueue.push_reply(bufchain);
|
||||
this.virtqueue.flush_replies();
|
||||
|
||||
this.tag_bufchain.delete(replytag);
|
||||
});
|
||||
}
|
||||
);
|
||||
this.virtqueue = this.virtio.queues[0];
|
||||
}
|
||||
|
||||
Virtio9pHandler.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.device.configspace_tagname;
|
||||
state[1] = this.device.configspace_taglen;
|
||||
state[2] = this.device.virtio;
|
||||
state[0] = this.configspace_tagname;
|
||||
state[1] = this.configspace_taglen;
|
||||
state[2] = this.virtio;
|
||||
state[3] = this.tag_bufchain;
|
||||
|
||||
return state;
|
||||
|
|
@ -948,16 +956,17 @@ Virtio9pHandler.prototype.get_state = function()
|
|||
|
||||
Virtio9pHandler.prototype.set_state = function(state)
|
||||
{
|
||||
this.device.configspace_tagname = state[0];
|
||||
this.device.configspace_taglen = state[1];
|
||||
this.device.virtio.set_state(state[2]);
|
||||
this.device.virtqueue = this.device.virtio.queues[0];
|
||||
this.configspace_tagname = state[0];
|
||||
this.configspace_taglen = state[1];
|
||||
this.virtio.set_state(state[2]);
|
||||
this.virtqueue = this.virtio.queues[0];
|
||||
this.tag_bufchain = state[3];
|
||||
};
|
||||
|
||||
|
||||
Virtio9pHandler.prototype.reset = function() {
|
||||
this.device.virtio.reset();
|
||||
Virtio9pHandler.prototype.reset = function()
|
||||
{
|
||||
this.virtio.reset();
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -982,26 +991,36 @@ export function Virtio9pProxy(url, cpu)
|
|||
this.destroyed = false;
|
||||
|
||||
this.tag_bufchain = new Map();
|
||||
this.device = new Virtio9pDevice(cpu, async (bufchain) => {
|
||||
// TODO: split into header + data blobs to avoid unnecessary copying.
|
||||
const reqbuf = new Uint8Array(bufchain.length_readable);
|
||||
bufchain.get_next_blob(reqbuf);
|
||||
|
||||
const reqheader = marshall.Unmarshall(["w", "b", "h"], reqbuf, { offset : 0 });
|
||||
const reqtag = reqheader[2];
|
||||
|
||||
this.tag_bufchain.set(reqtag, bufchain);
|
||||
this.send(reqbuf);
|
||||
});
|
||||
|
||||
this.configspace_tagname = [0x68, 0x6F, 0x73, 0x74, 0x39, 0x70]; // "host9p" string
|
||||
this.configspace_taglen = this.configspace_tagname.length; // num bytes
|
||||
|
||||
this.virtio = init_virtio(
|
||||
cpu,
|
||||
this.configspace_taglen,
|
||||
this.configspace_tagname,
|
||||
async (bufchain) => {
|
||||
// TODO: split into header + data blobs to avoid unnecessary copying.
|
||||
const reqbuf = new Uint8Array(bufchain.length_readable);
|
||||
bufchain.get_next_blob(reqbuf);
|
||||
|
||||
const reqheader = marshall.Unmarshall(["w", "b", "h"], reqbuf, { offset : 0 });
|
||||
const reqtag = reqheader[2];
|
||||
|
||||
this.tag_bufchain.set(reqtag, bufchain);
|
||||
this.send(reqbuf);
|
||||
}
|
||||
);
|
||||
this.virtqueue = this.virtio.queues[0];
|
||||
}
|
||||
|
||||
Virtio9pProxy.prototype.get_state = function()
|
||||
{
|
||||
var state = [];
|
||||
|
||||
state[0] = this.device.configspace_tagname;
|
||||
state[1] = this.device.configspace_taglen;
|
||||
state[2] = this.device.virtio;
|
||||
state[0] = this.configspace_tagname;
|
||||
state[1] = this.configspace_taglen;
|
||||
state[2] = this.virtio;
|
||||
state[3] = this.tag_bufchain;
|
||||
|
||||
return state;
|
||||
|
|
@ -1009,16 +1028,15 @@ Virtio9pProxy.prototype.get_state = function()
|
|||
|
||||
Virtio9pProxy.prototype.set_state = function(state)
|
||||
{
|
||||
this.device.configspace_tagname = state[0];
|
||||
this.device.configspace_taglen = state[1];
|
||||
this.device.virtio.set_state(state[2]);
|
||||
this.device.virtqueue = this.device.virtio.queues[0];
|
||||
this.configspace_tagname = state[0];
|
||||
this.configspace_taglen = state[1];
|
||||
this.virtio.set_state(state[2]);
|
||||
this.virtqueue = this.virtio.queues[0];
|
||||
this.tag_bufchain = state[3];
|
||||
};
|
||||
|
||||
|
||||
Virtio9pProxy.prototype.reset = function() {
|
||||
this.device.virtio.reset();
|
||||
this.virtio.reset();
|
||||
};
|
||||
|
||||
Virtio9pProxy.prototype.handle_message = function(e)
|
||||
|
|
@ -1028,14 +1046,15 @@ Virtio9pProxy.prototype.handle_message = function(e)
|
|||
const replytag = replyheader[2];
|
||||
|
||||
const bufchain = this.tag_bufchain.get(replytag);
|
||||
if (!bufchain) {
|
||||
if(!bufchain)
|
||||
{
|
||||
console.error("Virtio9pProxy: No bufchain found for tag: " + replytag);
|
||||
return;
|
||||
}
|
||||
|
||||
bufchain.set_next_blob(replybuf);
|
||||
this.device.virtqueue.push_reply(bufchain);
|
||||
this.device.virtqueue.flush_replies();
|
||||
this.virtqueue.push_reply(bufchain);
|
||||
this.virtqueue.flush_replies();
|
||||
|
||||
this.tag_bufchain.delete(replytag);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -426,13 +426,11 @@ V86.prototype.continue_init = async function(emulator, options)
|
|||
{
|
||||
settings.handle9p = options.filesystem.handle9p;
|
||||
}
|
||||
|
||||
if(options.filesystem && options.filesystem.proxy_url)
|
||||
else if(options.filesystem && options.filesystem.proxy_url)
|
||||
{
|
||||
settings.proxy9p = options.filesystem.proxy_url;
|
||||
}
|
||||
|
||||
if(options.filesystem && !options.filesystem.handle9p && !options.filesystem.proxy_url)
|
||||
else if(options.filesystem)
|
||||
{
|
||||
var fs_url = options.filesystem.basefs;
|
||||
var base_url = options.filesystem.baseurl;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue