Open LekKit opened 1 year ago
Is it possible to build librvvm.a
with pkg-config information?
I tried to adapt UserlandVM to new librvvm API and it currently crash in riscv_mmu_op
.
I tried to adapt UserlandVM to new librvvm API and it currently crash in
riscv_mmu_op
.
Can you give a backtrace?
Is it possible to build
librvvm.a
with pkg-config information?
Will do. I have no experience with pkg-config however 😅
Some obvious fixes:
diff --git a/src/rvvm.c b/src/rvvm.c
index c782080..a3427af 100644
--- a/src/rvvm.c
+++ b/src/rvvm.c
@@ -707,11 +707,15 @@ PUBLIC rvvm_cpu_handle_t rvvm_create_user_thread(rvvm_machine_t* machine)
vector_emplace_back(machine->harts);
rvvm_hart_t* vm = &vector_at(machine->harts, vector_size(machine->harts) - 1);
riscv_hart_init(vm, machine->rv64);
+ vm->machine = machine;
+ vm->mem = machine->mem;
#ifdef USE_FPU
// Initialize FPU properly
#endif
return (rvvm_cpu_handle_t)vm;
}
@@ -743,8 +747,9 @@ PUBLIC rvvm_addr_t rvvm_read_cpu_reg(rvvm_cpu_handle_t cpu, size_t reg_id)
return vm->csr.cause[PRIVILEGE_USER];
} else if (reg_id == RVVM_REGID_TVAL) {
return vm->csr.tval[PRIVILEGE_USER];
+ } else {
+ rvvm_warn("Unknown register %d in rvvm_read_cpu_reg()!", (uint32_t)reg_id);
}
- rvvm_warn("Unknown register %d in rvvm_read_cpu_reg()!", (uint32_t)reg_id);
return 0;
}
@@ -763,6 +768,7 @@ PUBLIC void rvvm_write_cpu_reg(rvvm_cpu_handle_t cpu, size_t reg_id, rvvm_addr_t
vm->csr.cause[PRIVILEGE_USER] = reg;
} else if (reg_id == RVVM_REGID_TVAL) {
vm->csr.tval[PRIVILEGE_USER] = reg;
+ } else {
+ rvvm_warn("Unknown register %d in rvvm_write_cpu_reg()!", (uint32_t)reg_id);
}
- rvvm_warn("Unknown register %d in rvvm_write_cpu_reg()!", (uint32_t)reg_id);
}
Some obvious fixes:
diff --git a/src/rvvm.c b/src/rvvm.c index c782080..a3427af 100644 --- a/src/rvvm.c +++ b/src/rvvm.c @@ -707,11 +707,15 @@ PUBLIC rvvm_cpu_handle_t rvvm_create_user_thread(rvvm_machine_t* machine) vector_emplace_back(machine->harts); rvvm_hart_t* vm = &vector_at(machine->harts, vector_size(machine->harts) - 1); riscv_hart_init(vm, machine->rv64); + vm->machine = machine; + vm->mem = machine->mem; #ifdef USE_FPU // Initialize FPU properly #endif return (rvvm_cpu_handle_t)vm; } @@ -743,8 +747,9 @@ PUBLIC rvvm_addr_t rvvm_read_cpu_reg(rvvm_cpu_handle_t cpu, size_t reg_id) return vm->csr.cause[PRIVILEGE_USER]; } else if (reg_id == RVVM_REGID_TVAL) { return vm->csr.tval[PRIVILEGE_USER]; + } else { + rvvm_warn("Unknown register %d in rvvm_read_cpu_reg()!", (uint32_t)reg_id); } - rvvm_warn("Unknown register %d in rvvm_read_cpu_reg()!", (uint32_t)reg_id); return 0; } @@ -763,6 +768,7 @@ PUBLIC void rvvm_write_cpu_reg(rvvm_cpu_handle_t cpu, size_t reg_id, rvvm_addr_t vm->csr.cause[PRIVILEGE_USER] = reg; } else if (reg_id == RVVM_REGID_TVAL) { vm->csr.tval[PRIVILEGE_USER] = reg; + } else { + rvvm_warn("Unknown register %d in rvvm_write_cpu_reg()!", (uint32_t)reg_id); } - rvvm_warn("Unknown register %d in rvvm_write_cpu_reg()!", (uint32_t)reg_id); }
Oh... Silly me Does it work now?
Apart from the possible explosions from RVJIT and my poor checking of my own code, I tried to copy your approach and also used some proper functions for FPU enablement and other cpu state setup
Does it work now?
Not yet. Crash after first syscall with NULL guest dereference. Maybe my fault, need to debug more. TinyEMU engine still working.
Does it work now?
Not yet. Crash after first syscall with NULL guest dereference. Maybe my fault, need to debug more. TinyEMU engine still working.
See my comment from d20c2d2 (Concern about PC increment behavior)
Where should the PC increment happen? In UserlandVM, merely returning from riscv_trap() means we land on a next instruction after the one that triggered the trap. This implementation preserves this behavior, but may need some re-arrangement. For example, we can increment the PC on the next entry to riscv_hart_run_userland(), or perhaps defer this to outside code (Will require changes on UserlandVM side)
This part should be more explicit and well documented. I'm not sure if this is the thing that broke for you, but just be aware. As for now, I'm not sure how do i set up UserlandVM to debug this myself, and not sure if any intervention is needed. There isn't much code changed so maybe you can wriggle around it and see potential fixes.
PC register is 4 inside syscall handler.
> UserlandVM /boot/home/Tests/UserlandVM/apps/StyledEdit
syscall 193(_kern_create_area)
PC: 4
[!] unhandled trap: Hart 0x7fda61ed74d0 trap at 00000000, cause 1, tval 0x000004
FP: 0x138f4fc8fd0, PC: 0
FP: 0x138f4fc9000, PC: 0xf6ae739332
FP: 0, PC: 0x209fe946018
Virtual CPU still try to jump at TVEC that is zero. It should be not done for userland emulation mode.
Virtual CPU still try to jump at TVEC that is zero. It should be not done for userland emulation mode.
Weird. I'm not sure how that's happening (Unless you are calling riscv_hart_run() or clearing vm->user_traps), I grep'ed the source tree for manupulations on REGISTER_PC and did not see any other way.
I used older version of riscv_hart.c
😅.
Now it seems crash on FPU instruction:
syscall 223(_kern_write_port_etc)
PC: 1052861742872
syscall 219(_kern_port_buffer_size_etc)
PC: 1052861742808
syscall 221(_kern_read_port_etc)
PC: 1052861742840
[!] unhandled trap: Hart 0x7f314e9fc940 trap at 0x193b9f4cc70, cause 2, tval 0x102773
FP: 0xb4e19de740, PC: </boot/home/Tests/UserlandVM/apps/lib/libbe.so> 0x193c70
FP: 0xb4e19de7e0, PC: </boot/home/Tests/UserlandVM/apps/lib/libtracker.so> 0x11362a
FP: 0xb4e19de820, PC: </boot/home/Tests/UserlandVM/apps/lib/libtracker.so> 0x11392e
FP: 0xb4e19de8c0, PC: </boot/home/Tests/UserlandVM/apps/lib/libtracker.so> 0xe30ce
FP: 0xb4e19dead0, PC: </boot/home/Tests/UserlandVM/apps/lib/libtracker.so> 0xe4738
FP: 0xb4e19dec50, PC: </boot/home/Tests/UserlandVM/apps/lib/libtracker.so> 0xe53ac
FP: 0xb4e19ded20, PC: </boot/home/Tests/UserlandVM/apps/lib/libtracker.so> 0xe0156
FP: 0xb4e19dedf0, PC: </boot/home/Tests/UserlandVM/apps/StyledEdit> 0x152c0
FP: 0xb4e19defa0, PC: </boot/home/Tests/UserlandVM/apps/StyledEdit> 0x12100
FP: 0xb4e19defd0, PC: </boot/home/Tests/UserlandVM/apps/StyledEdit> 0x121f6
FP: 0xb4e19df000, PC: 0x9476af3370
FP: 0, PC: 0x10e62d5e018
It started after recovering my old HART state initialization code:
maxlen_t mstatus = 0xA00000000 + (FS_INITIAL << 13);
riscv_csr_op(vm, 0x300, &mstatus, CSR_SWAP);
It started after recovering my old HART state initialization code:
Neat! I will provide upstream fixes soon. Does RVJIT work? 😅
Seems yes, but not with all programs.
Seems yes, but not with all programs.
Well, considering the absolute lack of cache coherence in userland mode, it's understandable. I think there are places where you could've missed the need to call rvvm_icache_flush(), for example munmap syscalls and other stuff that invalidates the code in memory. Alas, rvvm_icache_flush() is also potentially racy. I don't know for sure, would need to have your environment & working ThreadSanitizer. I remember you tried wrapping cpu runner in a lock for TEmu, so maybe you can try the same & see if it fixes anything.
Something wrong is happening with multiple threads (host heap corruption etc.).
This part should be more explicit and well documented. I'm not sure if this is the thing that broke for you, but just be aware.
Real RISC-V behavior is not incrementing PC on ECALL trap. This is also what TinyEMU does: https://github.com/X547/UserlandVM/blob/master/VirtualCpuRiscVTemu.cpp#L48.
Real RISC-V behavior is not incrementing PC on ECALL trap. This is also what TinyEMU does: https://github.com/X547/UserlandVM/blob/master/VirtualCpuRiscVTemu.cpp#L48.
I know, it's just an implementation detail (And optimization) of RVVM interpreter that leaked when we abandoned machine mode. After each interpreted instruction it increments PC by instruction size, but the trap handling jumps to TVEC which makes the PC increment invisible to the guest.
Omitting the increment for userland emulation also adds confusion when it's not the ECALL instruction: we aren't sure what's the size of the instruction (Which is why it was initially done this way internally)
rvvm_create_user_thread
have no machine->harts
thread protection and rvvm_free_user_thread
do not remove hart
from list.
rvvm_create_user_thread
have nomachine->harts
thread protection andrvvm_free_user_thread
do not removehart
from list.
There are some disastrous things from that vector manipulation already with CPU hotplug, a patch is on the way. You can try placing spin_lock(&global_lock)
there, but another horrific issue arises from the vector reallocation which moves our cpus in memory (OH GOD).
So heh, i think another round or two of patches is expected.
Just looked at my git diff --stat
21 files changed, 3502 insertions(+), 3152 deletions(-)
Oh... Poor networking, hid & fb stuff... I probably should start upstreaming them somehow
I removed hart
registration in machine
and more complex applications started working (no JIT).
It also works with JIT. hart
registration is currently main problem of multi-thread app failures.
It also works with JIT.
hart
registration is currently main problem of multi-thread app failures.
Hmm, thanks. I will switch from this task for a bit if you're alright with that, have some more stuff to do (Both related and unrelated to RVVM). I also have some questions about Haiku networking, and some HID API design decisions which need approval, but I'm not sure if that's related to any of the opened issues.
@X547 Can you make some kind of torture test for this API that will work outside of Haiku? I need that so I can test it using ThreadSanitizer & other stuff.
I made UserlandVM for Haiku only. Currently I have no tests that will work on Linux. There is a project that implement Haiku syscalls on Linux at library level (_kern_*
functions in libroot.so
), maybe it can be used to run something like 7z b
or JavaScript/Lua JIT.
Maybe it is not too hard to make some basic userland VM for Linux, but I am not familiar with Linux syscalls.
Can you fix multiple virtual HART registration/unregistration first? I think it can be done without advanced debugging tools like ThreadSatinizer.
Can you fix multiple virtual HART registration/unregistration first? I think it can be done without advanced debugging tools like ThreadSatinizer.
Done, see staging branch. Be aware I've been committing code without any testing because I have no idea how to get this working. It compiles & passes static analysis at least, but otherwise you're the only user of this API who can confirm if I did things right.
There is a project that implement Haiku syscalls on Linux at library level (
_kern_*
functions inlibroot.so
), maybe it can be used to run something like7z b
or JavaScript/Lua JIT.
Where do I get it? Sounds good
Maybe it is not too hard to make some basic userland VM for Linux, but I am not familiar with Linux syscalls.
Will be implemented at some point, but right now I'm more focused at upstreaming machine-related stuff (Networking) and helping you with existing userland emulator instead of writing one from scratch.
Latest version fails to build for me:
> git log
commit 3e970a388d333e3933c36437a6cf855b7d9626ff (HEAD -> master3, origin/staging)
Author: LekKit <50500857+LekKit@users.noreply.github.com>
Date: Sun Nov 20 13:20:32 2022 +0200
Use machine->harts pointers properly in PLIC
> git diff
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 749cfbe..faddc34 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -161,9 +161,9 @@ list(REMOVE_ITEM RVVM_DEVICES_SRC
if (RVVM_USE_FB)
if (HAIKU)
- target_sources(rvvm PRIVATE "${RVVM_HAIKU_SRC}")
+ target_sources(rvvm_common INTERFACE "${RVVM_HAIKU_SRC}")
find_library(RVVM_BE_LIB be REQUIRED)
- target_link_libraries(rvvm PRIVATE ${RVVM_BE_LIB})
+ target_link_libraries(rvvm_common INTERFACE ${RVVM_BE_LIB})
elseif (UNIX)
find_package(X11)
if (NOT TARGET X11::X11)
> cmake .. -DRVVM_USE_FB=ON -DRVVM_USE_JIT=ON -DCMAKE_BUILD_TYPE=Release -G Ninja
> ninja
[0/2] Re-checking globbed directories...
[56/56] Linking CXX executable rvvm
FAILED: rvvm
: && /bin/c++ -O3 -DNDEBUG -flto -fno-fat-lto-objects -flto=auto CMakeFiles/rvvm_bin.dir/src/main.c.o CMakeFiles/rvvm_bin.dir/src/devices/haiku_window.cpp.o -o rvvm -Wl,-rpath,/boot/system/lib librvvm.a librvvm_cpu32.a librvvm_cpu64.a librvjit.a librvvm_cpu32.a librvvm_cpu64.a librvjit.a /boot/system/lib/libatomic.so /boot/system/develop/lib/libm.a /boot/system/lib/libbe.so && :
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: /tmp//ccUAaQQJ.ltrans3.ltrans.o: in function `rvjit_ctx_free':
<artificial>:(.text+0x1ab): undefined reference to `hashmap_clear'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x1b5): undefined reference to `hashmap_destroy'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x1bd): undefined reference to `hashmap_destroy'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: /tmp//ccUAaQQJ.ltrans3.ltrans.o: in function `rvjit_block_lookup':
<artificial>:(.text+0x3e1): undefined reference to `hashmap_rebalance'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x49b): undefined reference to `hashmap_rebalance'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x4ed): undefined reference to `hashmap_shrink'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x501): undefined reference to `hashmap_shrink'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: /tmp//ccUAaQQJ.ltrans3.ltrans.o: in function `rvjit_flush_cache':
<artificial>:(.text+0x857): undefined reference to `hashmap_clear'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x898): undefined reference to `hashmap_clear'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: /tmp//ccUAaQQJ.ltrans3.ltrans.o: in function `rvjit_ctx_init':
<artificial>:(.text+0xed7): undefined reference to `hashmap_init'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0xee5): undefined reference to `hashmap_init'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: /tmp//ccUAaQQJ.ltrans3.ltrans.o: in function `rvjit_block_finalize':
<artificial>:(.text+0x352f): undefined reference to `hashmap_rebalance'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x3620): undefined reference to `hashmap_grow'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x3656): undefined reference to `hashmap_shrink'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x366d): undefined reference to `hashmap_rebalance'
/boot/system/develop/tools/bin/../lib/gcc/x86_64-unknown-haiku/11.2.0/../../../../x86_64-unknown-haiku/bin/ld: <artificial>:(.text+0x368e): undefined reference to `hashmap_grow'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
But compiled fine with Clang, strange... Some LTO-related trouble?
Confirmed that UserlandVM works with JIT and multiple threads with latest RVVM version.
Where do I get it? Sounds good
But compiled fine with Clang, strange... Some LTO-related trouble?
What's even weirder, I managed to reproduce this on Linux where it surely should not hit that if (HAIKU) branch. This still happens after rolling CMakeLists back, which means either it was broken all this time or I somehow broke it by source tree changes (???). This happens regardless of LTO and only with GCC, not with Clang or MSVC. Reminds me of similar issue in GCC related to inline functions: if you ever define an inline function without static attribute, it will later fail at link stage with optimizations disabled. We sure are not violating this rule though, since otherwise make CFLAGS=-O0
would also fail.
I summoned the CMake Wizard, @cerg2010cerg2010 to help with this. He mentions that his initial logic to separate librvjit from librvvm may have been broken due to the fact we include librvvm parts from there (hashmap, etc)
What's even weirder, I managed to reproduce this on Linux where it surely should not hit that if (HAIKU) branch.
It can be link order trouble. GNU ld
is sensitive to object files link order, but LLVM lld
isn't.
Latest version fails to build for me:
Fixed in 7b9b375
This issue remains as a tracker. If any app doesn't work under UserlandVM and you believe it to be RVVM bug, please report here (With additional information, does it break with JIT or completely, etc). Thanks.
The remaining tasks in this issue are postponed to collect more information first.
I found one regression with new librvvm
: menu windows are displayed at wrong position and size. Issue is not present with old embedded RVVM code and with TinyEMU code. Probably FPU related because float
type is used in GUI coordinates.
rvvm:
rvvm2 (note grey thin rectangle at screen left side):
Probably FPU related because
float
type is used in GUI coordinates.
You may try rolling back src/cpu/riscv_f.c to older commits, there weren't much breaking changes relative to the other code base. Be aware that it was also slightly broken previously (Explained in each commit). Notice also, our FPU needs CFLAG -frounding-math to pass RISC-V tests because compiler madness... and I don't see that CMake sets such flag. I also had reports that -frounding-math is unsupported on older Clang.
Public CPU register accessors may also be at fault. They bitcast FPU registers into u64, and either this isn't right or you are misinterpreting that data
Public CPU register accessors may also be at fault. They bitcast FPU registers into u64, and either this isn't right or you are misinterpreting that data
I tried to turn off FPU registers access in rvvm2 engine add-on (UserlandVM currently do not touch FPU registers anyway) and it have no effect.
Public CPU register accessors may also be at fault. They bitcast FPU registers into u64, and either this isn't right or you are misinterpreting that data
I tried to turn off FPU registers access in rvvm2 engine add-on (UserlandVM currently do not touch FPU registers anyway) and it have no effect.
Does it work for rvvm1 though? Just asking 😅 I guess this is either a regression (easily bisectable since the FPU is a single source with stable API), a broken build (Compilers sure hell like to break FPU code) or something in your code is messing up FPU env (rounding mode, exceptions). It could also be unrelated to FPU, although i'm not sure what changed in order for that to happen...
Does it work for rvvm1 though? Just asking 😅
Yes (first screenshot).
Probably FPU related because
float
type is used in GUI coordinates.
Question: Does the software in question work properly inside Haiku RISC-V guest in RVVM machine instead of userland emulation?
Question: Does the software in question work properly inside Haiku RISC-V guest in RVVM machine instead of userland emulation?
Timer interrupts are currently broken in Haiku RVVM guest. I tried various combinations (OpenSBI timers and haiku_loader.riscv machine mode timer control code). Works with TinyEMU and QEmu.
Question: Does the software in question work properly inside Haiku RISC-V guest in RVVM machine instead of userland emulation?
Timer interrupts are currently broken in Haiku RVVM guest. I tried various combinations (OpenSBI timers and haiku_loader.riscv machine mode timer control code). Works with TinyEMU and QEmu.
Can you give images for investigation?
Can you give a patch that restore ATA driver?
Can you give a patch that restore ATA driver?
Sure thing
diff --git a/src/main.c b/src/main.c
index 3d66493..d2043a5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -32,6 +32,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "devices/nvme.h"
#include "devices/eth-oc.h"
+#include "devices/ata.h"
+
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
@@ -231,7 +233,8 @@ static int rvvm_main(int argc, const char** argv)
} else if (cmp_arg(arg_name, "k") || cmp_arg(arg_name, "kernel")) {
success = success && rvvm_load_kernel(machine, arg_val);
} else if (cmp_arg(arg_name, "i") || cmp_arg(arg_name, "image")) {
- success = success && nvme_init_auto(machine, arg_val, true);
+ //success = success && nvme_init_auto(machine, arg_val, true);
+ ata_init_auto(machine, rvvm_get_pci_bus(machine), blk_open(arg_val, BLKDEV_RW));
} else if (cmp_arg(arg_name, "cmdline")) {
rvvm_cmdline_set(machine, arg_val);
} else if (cmp_arg(arg_name, "append")) {
I may bring back some kind of -ata
option if you really need it. For now it's limited to librvvm as an API to create such devices.
WARN: Possible deadlock at /Haiku/data/packages/RVVM/src/devices/ns16550a.c@267
WARN: The lock was previously held at /Haiku/data/packages/RVVM/src/devices/ns16550a.c@168
WARN: Attempting to recover execution...
* * * * * * *
Repeatedly displayed.
RVVM is usable as a generic CPU execution engine, not just as a complete machine. This suggests for working userspace emulation, which runs RISC-V code inside a host process, directly accesses it's memory and defers syscall execution to the host kernel. For convenience, it's also great to expose an API for that, there is a working project that already needs that (https://github.com/X547/UserlandVM), which uses RVVM for HaikuOS RISC-V userland emulation.
Progress tracking:
Discussions & suggestions are welcome.