Dear Gem5 community,

I try to add PCI interface in RISCV arch doing the following steps (similar with ARM RealView - I use the gem5-v21):

1) Create a file gem5/src/dev/riscv/pci_host.cc with the following code:

#include "dev/riscv/pci_host.hh"
#include "params/GenericRiscvPciHost.hh"

GenericRiscvPciHost::GenericRiscvPciHost(const GenericRiscvPciHostParams &p)
    : GenericPciHost(p), intBase(p.int_base), intCount(p.int_count)
{
}

uint32_t
GenericRiscvPciHost::mapPciInterrupt(
    const PciBusAddr &addr, PciIntPin pin) const
{

    fatal_if(pin == PciIntPin::NO_INT,
             "%02x:%02x.%i: Interrupt from a device without interrupts\n",
             addr.bus, addr.dev, addr.func);

    return intBase + (addr.dev % intCount);
}

2) Create a file gem5/src/dev/riscv/pci_host.hh with the following code:

#ifndef __DEV_RISCV_PCI_HOST_HH__
#define __DEV_RISCV_PCI_HOST_HH__

#include "dev/pci/host.hh"

struct GenericRiscvPciHostParams;

class GenericRiscvPciHost : public GenericPciHost
{
  private:
    const uint32_t intBase;
    const uint32_t intCount;

  public:
    GenericRiscvPciHost(const GenericRiscvPciHostParams &p);
    virtual ~GenericRiscvPciHost() {}

  protected:
    uint32_t mapPciInterrupt(const PciBusAddr &addr,
                             PciIntPin pin) const override;
};

#endif // __DEV_RISCV_PCI_HOST_HH__

3) Add the "Source('pci_host.cc')" to gem5/src/dev/riscv/SConscript

4) Add the following code in gem5/src/dev/riscv/HiFive.py according to RealView GenericArmPciHost:

from m5.objects.Ethernet import NSGigE, IGbE_igb, IGbE_e1000

from m5.objects.Device import BasicPioDevice
from m5.objects.PciHost import *
from m5.SimObject import SimObject

class GenericRiscvPciHost(GenericPciHost): #Add this class (PCI)
    type = 'GenericRiscvPciHost'
    cxx_header = "dev/riscv/pci_host.hh"
    int_base   = Param.Unsigned("PCI interrupt base")
int_count = Param.Unsigned("Maximum number of interrupts used by this host")

    # This python parameter can be used in configuration scripts to turn
    # on/off the fdt dma-coherent flag when doing dtb autogeneration
    _dma_coherent = True

    def generateDeviceTree(self, state):
        local_state = FdtState(
            addr_cells=3, size_cells=2,
            cpu_cells=1, interrupt_cells=1)

        node = FdtNode("pci")

        if int(self.conf_device_bits) == 8:
            node.appendCompatible("pci-host-cam-generic")
        elif int(self.conf_device_bits) == 12:
            node.appendCompatible("pci-host-ecam-generic")
        else:
            m5.fatal("No compatibility string for the set conf_device_width")

        node.append(FdtPropertyStrings("device_type", ["pci"]))

        # Cell sizes of child nodes/peripherals
        node.append(local_state.addrCellsProperty())
        node.append(local_state.sizeCellsProperty())
        node.append(local_state.interruptCellsProperty())
        # PCI address for CPU
        node.append(FdtPropertyWords("reg",
            state.addrCells(self.conf_base) +
            state.sizeCells(self.conf_size) ))

        # Ranges mapping
        # For now some of this is hard coded, because the PCI module does not
        # have a proper full understanding of the memory map, but adapting the
        # PCI module is beyond the scope of what I'm trying to do here.
        # Values are taken from the VExpress_GEM5_V1 platform.
        ranges = []
        # Pio address range
        ranges += self.pciFdtAddr(space=1, addr=0)
        ranges += state.addrCells(self.pci_pio_base)
        ranges += local_state.sizeCells(0x10000)  # Fixed size

        # AXI memory address range
        ranges += self.pciFdtAddr(space=2, addr=0)
        ranges += state.addrCells(self.pci_mem_base)
        ranges += local_state.sizeCells(0x40000000) # Fixed size
        node.append(FdtPropertyWords("ranges", ranges))

if True: #Change this to True because Realview calls always ARM_PCI_INT_DEV
            plic = self._parent.unproxy(self).plic
            int_phandle = state.phandle(plic)
            # Interrupt mapping
            interrupts = []

            # child interrupt specifier
            child_interrupt = local_state.interruptCells(0x0)

            # parent unit address
parent_addr = 0x0 #get this from /gem5/system/arm/dt/platforms file

            for i in range(int(self.int_count)):
parent_interrupt = int(self.int_base) + i #RISCV uses only 1 interrupt_cell in plic

                interrupts += self.pciFdtAddr(device=i, addr=0) + \
                    child_interrupt + [int_phandle] + [parent_addr] + \
                    [parent_interrupt]

            node.append(FdtPropertyWords("interrupt-map", interrupts))

            int_count = int(self.int_count)
            if int_count & (int_count - 1):
                fatal("PCI interrupt count should be power of 2")

            intmask = self.pciFdtAddr(device=int_count - 1, addr=0) + [0x0]
            node.append(FdtPropertyWords("interrupt-map-mask", intmask))
        else:
            m5.fatal("Unsupported PCI interrupt policy " +
                     "for Device Tree generation")

        if self._dma_coherent:
            node.append(FdtProperty("dma-coherent"))

        yield node

class HiFive(Platform):
.........
pci_host = GenericRiscvPciHost( #Add these 3 lines (PCI)
        conf_base=0x30000000, conf_size='256MiB', conf_device_bits=12,
pci_pio_base=0x2f000000, pci_mem_base=0x40000000, int_base=100, int_count=4)

ethernet = IGbE_e1000(pci_bus=0, pci_dev=0, pci_func=0, #Add IGbE_e1000 PCI device (PCI)
                                   InterruptLine=1, InterruptPin=1)

        def attachPlic(self):
        """Count number of PLIC interrupt sources
        """
        plic_srcs = [self.uart_int_id]
        plic_srcs.append(self.pci_host.int_base)  #Add this line (PCI)
        for device in self._off_chip_devices():
            if hasattr(device, "interrupt_id"):
                plic_srcs.append(device.interrupt_id)
        self.plic.n_src = max(plic_srcs) + 1

5) Add the following code in gem5/configs/example/riscv/fs_linux.py     :

#system.bridge.ranges = system.platform._off_chip_ranges() #Replaced from 3 lines below

range_list = system.platform._off_chip_ranges()
range_list.append(AddrRange(0x2f000000, 0x80000000))
system.bridge.ranges = range_list

system.platform.pci_host.pio = system.iobus.mem_side_ports
system.platform.ethernet.host = system.platform.pci_host
system.platform.ethernet.pio = system.iobus.mem_side_ports
system.platform.ethernet.dma = system.iobus.cpu_side_ports


6) To be noticed that I use the prebuilt files from here: https://github.com/ppeetteerrs/gem5-RISC-V-FS-Linux/. In addition, I add the PCI and e1000 drivers to kernel.config and build the Linux Kernel v5.10 according to this github:
CONFIG_PCI_SYSCALL=y
CONFIG_PCI_STUB=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_NET_VENDOR_INTEL=y
CONFIG_E1000=y
CONFIG_E1000E=y
CONFIG_IGB=y
CONFIG_NET_VENDOR_I825XX=y

However, when I try to execute the gem5 (build/RISCV/gem5.opt -d $RISCV/logs configs/example/riscv/fs_linux.py --kernel=$OUT/bbl --caches --mem-size=1024MB --mem-type=DDR4_2400_8x8 --cpu-type=AtomicSimpleCPU --disk-image=$OUT/riscv_parsec_disk -n 1) I get the following panic:

info: Entering event queue @ 0.  Starting simulation...
1086842500: system.platform.terminal: attach terminal 0
panic: invalid access size(?) for PCI configspace!
Memory Usage: 437656 KBytes
Program aborted at tick 18474133000

Please help me to add PCI interface correctly! I think that it will be very useful to gem5 community in order to add a wide range of PCI devices!

You can find the files with the above changes here: https://www.dropbox.com/s/pf4iu3z31zy88vr/riscv_pci.tar.xz

Best regards,
Nikolaos

_______________________________________________
gem5-users mailing list -- gem5-users@gem5.org
To unsubscribe send an email to gem5-users-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s
  • [gem5-users] FS R... Νικόλαος Ταμπουρατζής via gem5-users

Reply via email to