240 lines
7.8 KiB
ObjectPascal
240 lines
7.8 KiB
ObjectPascal
{
|
|
Prog->WASM->WASMIO - WASI hook implementations bridging to POutBuf.
|
|
|
|
Provides concrete WASI callback functions that route fd 0/1/2
|
|
to the owning Asuro process's StdIn/StdOut/StdErr buffers.
|
|
|
|
Hooks resolve the shim from the currently scheduled process.
|
|
|
|
@author(Kieron Morris <[email protected]>)
|
|
}
|
|
unit app.wasm.io;
|
|
|
|
interface
|
|
|
|
uses
|
|
app.wasm.shim,
|
|
wasm.types.builtin,
|
|
wasm.types.context,
|
|
wasm.types.values;
|
|
|
|
|
|
|
|
{ WASI hook implementations — register via wasm_set_fd_write etc. }
|
|
function asuro_fd_write(fd : TWASMUInt32; buf : TWASMPUInt8; len : TWASMUInt32) : TWASMUInt32;
|
|
function asuro_fd_read(fd : TWASMUInt32; buf : TWASMPUInt8; len : TWASMUInt32) : TWASMUInt32;
|
|
procedure asuro_proc_exit(code : TWASMUInt32);
|
|
function asuro_clock_time_get(clock_id : TWASMUInt32; precision : TWASMUInt64; var time : TWASMUInt64) : TWASMUInt32;
|
|
function asuro_clock_res_get(clock_id : TWASMUInt32; var resolution : TWASMUInt64) : TWASMUInt32;
|
|
function asuro_random_get(buf : TWASMPUInt8; len : TWASMUInt32) : TWASMUInt32;
|
|
function asuro_args_sizes_get(var count : TWASMUInt32; var buf_size : TWASMUInt32) : TWASMUInt32;
|
|
function asuro_args_get(argv : TWASMPUInt32; argv_buf : TWASMPUInt8) : TWASMUInt32;
|
|
function asuro_environ_sizes_get(var count : TWASMUInt32; var buf_size : TWASMUInt32) : TWASMUInt32;
|
|
function asuro_environ_get(environ : TWASMPUInt32; environ_buf : TWASMPUInt8) : TWASMUInt32;
|
|
|
|
{ Direct host-function override for args_get (TWASMHostFunc signature).
|
|
The wasuro preview1 glue for args_get is a stub that does not call
|
|
the hook, so we register this as a host function to take its place. }
|
|
procedure asuro_wasi_args_get(Context : PWASMProcessContext);
|
|
|
|
implementation
|
|
|
|
uses
|
|
io.stdio, proc.types,
|
|
wasm.types.wasi, wasm.types.stack, wasm.types.heap,
|
|
proc.mgr, arch.platform.interrupts, arch.common.legacyirq, core.rand, core.util, arch.platform.cpu;
|
|
|
|
function ActiveShimPtr: PProcessWASMShim;
|
|
begin
|
|
ActiveShimPtr := nil;
|
|
if proc.mgr.CurrentProcess <> nil then
|
|
ActiveShimPtr := PProcessWASMShim(proc.mgr.CurrentProcess^.Local);
|
|
end;
|
|
|
|
{ ---- fd_write: fd 1 = stdout, fd 2 = stderr ---- }
|
|
|
|
function asuro_fd_write(fd : TWASMUInt32; buf : TWASMPUInt8; len : TWASMUInt32) : TWASMUInt32;
|
|
var
|
|
outbuf : POutBuf;
|
|
i : TWASMUInt32;
|
|
begin
|
|
asuro_fd_write := 0;
|
|
if ActiveShimPtr = nil then exit;
|
|
if ActiveShimPtr^.ProcessCtx = nil then exit;
|
|
|
|
case fd of
|
|
WASI_FD_STDOUT: outbuf := ActiveShimPtr^.ProcessCtx^.StdOut;
|
|
WASI_FD_STDERR: outbuf := ActiveShimPtr^.ProcessCtx^.StdErr;
|
|
else begin
|
|
asuro_fd_write := 0;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
if (outbuf = nil) or (len = 0) then exit;
|
|
|
|
{ Write byte-by-byte into the POutBuf }
|
|
for i := 0 to len - 1 do
|
|
io.stdio.bufWriteChar(outbuf, char(buf[i]));
|
|
|
|
asuro_fd_write := len;
|
|
end;
|
|
|
|
{ ---- fd_read: fd 0 = stdin (non-blocking for now) ---- }
|
|
|
|
function asuro_fd_read(fd : TWASMUInt32; buf : TWASMPUInt8; len : TWASMUInt32) : TWASMUInt32;
|
|
var
|
|
inbuf : POutBuf;
|
|
avail : uint32;
|
|
copyLen : uint32;
|
|
begin
|
|
asuro_fd_read := 0;
|
|
if ActiveShimPtr = nil then exit;
|
|
if ActiveShimPtr^.ProcessCtx = nil then exit;
|
|
|
|
if fd <> WASI_FD_STDIN then exit;
|
|
|
|
inbuf := ActiveShimPtr^.ProcessCtx^.StdIn;
|
|
if inbuf = nil then exit;
|
|
|
|
{ Non-blocking: return whatever is available, 0 if nothing }
|
|
avail := inbuf^.len;
|
|
if avail = 0 then exit;
|
|
if len < avail then copyLen := len else copyLen := avail;
|
|
memcpy(PtrUInt(inbuf^.buf), PtrUInt(buf), copyLen);
|
|
asuro_fd_read := copyLen;
|
|
end;
|
|
|
|
{ ---- proc_exit: propagate exit code to process ---- }
|
|
|
|
procedure asuro_proc_exit(code : TWASMUInt32);
|
|
begin
|
|
{ The WASURO VM has already set Running := false and ExitCode.
|
|
We just propagate to the Asuro process context. }
|
|
if ActiveShimPtr = nil then exit;
|
|
if ActiveShimPtr^.ProcessCtx = nil then exit;
|
|
ActiveShimPtr^.ProcessCtx^.ExitCode := code;
|
|
end;
|
|
|
|
{ ---- Monotonic time from the platform timer ---- }
|
|
|
|
function asuro_clock_time_get(clock_id : TWASMUInt32; precision : TWASMUInt64;
|
|
var time : TWASMUInt64) : TWASMUInt32;
|
|
var
|
|
ticks: uint64;
|
|
begin
|
|
ticks := arch.platform.interrupts.timerTicks;
|
|
time := (ticks div PIT_INPUT_HZ) * PIT_DIVISOR * 1000000000 +
|
|
((ticks mod PIT_INPUT_HZ) * PIT_DIVISOR * 1000000000) div PIT_INPUT_HZ;
|
|
asuro_clock_time_get := WASI_ESUCCESS;
|
|
end;
|
|
|
|
{ ---- clock_res_get: ~1ms resolution ---- }
|
|
|
|
function asuro_clock_res_get(clock_id : TWASMUInt32;
|
|
var resolution : TWASMUInt64) : TWASMUInt32;
|
|
begin
|
|
resolution := (uint64(PIT_DIVISOR) * 1000000000 + PIT_INPUT_HZ - 1) div PIT_INPUT_HZ;
|
|
asuro_clock_res_get := WASI_ESUCCESS;
|
|
end;
|
|
|
|
{ ---- random_get: fill buffer with random bytes ---- }
|
|
|
|
function asuro_random_get(buf : TWASMPUInt8; len : TWASMUInt32) : TWASMUInt32;
|
|
var
|
|
i : TWASMUInt32;
|
|
r : uint32;
|
|
begin
|
|
i := 0;
|
|
while i < len do begin
|
|
r := core.rand.rand32;
|
|
buf[i] := uint8(r and $FF);
|
|
inc(i);
|
|
if i < len then begin buf[i] := uint8((r shr 8) and $FF); inc(i); end;
|
|
if i < len then begin buf[i] := uint8((r shr 16) and $FF); inc(i); end;
|
|
if i < len then begin buf[i] := uint8((r shr 24) and $FF); inc(i); end;
|
|
end;
|
|
asuro_random_get := WASI_ESUCCESS;
|
|
end;
|
|
|
|
{ ---- args: pass through params from io.stdio ---- }
|
|
|
|
function asuro_args_sizes_get(var count : TWASMUInt32; var buf_size : TWASMUInt32) : TWASMUInt32;
|
|
begin
|
|
if ActiveShimPtr = nil then begin
|
|
count := 0;
|
|
buf_size := 0;
|
|
end else begin
|
|
count := ActiveShimPtr^.ArgCount;
|
|
buf_size := ActiveShimPtr^.ArgBufSize;
|
|
end;
|
|
asuro_args_sizes_get := WASI_ESUCCESS;
|
|
end;
|
|
|
|
function asuro_args_get(argv : TWASMPUInt32; argv_buf : TWASMPUInt8) : TWASMUInt32;
|
|
begin
|
|
{ This hook is not called by the wasuro preview1 glue;
|
|
asuro_wasi_args_get handles args_get as a direct host function. }
|
|
asuro_args_get := WASI_ESUCCESS;
|
|
end;
|
|
|
|
{ Direct host-function override for args_get.
|
|
Pops argv_ptr and argv_buf_ptr from the operand stack,
|
|
writes arg data into WASM linear memory, and pushes ESUCCESS. }
|
|
procedure asuro_wasi_args_get(Context : PWASMProcessContext);
|
|
var
|
|
argv_ptr, argv_buf_ptr : TWASMUInt32;
|
|
os : PWASMStack;
|
|
mem : PWasmHeap;
|
|
i, j : TWASMUInt32;
|
|
off : TWASMUInt32;
|
|
begin
|
|
os := Context^.ExecutionState.Operand_Stack;
|
|
mem := Context^.ExecutionState.Memory;
|
|
|
|
argv_buf_ptr := TWASMUInt32(wasm.types.stack.popi32(os));
|
|
argv_ptr := TWASMUInt32(wasm.types.stack.popi32(os));
|
|
|
|
if (ActiveShimPtr = nil) or (ActiveShimPtr^.ArgCount = 0) then begin
|
|
wasm.types.stack.pushi32(os, TWASMInt32(WASI_ESUCCESS));
|
|
exit;
|
|
end;
|
|
|
|
{ Walk the flat ArgBuf, writing each null-terminated string into
|
|
WASM memory at argv_buf_ptr+offset, and recording the WASM-side
|
|
pointer in the argv array. }
|
|
off := 0;
|
|
j := 0;
|
|
for i := 0 to ActiveShimPtr^.ArgCount - 1 do begin
|
|
{ argv[i] = WASM offset of this string }
|
|
wasm.types.heap.write_uint32(argv_ptr + (i * 4), mem, argv_buf_ptr + off);
|
|
|
|
{ Copy bytes including the null terminator }
|
|
while (j < ActiveShimPtr^.ArgBufSize) do begin
|
|
wasm.types.heap.write_uint8(argv_buf_ptr + off, mem,
|
|
TWASMUInt8(byte(ActiveShimPtr^.ArgBuf[j])));
|
|
inc(off);
|
|
inc(j);
|
|
if ActiveShimPtr^.ArgBuf[j - 1] = #0 then break;
|
|
end;
|
|
end;
|
|
|
|
wasm.types.stack.pushi32(os, TWASMInt32(WASI_ESUCCESS));
|
|
end;
|
|
|
|
{ ---- environ: no environment variables ---- }
|
|
|
|
function asuro_environ_sizes_get(var count : TWASMUInt32; var buf_size : TWASMUInt32) : TWASMUInt32;
|
|
begin
|
|
count := 0;
|
|
buf_size := 0;
|
|
asuro_environ_sizes_get := WASI_ESUCCESS;
|
|
end;
|
|
|
|
function asuro_environ_get(environ : TWASMPUInt32; environ_buf : TWASMPUInt8) : TWASMUInt32;
|
|
begin
|
|
asuro_environ_get := WASI_ESUCCESS;
|
|
end;
|
|
|
|
end.
|