Coder Social home page Coder Social logo

Comments (18)

fire avatar fire commented on May 10, 2024

For my personal historical reference.

game.zip
libgdsummator.linux.release.64.zip

from libriscv.

fire avatar fire commented on May 10, 2024

From reading https://github.com/fwsGonzo/rvscript/blob/master/engine/mods/hello_world/scripts/src/gameplay.cpp.

The translated design seems to be:

// RSICV
#define PUBLIC(x) extern "C" __attribute__((used, retain)) x

PUBLIC(GDNativeBool summator_library_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization));
// Godot Engine
NativeExtensionRISCV::open_library("scripts/summator.elf", "summator_library_init", "scripts/summator.map");
// Inside open_library 
// https://github.com/fwsGonzo/rvscript/blob/121c3990aa6c1afa79a7673b7f6e5c7a34642f31/engine/src/manage_scripts.cpp#L10
err = get_dynamic_library_symbol_handle(library, p_entry_symbol, symbol_map, entry_funcptr, false);
if (err != OK) {
    close_dynamic_library(library);
    return err;
}	
GDNativeInitializationFunction initialization_function = (GDNativeInitializationFunction)entry_funcptr;
initialization_function(&gdnative_interface, this, &initialization);
level_initialized = -1;
return OK;
// Others
NativeExtensionRISCV::preempt() {}
NativeExtensionRISCV::resume() {}

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

There is no shared library support right now, although it would be possible to add support for simple shared libraries. I can whip up some code that lets you load dependency-free shared libraries but I don't know if that is what you want.

libriscv primarily supports static binaries, so compiling the code with -static is the best option. Then you get everything you need inside the program. You can still make function calls and retrieve symbols from the binary, just like normal.

Looking at your shared object, it seems to have many dependencies:

 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-riscv64-lp64d.so.1]

This is what makes it a little bit harder to support shared libraries.

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

Looking at https://godotengine.org/article/introducing-gd-extensions it seems to require you to compile shared libraries for your native system anyway. So GDExtensionSummator would be compiled to amd64 (x86_64), or you can't load it on your system with dlopen.

On the other hand... you could create a GDExtension that loads RISC-V binaries and provides scripting facilities that way. But in the end it has to be compiled down to a shared library compatible with your native system.

from libriscv.

fire avatar fire commented on May 10, 2024

I was able to provide a main() and call that singular function maybe there some room to work with. It crashes with unaligned memory access in librisc. Will post later today.

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

I'm not sure what could cause that but there are some candidates. For example, in C++ there are often global objects with constructors and destructors, and guess what happens when you return from main? The destructors of all the global objects gets called. So, one way to avoid that is to just stop the emulator just before returning from main.

There is a secret halt instruction that you can invoke like this, which simply makes the emulator stop running:

inline void halt() {
	// Clobber memory because wake-ups can have things changed
	asm (".insn i SYSTEM, 0, x0, x0, 0x7ff" ::: "memory");
}

You can also call _exit(status) and get the status via machine.return_value() if you need that. There are many tricks!
I would need to see the code and how you call into the VM to understand the problem better.

from libriscv.

fire avatar fire commented on May 10, 2024
/opt/libriscv/emulator/build/rvlinux game/bin/summator/libgdsummator.linux.release.64.elf
>>> Program exited, exit code = 0 (0x0)
Instructions executed: 59159
Pages in use: 59 (236 kB memory)

libgdsummator.linux.release.64.zip

I'll try to describe the environment but it gets tricky.

  1. https://github.com/fire/GDExtensionSummator/tree/riscv
  2. https://github.com/V-Sekai/godot/tree/native-extension-riscv

I'll post this and then post more info.

from libriscv.

fire avatar fire commented on May 10, 2024

So using the testsuite64 I was able to load that file up to the opening /etc/hostname and then it stops from a windows embedded into Godot Engine binary. Still looking for more clues.

from libriscv.

fire avatar fire commented on May 10, 2024

image

https://github.com/fwsGonzo/libriscv/blob/master/lib/libriscv/win32/system_calls.cpp#L268-L302

Works with newlib64. Although I have no idea why linux64 is failing with opening /etc/hostname.

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

It's likely because there's something wrong with the system call handler in lib/libriscv/win32/system_calls.cpp.
None of the Linux system calls for Windows have been tested or even written properly. All they do is build, with a lot of warnings. Pay special attention to the wording. We are simulating a Linux program, on Windows, so the Linux system calls have to be handled on a Windows host, as if they were on Linux.

Newlib working makes sense, because it doesn't pretend to have many working system calls, and simply says no (-ENOSYS).
rvscript is using Newlib as a base, with a game engine API on top.

from libriscv.

fire avatar fire commented on May 10, 2024

I thought rvscript was using linux64. I missed the detail! The explanations are helpful!

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

You don't really need many system calls to get going. My advice is for every need to make a dedicated system call.
If you need to read a file into a string in the RISC-V program, just make a new system call for it, and have it take a buffer-length combo as arguments. If you are wondering how to implement your own system calls check out script_functions.cpp in rvscript repo, or just ask.

from libriscv.

fire avatar fire commented on May 10, 2024

I only need this one call from the starting comment.

address = machine.address_of(p_entry_symbol.utf8().get_data());
machine.vmcall<MAX_MEMORY>(address, &gdnative_interface, this, &initialization);

It does look tough though.

I also had some problems with the execution direction.

The Godot Engine API calls the p_entry_symbol to initialize structures on the host. Then I think Godot Engine uses that api structure to call something to be determined.

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

Without looking at all the code I can't tell if that's going to work, but I'm going to guess no. There is a hard border between a sandbox and the host environment that exists in all cases, also with WebAssembly. To work with it you have to think of the RISC-V program as being completely separate, so when you want to run code that needs some data, that data needs to be copied into the RISC-V program (or using shared pages).

I built a framework (rvscript) to simplify some things, but in the end, creating sandbox APIs are a little bit of extra work because of the total isolation.

For example, looking at your code you are passing this into the VM, however it lives in a completely separate (isolated) address space. The correct thing to do here is to probably call that function yourself. My advice is to implement the Godot extension as a regular DLL, on Windows, using the normal method. Add libriscv as a dependency, and then use libriscv inside your Godot extension DLL. It is not possible to build the extension itself inside the RISC-V program (at least not very fun).

Instead, you can make your Godot extension a plugin that loads a RISC-V program and interfaces with Godot using your plugin. That would work, and you don't have to write a ton of code to get started.

from libriscv.

fire avatar fire commented on May 10, 2024

Thinking about this:

  1. It should be possible execute main() on the riscv program
  2. inside of main() it can has a bool syscall(SYSCALL_GODOT_GDEXTENSION, const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization)
  3. This design won't work as is.

GDNativeInitialization contains a int, a byte buffer, and function pointer.
GDNativeExtensionClassLibraryPtr is used to call the host runtime.
GDNativeInterface is a struct that contains uint, uint, string buffer and 5 pages of function pointers.

I think the function pointers need to converted to syscalls.

From the guest it needs to tell Godot Engine the exposed things which are also function pointers.. so converted to syscalls.

classdb_register_extension_class
classdb_register_extension_class_method
classdb_register_extension_class_integer_constant
classdb_register_extension_class_property
classdb_register_extension_class_property_group
classdb_register_extension_class_property_subgroup
classdb_register_extension_class_signal
classdb_unregister_extension_class

Godot Engine can now call the listings through machine.vmcall.

This does sound workable hm.

from libriscv.

fire avatar fire commented on May 10, 2024

I'd like to have the scripting to be done via riscv programs.

Godot extension a plugin that loads a RISC-V program and interfaces with Godot using your plugin.

I think you're suggesting making a gdextension that implements the riscv host and write a new interface for the riscv host to load riscv programs. This is too complicated. godot -> gdextension -> riscv script has three stages. I think the gdextension layer is not essential. So it becomes godot riscv host -> riscv script.

The proposed design of the riscv host is it executes the main() of the riscv program. The main calls a number of syscalls that sets up the version, the levels (of engine subsystems) and then calls the syscalls to register the rest. The godot engine host may call through the listings given previously through machine.vmcall.

Will this work?

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

If you do away with the extension then you can have godot <-> riscv script, and you are right about how this would work.

I pressed close issue somehow, maybe an accidental keyboard shortcut. 😞

from libriscv.

fwsGonzo avatar fwsGonzo commented on May 10, 2024

If the initialization is very boilerplate I would consider making a single system call, or calling it automatically outside of RISC-V. It really depends on how it works. But a single system call that just takes a struct by reference is OK. You can pass function pointers from RISC-V to the host, but they have no meaning, so you will need to vmcall the function pointer later to get the scripting behavior. It's used as a common way to create events.

In my (private) engine events are wrapped RISC-V function calls, and it looks like this:

	Script*  m_script = nullptr;
	Script::gaddr_t m_funcaddr;

Basically, which RISC-V program the function belongs to, and then the address itself.

Modern game engines are very data oriented, and that makes it easier to create a simple system call API that can modify the ECS.

from libriscv.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.