Open X547 opened 6 months ago
Afaik pstore
is CFI flash device, which I've looked into but never finished it, I'll check on that.
Did you try building and running a QEMU virt firmware?
Okay I've built the firmware. It seems that RISCV_VIRT_CODE.fd
should be loaded as S-mode kernel, and RISCV_VIRT_VARS.fd
should be in rw pstore
flash device.
I've tried to run RISCV_VIRT_CODE.fd
as -kernel
in RVVM, but it simply hangs. Note the same thing happens under QEMU if we replicate the approach, so apparently we really need that pstore
thingy.
Here is a QEMU cmdline that actually works:
qemu-system-riscv64 -M virt,pflash0=pflash0,pflash1=pflash1,acpi=off -nographic -blockdev node-name=pflash0,driver=file,read-only=on,filename=RISCV_VIRT_CODE.fd -blockdev node-name=pflash1,driver=file,filename=RISCV_VIRT_VARS.fd
Here is my build from tianocore/edk2@c0dfe3e: riscv_edk2.zip
Did you try building and running a QEMU virt firmware?
Yes, I built it and managed to run Haiku in QEMU with it. It builds surprisingly easy in Haiku host using Clang cross compiler.
I used pflash for specifying EDK2 firmware ROM, other options did not work.
Question: Does it only support UEFI or some way to simply load a kernel like with U-Boot scripts is also present?
I am not completely confident, but I think that EDK2 supports running EFI PE binaries only and no scripts are supported. Some Linux distros such as Fedora provide EFI boot loader for riscv64 target. GRUB also probably works.
For now I figured that EDK2 isn't loaded at usual 0x80200000
kernel payload address, but at some different location and QEMU is using fw_dynamic
instead of fw_jump
to specify jump address.
Is there some kind of spec/documentation to all of this?
I suspect that it use dynamic address allocation. It should just work after implementing requirements such as pflash without need to know all inner workings.
I am able to get EDK2 output even when I use RVVM device tree with QEMU (or any tiny device tree with plic, clint, uart only). It crashes, but it at least outputs a crash so that I know it tried to do something.
!!!! RISCV64 Exception Type - 000000000000000D(EXCEPT_RISCV_LOAD_ACCESS_PAGE_FAULT) !!!!
t0 = 0x00000000000000000 t1 = 0x000000000836788C8
t2 = 0x00000000000001000 t3 = 0x00000000000000010
t4 = 0x00000000080026DDA t5 = 0x0000000000000000F
t6 = 0x00000000000000027 s0 = 0x00000000083FFFAF0
s1 = 0x00000000000000001 s2 = 0x00000000000000000
s3 = 0x00000000020000000 s4 = 0x00000000000000000
s5 = 0x00000000087E00000 s6 = 0x08000000A00006800
s7 = 0x00000000080020040 s8 = 0x00000000000002000
s9 = 0x000000000800226E0 s10 = 0x00000000000000000
s11 = 0x00000000000000000 a0 = 0x00000000087FA2018
a1 = 0x00000000022000000 a2 = 0x00000000000040000
a3 = 0x00000000000040000 a4 = 0x00000000022000000
a5 = 0x0000000002203FFF8 a6 = 0x00000000000000001
a7 = 0x00000000083FFFA64 zero = 0x00000000000000000
ra = 0x00000000087EAE242 sp = 0x00000000083684BD4
gp = 0x00000000000000000 tp = 0x00000000080027000
sepc = 0x00000000087EAE53E sstatus = 0x08000000200006120
stval = 0x0000000002203FFF8
On the other hand when fully running on RVVM and passing EDK2 as -kernel
payload, nothing is output, so I want to tackle that first (because it feels like we are loading it incorrectly to begin with)
I know about fw_dynamic
. I want to figure out how exactly edk2 wants to be loaded/jumped into because it seems that RISCV_VIRT_CODE.fd
has some custom layout as opposed to directly containing the S-mode payload
Okay so apparently it jumps into 0x20000000
which is a base address of the CFI flash:
flash@20000000 {
bank-width = <0x04>;
reg = <0x00 0x20000000 0x00 0x2000000 0x00 0x22000000 0x00 0x2000000>;
compatible = "cfi-flash";
}
And it is likely not relocatable which would explains everything
I also would like to ask a few unrelated/barely related questions that I had for a while:
Should RVVM have ACPI support at any point in future?
For now I do not see cases where ACPI support is really required for RISC-V operating systems. I also do not know any real ACPI RISC-V hardware. But ACPI support may become needed if Microsoft decides to port Windows to RISC-V, Windows support ACPI only. For Haiku both ACPI and FDT support is planned. I managed to run my Haiku development branch on QEMU with ACPI after fixing minor QEMU bug (https://github.com/qemu/qemu/commit/301876597112218c1e465ecc2b2fef6b27d5c27b).
Maybe this concept could be tested on Haiku?
I think it can if it do not need too invasive and global changes to Haiku kernel. First some detailed discussion is needed about necessary kernel features and kernel <-> VM communication protocol.
I think it can if it do not need too invasive and global changes to Haiku kernel. First some detailed discussion is needed about necessary kernel features and kernel <-> VM communication protocol.
Basic idea is:
rvvm_hart_t
struct into it's respective U-mode "runner" context on the hostrvvm_hart_t
and interprets the faulting instruction as usual.This approach generally allows fully native execution, with the following downsides compared to full H-ext virtualization:
My initial idea of VM<->kernel interface (Pseudocode, this can really be implemented as a syscall or ioctl or whatever):
// Creates a shadow pagetable, destroy with close()
int vm_pgt_create();
// Shares memory from a usual process into the shadow pagetable
// Can be replaced with mmap-like interface that accepts a FD if that makes things simpler, but this approach seems more extensible
int vcpu_map_pages(int pgt_fd, size_t va, void* uptr, size_t size);
int vcpu_unmap_pages(int pgt_fd, size_t va, size_t size);
struct vcpu_runner_state {
size_t pc;
size_t gpr[31];
double fpr[32];
size_t fcsr;
};
// Accepts initial vCPU U-mode state & shadow pagetable handle for address space
// Runs the vCPU until any kind of exception, modifies vcpu_state post execution
// This design allows vCPU entry/exit & state manipulation in a single syscall
int vcpu_run(int pgt_fd, struct vcpu_runner_state* vcpu_state);
Ah, almost forgot about interrupts.
This API is pretty similar to Linux KVM API but simplified a lot (And based on a notion that a lot of work is moved into userspace). In KVM they send a signal to a vCPU thread to interrupt vcpu_run()
and force it to return immediately.
We could either adopt this approach, or add some kind of vCPU runner handle and a vcpu_kick(int vcpu_fd)
kernel interface (Because signals are ugly IMO).
About EDK2: Maybe it makes more sense to ask them for an S-mode payload without cfi-flash requirement?
If they won't agree then we can implement RVVM support anyways, but it probably makes more sense to have a more generic payload that may actually run on real hardware.
The biggest problem with EDK2 riscv support currently is the requirement to use fw_dynamic
OpenSBI variant to jump into flash ROM for S-mode payload. I imagine no hardware currently has means to actually do that.
Asked for a generic S-mode payload in https://github.com/tianocore/edk2/discussions/5815
Reference: https://github.com/tianocore/edk2/tree/master/OvmfPkg/RiscVVirt
Note that EDK 2 support both ACPI and FDT hardware definitions, so existing FDT generation should be fine. Some NVRAM emulation may be needed.