mirror of
https://github.com/ringtailsoftware/uvm32.git
synced 2026-06-05 22:43:39 +00:00
Rename ioreq to syscall
This commit is contained in:
parent
b79a107a3d
commit
61fe0e8647
20 changed files with 187 additions and 190 deletions
32
README.md
32
README.md
|
|
@ -15,7 +15,7 @@ Although based on a fully fledged CPU emulator, uvm32 is intended for executing
|
|||
|
||||
## Samples
|
||||
|
||||
* [host](host) vm host which loads a binary and runs to completion, handling multiple ioreq types
|
||||
* [host](host) vm host which loads a binary and runs to completion, handling multiple syscall types
|
||||
* [host-mini](host-mini) minimal vm host (shown above), with baked in bytecode
|
||||
* [host-parallel](host-parallel) parallel vm host running multiple vm instances concurrently, with baked in bytecode
|
||||
* [host-arduino](host-arduino) vm host as Arduino sketch (tested on Arduino Uno ATmega328P, uses 9950 bytes of flash/1254 bytes RAM)
|
||||
|
|
@ -70,7 +70,7 @@ Once loaded with bytecode, uvm32's state is advanced by calling `uvm32_run()`.
|
|||
uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
|
||||
|
||||
`uvm32_run()` will execute until the bytecode requests some IO activity from the host.
|
||||
These IO activities are called "ioreqs" and are the only way for bytecode to communicate with the host.
|
||||
These IO activities are called "syscalls" and are the only way for bytecode to communicate with the host.
|
||||
If the bytecode attempts to execute more instructions than the the passed value of `instr_meter` it is assumed to have crashed and an error is reported.
|
||||
|
||||
(As with a watchdog on an embedded system, the `yield()` bytecode function tells the host that the code requires more time to complete and has not hung)
|
||||
|
|
@ -80,7 +80,7 @@ If the bytecode attempts to execute more instructions than the the passed value
|
|||
* `UVM32_EVT_END` the program has ended
|
||||
* `UVM32_EVT_ERR` the program has encountered an error
|
||||
* `UVM32_EVT_YIELD` the program has called `yield()` signifying that it requires more instructions to be executed, but has not crashed/hung
|
||||
* `UVM32_EVT_IOREQ` the program requests some IO via the host
|
||||
* `UVM32_EVT_UVM32_SYSCALL` the program requests some IO via the host
|
||||
|
||||
## Internals
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ uvm32 is always in one of 4 states, paused, running, ended or error.
|
|||
stateDiagram
|
||||
[*] --> UVM32_STATUS_PAUSED : uvm32_init()
|
||||
UVM32_STATUS_PAUSED-->UVM32_STATUS_RUNNING : uvm32_run()
|
||||
UVM32_STATUS_RUNNING --> UVM32_STATUS_PAUSED : ioreq event
|
||||
UVM32_STATUS_RUNNING --> UVM32_STATUS_PAUSED : syscall event
|
||||
UVM32_STATUS_RUNNING --> UVM32_STATUS_ENDED : halt()
|
||||
UVM32_STATUS_RUNNING --> UVM32_STATUS_ERROR
|
||||
```
|
||||
|
|
@ -105,7 +105,7 @@ At boot, the whole memory is zeroed. The user program is placed at the start, th
|
|||
|
||||
All communication between bytecode and the vm host is performed via syscalls.
|
||||
|
||||
To make a syscall, register `a7` is set with the syscall number (an `IOREQ_x`) and `a0` is set with the syscall parameter. The response is returned in `a1`.
|
||||
To make a syscall, register `a7` is set with the syscall number (a `UVM32_SYSCALL_x`) and `a0` is set with the syscall parameter. The response is returned in `a1`.
|
||||
|
||||
[target.h](common/uvm32_target.h#L12)
|
||||
|
||||
|
|
@ -125,14 +125,14 @@ static uint32_t syscall(uint32_t id, uint32_t param) {
|
|||
}
|
||||
```
|
||||
|
||||
## ioreqs
|
||||
## syscalls
|
||||
|
||||
There are two system ioreqs used by uvm32, `halt()` and `yield()`.
|
||||
There are two system syscalls used by uvm32, `halt()` and `yield()`.
|
||||
|
||||
`halt()` tells the host that the program has ended normally. `yield()` tells the host that the program requires more instructions to be executed.
|
||||
|
||||
New ioreqs can be added to the host via `uvm32_init()`.
|
||||
Each ioreq maps a syscall number to a value understood by the host (`F_PRINTD` below) and has an associated type which tells the host how to interpret the data passed to the syscall.
|
||||
New syscalls can be added to the host via `uvm32_init()`.
|
||||
Each syscall maps a syscall number to a value understood by the host (`F_PRINTD` below) and has an associated type which tells the host how to interpret the data passed to the syscall.
|
||||
|
||||
Here is a full example of a working VM host from [apps/host-mini](apps/host-mini)
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ Here is a full example of a working VM host from [apps/host-mini](apps/host-mini
|
|||
#include "../common/uvm32_common_custom.h"
|
||||
|
||||
// Precompiled binary program to print integers
|
||||
// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h)
|
||||
// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h)
|
||||
uint8_t rom[] = {
|
||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x73, 0x50, 0x80, 0x13,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x07, 0x00, 0x00,
|
||||
|
|
@ -159,9 +159,9 @@ typedef enum {
|
|||
F_PRINTD,
|
||||
} f_code_t;
|
||||
|
||||
// Map VM ioreq IOREQ_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32
|
||||
// Map VM syscall UVM32_SYSCALL_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32
|
||||
const uvm32_mapping_t env[] = {
|
||||
{ .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD },
|
||||
{ .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD },
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
|
@ -179,11 +179,11 @@ int main(int argc, char *argv[]) {
|
|||
case UVM32_EVT_END:
|
||||
isrunning = false;
|
||||
break;
|
||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
||||
switch((f_code_t)evt.data.ioreq.code) {
|
||||
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||
switch((f_code_t)evt.data.syscall.code) {
|
||||
case F_PRINTD:
|
||||
// Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in evt.data.ioreq.val.u32
|
||||
printf("%d\n", evt.data.ioreq.val.u32);
|
||||
// Type of F_PRINTD is UVM32_SYSCALL_TYP_U32_WR, so expect value in evt.data.syscall.val.u32
|
||||
printf("%d\n", evt.data.syscall.val.u32);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ jal ra, main
|
|||
#include "non-rust-crt0-hack.S"
|
||||
#else
|
||||
// only rust will see this
|
||||
li a7, {IOREQ_HALT}
|
||||
li a7, {UVM32_SYSCALL_HALT}
|
||||
#endif
|
||||
ecall
|
||||
.section .data
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
.global _start
|
||||
_start:
|
||||
la a0, str
|
||||
li a7, IOREQ_PRINTLN
|
||||
li a7, UVM32_SYSCALL_PRINTLN
|
||||
ecall
|
||||
li a7, IOREQ_HALT
|
||||
li a7, UVM32_SYSCALL_HALT
|
||||
ecall
|
||||
str:
|
||||
.ascii "Hi\0"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
li a7,IOREQ_HALT
|
||||
li a7,UVM32_SYSCALL_HALT
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ use core::arch::global_asm;
|
|||
use core::arch::asm;
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
// fetch IOREQ definitions from C header
|
||||
// fetch UVM32_SYSCALL definitions from C header
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
|
||||
// startup code
|
||||
global_asm!(include_str!("../../crt0.S"), IOREQ_HALT = const IOREQ_HALT);
|
||||
global_asm!(include_str!("../../crt0.S"), UVM32_SYSCALL_HALT = const UVM32_SYSCALL_HALT);
|
||||
|
||||
fn syscall(id: u32, n: u32) -> u32 {
|
||||
let mut value;
|
||||
|
|
@ -25,11 +25,11 @@ fn syscall(id: u32, n: u32) -> u32 {
|
|||
|
||||
fn println(message: &str) {
|
||||
let addr_value = message.as_ptr() as u32;
|
||||
syscall(IOREQ_PRINTLN, addr_value);
|
||||
syscall(UVM32_SYSCALL_PRINTLN, addr_value);
|
||||
}
|
||||
|
||||
fn printd(n: u32) {
|
||||
syscall(IOREQ_PRINTD, n);
|
||||
syscall(UVM32_SYSCALL_PRINTD, n);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@ pub inline fn syscall(id: u32, param: u32) u32 {
|
|||
}
|
||||
|
||||
pub inline fn println(val: [:0]const u8) void {
|
||||
_ = syscall(uvm32.IOREQ_PRINTLN, @intFromPtr(val.ptr));
|
||||
_ = syscall(uvm32.UVM32_SYSCALL_PRINTLN, @intFromPtr(val.ptr));
|
||||
}
|
||||
|
||||
pub inline fn yield() void {
|
||||
_ = syscall(uvm32.IOREQ_YIELD, 0);
|
||||
_ = syscall(uvm32.UVM32_SYSCALL_YIELD, 0);
|
||||
}
|
||||
|
||||
pub inline fn printc(c:u8) void {
|
||||
_ = syscall(uvm32.IOREQ_PRINTC, c);
|
||||
_ = syscall(uvm32.UVM32_SYSCALL_PRINTC, c);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ pub inline fn syscall(id: u32, param: u32) u32 {
|
|||
}
|
||||
|
||||
pub inline fn getch() ?u8 {
|
||||
const key = syscall(uvm32.IOREQ_GETC, 0);
|
||||
const key = syscall(uvm32.UVM32_SYSCALL_GETC, 0);
|
||||
if (key == 0xFFFFFFFF) {
|
||||
return null;
|
||||
} else {
|
||||
|
|
@ -24,7 +24,7 @@ pub inline fn getch() ?u8 {
|
|||
}
|
||||
|
||||
pub inline fn millis() u32 {
|
||||
return syscall(uvm32.IOREQ_MILLIS, 0);
|
||||
return syscall(uvm32.UVM32_SYSCALL_MILLIS, 0);
|
||||
}
|
||||
|
||||
// dupeZ would be better, but want to avoid using an allocator
|
||||
|
|
@ -35,21 +35,21 @@ pub inline fn print(m: []const u8) void {
|
|||
@memcpy(termination_buf[0..m.len], m);
|
||||
termination_buf[m.len] = 0;
|
||||
const s = termination_buf[0..m.len :0];
|
||||
_ = syscall(uvm32.IOREQ_PRINT, @intFromPtr(s.ptr));
|
||||
_ = syscall(uvm32.UVM32_SYSCALL_PRINT, @intFromPtr(s.ptr));
|
||||
}
|
||||
|
||||
pub inline fn println(m: []const u8) void {
|
||||
@memcpy(termination_buf[0..m.len], m);
|
||||
termination_buf[m.len] = 0;
|
||||
const s = termination_buf[0..m.len :0];
|
||||
_ = syscall(uvm32.IOREQ_PRINTLN, @intFromPtr(s.ptr));
|
||||
_ = syscall(uvm32.UVM32_SYSCALL_PRINTLN, @intFromPtr(s.ptr));
|
||||
}
|
||||
|
||||
pub inline fn yield() void {
|
||||
_ = syscall(uvm32.IOREQ_YIELD, 0);
|
||||
_ = syscall(uvm32.UVM32_SYSCALL_YIELD, 0);
|
||||
}
|
||||
|
||||
pub inline fn printc(c:u8) void {
|
||||
_ = syscall(uvm32.IOREQ_PRINTC, c);
|
||||
_ = syscall(uvm32.UVM32_SYSCALL_PRINTC, c);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Definitions needed by both host and target
|
||||
|
||||
// syscalls for exposed host functions
|
||||
#define IOREQ_PRINT 0x13A
|
||||
#define IOREQ_PRINTLN 0x13B
|
||||
#define IOREQ_PRINTD 0x13C
|
||||
#define IOREQ_PRINTX 0x13D
|
||||
#define IOREQ_MILLIS 0x13F
|
||||
#define IOREQ_PRINTC 0x140
|
||||
#define IOREQ_GETC 0x141
|
||||
#define UVM32_SYSCALL_PRINT 0x13A
|
||||
#define UVM32_SYSCALL_PRINTLN 0x13B
|
||||
#define UVM32_SYSCALL_PRINTD 0x13C
|
||||
#define UVM32_SYSCALL_PRINTX 0x13D
|
||||
#define UVM32_SYSCALL_MILLIS 0x13F
|
||||
#define UVM32_SYSCALL_PRINTC 0x140
|
||||
#define UVM32_SYSCALL_GETC 0x141
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// System provided IOREQs
|
||||
#define IOREQ_HALT 0x138
|
||||
#define IOREQ_YIELD 0x139
|
||||
// System provided UVM32_SYSCALLs
|
||||
#define UVM32_SYSCALL_HALT 0x138
|
||||
#define UVM32_SYSCALL_YIELD 0x139
|
||||
|
||||
#include "uvm32_common_custom.h"
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ static uint32_t syscall(uint32_t id, uint32_t param) {
|
|||
}
|
||||
|
||||
#define syscall_cast(id, x) syscall((uint32_t)id, (uint32_t)x)
|
||||
#define println(x) syscall_cast(IOREQ_PRINTLN, x)
|
||||
#define print(x) syscall_cast(IOREQ_PRINT, x)
|
||||
#define printd(x) syscall_cast(IOREQ_PRINTD, x)
|
||||
#define printx(x) syscall_cast(IOREQ_PRINTX, x)
|
||||
#define millis() syscall_cast(IOREQ_MILLIS, 0)
|
||||
#define printc() syscall_cast(IOREQ_PRINTC, 0)
|
||||
#define getc() syscall_cast(IOREQ_GETC, 0)
|
||||
#define yield() syscall_cast(IOREQ_YIELD, 0)
|
||||
#define println(x) syscall_cast(UVM32_SYSCALL_PRINTLN, x)
|
||||
#define print(x) syscall_cast(UVM32_SYSCALL_PRINT, x)
|
||||
#define printd(x) syscall_cast(UVM32_SYSCALL_PRINTD, x)
|
||||
#define printx(x) syscall_cast(UVM32_SYSCALL_PRINTX, x)
|
||||
#define millis() syscall_cast(UVM32_SYSCALL_MILLIS, 0)
|
||||
#define printc() syscall_cast(UVM32_SYSCALL_PRINTC, 0)
|
||||
#define getc() syscall_cast(UVM32_SYSCALL_GETC, 0)
|
||||
#define yield() syscall_cast(UVM32_SYSCALL_YIELD, 0)
|
||||
|
||||
#include "uvm32_common_custom.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Definitions needed by both host and target
|
||||
|
||||
// CSRs for exposed host functions
|
||||
#define IOREQ_PRINT 0x13A
|
||||
#define IOREQ_PRINTLN 0x13B
|
||||
#define IOREQ_PRINTD 0x13C
|
||||
#define IOREQ_PRINTX 0x13D
|
||||
#define IOREQ_MILLIS 0x13F
|
||||
#define IOREQ_PRINTC 0x140
|
||||
#define UVM32_SYSCALL_PRINT 0x13A
|
||||
#define UVM32_SYSCALL_PRINTLN 0x13B
|
||||
#define UVM32_SYSCALL_PRINTD 0x13C
|
||||
#define UVM32_SYSCALL_PRINTX 0x13D
|
||||
#define UVM32_SYSCALL_MILLIS 0x13F
|
||||
#define UVM32_SYSCALL_PRINTC 0x140
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// System provided IOREQs
|
||||
#define IOREQ_HALT 0x138
|
||||
#define IOREQ_YIELD 0x139
|
||||
// System provided UVM32_SYSCALLs
|
||||
#define UVM32_SYSCALL_HALT 0x138
|
||||
#define UVM32_SYSCALL_YIELD 0x139
|
||||
|
||||
#include "uvm32_common_custom.h"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "common/uvm32_common_custom.h"
|
||||
|
||||
// Precompiled binary program to print integers
|
||||
// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h)
|
||||
// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h)
|
||||
uint8_t rom[] = {
|
||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0xc0, 0x00, 0x93, 0x08, 0x80, 0x13,
|
||||
0x73, 0x00, 0x00, 0x00, 0x37, 0xf5, 0xff, 0xff, 0xb7, 0x15, 0x00, 0x00,
|
||||
|
|
@ -34,11 +34,11 @@ typedef enum {
|
|||
F_PRINTC,
|
||||
} f_code_t;
|
||||
|
||||
// Map VM ioreq IOREQ_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32
|
||||
// Map VM syscall UVM32_SYSCALL_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32
|
||||
const uvm32_mapping_t env[] = {
|
||||
{ IOREQ_PRINTD, F_PRINTD, IOREQ_TYP_U32_WR },
|
||||
{ IOREQ_PRINTC, F_PRINTC, IOREQ_TYP_U32_WR },
|
||||
{ IOREQ_PRINTLN, F_PRINTLN, IOREQ_TYP_BUF_TERMINATED_WR },
|
||||
{ UVM32_SYSCALL_PRINTD, F_PRINTD, UVM32_SYSCALL_TYP_U32_WR },
|
||||
{ UVM32_SYSCALL_PRINTC, F_PRINTC, UVM32_SYSCALL_TYP_U32_WR },
|
||||
{ UVM32_SYSCALL_PRINTLN, F_PRINTLN, UVM32_SYSCALL_TYP_BUF_TERMINATED_WR },
|
||||
};
|
||||
|
||||
uvm32_state_t vmst;
|
||||
|
|
@ -68,17 +68,17 @@ void loop(void) {
|
|||
case UVM32_EVT_END:
|
||||
isrunning = false;
|
||||
break;
|
||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
||||
switch((f_code_t)evt.data.ioreq.code) {
|
||||
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||
switch((f_code_t)evt.data.syscall.code) {
|
||||
case F_PRINTD:
|
||||
Serial.println(evt.data.ioreq.val.u32);
|
||||
Serial.println(evt.data.syscall.val.u32);
|
||||
break;
|
||||
case F_PRINTC:
|
||||
Serial.print((char)evt.data.ioreq.val.u32);
|
||||
Serial.print((char)evt.data.syscall.val.u32);
|
||||
break;
|
||||
case F_PRINTLN:
|
||||
for (int i=0;i<evt.data.ioreq.val.buf.len;i++) {
|
||||
Serial.print((char)evt.data.ioreq.val.buf.ptr[i]);
|
||||
for (int i=0;i<evt.data.syscall.val.buf.len;i++) {
|
||||
Serial.print((char)evt.data.syscall.val.buf.ptr[i]);
|
||||
}
|
||||
Serial.println("");
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ bool uvm32_load(uvm32_state_t *vmst, uint8_t *rom, int len) {
|
|||
}
|
||||
|
||||
// Read C-string up to terminator and return len,ptr
|
||||
static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t terminator, uvm32_evt_ioreq_buf_t *buf) {
|
||||
static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t terminator, uvm32_evt_syscall_buf_t *buf) {
|
||||
uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||
uint32_t p = ptrstart;
|
||||
if (p >= UVM32_MEMORY_SIZE) {
|
||||
|
|
@ -91,7 +91,7 @@ static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t t
|
|||
}
|
||||
|
||||
#if 0
|
||||
static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_ioreq_buf_t *buf) {
|
||||
static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_syscall_buf_t *buf) {
|
||||
uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||
if (ptrstart + len >= UVM32_MEMORY_SIZE) {
|
||||
setStatusErr(vmst, UVM32_ERR_MEM_RD);
|
||||
|
|
@ -104,7 +104,7 @@ static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_
|
|||
|
||||
uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) {
|
||||
uint32_t num_instr = 0;
|
||||
// uvm32_evt_ioreq_buf_t b;
|
||||
// uvm32_evt_syscall_buf_t b;
|
||||
|
||||
if (vmst->status != UVM32_STATUS_PAUSED) {
|
||||
setStatusErr(vmst, UVM32_ERR_NOTREADY);
|
||||
|
|
@ -128,11 +128,11 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
|
|||
vmst->core->pc += 4;
|
||||
switch(syscall) {
|
||||
// inbuilt syscalls
|
||||
case IOREQ_HALT:
|
||||
case UVM32_SYSCALL_HALT:
|
||||
setStatus(vmst, UVM32_STATUS_ENDED);
|
||||
syscall_valid = true;
|
||||
break;
|
||||
case IOREQ_YIELD:
|
||||
case UVM32_SYSCALL_YIELD:
|
||||
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||
syscall_valid = true;
|
||||
|
|
@ -145,24 +145,21 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
|
|||
if (syscall == vmst->mappings[i].syscall) {
|
||||
// setup ioevt.data according to mapping typ
|
||||
switch(vmst->mappings[i].typ) {
|
||||
case IOREQ_TYP_VOID:
|
||||
case UVM32_SYSCALL_TYP_VOID:
|
||||
break;
|
||||
case IOREQ_TYP_U32_WR:
|
||||
vmst->ioevt.data.ioreq.val.u32 = value;
|
||||
case UVM32_SYSCALL_TYP_U32_WR:
|
||||
vmst->ioevt.data.syscall.val.u32 = value;
|
||||
break;
|
||||
case IOREQ_TYP_BUF_TERMINATED_WR:
|
||||
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.ioreq.val.buf);
|
||||
case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR:
|
||||
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.syscall.val.buf);
|
||||
break;
|
||||
case IOREQ_TYP_U32_RD:
|
||||
// get_safeptr(vmst, value, 4, &b);
|
||||
vmst->ioevt.data.ioreq.val.u32p = &vmst->core->regs[11]; // r1, //(uint32_t *)b.ptr;
|
||||
case UVM32_SYSCALL_TYP_U32_RD:
|
||||
vmst->ioevt.data.syscall.val.u32p = &vmst->core->regs[11];
|
||||
break;
|
||||
}
|
||||
vmst->ioevt.typ = UVM32_EVT_IOREQ;
|
||||
vmst->ioevt.data.ioreq.code = vmst->mappings[i].code;
|
||||
vmst->ioevt.data.ioreq.typ = vmst->mappings[i].typ;
|
||||
//#warning FIXME, retval
|
||||
// vmst->core->regs[11] = 456; // r1
|
||||
vmst->ioevt.typ = UVM32_EVT_UVM32_SYSCALL;
|
||||
vmst->ioevt.data.syscall.code = vmst->mappings[i].code;
|
||||
vmst->ioevt.data.syscall.typ = vmst->mappings[i].typ;
|
||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||
syscall_valid = true;
|
||||
break; // stop searching
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// "well-known" system IOREQ functions
|
||||
#define IOREQ_HALT 0x138
|
||||
#define IOREQ_YIELD 0x139
|
||||
// "well-known" system UVM32_SYSCALL functions
|
||||
#define UVM32_SYSCALL_HALT 0x138
|
||||
#define UVM32_SYSCALL_YIELD 0x139
|
||||
|
||||
#define LIST_OF_UVM32_ERRS \
|
||||
X(UVM32_ERR_NONE) \
|
||||
|
|
@ -26,41 +26,41 @@ typedef enum {
|
|||
|
||||
typedef enum {
|
||||
UVM32_EVT_ERR,
|
||||
UVM32_EVT_IOREQ,
|
||||
UVM32_EVT_UVM32_SYSCALL,
|
||||
UVM32_EVT_YIELD,
|
||||
UVM32_EVT_END,
|
||||
} uvm32_evt_typ_t;
|
||||
|
||||
typedef enum {
|
||||
IOREQ_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_ioreq_t.val.buf
|
||||
IOREQ_TYP_VOID, // no data
|
||||
IOREQ_TYP_U32_WR, // data write from vm, in uvm32_evt_ioreq_t.val.u32
|
||||
IOREQ_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_ioreq_t.val.u32p
|
||||
} uvm32_ioreq_typ_t;
|
||||
UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_syscall_t.val.buf
|
||||
UVM32_SYSCALL_TYP_VOID, // no data
|
||||
UVM32_SYSCALL_TYP_U32_WR, // data write from vm, in uvm32_evt_syscall_t.val.u32
|
||||
UVM32_SYSCALL_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_syscall_t.val.u32p
|
||||
} uvm32_syscall_typ_t;
|
||||
|
||||
typedef uint32_t uvm32_user_ioreq_code_t;
|
||||
typedef uint32_t uvm32_user_syscall_code_t;
|
||||
|
||||
// user supplied mapping from syscall to typed ioreq
|
||||
// user supplied mapping from syscall to typed syscall
|
||||
typedef struct {
|
||||
uint32_t syscall;
|
||||
uvm32_user_ioreq_code_t code;
|
||||
uvm32_ioreq_typ_t typ;
|
||||
uvm32_user_syscall_code_t code;
|
||||
uvm32_syscall_typ_t typ;
|
||||
} uvm32_mapping_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *ptr;
|
||||
uint32_t len;
|
||||
} uvm32_evt_ioreq_buf_t;
|
||||
} uvm32_evt_syscall_buf_t;
|
||||
|
||||
typedef struct {
|
||||
uvm32_ioreq_typ_t typ;
|
||||
uvm32_user_ioreq_code_t code;
|
||||
uvm32_syscall_typ_t typ;
|
||||
uvm32_user_syscall_code_t code;
|
||||
union {
|
||||
uvm32_evt_ioreq_buf_t buf;
|
||||
uvm32_evt_syscall_buf_t buf;
|
||||
uint32_t u32;
|
||||
uint32_t *u32p;
|
||||
} val;
|
||||
} uvm32_evt_ioreq_t;
|
||||
} uvm32_evt_syscall_t;
|
||||
|
||||
typedef struct {
|
||||
uvm32_err_t errcode;
|
||||
|
|
@ -70,7 +70,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
uvm32_evt_typ_t typ;
|
||||
union {
|
||||
uvm32_evt_ioreq_t ioreq;
|
||||
uvm32_evt_syscall_t syscall;
|
||||
uvm32_evt_err_t err;
|
||||
} data;
|
||||
} uvm32_evt_t;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "../common/uvm32_common_custom.h"
|
||||
|
||||
// Precompiled binary program to print integers
|
||||
// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h)
|
||||
// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h)
|
||||
uint8_t rom[] = {
|
||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13,
|
||||
0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00,
|
||||
|
|
@ -18,9 +18,9 @@ typedef enum {
|
|||
F_PRINTD,
|
||||
} f_code_t;
|
||||
|
||||
// Map VM ioreq IOREQ_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32
|
||||
// Map VM syscall UVM32_SYSCALL_PRINTD (0x13C) to F_PRINTD, tell VM to expect write of a U32
|
||||
const uvm32_mapping_t env[] = {
|
||||
{ .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD },
|
||||
{ .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD },
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
|
@ -38,11 +38,11 @@ int main(int argc, char *argv[]) {
|
|||
case UVM32_EVT_END:
|
||||
isrunning = false;
|
||||
break;
|
||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
||||
switch((f_code_t)evt.data.ioreq.code) {
|
||||
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||
switch((f_code_t)evt.data.syscall.code) {
|
||||
case F_PRINTD:
|
||||
// Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in evt.data.ioreq.val.u32
|
||||
printf("%d\n", evt.data.ioreq.val.u32);
|
||||
// Type of F_PRINTD is UVM32_SYSCALL_TYP_U32_WR, so expect value in evt.data.syscall.val.u32
|
||||
printf("%d\n", evt.data.syscall.val.u32);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#define SCHEDULE_RANDOM() scheduler_index = rand()%NUM_VM
|
||||
|
||||
// Precompiled binary program to print integers
|
||||
// This code expects to print via syscall 0x13C (IOREQ_PRINTD in common/uvm32_common_custom.h)
|
||||
// This code expects to print via syscall 0x13C (UVM32_SYSCALL_PRINTD in common/uvm32_common_custom.h)
|
||||
uint8_t rom[] = {
|
||||
0x23, 0x26, 0x11, 0x00, 0xef, 0x00, 0x00, 0x01, 0x93, 0x08, 0x80, 0x13,
|
||||
0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x05, 0x00, 0x00,
|
||||
|
|
@ -26,9 +26,9 @@ typedef enum {
|
|||
F_PRINTD,
|
||||
} f_code_t;
|
||||
|
||||
// Map VM ioreq IOREQ_PRINTD to F_PRINTD, tell VM to expect write of a U32
|
||||
// Map VM syscall UVM32_SYSCALL_PRINTD to F_PRINTD, tell VM to expect write of a U32
|
||||
const uvm32_mapping_t env[] = {
|
||||
{ .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD },
|
||||
{ .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD },
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
|
@ -55,11 +55,11 @@ int main(int argc, char *argv[]) {
|
|||
printf("[VM %d ended]\n", scheduler_index);
|
||||
numVmRunning--;
|
||||
break;
|
||||
case UVM32_EVT_IOREQ: // vm has paused to handle IOREQ
|
||||
switch((f_code_t)evt.data.ioreq.code) {
|
||||
case UVM32_EVT_UVM32_SYSCALL: // vm has paused to handle UVM32_SYSCALL
|
||||
switch((f_code_t)evt.data.syscall.code) {
|
||||
case F_PRINTD:
|
||||
// Type of F_PRINTD is IOREQ_TYP_U32_WR, so expect value in evt.data.ioreq.val.u32
|
||||
printf("[VM %d]: %d\n", scheduler_index, evt.data.ioreq.val.u32);
|
||||
// Type of F_PRINTD is UVM32_SYSCALL_TYP_U32_WR, so expect value in evt.data.syscall.val.u32
|
||||
printf("[VM %d]: %d\n", scheduler_index, evt.data.syscall.val.u32);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
68
host/host.c
68
host/host.c
|
|
@ -12,7 +12,7 @@
|
|||
// stash terminal settings on startup
|
||||
static struct termios orig_termios;
|
||||
|
||||
// ioreqs exposed to vm environement
|
||||
// syscalls exposed to vm environement
|
||||
typedef enum {
|
||||
F_PRINT,
|
||||
F_PRINTD,
|
||||
|
|
@ -23,15 +23,15 @@ typedef enum {
|
|||
F_GETC,
|
||||
} f_code_t;
|
||||
|
||||
// Map exposed ioreqs to syscalls
|
||||
// Map exposed syscalls to syscalls
|
||||
const uvm32_mapping_t env[] = {
|
||||
{ .syscall = IOREQ_PRINTLN, .typ = IOREQ_TYP_BUF_TERMINATED_WR, .code = F_PRINTLN },
|
||||
{ .syscall = IOREQ_PRINT, .typ = IOREQ_TYP_BUF_TERMINATED_WR, .code = F_PRINT },
|
||||
{ .syscall = IOREQ_PRINTD, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTD },
|
||||
{ .syscall = IOREQ_PRINTX, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTX },
|
||||
{ .syscall = IOREQ_PRINTC, .typ = IOREQ_TYP_U32_WR, .code = F_PRINTC },
|
||||
{ .syscall = IOREQ_MILLIS, .typ = IOREQ_TYP_U32_RD, .code = F_MILLIS },
|
||||
{ .syscall = IOREQ_GETC, .typ = IOREQ_TYP_U32_RD, .code = F_GETC },
|
||||
{ .syscall = UVM32_SYSCALL_PRINTLN, .typ = UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, .code = F_PRINTLN },
|
||||
{ .syscall = UVM32_SYSCALL_PRINT, .typ = UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, .code = F_PRINT },
|
||||
{ .syscall = UVM32_SYSCALL_PRINTD, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTD },
|
||||
{ .syscall = UVM32_SYSCALL_PRINTX, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTX },
|
||||
{ .syscall = UVM32_SYSCALL_PRINTC, .typ = UVM32_SYSCALL_TYP_U32_WR, .code = F_PRINTC },
|
||||
{ .syscall = UVM32_SYSCALL_MILLIS, .typ = UVM32_SYSCALL_TYP_U32_RD, .code = F_MILLIS },
|
||||
{ .syscall = UVM32_SYSCALL_GETC, .typ = UVM32_SYSCALL_TYP_U32_RD, .code = F_GETC },
|
||||
};
|
||||
|
||||
void disableRawMode(void) {
|
||||
|
|
@ -159,14 +159,14 @@ int main(int argc, char *argv[]) {
|
|||
uvm32_evt_t evt;
|
||||
bool isrunning = true;
|
||||
uint32_t total_instrs = 0;
|
||||
uint32_t num_ioreqs = 0;
|
||||
uint32_t num_syscalls = 0;
|
||||
|
||||
// setup terminal for getch()
|
||||
enableRawMode();
|
||||
|
||||
while(isrunning) {
|
||||
total_instrs += uvm32_run(&vmst, &evt, 1000000); // num instructions before vm considered hung
|
||||
num_ioreqs++;
|
||||
num_syscalls++;
|
||||
|
||||
switch(evt.typ) {
|
||||
case UVM32_EVT_END:
|
||||
|
|
@ -175,57 +175,57 @@ int main(int argc, char *argv[]) {
|
|||
break;
|
||||
case UVM32_EVT_YIELD:
|
||||
//printf("UVM32_EVT_YIELD\n");
|
||||
// program has paused, but no ioreq
|
||||
// program has paused, but no syscall
|
||||
break;
|
||||
case UVM32_EVT_ERR:
|
||||
printf("UVM32_EVT_ERR '%s' (%d)\n", evt.data.err.errstr, (int)evt.data.err.errcode);
|
||||
isrunning = false;
|
||||
break;
|
||||
case UVM32_EVT_IOREQ:
|
||||
switch((f_code_t)evt.data.ioreq.code) {
|
||||
case UVM32_EVT_UVM32_SYSCALL:
|
||||
switch((f_code_t)evt.data.syscall.code) {
|
||||
case F_PRINT:
|
||||
printf("%.*s", evt.data.ioreq.val.buf.len, evt.data.ioreq.val.buf.ptr);
|
||||
printf("%.*s", evt.data.syscall.val.buf.len, evt.data.syscall.val.buf.ptr);
|
||||
break;
|
||||
case F_PRINTLN:
|
||||
printf("%.*s\n", evt.data.ioreq.val.buf.len, evt.data.ioreq.val.buf.ptr);
|
||||
printf("%.*s\n", evt.data.syscall.val.buf.len, evt.data.syscall.val.buf.ptr);
|
||||
break;
|
||||
case F_PRINTD:
|
||||
printf("%d\n", evt.data.ioreq.val.u32);
|
||||
printf("%d\n", evt.data.syscall.val.u32);
|
||||
break;
|
||||
case F_PRINTC:
|
||||
printf("%c", evt.data.ioreq.val.u32);
|
||||
printf("%c", evt.data.syscall.val.u32);
|
||||
break;
|
||||
case F_PRINTX:
|
||||
printf("%08x", evt.data.ioreq.val.u32);
|
||||
printf("%08x", evt.data.syscall.val.u32);
|
||||
break;
|
||||
case F_GETC: {
|
||||
uint8_t ch;
|
||||
if (poll_getch(&ch)) {
|
||||
*evt.data.ioreq.val.u32p = ch;
|
||||
*evt.data.syscall.val.u32p = ch;
|
||||
} else {
|
||||
*evt.data.ioreq.val.u32p = 0xFFFFFFFF; // nothing
|
||||
*evt.data.syscall.val.u32p = 0xFFFFFFFF; // nothing
|
||||
}
|
||||
} break;
|
||||
case F_MILLIS: {
|
||||
clock_t now = clock() / (CLOCKS_PER_SEC / 1000);
|
||||
*evt.data.ioreq.val.u32p = now - start_time;
|
||||
*evt.data.syscall.val.u32p = now - start_time;
|
||||
} break;
|
||||
default: // catch any others
|
||||
switch(evt.data.ioreq.typ) {
|
||||
case IOREQ_TYP_BUF_TERMINATED_WR:
|
||||
printf("IOREQ_TYP_BUF_TERMINATED_WR code=%d val=", evt.data.ioreq.code);
|
||||
hexdump(evt.data.ioreq.val.buf.ptr, evt.data.ioreq.val.buf.len);
|
||||
switch(evt.data.syscall.typ) {
|
||||
case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR:
|
||||
printf("UVM32_SYSCALL_TYP_BUF_TERMINATED_WR code=%d val=", evt.data.syscall.code);
|
||||
hexdump(evt.data.syscall.val.buf.ptr, evt.data.syscall.val.buf.len);
|
||||
printf("\n");
|
||||
break;
|
||||
case IOREQ_TYP_VOID:
|
||||
printf("IOREQ_TYP_VOID code=%d\n", evt.data.ioreq.code);
|
||||
case UVM32_SYSCALL_TYP_VOID:
|
||||
printf("UVM32_SYSCALL_TYP_VOID code=%d\n", evt.data.syscall.code);
|
||||
break;
|
||||
case IOREQ_TYP_U32_WR:
|
||||
printf("IOREQ_TYP_U32_WR code=%d val=%d (0x%08x)\n", evt.data.ioreq.code, evt.data.ioreq.val.u32, evt.data.ioreq.val.u32);
|
||||
case UVM32_SYSCALL_TYP_U32_WR:
|
||||
printf("UVM32_SYSCALL_TYP_U32_WR code=%d val=%d (0x%08x)\n", evt.data.syscall.code, evt.data.syscall.val.u32, evt.data.syscall.val.u32);
|
||||
break;
|
||||
case IOREQ_TYP_U32_RD:
|
||||
printf("IOREQ_TYP_U32_RD code=%d\n", evt.data.ioreq.code);
|
||||
*evt.data.ioreq.val.u32p = 123456;
|
||||
case UVM32_SYSCALL_TYP_U32_RD:
|
||||
printf("UVM32_SYSCALL_TYP_U32_RD code=%d\n", evt.data.syscall.code);
|
||||
*evt.data.syscall.val.u32p = 123456;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
@ -239,7 +239,7 @@ int main(int argc, char *argv[]) {
|
|||
fflush(stdout);
|
||||
}
|
||||
|
||||
printf("Executed total of %d instructions and %d ioreqs\n", (int)total_instrs, (int)num_ioreqs);
|
||||
printf("Executed total of %d instructions and %d syscalls\n", (int)total_instrs, (int)num_syscalls);
|
||||
|
||||
free(rom);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ bool uvm32_load(uvm32_state_t *vmst, uint8_t *rom, int len) {
|
|||
}
|
||||
|
||||
// Read C-string up to terminator and return len,ptr
|
||||
static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t terminator, uvm32_evt_ioreq_buf_t *buf) {
|
||||
static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t terminator, uvm32_evt_syscall_buf_t *buf) {
|
||||
uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||
uint32_t p = ptrstart;
|
||||
if (p >= UVM32_MEMORY_SIZE) {
|
||||
|
|
@ -90,7 +90,7 @@ static void get_safeptr_terminated(uvm32_state_t *vmst, uint32_t addr, uint8_t t
|
|||
}
|
||||
|
||||
#if 0
|
||||
static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_ioreq_buf_t *buf) {
|
||||
static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_evt_syscall_buf_t *buf) {
|
||||
uint32_t ptrstart = addr - MINIRV32_RAM_IMAGE_OFFSET;
|
||||
if (ptrstart + len >= UVM32_MEMORY_SIZE) {
|
||||
setStatusErr(vmst, UVM32_ERR_MEM_RD);
|
||||
|
|
@ -103,7 +103,7 @@ static void get_safeptr(uvm32_state_t *vmst, uint32_t addr, uint32_t len, uvm32_
|
|||
|
||||
uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter) {
|
||||
uint32_t num_instr = 0;
|
||||
// uvm32_evt_ioreq_buf_t b;
|
||||
// uvm32_evt_syscall_buf_t b;
|
||||
|
||||
if (vmst->status != UVM32_STATUS_PAUSED) {
|
||||
setStatusErr(vmst, UVM32_ERR_NOTREADY);
|
||||
|
|
@ -127,11 +127,11 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
|
|||
vmst->core->pc += 4;
|
||||
switch(syscall) {
|
||||
// inbuilt syscalls
|
||||
case IOREQ_HALT:
|
||||
case UVM32_SYSCALL_HALT:
|
||||
setStatus(vmst, UVM32_STATUS_ENDED);
|
||||
syscall_valid = true;
|
||||
break;
|
||||
case IOREQ_YIELD:
|
||||
case UVM32_SYSCALL_YIELD:
|
||||
vmst->ioevt.typ = UVM32_EVT_YIELD;
|
||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||
syscall_valid = true;
|
||||
|
|
@ -144,22 +144,22 @@ uint32_t uvm32_run(uvm32_state_t *vmst, uvm32_evt_t *evt, uint32_t instr_meter)
|
|||
if (syscall == vmst->mappings[i].syscall) {
|
||||
// setup ioevt.data according to mapping typ
|
||||
switch(vmst->mappings[i].typ) {
|
||||
case IOREQ_TYP_VOID:
|
||||
case UVM32_SYSCALL_TYP_VOID:
|
||||
break;
|
||||
case IOREQ_TYP_U32_WR:
|
||||
vmst->ioevt.data.ioreq.val.u32 = value;
|
||||
case UVM32_SYSCALL_TYP_U32_WR:
|
||||
vmst->ioevt.data.syscall.val.u32 = value;
|
||||
break;
|
||||
case IOREQ_TYP_BUF_TERMINATED_WR:
|
||||
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.ioreq.val.buf);
|
||||
case UVM32_SYSCALL_TYP_BUF_TERMINATED_WR:
|
||||
get_safeptr_terminated(vmst, value, 0x00, &vmst->ioevt.data.syscall.val.buf);
|
||||
break;
|
||||
case IOREQ_TYP_U32_RD:
|
||||
case UVM32_SYSCALL_TYP_U32_RD:
|
||||
// pass link to r1 for user function to update
|
||||
vmst->ioevt.data.ioreq.val.u32p = &vmst->core->regs[11];
|
||||
vmst->ioevt.data.syscall.val.u32p = &vmst->core->regs[11];
|
||||
break;
|
||||
}
|
||||
vmst->ioevt.typ = UVM32_EVT_IOREQ;
|
||||
vmst->ioevt.data.ioreq.code = vmst->mappings[i].code;
|
||||
vmst->ioevt.data.ioreq.typ = vmst->mappings[i].typ;
|
||||
vmst->ioevt.typ = UVM32_EVT_UVM32_SYSCALL;
|
||||
vmst->ioevt.data.syscall.code = vmst->mappings[i].code;
|
||||
vmst->ioevt.data.syscall.typ = vmst->mappings[i].typ;
|
||||
setStatus(vmst, UVM32_STATUS_PAUSED);
|
||||
syscall_valid = true;
|
||||
break; // stop searching
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// "well-known" system IOREQ functions
|
||||
#define IOREQ_HALT 0x138
|
||||
#define IOREQ_YIELD 0x139
|
||||
// "well-known" system UVM32_SYSCALL functions
|
||||
#define UVM32_SYSCALL_HALT 0x138
|
||||
#define UVM32_SYSCALL_YIELD 0x139
|
||||
|
||||
#define LIST_OF_UVM32_ERRS \
|
||||
X(UVM32_ERR_NONE) \
|
||||
|
|
@ -26,41 +26,41 @@ typedef enum {
|
|||
|
||||
typedef enum {
|
||||
UVM32_EVT_ERR,
|
||||
UVM32_EVT_IOREQ,
|
||||
UVM32_EVT_UVM32_SYSCALL,
|
||||
UVM32_EVT_YIELD,
|
||||
UVM32_EVT_END,
|
||||
} uvm32_evt_typ_t;
|
||||
|
||||
typedef enum {
|
||||
IOREQ_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_ioreq_t.val.buf
|
||||
IOREQ_TYP_VOID, // no data
|
||||
IOREQ_TYP_U32_WR, // data write from vm, in uvm32_evt_ioreq_t.val.u32
|
||||
IOREQ_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_ioreq_t.val.u32p
|
||||
} uvm32_ioreq_typ_t;
|
||||
UVM32_SYSCALL_TYP_BUF_TERMINATED_WR, // data write from vm, NULL terminated string of bytes, in uvm32_evt_syscall_t.val.buf
|
||||
UVM32_SYSCALL_TYP_VOID, // no data
|
||||
UVM32_SYSCALL_TYP_U32_WR, // data write from vm, in uvm32_evt_syscall_t.val.u32
|
||||
UVM32_SYSCALL_TYP_U32_RD, // data read from vm, expects response in uvm32_evt_syscall_t.val.u32p
|
||||
} uvm32_syscall_typ_t;
|
||||
|
||||
typedef uint32_t uvm32_user_ioreq_code_t;
|
||||
typedef uint32_t uvm32_user_syscall_code_t;
|
||||
|
||||
// user supplied mapping from syscall to typed ioreq
|
||||
// user supplied mapping from syscall to typed syscall
|
||||
typedef struct {
|
||||
uint32_t syscall;
|
||||
uvm32_user_ioreq_code_t code;
|
||||
uvm32_ioreq_typ_t typ;
|
||||
uvm32_user_syscall_code_t code;
|
||||
uvm32_syscall_typ_t typ;
|
||||
} uvm32_mapping_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *ptr;
|
||||
uint32_t len;
|
||||
} uvm32_evt_ioreq_buf_t;
|
||||
} uvm32_evt_syscall_buf_t;
|
||||
|
||||
typedef struct {
|
||||
uvm32_ioreq_typ_t typ;
|
||||
uvm32_user_ioreq_code_t code;
|
||||
uvm32_syscall_typ_t typ;
|
||||
uvm32_user_syscall_code_t code;
|
||||
union {
|
||||
uvm32_evt_ioreq_buf_t buf;
|
||||
uvm32_evt_syscall_buf_t buf;
|
||||
uint32_t u32;
|
||||
uint32_t *u32p;
|
||||
} val;
|
||||
} uvm32_evt_ioreq_t;
|
||||
} uvm32_evt_syscall_t;
|
||||
|
||||
typedef struct {
|
||||
uvm32_err_t errcode;
|
||||
|
|
@ -70,7 +70,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
uvm32_evt_typ_t typ;
|
||||
union {
|
||||
uvm32_evt_ioreq_t ioreq;
|
||||
uvm32_evt_syscall_t syscall;
|
||||
uvm32_evt_err_t err;
|
||||
} data;
|
||||
} uvm32_evt_t;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue