-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactoring RISC-V emulation APIs for easier adoption and porting #310
Comments
I would like to invite @RinHizakura, @qwe661234, and @visitorckw to join the discussion and contribute to the refinement of the API. |
In the initial stages of developing this emulator, I redirected I/O operations to files for comparison purposes. However, I now recognize that this approach to the function interface was not as flexible as I had initially thought. |
So, it could be useful to provide an abstract way for defining the desired |
I think the distinction between modules is a little bit unclear in the current design of
So, if it doesn't matter to provide user-specific operations on memory, providing them on the build time for the library will also be a great solution. |
Not quite sure about whether changing the memory size directly is safe. As I remember, some implementations of rv32emu intensionally rely on the fact that the memory size is 2^32 - 1 to have some trick. Or maybe I mix up with some project else. Looking for others to answer the question. |
The built-in ELF programs do not seem to need a lot of memory so I think 2GB - 4GB is a safe region. Dynamically changing the memory size in different runtime might be needed. For example, 64KiB multiples should be used in WebAssembly. The |
I would like to introduce Then, |
For example:
|
I agree. By the way, |
The repository mnurzia/rv serves as an additional reference for API refinement. It features three main APIs:
These APIs collectively provide a structure for memory access, CPU initialization, and step-wise execution in the CPU simulation. |
As previously suggested, the maximum memory ( Makefile:
Thus, adjusting stack size should be a part in public API. |
I think Currently,
I would like to introduce the sixth attribute of Prefix of all vm-related functions should be consistent ( more discussion ). |
It sounds promising. Please send pull request(s) to refine APIs.
How about
|
Since the envp is not accessible for now, place a TODO in
It is related to |
After streamlining the API, we can control the exit code by storing it in a specific structure, instead of displaying it directly in the console. |
For abstracting file or file descriptor, we could have an attribute called |
Since we should also have to maintain the file descriptor if struct {
...
int stdin;
int stdout;
int stderr;
} vm_attr_t; Note: The variable's name should be refined. I just can't come up with a suitable and concise name now These file descriptors are assigned to 0, 1, and 2 by default, and modified if |
Thanks for tips! I think the boolean really redundant since |
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user; as a result, setting a configuration value (vm_attr_t) is sufficient. The user should concern about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. The vm_attr_t has multiple fields and they are commented clearly in the code. Note that logging feature and system emulator integration are not implemented yet. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user; as a result, setting a configuration value (vm_attr_t) is sufficient. For stdio redirection, rv_register_stdio function is introduced. The user should concern about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. The vm_attr_t has multiple fields and they are commented clearly in the code. Note that logging feature and system emulator integration are not implemented yet. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user, as a result, setting a configuration value (vm_attr_t) is sufficient. The user should manage about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. For stdio remapping, rv_remap_stdstream function is introduced. The vm_attr_t has multiple fields and they are commented clearly in the code. elf_t is reopened in run_and_trace and dump_test_signature because elf_t is allocated inside rv_create and they cannot access them. It is acceptable to reopen elf_t since they are only for testing and debugging. PRINT_EXIT_CODE build macro is introduced to enable syscall_exit to print exit code to console only during testing since the actual usage of exit code is really depending on applications. The io interface is not changed in this PR because it could maybe reused with semu in some way, still need to be investigated. Also, Logging feature and system emulator integration are not implemented yet. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user, as a result, setting a configuration value (vm_attr_t) is sufficient. The user should manage about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. For stdio remapping, rv_remap_stdstream function is introduced. The vm_attr_t has multiple fields and they are commented clearly in the code. elf is reopened in run_and_trace and dump_test_signature because elf is allocated inside rv_create and they cannot access them. It is acceptable to reopen elf since they are only for testing and debugging. Print inferior exit code to console inside main instead of syscall_exit because the actual usage of exit code depends on applications of using riscv public API. The io interface is not changed in this PR because it could maybe reused with semu in some way, still need to be investigated. Also, Logging feature and system emulator integration are not implemented yet. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user, as a result, setting a configuration value (vm_attr_t) is sufficient. The user should manage about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. For stdio remapping, rv_remap_stdstream function is introduced. The vm_attr_t has multiple fields and they are commented clearly in the code. elf is reopened in dump_test_signature because elf is allocated during rv_create. It is acceptable to reopen elf since it is only for testing. Print inferior exit code to console inside main instead of syscall_exit because the actual usage of exit code depends on applications of using riscv public API. The io interface is not changed in this PR because it could maybe reused with semu in some way, still need to be investigated. Also, Logging feature and system emulator integration are not implemented yet. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user, as a result, setting a configuration value (vm_attr_t) is sufficient. The user should manage about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. The vm_attr_t has multiple fields and they are commented clearly in the code. As you can see in "main", there are various mode to run the emulator such as "run_and_trace", "gdbstub", and "profiling". Thus, a field call "run_flag" is introduced in vm_attr_t. For standard stream remapping, rv_remap_stdstream function is introduced. The emulator can remap default standard stream to required streams after creating the emulator by calling the rv_remap_stdstream function. elf is reopened in dump_test_signature because elf is allocated during rv_create. It is acceptable to reopen elf since it is only for testing. Print inferior exit code to console inside main instead of syscall_exit because the actual usage of exit code depends on applications of using riscv public API. The io interface is not changed in this PR because it could maybe reused with semu in some way, still need to be investigated. Also, Logging feature and system emulator integration are not implemented yet. A validator for validating the user-defined vm_attr_t might need to be introduced. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user, as a result, setting a configuration value (vm_attr_t) is sufficient. The user should manage about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. The vm_attr_t has multiple fields and they are commented clearly in the code. As you can see in "main", there are various mode to run the emulator such as "run_and_trace", "gdbstub", and "profiling". Thus, a field call "run_flag" is introduced in vm_attr_t. For standard stream remapping, rv_remap_stdstream function is introduced. The emulator can remap default standard stream to required streams after creating the emulator by calling the rv_remap_stdstream function. rv_userdata has been dropped since PRIV macro is sufficient for internal implemntation. Also, application will not need to direct access it. elf is reopened in dump_test_signature because elf is allocated during rv_create. It is acceptable to reopen elf since it is only for testing. Print inferior exit code to console inside main instead of syscall_exit because the actual usage of exit code depends on applications of using riscv public API. The io interface is not changed in this PR because it could maybe reused with semu in some way, still need to be investigated. Also, Logging feature and system emulator integration are not implemented yet. A validator for validating the user-defined vm_attr_t might need to be introduced. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user, as a result, setting a configuration value (vm_attr_t) is sufficient. The user should manage about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. The vm_attr_t has multiple fields and they are commented clearly in the code. As you can see in "main", there are various mode to run the emulator such as "run_and_trace", "gdbstub", and "profiling". Thus, a field call "run_flag" is introduced in vm_attr_t. For standard stream remapping, rv_remap_stdstream function is introduced. The emulator can remap default standard stream to required streams after creating the emulator by calling the rv_remap_stdstream function. rv_userdata has been dropped since PRIV macro is sufficient for internal implemntation. Also, application will not need to direct access it. elf is reopened in dump_test_signature because elf is allocated during rv_create. It is acceptable to reopen elf since it is only for testing. Print inferior exit code to console inside main instead of syscall_exit because the actual usage of exit code depends on applications of using riscv public API. The io interface is not changed in this PR because it could maybe reused with semu in some way, still need to be investigated. Also, Logging feature and system emulator integration are not implemented yet. A validator for validating the user-defined vm_attr_t might need to be introduced. related: sysprog21#310
The following should be included in an emulator's simple and clear public API: 1. create/init core 2. run emulation 3. delete/destroy core Other components, including as memory, file systems, program data, etc., should be abstracted from the user, as a result, setting a configuration value (vm_attr_t) is sufficient. The user should manage about memory (state_t) and elf stuff before this PR. The user may just construct a core, run it, and shut it down after this PR, so they won't need to worry about them anymore. The vm_attr_t has multiple fields and they are commented clearly in the code. As you can see in "main", there are various mode to run the emulator such as "run_and_trace", "gdbstub", and "profiling". Thus, a field call "run_flag" is introduced in vm_attr_t. For standard stream remapping, rv_remap_stdstream function is introduced. The emulator can remap default standard stream to required streams after creating the emulator by calling the rv_remap_stdstream function. rv_userdata has been dropped since PRIV macro is sufficient for internal implemntation. Also, application will not need to direct access it. elf is reopened in dump_test_signature because elf is allocated during rv_create. It is acceptable to reopen elf since it is only for testing. Print inferior exit code to console inside main instead of syscall_exit because the actual usage of exit code depends on applications of using riscv public API. The io interface is not changed in this PR because it could maybe reused with semu in some way, still need to be investigated. Also, Logging feature and system emulator integration are not implemented yet. A validator for validating the user-defined vm_attr_t might need to be introduced. related: sysprog21#310
The RV32I memory ordering instruction FENCE is used to order device I/O and memory accesses as viewed by other RISC-V harts and external devices or coprocessors. Linux kernel leverage this instruction for synchronization, support emulating this instruction is needed to boot Linux kernel. The implemention of this instruction is straight forward since there is only single hart at present. Related: sysprog21#310
The RV32I memory ordering instruction FENCE is used to order device I/O and memory accesses as viewed by other RISC-V harts and external devices or coprocessors. Linux kernel leverage this instruction for synchronization, support emulating this instruction is needed to boot Linux kernel. The implemention of this instruction is straight forward since there is only single hart at present. Related: sysprog21#310
The RV32I memory ordering instruction FENCE is used to order device I/O and memory accesses as viewed by other RISC-V harts and external devices or coprocessors. Linux kernel leverage this instruction for synchronization, support emulating this instruction is needed to boot Linux kernel. The implemention of this instruction is straight forward since there is only single hart at present. Related: sysprog21#310
The Wait for Interrupt instruction (WFI) provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing. As well, Linux kernel might call wait_for_interrupt() to enter idle state. In this commit, we could simply make PC + 4 and not really enter idle state. Related: sysprog21#310
Trap might occurs during block emulation, for example, page fault. In order to handle trap, we have to temporarily escape from block and jump to the trap handler to handle the trap PC by PC. Once trap is handled, resume the previous execution flow where cause the trap. To support this, we leverage setjmp function to store the state and a flag called is_trapped to indicate the emulation is in a trap handling mode currently. The sret and mret implementation are refactored to control the corresponding CSR before get out from trap. Some S-mode CSRs are added to riscv_internal to support S-mode. S-mode, and M-mode CSR helper macros are also introduced, so that the CSR can be manipulated in an easier manner. A test suite shall be introduced with this PR, please do not merge yet. Related: sysprog21#310
Trap might occurs during block emulation, for example, page fault. In order to handle trap, we have to temporarily escape from block and jump to the trap handler to handle the trap PC by PC. Once trap is handled, resume the previous execution flow where cause the trap. To support this, we leverage setjmp function to store the state and a flag called is_trapped to indicate the emulation is in a trap handling mode currently. The sret and mret implementation are refactored to control the corresponding CSR before get out from trap. Some S-mode CSRs are added to riscv_internal to support S-mode. S-mode, and M-mode CSR helper macros are also introduced, so that the CSR can be manipulated in an easier manner. A test suite shall be introduced with this PR, please do not merge yet. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is Sv32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Some S-mode CSRs are added to riscv_internal to support S-mode. PTE, S-mode, and M-mode CSR helper macros are also introduced. Related: sysprog21#310
Traps can occur during block emulation, such as from misaligned access. To handle a trap, we temporarily exit the block and transfer control to the trap handler, processing each instruction by stepping. After the trap is resolved, execution resumes from the point where it occurred. We use a flag called 'is_trapped' to indicate when the emulation is in trap-handling mode. Additionally, the 'sret' instruction is used to adjust the relevant supervisor CSR before returning from a trap. Support for S-mode has been enhanced by adding most S-mode CSRs to 'riscv_internal', along with helper macros for easier manipulation of S-mode and M-mode CSRs. Although M-mode CSRs are not directly used during emulation, the helpers have been added for potential future use. Conditional checks for 'SYSTEM' were added where necessary. The 'LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE' functionality is disabled during trap handling, as traps are managed one instruction at a time rather than as a chained block. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is Sv32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Some S-mode CSRs are added to riscv_internal to support S-mode. PTE, S-mode, and M-mode CSR helper macros are also introduced. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is Sv32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, we must first support MMU emulation. The virtual memory scheme to be supported is SV32. The major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, we modified its prototype. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux. Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the aforementioned page faults. Add a trap_handler callback to riscv_io_t interface to route the actual trap handler. This allows dispatch_table and TRAP_HANDLER_IMPL to remain static (encapsulated) within emulate.c, aligning the schema with other handlers like ebreak_handler and ecall_handler. The SET_CAUSE_AND_TVAL_THEN_TRAP helper macro is introduced to simplify the dispatch process when invoking a trap. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is essential. The virtual memory scheme required is SV32. Major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, its prototype is modified to allow access to the RISC-V core instance as the first parameter, since MMU-enabled I/O requires access to the SATP CSR. Additionally, a trap_handler callback is added to the riscv_io_t interface to route the actual trap handler. This approach keeps the dispatch_table and TRAP_HANDLER_IMPL static within emulate.c, aligning the schema with other handlers like ebreak_handler and ecall_handler. The SET_CAUSE_AND_TVAL_THEN_TRAP macro is introduced to simplify the dispatch process when invoking a trap. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is essential. The virtual memory scheme required is SV32. Major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, its prototype is modified to allow access to the RISC-V core instance as the first parameter, since MMU-enabled I/O requires access to the SATP CSR. Additionally, a trap_handler callback is added to the riscv_io_t interface to route the actual trap handler. This approach keeps the dispatch_table and TRAP_HANDLER_IMPL static within emulate.c, aligning the schema with other handlers like ebreak_handler and ecall_handler. The SET_CAUSE_AND_TVAL_THEN_TRAP macro is introduced to simplify the dispatch process when invoking a trap. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is essential. The virtual memory scheme required is SV32. Major changes in this commit include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To reuse the riscv_io_t interface, its prototype is modified to allow access to the RISC-V core instance as the first parameter, since MMU-enabled I/O requires access to the SATP CSR. Additionally, a trap_handler callback is added to the riscv_io_t interface to route the actual trap handler. This approach keeps the dispatch_table and TRAP_HANDLER_IMPL static within emulate.c, aligning the schema with other handlers like ebreak_handler and ecall_handler. The SET_CAUSE_AND_TVAL_THEN_TRAP macro is introduced to simplify the dispatch process when invoking a trap. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is crucial, using the SV32 virtual memory scheme. This commit’s main changes include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To enable reuse of riscv_io_t, its prototype is modified to accept the RISC-V core instance as the first parameter, allowing MMU-enabled I/O to access the SATP CSR. A trap_handler callback is also added to the riscv_io_t interface. This keeps the dispatch_table and _trap_handler static within emulate.c, aligning the schema with other handlers, like ebreak_handler and ecall_handler. With m/scause and m/stval set in SET_CAUSE_AND_TVAL_THEN_TRAP, _trap_handler can immediately dispatch without rechecking scause, avoiding the need for additional call of specific type of trap handler, thus no more need of TRAP_HANDLER_IMPL. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310 tmp
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is crucial, using the SV32 virtual memory scheme. This commit’s main changes include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To enable reuse of riscv_io_t, its prototype is modified to accept the RISC-V core instance as the first parameter, allowing MMU-enabled I/O to access the SATP CSR. A trap_handler callback is also added to the riscv_io_t interface. This keeps the dispatch_table and _trap_handler static within emulate.c, aligning the schema with other handlers, like ebreak_handler and ecall_handler. With m/scause and m/stval set in SET_CAUSE_AND_TVAL_THEN_TRAP, _trap_handler can immediately dispatch without rechecking scause, avoiding the need for additional call of specific type of trap handler, thus no more need of TRAP_HANDLER_IMPL. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is crucial, using the SV32 virtual memory scheme. This commit’s main changes include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To enable reuse of riscv_io_t, its prototype is modified to accept the RISC-V core instance as the first parameter, allowing MMU-enabled I/O to access the SATP CSR. A trap_handler callback is also added to the riscv_io_t interface. This keeps the dispatch_table and _trap_handler static within emulate.c, aligning the schema with other handlers, like ebreak_handler and ecall_handler. With m/scause and m/stval set in SET_CAUSE_AND_TVAL_THEN_TRAP, _trap_handler can immediately dispatch without rechecking scause, avoiding the need for additional call of specific type of trap handler, thus no more need of TRAP_HANDLER_IMPL. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is crucial, using the SV32 virtual memory scheme. This commit’s main changes include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To enable reuse of riscv_io_t, its prototype is modified to accept the RISC-V core instance as the first parameter, allowing MMU-enabled I/O to access the SATP CSR. A trap_handler callback is also added to the riscv_io_t interface. This keeps the dispatch_table and _trap_handler static within emulate.c, aligning the schema with other handlers, like ebreak_handler and ecall_handler. With m/scause and m/stval set in SET_CAUSE_AND_TVAL_THEN_TRAP, _trap_handler can immediately dispatch without rechecking scause, avoiding the need for additional call of specific type of trap handler, thus no more need of TRAP_HANDLER_IMPL. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310
To boot a 32-bit RISC-V Linux with MMU, MMU emulation support is crucial, using the SV32 virtual memory scheme. This commit’s main changes include implementing the MMU-related riscv_io_t interface and binding it during RISC-V instance initialization. To enable reuse of riscv_io_t, its prototype is modified to accept the RISC-V core instance as the first parameter, allowing MMU-enabled I/O to access the SATP CSR. A trap_handler callback is also added to the riscv_io_t interface. This keeps the dispatch_table and _trap_handler static within emulate.c, aligning the schema with other handlers, like ebreak_handler and ecall_handler. With m/scause and m/stval set in SET_CAUSE_AND_TVAL_THEN_TRAP, _trap_handler can immediately dispatch without rechecking scause, avoiding the need for additional call of specific type of trap handler, thus no more need of TRAP_HANDLER_IMPL. For each memory access, the page table is walked to get the corresponding PTE. Depending on the PTE retrieval, several page faults may need handling. Thus, three exception handlers have been introduced: insn_pgfault, load_pgfault, and store_pgfault, used in MMU_CHECK_FAULT. This commit does not fully handle access faults since they are related to PMA and PMP, which may not be necessary for booting 32-bit RISC-V Linux (possibly supported in the future). Since Linux has not been booted yet, a test suite is needed to test the MMU emulation. This commit includes a test suite that implements a simple kernel space supervisor and a user space application. The supervisor prepares the page table and then passes control to the user space application to test the three aforementioned page faults. Related: sysprog21#310
First trial of refactoring, the wasm branch's latest commit is the result.
Since
state_t
is a user-provided data, so all runtime defined value(often change) shall be stored there. For instance, the emulated target program's argc and argv, and the emulator's parameter. The following have been adjusted to reflect the changes:state_t *state_new(void)
----->state_t *state_new(uint32_t mem_size, int argc, char **argv, bool allow_misalign, bool quiet_output)
mem_size
is used formemory_new
because different runtimes may have memory requirements (for example, the page size in WebAssembly is 64KiB), the defaultMEM_SIZE
(2^32 - 1) is not appropriate for that. The rest of parameters are runtime defined value.riscv_t *rv_create(const riscv_io_t *io, riscv_user_t userdata, int argc, char **args, bool output_exit_code)
----->riscv_t *rv_create(riscv_user_t userdata)
Much cleaner function signature.
void rv_reset(riscv_t *rv, riscv_word_t pc, int argc, char **args)
----->void rv_reset(riscv_t *rv, riscv_word_t pc)
We can use
rv->userdata
to get the requiredargc
andargv
.Since memory I/O handlers are rarely changed, it makes less sense to define them during runtime (makes porting difficult). Instead, I believe it is preferable to link them during build time. If really want to change the implementations, make a new C file and link it during build time might be a better choice.
To do this, some changes are made:
rv_create
and link during build timeMEM_WRITE_IMPL
macro has to be changed:src/io.c
memory_write_w
in "src/syscall.c" shall be changed accordingly:src/syscall.c
For notably change, the "pre.js" of the wasm branch do not define IO on its own anymore compare to first attempt.(more abstraction)
Change all
uint32_t
anduint16_t
anduint8_t
in riscv.[ch] toriscv_word_t
andriscv_half_t
andriscv_byte_t
in function signature respectively for consistency.bool elf_load(elf_t *e, riscv_t *rv, memory_t *mem);
----->bool elf_load(elf_t *e, riscv_t *rv);
The memory instance required by
elf_load
can be accessed viarv
's userdata.I am wondering shall we abstract the
FILE
defined instate_new
as a parameter ofstate_new
. Without abstraction, the emulator always depends on standard io(e.g.,stdin
,stdout
,stderr
). What if the user want to use a file instead ofstdout
?Related to: #75
The text was updated successfully, but these errors were encountered: