diff options
author | Peter Maydell | 2021-03-05 11:47:46 +0100 |
---|---|---|
committer | Peter Maydell | 2021-03-05 11:47:46 +0100 |
commit | 9a7beaad3dbba982f7a461d676b55a5c3851d312 (patch) | |
tree | 496d7cc40878c8a72111d375072cd67b6b05872d | |
parent | Merge remote-tracking branch 'remotes/kraxel/tags/ui-20210304-pull-request' i... (diff) | |
parent | hw/riscv: virt: Map high mmio for PCIe (diff) | |
download | qemu-9a7beaad3dbba982f7a461d676b55a5c3851d312.tar.gz qemu-9a7beaad3dbba982f7a461d676b55a5c3851d312.tar.xz qemu-9a7beaad3dbba982f7a461d676b55a5c3851d312.zip |
Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20210304' into staging
RISC-V PR for 6.0
This PR is a collection of RISC-V patches:
- Improvements to SiFive U OTP
- Upgrade OpenSBI to v0.9
- Support the QMP dump-guest-memory
- Add support for the SiFive SPI controller (sifive_u)
- Initial RISC-V system documentation
- A fix for the Goldfish RTC
- MAINTAINERS updates
- Support for high PCIe memory in the virt machine
# gpg: Signature made Thu 04 Mar 2021 14:44:31 GMT
# gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full]
# Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054
* remotes/alistair/tags/pull-riscv-to-apply-20210304:
hw/riscv: virt: Map high mmio for PCIe
hw/riscv: virt: Limit RAM size in a 32-bit system
hw/riscv: virt: Drop the 'link_up' parameter of gpex_pcie_init()
hw/riscv: Drop 'struct MemmapEntry'
MAINTAINERS: Add a SiFive machine section
goldfish_rtc: re-arm the alarm after migration
docs/system: riscv: Add documentation for sifive_u machine
docs/system: Add RISC-V documentation
docs/system: Sort targets in alphabetical order
hw/riscv: sifive_u: Change SIFIVE_U_GEM_IRQ to decimal value
hw/riscv: sifive_u: Add QSPI2 controller and connect an SD card
hw/riscv: sifive_u: Add QSPI0 controller and connect a flash
hw/ssi: Add SiFive SPI controller support
hw/block: m25p80: Add various ISSI flash information
hw/block: m25p80: Add ISSI SPI flash support
target-riscv: support QMP dump-guest-memory
roms/opensbi: Upgrade from v0.8 to v0.9
hw/misc: sifive_u_otp: Use error_report() when block operation fails
target/riscv: Declare csr_ops[] with a known size
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
29 files changed, 1285 insertions, 64 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 9b2aa18e1f..26c9454823 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1373,6 +1373,15 @@ F: include/hw/misc/mchp_pfsoc_dmc.h F: include/hw/misc/mchp_pfsoc_ioscb.h F: include/hw/misc/mchp_pfsoc_sysreg.h +SiFive Machines +M: Alistair Francis <Alistair.Francis@wdc.com> +M: Bin Meng <bin.meng@windriver.com> +M: Palmer Dabbelt <palmer@dabbelt.com> +L: qemu-riscv@nongnu.org +S: Supported +F: hw/*/*sifive*.c +F: include/hw/*/*sifive*.h + RX Machines ----------- rx-gdbsim diff --git a/docs/system/riscv/sifive_u.rst b/docs/system/riscv/sifive_u.rst new file mode 100644 index 0000000000..98e7562848 --- /dev/null +++ b/docs/system/riscv/sifive_u.rst @@ -0,0 +1,336 @@ +SiFive HiFive Unleashed (``sifive_u``) +====================================== + +SiFive HiFive Unleashed Development Board is the ultimate RISC-V development +board featuring the Freedom U540 multi-core RISC-V processor. + +Supported devices +----------------- + +The ``sifive_u`` machine supports the following devices: + + * 1 E51 / E31 core + * Up to 4 U54 / U34 cores + * Core Level Interruptor (CLINT) + * Platform-Level Interrupt Controller (PLIC) + * Power, Reset, Clock, Interrupt (PRCI) + * L2 Loosely Integrated Memory (L2-LIM) + * DDR memory controller + * 2 UARTs + * 1 GEM Ethernet controller + * 1 GPIO controller + * 1 One-Time Programmable (OTP) memory with stored serial number + * 1 DMA controller + * 2 QSPI controllers + * 1 ISSI 25WP256 flash + * 1 SD card in SPI mode + +Please note the real world HiFive Unleashed board has a fixed configuration of +1 E51 core and 4 U54 core combination and the RISC-V core boots in 64-bit mode. +With QEMU, one can create a machine with 1 E51 core and up to 4 U54 cores. It +is also possible to create a 32-bit variant with the same peripherals except +that the RISC-V cores are replaced by the 32-bit ones (E31 and U34), to help +testing of 32-bit guest software. + +Hardware configuration information +---------------------------------- + +The ``sifive_u`` machine automatically generates a device tree blob ("dtb") +which it passes to the guest. This provides information about the addresses, +interrupt lines and other configuration of the various devices in the system. +Guest software should discover the devices that are present in the generated +DTB instead of using a DTB for the real hardware, as some of the devices are +not modeled by QEMU and trying to access these devices may cause unexpected +behavior. + +Boot options +------------ + +The ``sifive_u`` machine can start using the standard -kernel functionality +for loading a Linux kernel, a VxWorks kernel, a modified U-Boot bootloader +(S-mode) or ELF executable with the default OpenSBI firmware image as the +-bios. It also supports booting the unmodified U-Boot bootloader using the +standard -bios functionality. + +Machine-specific options +------------------------ + +The following machine-specific options are supported: + +- serial=nnn + + The board serial number. When not given, the default serial number 1 is used. + + SiFive reserves the first 1 KiB of the 16 KiB OTP memory for internal use. + The current usage is only used to store the serial number of the board at + offset 0xfc. U-Boot reads the serial number from the OTP memory, and uses + it to generate a unique MAC address to be programmed to the on-chip GEM + Ethernet controller. When multiple QEMU ``sifive_u`` machines are created + and connected to the same subnet, they all have the same MAC address hence + it creates an unusable network. In such scenario, user should give different + values to serial= when creating different ``sifive_u`` machines. + +- start-in-flash + + When given, QEMU's ROM codes jump to QSPI memory-mapped flash directly. + Otherwise QEMU will jump to DRAM or L2LIM depending on the msel= value. + When not given, it defaults to direct DRAM booting. + +- msel=[6|11] + + Mode Select (MSEL[3:0]) pins value, used to control where to boot from. + + The FU540 SoC supports booting from several sources, which are controlled + using the Mode Select pins on the chip. Typically, the boot process runs + through several stages before it begins execution of user-provided programs. + These stages typically include the following: + + 1. Zeroth Stage Boot Loader (ZSBL), which is contained in an on-chip mask + ROM and provided by QEMU. Note QEMU implemented ROM codes are not the + same as what is programmed in the hardware. The QEMU one is a simplified + version, but it provides the same functionality as the hardware. + 2. First Stage Boot Loader (FSBL), which brings up PLLs and DDR memory. + This is U-Boot SPL. + 3. Second Stage Boot Loader (SSBL), which further initializes additional + peripherals as needed. This is U-Boot proper combined with an OpenSBI + fw_dynamic firmware image. + + msel=6 means FSBL and SSBL are both on the QSPI flash. msel=11 means FSBL + and SSBL are both on the SD card. + +Running Linux kernel +-------------------- + +Linux mainline v5.10 release is tested at the time of writing. To build a +Linux mainline kernel that can be booted by the ``sifive_u`` machine in +64-bit mode, simply configure the kernel using the defconfig configuration: + +.. code-block:: bash + + $ export ARCH=riscv + $ export CROSS_COMPILE=riscv64-linux- + $ make defconfig + $ make + +To boot the newly built Linux kernel in QEMU with the ``sifive_u`` machine: + +.. code-block:: bash + + $ qemu-system-riscv64 -M sifive_u -smp 5 -m 2G \ + -display none -serial stdio \ + -kernel arch/riscv/boot/Image \ + -initrd /path/to/rootfs.ext4 \ + -append "root=/dev/ram" + +To build a Linux mainline kernel that can be booted by the ``sifive_u`` machine +in 32-bit mode, use the rv32_defconfig configuration. A patch is required to +fix the 32-bit boot issue for Linux kernel v5.10. + +.. code-block:: bash + + $ export ARCH=riscv + $ export CROSS_COMPILE=riscv64-linux- + $ curl https://patchwork.kernel.org/project/linux-riscv/patch/20201219001356.2887782-1-atish.patra@wdc.com/mbox/ > riscv.patch + $ git am riscv.patch + $ make rv32_defconfig + $ make + +Replace ``qemu-system-riscv64`` with ``qemu-system-riscv32`` in the command +line above to boot the 32-bit Linux kernel. A rootfs image containing 32-bit +applications shall be used in order for kernel to boot to user space. + +Running VxWorks kernel +---------------------- + +VxWorks 7 SR0650 release is tested at the time of writing. To build a 64-bit +VxWorks mainline kernel that can be booted by the ``sifive_u`` machine, simply +create a VxWorks source build project based on the sifive_generic BSP, and a +VxWorks image project to generate the bootable VxWorks image, by following the +BSP documentation instructions. + +A pre-built 64-bit VxWorks 7 image for HiFive Unleashed board is available as +part of the VxWorks SDK for testing as well. Instructions to download the SDK: + +.. code-block:: bash + + $ wget https://labs.windriver.com/downloads/wrsdk-vxworks7-sifive-hifive-1.01.tar.bz2 + $ tar xvf wrsdk-vxworks7-sifive-hifive-1.01.tar.bz2 + $ ls bsps/sifive_generic_1_0_0_0/uboot/uVxWorks + +To boot the VxWorks kernel in QEMU with the ``sifive_u`` machine, use: + +.. code-block:: bash + + $ qemu-system-riscv64 -M sifive_u -smp 5 -m 2G \ + -display none -serial stdio \ + -nic tap,ifname=tap0,script=no,downscript=no \ + -kernel /path/to/vxWorks \ + -append "gem(0,0)host:vxWorks h=192.168.200.1 e=192.168.200.2:ffffff00 u=target pw=vxTarget f=0x01" + +It is also possible to test 32-bit VxWorks on the ``sifive_u`` machine. Create +a 32-bit project to build the 32-bit VxWorks image, and use exact the same +command line options with ``qemu-system-riscv32``. + +Running U-Boot +-------------- + +U-Boot mainline v2021.01 release is tested at the time of writing. To build a +U-Boot mainline bootloader that can be booted by the ``sifive_u`` machine, use +the sifive_fu540_defconfig with similar commands as described above for Linux: + +.. code-block:: bash + + $ export CROSS_COMPILE=riscv64-linux- + $ export OPENSBI=/path/to/opensbi-riscv64-generic-fw_dynamic.bin + $ make sifive_fu540_defconfig + +You will get spl/u-boot-spl.bin and u-boot.itb file in the build tree. + +To start U-Boot using the ``sifive_u`` machine, prepare an SPI flash image, or +SD card image that is properly partitioned and populated with correct contents. +genimage_ can be used to generate these images. + +A sample configuration file for a 128 MiB SD card image is: + +.. code-block:: bash + + $ cat genimage_sdcard.cfg + image sdcard.img { + size = 128M + + hdimage { + gpt = true + } + + partition u-boot-spl { + image = "u-boot-spl.bin" + offset = 17K + partition-type-uuid = 5B193300-FC78-40CD-8002-E86C45580B47 + } + + partition u-boot { + image = "u-boot.itb" + offset = 1041K + partition-type-uuid = 2E54B353-1271-4842-806F-E436D6AF6985 + } + } + +SPI flash image has slightly different partition offsets, and the size has to +be 32 MiB to match the ISSI 25WP256 flash on the real board: + +.. code-block:: bash + + $ cat genimage_spi-nor.cfg + image spi-nor.img { + size = 32M + + hdimage { + gpt = true + } + + partition u-boot-spl { + image = "u-boot-spl.bin" + offset = 20K + partition-type-uuid = 5B193300-FC78-40CD-8002-E86C45580B47 + } + + partition u-boot { + image = "u-boot.itb" + offset = 1044K + partition-type-uuid = 2E54B353-1271-4842-806F-E436D6AF6985 + } + } + +Assume U-Boot binaries are put in the same directory as the config file, +we can generate the image by: + +.. code-block:: bash + + $ genimage --config genimage_<boot_src>.cfg --inputpath . + +Boot U-Boot from SD card, by specifying msel=11 and pass the SD card image +to QEMU ``sifive_u`` machine: + +.. code-block:: bash + + $ qemu-system-riscv64 -M sifive_u,msel=11 -smp 5 -m 8G \ + -display none -serial stdio \ + -bios /path/to/u-boot-spl.bin \ + -drive file=/path/to/sdcard.img,if=sd + +Changing msel= value to 6, allows booting U-Boot from the SPI flash: + +.. code-block:: bash + + $ qemu-system-riscv64 -M sifive_u,msel=6 -smp 5 -m 8G \ + -display none -serial stdio \ + -bios /path/to/u-boot-spl.bin \ + -drive file=/path/to/spi-nor.img,if=mtd + +Note when testing U-Boot, QEMU automatically generated device tree blob is +not used because U-Boot itself embeds device tree blobs for U-Boot SPL and +U-Boot proper. Hence the number of cores and size of memory have to match +the real hardware, ie: 5 cores (-smp 5) and 8 GiB memory (-m 8G). + +Above use case is to run upstream U-Boot for the SiFive HiFive Unleashed +board on QEMU ``sifive_u`` machine out of the box. This allows users to +develop and test the recommended RISC-V boot flow with a real world use +case: ZSBL (in QEMU) loads U-Boot SPL from SD card or SPI flash to L2LIM, +then U-Boot SPL loads the combined payload image of OpenSBI fw_dynamic +firmware and U-Boot proper. However sometimes we want to have a quick test +of booting U-Boot on QEMU without the needs of preparing the SPI flash or +SD card images, an alternate way can be used, which is to create a U-Boot +S-mode image by modifying the configuration of U-Boot: + +.. code-block:: bash + + $ make menuconfig + +then manually select the following configuration in U-Boot: + + Device Tree Control > Provider of DTB for DT Control > Prior Stage bootloader DTB + +This lets U-Boot to use the QEMU generated device tree blob. During the build, +a build error will be seen below: + +.. code-block:: none + + MKIMAGE u-boot.img + ./tools/mkimage: Can't open arch/riscv/dts/hifive-unleashed-a00.dtb: No such file or directory + ./tools/mkimage: failed to build FIT + make: *** [Makefile:1440: u-boot.img] Error 1 + +The above errors can be safely ignored as we don't run U-Boot SPL under QEMU +in this alternate configuration. + +Boot the 64-bit U-Boot S-mode image directly: + +.. code-block:: bash + + $ qemu-system-riscv64 -M sifive_u -smp 5 -m 2G \ + -display none -serial stdio \ + -kernel /path/to/u-boot.bin + +It's possible to create a 32-bit U-Boot S-mode image as well. + +.. code-block:: bash + + $ export CROSS_COMPILE=riscv64-linux- + $ make sifive_fu540_defconfig + $ make menuconfig + +then manually update the following configuration in U-Boot: + + Device Tree Control > Provider of DTB for DT Control > Prior Stage bootloader DTB + RISC-V architecture > Base ISA > RV32I + Boot images > Text Base > 0x80400000 + +Use the same command line options to boot the 32-bit U-Boot S-mode image: + +.. code-block:: bash + + $ qemu-system-riscv32 -M sifive_u -smp 5 -m 2G \ + -display none -serial stdio \ + -kernel /path/to/u-boot.bin + +.. _genimage: https://github.com/pengutronix/genimage diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst new file mode 100644 index 0000000000..94d99c4c82 --- /dev/null +++ b/docs/system/target-riscv.rst @@ -0,0 +1,72 @@ +.. _RISC-V-System-emulator: + +RISC-V System emulator +====================== + +QEMU can emulate both 32-bit and 64-bit RISC-V CPUs. Use the +``qemu-system-riscv64`` executable to simulate a 64-bit RISC-V machine, +``qemu-system-riscv32`` executable to simulate a 32-bit RISC-V machine. + +QEMU has generally good support for RISC-V guests. It has support for +several different machines. The reason we support so many is that +RISC-V hardware is much more widely varying than x86 hardware. RISC-V +CPUs are generally built into "system-on-chip" (SoC) designs created by +many different companies with different devices, and these SoCs are +then built into machines which can vary still further even if they use +the same SoC. + +For most boards the CPU type is fixed (matching what the hardware has), +so typically you don't need to specify the CPU type by hand, except for +special cases like the ``virt`` board. + +Choosing a board model +---------------------- + +For QEMU's RISC-V system emulation, you must specify which board +model you want to use with the ``-M`` or ``--machine`` option; +there is no default. + +Because RISC-V systems differ so much and in fundamental ways, typically +operating system or firmware images intended to run on one machine +will not run at all on any other. This is often surprising for new +users who are used to the x86 world where every system looks like a +standard PC. (Once the kernel has booted, most user space software +cares much less about the detail of the hardware.) + +If you already have a system image or a kernel that works on hardware +and you want to boot with QEMU, check whether QEMU lists that machine +in its ``-machine help`` output. If it is listed, then you can probably +use that board model. If it is not listed, then unfortunately your image +will almost certainly not boot on QEMU. (You might be able to +extract the file system and use that with a different kernel which +boots on a system that QEMU does emulate.) + +If you don't care about reproducing the idiosyncrasies of a particular +bit of hardware, such as small amount of RAM, no PCI or other hard +disk, etc., and just want to run Linux, the best option is to use the +``virt`` board. This is a platform which doesn't correspond to any +real hardware and is designed for use in virtual machines. You'll +need to compile Linux with a suitable configuration for running on +the ``virt`` board. ``virt`` supports PCI, virtio, recent CPUs and +large amounts of RAM. It also supports 64-bit CPUs. + +Board-specific documentation +---------------------------- + +Unfortunately many of the RISC-V boards QEMU supports are currently +undocumented; you can get a complete list by running +``qemu-system-riscv64 --machine help``, or +``qemu-system-riscv32 --machine help``. + +.. + This table of contents should be kept sorted alphabetically + by the title text of each file, which isn't the same ordering + as an alphabetical sort by filename. + +.. toctree:: + :maxdepth: 1 + + riscv/sifive_u + +RISC-V CPU features +------------------- diff --git a/docs/system/targets.rst b/docs/system/targets.rst index 560783644d..75ed1087fd 100644 --- a/docs/system/targets.rst +++ b/docs/system/targets.rst @@ -7,16 +7,22 @@ various targets are mentioned in the following sections. Contents: +.. + This table of contents should be kept sorted alphabetically + by the title text of each file, which isn't the same ordering + as an alphabetical sort by filename. + .. toctree:: - target-i386 + target-arm + target-avr + target-m68k + target-mips target-ppc + target-riscv + target-rx + target-s390x target-sparc target-sparc64 - target-mips - target-arm - target-m68k + target-i386 target-xtensa - target-s390x - target-rx - target-avr diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 0412d3e7f4..5f9471d83c 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -210,6 +210,19 @@ static const FlashPartInfo known_devices[] = { { INFO("640s33b", 0x898913, 0, 64 << 10, 128, 0) }, { INFO("n25q064", 0x20ba17, 0, 64 << 10, 128, 0) }, + /* ISSI */ + { INFO("is25lq040b", 0x9d4013, 0, 64 << 10, 8, ER_4K) }, + { INFO("is25lp080d", 0x9d6014, 0, 64 << 10, 16, ER_4K) }, + { INFO("is25lp016d", 0x9d6015, 0, 64 << 10, 32, ER_4K) }, + { INFO("is25lp032", 0x9d6016, 0, 64 << 10, 64, ER_4K) }, + { INFO("is25lp064", 0x9d6017, 0, 64 << 10, 128, ER_4K) }, + { INFO("is25lp128", 0x9d6018, 0, 64 << 10, 256, ER_4K) }, + { INFO("is25lp256", 0x9d6019, 0, 64 << 10, 512, ER_4K) }, + { INFO("is25wp032", 0x9d7016, 0, 64 << 10, 64, ER_4K) }, + { INFO("is25wp064", 0x9d7017, 0, 64 << 10, 128, ER_4K) }, + { INFO("is25wp128", 0x9d7018, 0, 64 << 10, 256, ER_4K) }, + { INFO("is25wp256", 0x9d7019, 0, 64 << 10, 512, ER_4K) }, + /* Macronix */ { INFO("mx25l2005a", 0xc22012, 0, 64 << 10, 4, ER_4K) }, { INFO("mx25l4005a", 0xc22013, 0, 64 << 10, 8, ER_4K) }, @@ -412,6 +425,7 @@ typedef enum { MAN_NUMONYX, MAN_WINBOND, MAN_SST, + MAN_ISSI, MAN_GENERIC, } Manufacturer; @@ -487,6 +501,8 @@ static inline Manufacturer get_man(Flash *s) return MAN_MACRONIX; case 0xBF: return MAN_SST; + case 0x9D: + return MAN_ISSI; default: return MAN_GENERIC; } @@ -706,6 +722,9 @@ static void complete_collecting_data(Flash *s) case MAN_SPANSION: s->quad_enable = !!(s->data[1] & 0x02); break; + case MAN_ISSI: + s->quad_enable = extract32(s->data[0], 6, 1); + break; case MAN_MACRONIX: s->quad_enable = extract32(s->data[0], 6, 1); if (s->len > 1) { @@ -895,6 +914,19 @@ static void decode_fast_read_cmd(Flash *s) SPANSION_DUMMY_CLK_LEN ); break; + case MAN_ISSI: + /* + * The Fast Read instruction code is followed by address bytes and + * dummy cycles, transmitted via the SI line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 8 is used. + * + * QPI (Quad Peripheral Interface) mode has different default value + * of dummy cycles, but this is unsupported at the time being. + */ + s->needed_bytes += 1; + break; default: break; } @@ -934,6 +966,16 @@ static void decode_dio_read_cmd(Flash *s) break; } break; + case MAN_ISSI: + /* + * The Fast Read Dual I/O instruction code is followed by address bytes + * and dummy cycles, transmitted via the IO1 and IO0 line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 4 is used. + */ + s->needed_bytes += 1; + break; default: break; } @@ -974,6 +1016,19 @@ static void decode_qio_read_cmd(Flash *s) break; } break; + case MAN_ISSI: + /* + * The Fast Read Quad I/O instruction code is followed by address bytes + * and dummy cycles, transmitted via the IO3, IO2, IO1 and IO0 line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 6 is used. + * + * QPI (Quad Peripheral Interface) mode has different default value + * of dummy cycles, but this is unsupported at the time being. + */ + s->needed_bytes += 3; + break; default: break; } @@ -1132,7 +1187,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) case RDSR: s->data[0] = (!!s->write_enable) << 1; - if (get_man(s) == MAN_MACRONIX) { + if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) { s->data[0] |= (!!s->quad_enable) << 6; } if (get_man(s) == MAN_SST) { diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index b8e8b9eebe..18aa0bd55d 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -23,6 +23,7 @@ #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/sysbus.h" +#include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/misc/sifive_u_otp.h" @@ -65,8 +66,7 @@ static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, SIFIVE_U_OTP_FUSE_WORD) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "read error index<%d>\n", s->pa); + error_report("read error index<%d>", s->pa); return 0xff; } @@ -169,8 +169,7 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr, if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", s->pa); + error_report("write error index<%d>", s->pa); } } @@ -260,15 +259,13 @@ static void sifive_u_otp_reset(DeviceState *dev) serial_data = s->serial; if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", index); + error_report("write error index<%d>", index); } serial_data = ~(s->serial); if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", index + 1); + error_report("write error index<%d>", index + 1); } } diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index facb0cbacc..d139074b02 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -52,9 +52,12 @@ config SIFIVE_U select SIFIVE_GPIO select SIFIVE_PDMA select SIFIVE_PLIC + select SIFIVE_SPI select SIFIVE_UART select SIFIVE_U_OTP select SIFIVE_U_PRCI + select SSI_M25P80 + select SSI_SD select UNIMP config SPIKE diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index e952b49e8c..266f1c3342 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -86,10 +86,7 @@ * - Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm * describes the complete IOSCB modules memory maps */ -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} microchip_pfsoc_memmap[] = { +static const MemMapEntry microchip_pfsoc_memmap[] = { [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 }, [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 }, [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 }, @@ -182,7 +179,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev); - const struct MemmapEntry *memmap = microchip_pfsoc_memmap; + const MemMapEntry *memmap = microchip_pfsoc_memmap; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *rsvd0_mem = g_new(MemoryRegion, 1); MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1); @@ -451,7 +448,7 @@ type_init(microchip_pfsoc_soc_register_types) static void microchip_icicle_kit_machine_init(MachineState *machine) { MachineClass *mc = MACHINE_GET_CLASS(machine); - const struct MemmapEntry *memmap = microchip_pfsoc_memmap; + const MemMapEntry *memmap = microchip_pfsoc_memmap; MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mem_low = g_new(MemoryRegion, 1); diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index af3456932f..e168bffe69 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -28,10 +28,7 @@ #include "qemu/units.h" #include "sysemu/sysemu.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} ibex_memmap[] = { +static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_ROM] = { 0x00008000, 16 * KiB }, [IBEX_DEV_RAM] = { 0x10000000, 0x10000 }, [IBEX_DEV_FLASH] = { 0x20000000, 0x80000 }, @@ -66,7 +63,7 @@ static const struct MemmapEntry { static void opentitan_board_init(MachineState *machine) { - const struct MemmapEntry *memmap = ibex_memmap; + const MemMapEntry *memmap = ibex_memmap; OpenTitanState *s = g_new0(OpenTitanState, 1); MemoryRegion *sys_mem = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -114,7 +111,7 @@ static void lowrisc_ibex_soc_init(Object *obj) static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) { - const struct MemmapEntry *memmap = ibex_memmap; + const MemMapEntry *memmap = ibex_memmap; MachineState *ms = MACHINE(qdev_get_machine()); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); MemoryRegion *sys_mem = get_system_memory(); diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 59bac4cc9a..f939bcf9ea 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -50,10 +50,7 @@ #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} sifive_e_memmap[] = { +static MemMapEntry sifive_e_memmap[] = { [SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 }, [SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 }, [SIFIVE_E_DEV_OTP] = { 0x20000, 0x2000 }, @@ -77,7 +74,7 @@ static const struct MemmapEntry { static void sifive_e_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = sifive_e_memmap; + const MemMapEntry *memmap = sifive_e_memmap; SiFiveEState *s = RISCV_E_MACHINE(machine); MemoryRegion *sys_mem = get_system_memory(); @@ -187,7 +184,7 @@ static void sifive_e_soc_init(Object *obj) static void sifive_e_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); - const struct MemmapEntry *memmap = sifive_e_memmap; + const MemMapEntry *memmap = sifive_e_memmap; SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 59b61cea01..7b59942369 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -15,6 +15,8 @@ * 5) OTP (One-Time Programmable) memory with stored serial number * 6) GEM (Gigabit Ethernet Controller) and management block * 7) DMA (Direct Memory Access Controller) + * 8) SPI0 connected to an SPI flash + * 9) SPI2 connected to an SD card * * This board currently generates devicetree dynamically that indicates at least * two harts and up to five harts. @@ -44,6 +46,7 @@ #include "hw/char/serial.h" #include "hw/cpu/cluster.h" #include "hw/misc/unimp.h" +#include "hw/ssi/ssi.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_u.h" @@ -60,10 +63,7 @@ #include <libfdt.h> -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} sifive_u_memmap[] = { +static const MemMapEntry sifive_u_memmap[] = { [SIFIVE_U_DEV_DEBUG] = { 0x0, 0x100 }, [SIFIVE_U_DEV_MROM] = { 0x1000, 0xf000 }, [SIFIVE_U_DEV_CLINT] = { 0x2000000, 0x10000 }, @@ -74,6 +74,8 @@ static const struct MemmapEntry { [SIFIVE_U_DEV_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 }, + [SIFIVE_U_DEV_QSPI0] = { 0x10040000, 0x1000 }, + [SIFIVE_U_DEV_QSPI2] = { 0x10050000, 0x1000 }, [SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_DEV_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_DEV_GEM] = { 0x10090000, 0x2000 }, @@ -86,7 +88,7 @@ static const struct MemmapEntry { #define OTP_SERIAL 1 #define GEM_REVISION 0x10070109 -static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, +static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -342,6 +344,57 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, "sifive,fu540-c000-ccache"); g_free(nodename); + nodename = g_strdup_printf("/soc/spi@%lx", + (long)memmap[SIFIVE_U_DEV_QSPI2].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI2_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_QSPI2].base, + 0x0, memmap[SIFIVE_U_DEV_QSPI2].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx/mmc@0", + (long)memmap[SIFIVE_U_DEV_QSPI2].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop(fdt, nodename, "disable-wp", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "voltage-ranges", 3300, 3300); + qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 20000000); + qemu_fdt_setprop_cell(fdt, nodename, "reg", 0); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "mmc-spi-slot"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx", + (long)memmap[SIFIVE_U_DEV_QSPI0].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI0_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_QSPI0].base, + 0x0, memmap[SIFIVE_U_DEV_QSPI0].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx/flash@0", + (long)memmap[SIFIVE_U_DEV_QSPI0].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "spi-rx-bus-width", 4); + qemu_fdt_setprop_cell(fdt, nodename, "spi-tx-bus-width", 4); + qemu_fdt_setprop(fdt, nodename, "m25p,fast-read", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 50000000); + qemu_fdt_setprop_cell(fdt, nodename, "reg", 0); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "jedec,spi-nor"); + g_free(nodename); + phy_phandle = phandle++; nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_DEV_GEM].base); @@ -428,7 +481,7 @@ static void sifive_u_machine_reset(void *opaque, int n, int level) static void sifive_u_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = sifive_u_memmap; + const MemMapEntry *memmap = sifive_u_memmap; SiFiveUState *s = RISCV_U_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -439,6 +492,9 @@ static void sifive_u_machine_init(MachineState *machine) int i; uint32_t fdt_load_addr; uint64_t kernel_entry; + DriveInfo *dinfo; + DeviceState *flash_dev, *sd_dev; + qemu_irq flash_cs, sd_cs; /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); @@ -571,6 +627,25 @@ static void sifive_u_machine_init(MachineState *machine) riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base, memmap[SIFIVE_U_DEV_MROM].size, sizeof(reset_vec), kernel_entry); + + /* Connect an SPI flash to SPI0 */ + flash_dev = qdev_new("is25wp256"); + dinfo = drive_get_next(IF_MTD); + if (dinfo) { + qdev_prop_set_drive_err(flash_dev, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); + } + qdev_realize_and_unref(flash_dev, BUS(s->soc.spi0.spi), &error_fatal); + + flash_cs = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi0), 1, flash_cs); + + /* Connect an SD card to SPI2 */ + sd_dev = ssi_create_peripheral(s->soc.spi2.spi, "ssi-sd"); + + sd_cs = qdev_get_gpio_in_named(sd_dev, SSI_GPIO_CS, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi2), 1, sd_cs); } static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) @@ -680,13 +755,15 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA); + object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI); + object_initialize_child(obj, "spi2", &s->spi2, TYPE_SIFIVE_SPI); } static void sifive_u_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(dev); - const struct MemmapEntry *memmap = sifive_u_memmap; + const MemMapEntry *memmap = sifive_u_memmap; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); @@ -827,6 +904,17 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) create_unimplemented_device("riscv.sifive.u.l2cc", memmap[SIFIVE_U_DEV_L2CC].base, memmap[SIFIVE_U_DEV_L2CC].size); + + sysbus_realize(SYS_BUS_DEVICE(&s->spi0), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi0), 0, + memmap[SIFIVE_U_DEV_QSPI0].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi0), 0, + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI0_IRQ)); + sysbus_realize(SYS_BUS_DEVICE(&s->spi2), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi2), 0, + memmap[SIFIVE_U_DEV_QSPI2].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi2), 0, + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI2_IRQ)); } static Property sifive_u_soc_props[] = { diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 56986ecfe0..ed4ca9808e 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -43,16 +43,13 @@ #include "sysemu/qtest.h" #include "sysemu/sysemu.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} spike_memmap[] = { +static const MemMapEntry spike_memmap[] = { [SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_CLINT] = { 0x2000000, 0x10000 }, [SPIKE_DRAM] = { 0x80000000, 0x0 }, }; -static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, +static void create_fdt(SpikeState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { void *fdt; @@ -179,7 +176,7 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, static void spike_board_init(MachineState *machine) { - const struct MemmapEntry *memmap = spike_memmap; + const MemMapEntry *memmap = spike_memmap; SpikeState *s = SPIKE_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 2299b3a6be..4f0c2fbca0 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -43,10 +43,7 @@ #include "hw/pci/pci.h" #include "hw/pci-host/gpex.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} virt_memmap[] = { +static const MemMapEntry virt_memmap[] = { [VIRT_DEBUG] = { 0x0, 0x100 }, [VIRT_MROM] = { 0x1000, 0xf000 }, [VIRT_TEST] = { 0x100000, 0x1000 }, @@ -62,6 +59,15 @@ static const struct MemmapEntry { [VIRT_DRAM] = { 0x80000000, 0x0 }, }; +/* PCIe high mmio is fixed for RV32 */ +#define VIRT32_HIGH_PCIE_MMIO_BASE 0x300000000ULL +#define VIRT32_HIGH_PCIE_MMIO_SIZE (4 * GiB) + +/* PCIe high mmio for RV64, size is fixed but base depends on top of RAM */ +#define VIRT64_HIGH_PCIE_MMIO_SIZE (16 * GiB) + +static MemMapEntry virt_high_pcie_memmap; + #define VIRT_FLASH_SECTOR_SIZE (256 * KiB) static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, @@ -170,7 +176,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, 0x1800, 0, 0, 0x7); } -static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { void *fdt; @@ -374,7 +380,11 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, 1, FDT_PCI_RANGE_MMIO, 2, memmap[VIRT_PCIE_MMIO].base, - 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size); + 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size, + 1, FDT_PCI_RANGE_MMIO_64BIT, + 2, virt_high_pcie_memmap.base, + 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); + create_pcie_irq_map(fdt, name, plic_pcie_phandle); g_free(name); @@ -451,12 +461,14 @@ update_bootargs: static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, hwaddr ecam_base, hwaddr ecam_size, hwaddr mmio_base, hwaddr mmio_size, + hwaddr high_mmio_base, + hwaddr high_mmio_size, hwaddr pio_base, - DeviceState *plic, bool link_up) + DeviceState *plic) { DeviceState *dev; MemoryRegion *ecam_alias, *ecam_reg; - MemoryRegion *mmio_alias, *mmio_reg; + MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg; qemu_irq irq; int i; @@ -476,6 +488,13 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, mmio_reg, mmio_base, mmio_size); memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias); + /* Map high MMIO space */ + high_mmio_alias = g_new0(MemoryRegion, 1); + memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high", + mmio_reg, high_mmio_base, high_mmio_size); + memory_region_add_subregion(get_system_memory(), high_mmio_base, + high_mmio_alias); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); for (i = 0; i < GPEX_NUM_IRQS; i++) { @@ -490,7 +509,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, static void virt_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = virt_memmap; + const MemMapEntry *memmap = virt_memmap; RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -593,6 +612,23 @@ static void virt_machine_init(MachineState *machine) } } + if (riscv_is_32bit(&s->soc[0])) { +#if HOST_LONG_BITS == 64 + /* limit RAM size in a 32-bit system */ + if (machine->ram_size > 10 * GiB) { + machine->ram_size = 10 * GiB; + error_report("Limiting RAM size to 10 GiB"); + } +#endif + virt_high_pcie_memmap.base = VIRT32_HIGH_PCIE_MMIO_BASE; + virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE; + } else { + virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE; + virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size; + virt_high_pcie_memmap.base = + ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size); + } + /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv_virt_board.ram", machine->ram_size, &error_fatal); @@ -672,12 +708,14 @@ static void virt_machine_init(MachineState *machine) } gpex_pcie_init(system_memory, - memmap[VIRT_PCIE_ECAM].base, - memmap[VIRT_PCIE_ECAM].size, - memmap[VIRT_PCIE_MMIO].base, - memmap[VIRT_PCIE_MMIO].size, - memmap[VIRT_PCIE_PIO].base, - DEVICE(pcie_plic), true); + memmap[VIRT_PCIE_ECAM].base, + memmap[VIRT_PCIE_ECAM].size, + memmap[VIRT_PCIE_MMIO].base, + memmap[VIRT_PCIE_MMIO].size, + virt_high_pcie_memmap.base, + virt_high_pcie_memmap.size, + memmap[VIRT_PCIE_PIO].base, + DEVICE(pcie_plic)); serial_mm_init(system_memory, memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(DEVICE(mmio_plic), UART0_IRQ), 399193, diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 0f4e8185a7..e07ff0164e 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -211,6 +211,8 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->tick_offset = s->tick_offset_vmstate - delta; + goldfish_rtc_set_alarm(s); + return 0; } diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 9e54a0c8dd..7d90a02181 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -2,6 +2,10 @@ config PL022 bool select SSI +config SIFIVE_SPI + bool + select SSI + config SSI bool diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index dee00c0da6..3d6bc82ab1 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -2,6 +2,7 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c')) softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c')) softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c')) softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c')) +softmmu_ss.add(when: 'CONFIG_SIFIVE_SPI', if_true: files('sifive_spi.c')) softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_SPI', if_true: files('stm32f2xx_spi.c')) softmmu_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c')) diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c new file mode 100644 index 0000000000..0c9ebca3c8 --- /dev/null +++ b/hw/ssi/sifive_spi.c @@ -0,0 +1,358 @@ +/* + * QEMU model of the SiFive SPI Controller + * + * Copyright (c) 2021 Wind River Systems, Inc. + * + * Author: + * Bin Meng <bin.meng@windriver.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "sysemu/sysemu.h" +#include "qemu/fifo8.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/ssi/sifive_spi.h" + +#define R_SCKDIV (0x00 / 4) +#define R_SCKMODE (0x04 / 4) +#define R_CSID (0x10 / 4) +#define R_CSDEF (0x14 / 4) +#define R_CSMODE (0x18 / 4) +#define R_DELAY0 (0x28 / 4) +#define R_DELAY1 (0x2C / 4) +#define R_FMT (0x40 / 4) +#define R_TXDATA (0x48 / 4) +#define R_RXDATA (0x4C / 4) +#define R_TXMARK (0x50 / 4) +#define R_RXMARK (0x54 / 4) +#define R_FCTRL (0x60 / 4) +#define R_FFMT (0x64 / 4) +#define R_IE (0x70 / 4) +#define R_IP (0x74 / 4) + +#define FMT_DIR (1 << 3) + +#define TXDATA_FULL (1 << 31) +#define RXDATA_EMPTY (1 << 31) + +#define IE_TXWM (1 << 0) +#define IE_RXWM (1 << 1) + +#define IP_TXWM (1 << 0) +#define IP_RXWM (1 << 1) + +#define FIFO_CAPACITY 8 + +static void sifive_spi_txfifo_reset(SiFiveSPIState *s) +{ + fifo8_reset(&s->tx_fifo); + + s->regs[R_TXDATA] &= ~TXDATA_FULL; + s->regs[R_IP] &= ~IP_TXWM; +} + +static void sifive_spi_rxfifo_reset(SiFiveSPIState *s) +{ + fifo8_reset(&s->rx_fifo); + + s->regs[R_RXDATA] |= RXDATA_EMPTY; + s->regs[R_IP] &= ~IP_RXWM; +} + +static void sifive_spi_update_cs(SiFiveSPIState *s) +{ + int i; + + for (i = 0; i < s->num_cs; i++) { + if (s->regs[R_CSDEF] & (1 << i)) { + qemu_set_irq(s->cs_lines[i], !(s->regs[R_CSMODE])); + } + } +} + +static void sifive_spi_update_irq(SiFiveSPIState *s) +{ + int level; + + if (fifo8_num_used(&s->tx_fifo) < s->regs[R_TXMARK]) { + s->regs[R_IP] |= IP_TXWM; + } else { + s->regs[R_IP] &= ~IP_TXWM; + } + + if (fifo8_num_used(&s->rx_fifo) > s->regs[R_RXMARK]) { + s->regs[R_IP] |= IP_RXWM; + } else { + s->regs[R_IP] &= ~IP_RXWM; + } + + level = s->regs[R_IP] & s->regs[R_IE] ? 1 : 0; + qemu_set_irq(s->irq, level); +} + +static void sifive_spi_reset(DeviceState *d) +{ + SiFiveSPIState *s = SIFIVE_SPI(d); + + memset(s->regs, 0, sizeof(s->regs)); + + /* The reset value is high for all implemented CS pins */ + s->regs[R_CSDEF] = (1 << s->num_cs) - 1; + + /* Populate register with their default value */ + s->regs[R_SCKDIV] = 0x03; + s->regs[R_DELAY0] = 0x1001; + s->regs[R_DELAY1] = 0x01; + + sifive_spi_txfifo_reset(s); + sifive_spi_rxfifo_reset(s); + + sifive_spi_update_cs(s); + sifive_spi_update_irq(s); +} + +static void sifive_spi_flush_txfifo(SiFiveSPIState *s) +{ + uint8_t tx; + uint8_t rx; + + while (!fifo8_is_empty(&s->tx_fifo)) { + tx = fifo8_pop(&s->tx_fifo); + rx = ssi_transfer(s->spi, tx); + + if (!fifo8_is_full(&s->rx_fifo)) { + if (!(s->regs[R_FMT] & FMT_DIR)) { + fifo8_push(&s->rx_fifo, rx); + } + } + } +} + +static bool sifive_spi_is_bad_reg(hwaddr addr, bool allow_reserved) +{ + bool bad; + + switch (addr) { + /* reserved offsets */ + case 0x08: + case 0x0C: + case 0x1C: + case 0x20: + case 0x24: + case 0x30: + case 0x34: + case 0x38: + case 0x3C: + case 0x44: + case 0x58: + case 0x5C: + case 0x68: + case 0x6C: + bad = allow_reserved ? false : true; + break; + default: + bad = false; + } + + if (addr >= (SIFIVE_SPI_REG_NUM << 2)) { + bad = true; + } + + return bad; +} + +static uint64_t sifive_spi_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveSPIState *s = opaque; + uint32_t r; + + if (sifive_spi_is_bad_reg(addr, true)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read at address 0x%" + HWADDR_PRIx "\n", __func__, addr); + return 0; + } + + addr >>= 2; + switch (addr) { + case R_TXDATA: + if (fifo8_is_full(&s->tx_fifo)) { + return TXDATA_FULL; + } + r = 0; + break; + + case R_RXDATA: + if (fifo8_is_empty(&s->rx_fifo)) { + return RXDATA_EMPTY; + } + r = fifo8_pop(&s->rx_fifo); + break; + + default: + r = s->regs[addr]; + break; + } + + sifive_spi_update_irq(s); + + return r; +} + +static void sifive_spi_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveSPIState *s = opaque; + uint32_t value = val64; + + if (sifive_spi_is_bad_reg(addr, false)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write at addr=0x%" + HWADDR_PRIx " value=0x%x\n", __func__, addr, value); + return; + } + + addr >>= 2; + switch (addr) { + case R_CSID: + if (value >= s->num_cs) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csid %d\n", + __func__, value); + } else { + s->regs[R_CSID] = value; + sifive_spi_update_cs(s); + } + break; + + case R_CSDEF: + if (value >= (1 << s->num_cs)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csdef %x\n", + __func__, value); + } else { + s->regs[R_CSDEF] = value; + } + break; + + case R_CSMODE: + if (value > 3) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csmode %x\n", + __func__, value); + } else { + s->regs[R_CSMODE] = value; + sifive_spi_update_cs(s); + } + break; + + case R_TXDATA: + if (!fifo8_is_full(&s->tx_fifo)) { + fifo8_push(&s->tx_fifo, (uint8_t)value); + sifive_spi_flush_txfifo(s); + } + break; + + case R_RXDATA: + case R_IP: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid write to read-only reigster 0x%" + HWADDR_PRIx " with 0x%x\n", __func__, addr << 2, value); + break; + + case R_TXMARK: + case R_RXMARK: + if (value >= FIFO_CAPACITY) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid watermark %d\n", + __func__, value); + } else { + s->regs[addr] = value; + } + break; + + case R_FCTRL: + case R_FFMT: + qemu_log_mask(LOG_UNIMP, + "%s: direct-map flash interface unimplemented\n", + __func__); + break; + + default: + s->regs[addr] = value; + break; + } + + sifive_spi_update_irq(s); +} + +static const MemoryRegionOps sifive_spi_ops = { + .read = sifive_spi_read, + .write = sifive_spi_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void sifive_spi_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + SiFiveSPIState *s = SIFIVE_SPI(dev); + int i; + + s->spi = ssi_create_bus(dev, "spi"); + sysbus_init_irq(sbd, &s->irq); + + s->cs_lines = g_new0(qemu_irq, s->num_cs); + for (i = 0; i < s->num_cs; i++) { + sysbus_init_irq(sbd, &s->cs_lines[i]); + } + + memory_region_init_io(&s->mmio, OBJECT(s), &sifive_spi_ops, s, + TYPE_SIFIVE_SPI, 0x1000); + sysbus_init_mmio(sbd, &s->mmio); + + fifo8_create(&s->tx_fifo, FIFO_CAPACITY); + fifo8_create(&s->rx_fifo, FIFO_CAPACITY); +} + +static Property sifive_spi_properties[] = { + DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, sifive_spi_properties); + dc->reset = sifive_spi_reset; + dc->realize = sifive_spi_realize; +} + +static const TypeInfo sifive_spi_info = { + .name = TYPE_SIFIVE_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveSPIState), + .class_init = sifive_spi_class_init, +}; + +static void sifive_spi_register_types(void) +{ + type_register_static(&sifive_spi_info); +} + +type_init(sifive_spi_register_types) diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index a9f7b4a084..2656b39808 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -26,6 +26,7 @@ #include "hw/gpio/sifive_gpio.h" #include "hw/misc/sifive_u_otp.h" #include "hw/misc/sifive_u_prci.h" +#include "hw/ssi/sifive_spi.h" #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" #define RISCV_U_SOC(obj) \ @@ -45,6 +46,8 @@ typedef struct SiFiveUSoCState { SIFIVEGPIOState gpio; SiFiveUOTPState otp; SiFivePDMAState dma; + SiFiveSPIState spi0; + SiFiveSPIState spi2; CadenceGEMState gem; uint32_t serial; @@ -82,6 +85,8 @@ enum { SIFIVE_U_DEV_UART0, SIFIVE_U_DEV_UART1, SIFIVE_U_DEV_GPIO, + SIFIVE_U_DEV_QSPI0, + SIFIVE_U_DEV_QSPI2, SIFIVE_U_DEV_OTP, SIFIVE_U_DEV_DMC, SIFIVE_U_DEV_FLASH0, @@ -96,6 +101,7 @@ enum { SIFIVE_U_L2CC_IRQ2 = 3, SIFIVE_U_UART0_IRQ = 4, SIFIVE_U_UART1_IRQ = 5, + SIFIVE_U_QSPI2_IRQ = 6, SIFIVE_U_GPIO_IRQ0 = 7, SIFIVE_U_GPIO_IRQ1 = 8, SIFIVE_U_GPIO_IRQ2 = 9, @@ -120,7 +126,8 @@ enum { SIFIVE_U_PDMA_IRQ5 = 28, SIFIVE_U_PDMA_IRQ6 = 29, SIFIVE_U_PDMA_IRQ7 = 30, - SIFIVE_U_GEM_IRQ = 0x35 + SIFIVE_U_QSPI0_IRQ = 51, + SIFIVE_U_GEM_IRQ = 53 }; enum { diff --git a/include/hw/ssi/sifive_spi.h b/include/hw/ssi/sifive_spi.h new file mode 100644 index 0000000000..47d0d6a47c --- /dev/null +++ b/include/hw/ssi/sifive_spi.h @@ -0,0 +1,47 @@ +/* + * QEMU model of the SiFive SPI Controller + * + * Copyright (c) 2021 Wind River Systems, Inc. + * + * Author: + * Bin Meng <bin.meng@windriver.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef HW_SIFIVE_SPI_H +#define HW_SIFIVE_SPI_H + +#define SIFIVE_SPI_REG_NUM (0x78 / 4) + +#define TYPE_SIFIVE_SPI "sifive.spi" +#define SIFIVE_SPI(obj) OBJECT_CHECK(SiFiveSPIState, (obj), TYPE_SIFIVE_SPI) + +typedef struct SiFiveSPIState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + qemu_irq irq; + + uint32_t num_cs; + qemu_irq *cs_lines; + + SSIBus *spi; + + Fifo8 tx_fifo; + Fifo8 rx_fifo; + + uint32_t regs[SIFIVE_SPI_REG_NUM]; +} SiFiveSPIState; + +#endif /* HW_SIFIVE_SPI_H */ diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin Binary files differindex 23b4dfb3b9..ae651e2993 100644 --- a/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin +++ b/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin diff --git a/pc-bios/opensbi-riscv32-generic-fw_dynamic.elf b/pc-bios/opensbi-riscv32-generic-fw_dynamic.elf Binary files differindex eb9ebf5674..3250d89408 100644 --- a/pc-bios/opensbi-riscv32-generic-fw_dynamic.elf +++ b/pc-bios/opensbi-riscv32-generic-fw_dynamic.elf diff --git a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin Binary files differindex 16c0cf4d0a..f039884483 100644 --- a/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin +++ b/pc-bios/opensbi-riscv64-generic-fw_dynamic.bin diff --git a/pc-bios/opensbi-riscv64-generic-fw_dynamic.elf b/pc-bios/opensbi-riscv64-generic-fw_dynamic.elf Binary files differindex 642a64e240..ef261c98d1 100644 --- a/pc-bios/opensbi-riscv64-generic-fw_dynamic.elf +++ b/pc-bios/opensbi-riscv64-generic-fw_dynamic.elf diff --git a/roms/opensbi b/roms/opensbi -Subproject a98258d0b537a295f517bbc8d813007336731fa +Subproject 234ed8e427f4d92903123199f6590d144e0d935 diff --git a/target/riscv/arch_dump.c b/target/riscv/arch_dump.c new file mode 100644 index 0000000000..709f621d82 --- /dev/null +++ b/target/riscv/arch_dump.c @@ -0,0 +1,202 @@ +/* Support for writing ELF notes for RISC-V architectures + * + * Copyright (C) 2021 Huawei Technologies Co., Ltd + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "elf.h" +#include "sysemu/dump.h" + +/* struct user_regs_struct from arch/riscv/include/uapi/asm/ptrace.h */ +struct riscv64_user_regs { + uint64_t pc; + uint64_t regs[31]; +} QEMU_PACKED; + +QEMU_BUILD_BUG_ON(sizeof(struct riscv64_user_regs) != 256); + +/* struct elf_prstatus from include/linux/elfcore.h */ +struct riscv64_elf_prstatus { + char pad1[32]; /* 32 == offsetof(struct elf_prstatus, pr_pid) */ + uint32_t pr_pid; + char pad2[76]; /* 76 == offsetof(struct elf_prstatus, pr_reg) - + offsetof(struct elf_prstatus, pr_ppid) */ + struct riscv64_user_regs pr_reg; + char pad3[8]; +} QEMU_PACKED; + +QEMU_BUILD_BUG_ON(sizeof(struct riscv64_elf_prstatus) != 376); + +struct riscv64_note { + Elf64_Nhdr hdr; + char name[8]; /* align_up(sizeof("CORE"), 4) */ + struct riscv64_elf_prstatus prstatus; +} QEMU_PACKED; + +#define RISCV64_NOTE_HEADER_SIZE offsetof(struct riscv64_note, prstatus) +#define RISCV64_PRSTATUS_NOTE_SIZE \ + (RISCV64_NOTE_HEADER_SIZE + sizeof(struct riscv64_elf_prstatus)) + +static void riscv64_note_init(struct riscv64_note *note, DumpState *s, + const char *name, Elf64_Word namesz, + Elf64_Word type, Elf64_Word descsz) +{ + memset(note, 0, sizeof(*note)); + + note->hdr.n_namesz = cpu_to_dump32(s, namesz); + note->hdr.n_descsz = cpu_to_dump32(s, descsz); + note->hdr.n_type = cpu_to_dump32(s, type); + + memcpy(note->name, name, namesz); +} + +int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque) +{ + struct riscv64_note note; + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + DumpState *s = opaque; + int ret, i = 0; + const char name[] = "CORE"; + + riscv64_note_init(¬e, s, name, sizeof(name), + NT_PRSTATUS, sizeof(note.prstatus)); + + note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); + + note.prstatus.pr_reg.pc = cpu_to_dump64(s, env->pc); + + for (i = 0; i < 31; i++) { + note.prstatus.pr_reg.regs[i] = cpu_to_dump64(s, env->gpr[i + 1]); + } + + ret = f(¬e, RISCV64_PRSTATUS_NOTE_SIZE, s); + if (ret < 0) { + return -1; + } + + return ret; +} + +struct riscv32_user_regs { + uint32_t pc; + uint32_t regs[31]; +} QEMU_PACKED; + +QEMU_BUILD_BUG_ON(sizeof(struct riscv32_user_regs) != 128); + +struct riscv32_elf_prstatus { + char pad1[24]; /* 24 == offsetof(struct elf_prstatus, pr_pid) */ + uint32_t pr_pid; + char pad2[44]; /* 44 == offsetof(struct elf_prstatus, pr_reg) - + offsetof(struct elf_prstatus, pr_ppid) */ + struct riscv32_user_regs pr_reg; + char pad3[4]; +} QEMU_PACKED; + +QEMU_BUILD_BUG_ON(sizeof(struct riscv32_elf_prstatus) != 204); + +struct riscv32_note { + Elf32_Nhdr hdr; + char name[8]; /* align_up(sizeof("CORE"), 4) */ + struct riscv32_elf_prstatus prstatus; +} QEMU_PACKED; + +#define RISCV32_NOTE_HEADER_SIZE offsetof(struct riscv32_note, prstatus) +#define RISCV32_PRSTATUS_NOTE_SIZE \ + (RISCV32_NOTE_HEADER_SIZE + sizeof(struct riscv32_elf_prstatus)) + +static void riscv32_note_init(struct riscv32_note *note, DumpState *s, + const char *name, Elf32_Word namesz, + Elf32_Word type, Elf32_Word descsz) +{ + memset(note, 0, sizeof(*note)); + + note->hdr.n_namesz = cpu_to_dump32(s, namesz); + note->hdr.n_descsz = cpu_to_dump32(s, descsz); + note->hdr.n_type = cpu_to_dump32(s, type); + + memcpy(note->name, name, namesz); +} + +int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque) +{ + struct riscv32_note note; + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + DumpState *s = opaque; + int ret, i; + const char name[] = "CORE"; + + riscv32_note_init(¬e, s, name, sizeof(name), + NT_PRSTATUS, sizeof(note.prstatus)); + + note.prstatus.pr_pid = cpu_to_dump32(s, cpuid); + + note.prstatus.pr_reg.pc = cpu_to_dump32(s, env->pc); + + for (i = 0; i < 31; i++) { + note.prstatus.pr_reg.regs[i] = cpu_to_dump32(s, env->gpr[i + 1]); + } + + ret = f(¬e, RISCV32_PRSTATUS_NOTE_SIZE, s); + if (ret < 0) { + return -1; + } + + return ret; +} + +int cpu_get_dump_info(ArchDumpInfo *info, + const GuestPhysBlockList *guest_phys_blocks) +{ + RISCVCPU *cpu; + CPURISCVState *env; + + if (first_cpu == NULL) { + return -1; + } + cpu = RISCV_CPU(first_cpu); + env = &cpu->env; + + info->d_machine = EM_RISCV; + +#if defined(TARGET_RISCV64) + info->d_class = ELFCLASS64; +#else + info->d_class = ELFCLASS32; +#endif + + info->d_endian = (env->mstatus & MSTATUS_UBE) != 0 + ? ELFDATA2MSB : ELFDATA2LSB; + + return 0; +} + +ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) +{ + size_t note_size; + + if (class == ELFCLASS64) { + note_size = RISCV64_PRSTATUS_NOTE_SIZE; + } else { + note_size = RISCV32_PRSTATUS_NOTE_SIZE; + } + + return note_size * nr_cpus; +} diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 16f1a34238..ddea8fbeeb 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -624,6 +624,8 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug; /* For now, mark unmigratable: */ cc->vmsd = &vmstate_riscv_cpu; + cc->write_elf64_note = riscv_cpu_write_elf64_note; + cc->write_elf32_note = riscv_cpu_write_elf32_note; #endif cc->gdb_arch_name = riscv_gdb_arch_name; cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 02758ae0eb..0edb2826a2 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -323,6 +323,10 @@ extern const char * const riscv_intr_names[]; const char *riscv_cpu_get_trap_name(target_ulong cause, bool async); void riscv_cpu_do_interrupt(CPUState *cpu); +int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque); +int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque); int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); @@ -487,7 +491,7 @@ enum { }; /* CSR function table */ -extern riscv_csr_operations csr_ops[]; +extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops); void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops); diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 4196ef8b69..caf4599207 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -368,6 +368,7 @@ #define MSTATUS_MIE 0x00000008 #define MSTATUS_UPIE 0x00000010 #define MSTATUS_SPIE 0x00000020 +#define MSTATUS_UBE 0x00000040 #define MSTATUS_MPIE 0x00000080 #define MSTATUS_SPP 0x00000100 #define MSTATUS_MPP 0x00001800 diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 14a5c62dac..88ab850682 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -26,6 +26,7 @@ riscv_ss.add(files( riscv_softmmu_ss = ss.source_set() riscv_softmmu_ss.add(files( + 'arch_dump.c', 'pmp.c', 'monitor.c', 'machine.c' |