Skip to content
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

How to build a RISCV64 platform #7

Open
estarriol43 opened this issue Jul 26, 2024 · 4 comments
Open

How to build a RISCV64 platform #7

estarriol43 opened this issue Jul 26, 2024 · 4 comments

Comments

@estarriol43
Copy link

I'm wondering if there is any document about how to build a RISCV64 platform. How can we configure the .lua file to build a platform that supports RISCV64?

@markfoodyburton
Copy link
Contributor

Should be fairly simple to build a riscv, the CPUs are available - but you will need a binary image etc.

@estarriol43
Copy link
Author

estarriol43 commented Aug 5, 2024

I'm using qbox v3.0.1 and libqemu v8.2-v0.1.4, and I found some errors while compiling the riscv64 target. The following is the patch I used to fix those errors.

The patch for libqemu v8.2-v0.1.4

diff --git a/CMakeLists.txt b/CMakeLists.txt
index fe3f6b1833..dbb2c5bb77 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ include(GNUInstallDirs)

 # Enabled QEMU targets
 if(NOT DEFINED LIBQEMU_TARGETS)
-    set(LIBQEMU_TARGETS aarch64)
+    set(LIBQEMU_TARGETS aarch64 riscv64)
 endif()

 # For the arm target, use the aarch64 target which is a superset of the former.
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 3872e05bb6..ed34941cab 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -297,7 +297,7 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
     for (i = 0; i < s->num_harts; i++) {
         CPUState *cpu = cpu_by_arch_id(s->hartid_base + i);
         RISCVCPU *rvcpu = RISCV_CPU(cpu);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
         riscv_aclint_mtimer_callback *cb =
             g_new0(riscv_aclint_mtimer_callback,1);

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e58b9151e3..db4f6b0520 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1154,7 +1154,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
     }

     if (cpu->cfg.hartid != -1) {
-        env->mhartid = cpu->cfg.hartid;
+        (&cpu->env)->mhartid = cpu->cfg.hartid;
     }

     riscv_cpu_register_gdb_regs_for_features(cs);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 5bf087db38..4c7bcbf219 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -690,7 +690,7 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t value)
     env->mip = (env->mip & ~mask) | (value & mask);

 #ifdef CONFIG_LIBQEMU
-    libqemu_cpu_riscv_mip_update_cb(CPU(cpu), env->mip);
+    libqemu_cpu_riscv_mip_update_cb(env_cpu(env), env->mip);
 #endif

     riscv_cpu_interrupt(env);

The following is the lua configuration for building a RISCV64 platform. I use a openSBI firmware with Linux kernel payload as binary image. The binary image has been tested on the vanilla QEMU.

-- Virtual platform configuration

function top()
    local str = debug.getinfo(2, "S").source:sub(2)
    if str:match("(.*/)")
    then
        return str:match("(.*/)")
    else
        return "./"
    end
 end

dofile(top().."../fw/utils.lua");
print ("Lua config running. . . ");

INITIAL_DDR_SPACE = 0x80000000

_FW_PAYLOAD_LOAD_ADDR = INITIAL_DDR_SPACE

local IS_SHARED_MEM = false

ACCEL = "tcg"
print("Virtual acceleration: " .. ACCEL)

local UART0 = 0x10000000

platform = {

    moduletype="Container";

    quantum_ns = 10000000;

    router = {
        moduletype="router";
        log_level=0;
    },

    ram_0=  {
        moduletype="gs_memory";
        target_socket = {address = INITIAL_DDR_SPACE; size = 0x100000000, bind= "&router.initiator_socket"},
        log_level=0,
        shared_memory=IS_SHARED_MEM
    };

    qemu_inst_mgr = {
        moduletype = "QemuInstanceManager";
    },

    qemu_inst= {
        moduletype="QemuInstance";
        args = {"&platform.qemu_inst_mgr", "RISCV64"};
        accel = ACCEL,
        tcg_mode="MULTI",
        sync_policy = "multithread-unconstrained"
    },

    charbackend_stdio_0 = {
        moduletype = "char_backend_stdio";
        read_write = true;
    };

    pl011_uart_0 = {
        moduletype = "Pl011",
        dylib_path = "uart-pl011",
        target_socket = {address= UART0, size=0x1000, bind = "&router.initiator_socket"},
        irq = {bind = "&plic.irq_in_10"},
        backend_socket = {bind = "&charbackend_stdio_0.biflow_socket"},
    };

    fallback_0=  {
        moduletype="gs_memory";
        target_socket = {address = 0x0; size = 0x800000000, bind= "&router.initiator_socket", priority=1},
        dmi_allow=false,
        log_level=0,
        shared_memory=IS_SHARED_MEM};

    load = {
        moduletype = "loader",
        initiator_socket = {bind = "&router.target_socket"};
        { bin_file=top().."fw/Artifacts/fw_payload.elf", address=_FW_PAYLOAD_LOAD_ADDR };
    };

    plic = {
        moduletype = "plic_sifive";
        args = {"&platform.qemu_inst"};
    };

    riscv_aclint_swi = {
        moduletype = "riscv_aclint_swi";
        args = {"&platform.qemu_inst"};
        num_harts = 1;
    };

    riscv_aclint_mtimer = {
        moduletype = "riscv_aclint_mtimer";
        args = {"&platform.qemu_inst"};
        num_harts = 1;
    };
        
    cpu_0 = {
        moduletype = "cpu_riscv64";
        args = {"&platform.qemu_inst", 0};
        mem = {bind = "&router.target_socket"};
    };
};

print ("fw_payload is loaded at: 0x"..string.format("%x",_FW_PAYLOAD_LOAD_ADDR));

I tried running the RISCV64 platform but no luck. I found that riscv_cpu_claim_interrupts function triggered a segmentation fault when it accessed a NULL RISCVCPU pointer.

[D] [                0 s ](I1) : LuaFile_Tool Constructor
[D] [                0 s ](I1) : ArgParser Constructor
[I] [                0 s ](I1) : Parse command line for --gs_luafile option (3 arguments)
[I] [                0 s ](I1) : Option --gs_luafile with value /home/estarriol/qbox/platforms/riscv64-linux/conf.lua
[I] [                0 s ](I1) : Lua file command line parser: parse option --gs_luafile /home/estarriol/qbox/platforms/riscv64-linux/conf.lua

[I] [                0 s ](I1) : Read lua file '/home/estarriol/qbox/platforms/riscv64-linux/conf.lua'
Lua config running. . .
Virtual acceleration: tcg
fw_payload is loaded at: 0x80000000
[D] [                0 s ]platform                      : ContainerBase Constructor
[I] [                0 s ]platform                      : Adding a char_backend_stdio with name platform.charbackend_stdio_0
[I] [                0 s ]platform                      : 0 arguments found for char_backend_stdio
libname =char_backend_stdio.so
[I] [                0 s ]platform                      : Adding a gs_memory with name platform.fallback_0
[I] [                0 s ]platform                      : 0 arguments found for gs_memory
libname =gs_memory.so
[D] [                0 s ]MemoryServices                : MemoryServices constructor
[D] [                0 s ]MemoryServices                : Memory Services Initialization
[I] [                0 s ]platform                      : Adding a loader with name platform.load
[I] [                0 s ]platform                      : 0 arguments found for loader
libname =loader.so
[I] [                0 s ]platform                      : Adding a Pl011 with name platform.pl011_uart_0
[I] [                0 s ]platform                      : 0 arguments found for Pl011
libname =uart-pl011.so
[I] [                0 s ]platform                      : Adding a QemuInstanceManager with name platform.qemu_inst_mgr
[I] [                0 s ]platform                      : 0 arguments found for QemuInstanceManager
[I] [                0 s ]platform                      : Adding a gs_memory with name platform.ram_0
[I] [                0 s ]platform                      : 0 arguments found for gs_memory
[D] [                0 s ]MemoryServices                : Memory Services Initialization
[I] [                0 s ]platform                      : Adding a router with name platform.router
[I] [                0 s ]platform                      : 0 arguments found for router
libname =router.so
[I] [                0 s ]platform                      : Adding a QemuInstance with name platform.qemu_inst
[I] [                0 s ]platform                      : 2 arguments found for QemuInstance
[D] [                0 s ]DMI.Libqbox                   : DmiManager Constructor
[D] [                0 s ]platform.qemu_inst            : Libqbox QemuInstance constructor
[I] [                0 s ]platform                      : Adding a riscv_aclint_mtimer with name platform.riscv_aclint_mtimer
[I] [                0 s ]platform                      : 1 arguments found for riscv_aclint_mtimer
libname =riscv_aclint_mtimer.so
[W] [                0 s ]platform.riscv_aclint_mtimer  : QOM Device creation riscv.aclint.mtimer
[I] [                0 s ]platform                      : Adding a riscv_aclint_swi with name platform.riscv_aclint_swi
[I] [                0 s ]platform                      : 1 arguments found for riscv_aclint_swi
libname =riscv_aclint_swi.so
[W] [                0 s ]platform.riscv_aclint_swi     : QOM Device creation riscv.aclint.swi
[I] [                0 s ]platform                      : Adding a cpu_riscv64 with name platform.cpu_0
[I] [                0 s ]platform                      : 2 arguments found for cpu_riscv64
libname =cpu_riscv64.so
[W] [                0 s ]platform.cpu_0                : QOM Device creation rv64-riscv-cpu
[D] [                0 s ](I1) : QemuInitiatorSocket constructor
[I] [                0 s ]platform                      : Adding a plic_sifive with name platform.plic
[I] [                0 s ]platform                      : 1 arguments found for plic_sifive
libname =plic_sifive.so
[W] [                0 s ]platform.plic                 : QOM Device creation riscv.sifive.plic
[I] [                0 s ]platform                      : Binding initiator socket: platform.router.initiator_socket(PN9tlm_utils15multi_init_baseILj32EN3tlm23tlm_base_protocol_typesELj0ELN7sc_core14sc_port_policyE0EEE) with the target socket: platform.fallback_0.target_socket(PN9tlm_utils17multi_target_baseILj32EN3tlm23tlm_base_protocol_typesELj0ELN7sc_core14sc_port_policyE0EEE)
[I] [                0 s ]platform                      : Binding initiator socket: platform.load.initiator_socket(PN3tlm25tlm_base_initiator_socketILj32ENS_19tlm_fw_transport_ifINS_23tlm_base_protocol_typesEEENS_19tlm_bw_transport_ifIS2_EELi1ELN7sc_core14sc_port_policyE1EEE) with the target socket: platform.router.target_socket(PN9tlm_utils17multi_target_baseILj32EN3tlm23tlm_base_protocol_typesELj0ELN7sc_core14sc_port_policyE0EEE)
[I] [                0 s ]platform                      : Binding initiator socket: platform.charbackend_stdio_0.biflow_socket(PN2gs15biflow_bindableE) with the target socket: platform.pl011_uart_0.backend_socket(PN2gs15biflow_bindableE)
[I] [                0 s ]platform                      : Binding initiator socket: platform.pl011_uart_0.irq(PN7sc_core7sc_portINS_18sc_signal_inout_ifIbEELi1ELNS_14sc_port_policyE1EEE) with the target socket: platform.plic.irq_in_10(P18TargetSignalSocketIbE)
[I] [                0 s ]platform                      : Binding initiator socket: platform.router.initiator_socket(PN9tlm_utils15multi_init_baseILj32EN3tlm23tlm_base_protocol_typesELj0ELN7sc_core14sc_port_policyE0EEE) with the target socket: platform.pl011_uart_0.target_socket(PN3tlm22tlm_base_target_socketILj32ENS_19tlm_fw_transport_ifINS_23tlm_base_protocol_typesEEENS_19tlm_bw_transport_ifIS2_EELi1ELN7sc_core14sc_port_policyE0EEE)
[I] [                0 s ]platform                      : Binding initiator socket: platform.router.initiator_socket(PN9tlm_utils15multi_init_baseILj32EN3tlm23tlm_base_protocol_typesELj0ELN7sc_core14sc_port_policyE0EEE) with the target socket: platform.ram_0.target_socket(PN9tlm_utils17multi_target_baseILj32EN3tlm23tlm_base_protocol_typesELj0ELN7sc_core14sc_port_policyE0EEE)
[I] [                0 s ]platform                      : Binding initiator socket: platform.cpu_0.mem(PN3tlm25tlm_base_initiator_socketILj32ENS_19tlm_fw_transport_ifINS_23tlm_base_protocol_typesEEENS_19tlm_bw_transport_ifIS2_EELi1ELN7sc_core14sc_port_policyE1EEE) with the target socket: platform.router.target_socket(PN9tlm_utils17multi_target_baseILj32EN3tlm23tlm_base_protocol_typesELj0ELN7sc_core14sc_port_policyE0EEE)
[D] [                0 s ]platform                      : Container constructor
[I] [                0 s ]SystemC                       : SC_START
[I] [                0 s ]platform.qemu_inst            : Initializing QEMU instance with args:
[I] [                0 s ]platform.qemu_inst            : libqbox
[I] [                0 s ]platform.qemu_inst            : -M
[I] [                0 s ]platform.qemu_inst            : none
[I] [                0 s ]platform.qemu_inst            : -m
[I] [                0 s ]platform.qemu_inst            : 2048
[I] [                0 s ]platform.qemu_inst            : -monitor
[I] [                0 s ]platform.qemu_inst            : null
[I] [                0 s ]platform.qemu_inst            : -serial
[I] [                0 s ]platform.qemu_inst            : null
[I] [                0 s ]platform.qemu_inst            : -accel
[I] [                0 s ]platform.qemu_inst            : tcg,thread=multi
[I] [                0 s ]platform.qemu_inst            : -display
[I] [                0 s ]platform.qemu_inst            : none
Loading libqemu-system-riscv64.so
[I] [                0 s ]platform.load                 : Loading binary file: /home/estarriol/qbox/platforms/riscv64-linux/fw/Artifacts/fw_payload.elf starting at offset: 0 with size: 13460208 to addr: 2147483648
Fatal error: segmentation fault (SIGSEGV)!

gdb result:

Thread 5 "platforms-vp" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff1f4c640 (LWP 332313)]
0x00007ffff3b52c44 in riscv_cpu_claim_interrupts (cpu=0x0, interrupts=0x8) at ../../../../libqemu-src/target/riscv/cpu_helper.c:649
649         if (env->miclaim & interrupts) {

I'm wondering if you can help solve this problem. It would be very helpful if you could provide some insight.

@alwalidsalama
Copy link
Contributor

Hello @estarriol43, I am working on replicating the issue with riscv64 and Ill let you know ASAP.

@alwalidsalama
Copy link
Contributor

Hello @estarriol43,

Thank you for bringing attention to this issue. We can confirm that building qbox with -DLIBQEMU_TARGETS=riscv64 is failing. This patch fix the issue as you mentioned.

diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 3872e05bb6..ed34941cab 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -297,7 +297,7 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
     for (i = 0; i < s->num_harts; i++) {
         CPUState *cpu = cpu_by_arch_id(s->hartid_base + i);
         RISCVCPU *rvcpu = RISCV_CPU(cpu);
-        CPURISCVState *env = cpu ? cpu->env_ptr : NULL;
+        CPURISCVState *env = cpu ? cpu_env(cpu) : NULL;
         riscv_aclint_mtimer_callback *cb =
             g_new0(riscv_aclint_mtimer_callback,1);
 
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index e58b9151e3..3bb369c3a3 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -1134,6 +1134,7 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
     CPUState *cs = CPU(dev);
     RISCVCPU *cpu = RISCV_CPU(dev);
     RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev);
+    CPURISCVState *env = &cpu->env;
     Error *local_err = NULL;
 
     if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_CPU_ANY) != NULL) {
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 5bf087db38..76e8ee27f8 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -690,6 +690,7 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t value)
     env->mip = (env->mip & ~mask) | (value & mask);
 
 #ifdef CONFIG_LIBQEMU
+    RISCVCPU *cpu = env_archcpu(env);
     libqemu_cpu_riscv_mip_update_cb(CPU(cpu), env->mip);
 #endif
 

Additionally, in the Lua file, please set the components properly and bind them to the router. Please adjust the addresses according to your setup:

in conf.lua:

    plic_0=   {
            moduletype = "plic_sifive",
            args = {"&platform.qemu_inst"},
            mem    = {address=0x0c000000, size=0x4000000, bind = "&router.initiator_socket"},
            num_sources = 280,
            num_priorities = 7,
            priority_base = 0x04,
            pending_base = 0x1000,
            enable_base = 0x2000,
            enable_stride = 0x80,
            context_base = 0x200000,
            context_stride = 0x1000,
            aperture_size = 0x4000000,
            hart_config = "MS"
    };

Reference : plic-sifive.h

Moreover, to avoid the segmentation fault, you should pass the last cpu (in this case cpu_0, since there is only 1 cpu in your setup) to the interrupt controller to ensure it is initiated before. For example:
in conf.lua:

    swi_0=    {
            moduletype = "riscv_aclint_swi",
            args = {"&platform.qemu_inst", "&platform.cpu_0"},
            mem    = {address=0x2000000, size=0x4000, bind = "&router.initiator_socket"};
            num_harts = 1,
        };

Reference: riscv-aclint-swi.h

We would also like to mention that we will later add an example for riscv with images, device tree, and conf.lua.

Best regards,
Alwalid Salama

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants