| 1 | 'virt' Generic Virtual Platform (``virt``) |
| 2 | ========================================== |
| 3 | |
| 4 | The ``virt`` board is a platform which does not correspond to any real hardware; |
| 5 | it is designed for use in virtual machines. It is the recommended board type |
| 6 | if you simply want to run a guest such as Linux and do not care about |
| 7 | reproducing the idiosyncrasies and limitations of a particular bit of |
| 8 | real-world hardware. |
| 9 | |
| 10 | Supported devices |
| 11 | ----------------- |
| 12 | |
| 13 | The ``virt`` machine supports the following devices: |
| 14 | |
| 15 | * Up to 512 generic RV32GC/RV64GC cores, with optional extensions |
| 16 | * Core Local Interruptor (CLINT) |
| 17 | * Platform-Level Interrupt Controller (PLIC) |
| 18 | * CFI parallel NOR flash memory |
| 19 | * Either 1 or 2 NS16550 compatible UARTs |
| 20 | * 1 Google Goldfish RTC |
| 21 | * 1 SiFive Test device |
| 22 | * 8 virtio-mmio transport devices |
| 23 | * 1 generic PCIe host bridge |
| 24 | * The fw_cfg device that allows a guest to obtain data from QEMU |
| 25 | |
| 26 | The hypervisor extension has been enabled for the default CPU, so virtual |
| 27 | machines with hypervisor extension can simply be used without explicitly |
| 28 | declaring. |
| 29 | |
| 30 | The second UART only exists if a backend is configured explicitly (e.g. |
| 31 | with a second ``-serial`` command line option). |
| 32 | |
| 33 | Hardware configuration information |
| 34 | ---------------------------------- |
| 35 | |
| 36 | The ``virt`` machine automatically generates a device tree blob ("dtb") |
| 37 | which it passes to the guest, if there is no ``-dtb`` option. This provides |
| 38 | information about the addresses, interrupt lines and other configuration of |
| 39 | the various devices in the system. Guest software should discover the devices |
| 40 | that are present in the generated DTB. |
| 41 | |
| 42 | If users want to provide their own DTB, they can use the ``-dtb`` option. |
| 43 | These DTBs should have the following requirements: |
| 44 | |
| 45 | * The number of subnodes of the /cpus node should match QEMU's ``-smp`` option |
| 46 | * The /memory reg size should match QEMU’s selected ram_size via ``-m`` |
| 47 | * Should contain a node for the CLINT device with a compatible string |
| 48 | "riscv,clint0" if using with OpenSBI BIOS images |
| 49 | |
| 50 | Boot options |
| 51 | ------------ |
| 52 | |
| 53 | The ``virt`` machine can start using the standard -kernel functionality |
| 54 | for loading a Linux kernel, a VxWorks kernel, an S-mode U-Boot bootloader |
| 55 | with the default OpenSBI firmware image as the -bios. It also supports |
| 56 | the recommended RISC-V bootflow: U-Boot SPL (M-mode) loads OpenSBI fw_dynamic |
| 57 | firmware and U-Boot proper (S-mode), using the standard -bios functionality. |
| 58 | |
| 59 | Using flash devices |
| 60 | ------------------- |
| 61 | |
| 62 | By default, the first flash device (pflash0) is expected to contain |
| 63 | S-mode firmware code. It can be configured as read-only, with the |
| 64 | second flash device (pflash1) available to store configuration data. |
| 65 | |
| 66 | For example, booting edk2 looks like |
| 67 | |
| 68 | .. code-block:: bash |
| 69 | |
| 70 | $ qemu-system-riscv64 \ |
| 71 | -blockdev node-name=pflash0,driver=file,read-only=on,filename=<edk2_code> \ |
| 72 | -blockdev node-name=pflash1,driver=file,filename=<edk2_vars> \ |
| 73 | -M virt,pflash0=pflash0,pflash1=pflash1 \ |
| 74 | ... other args .... |
| 75 | |
| 76 | For TCG guests only, it is also possible to boot M-mode firmware from |
| 77 | the first flash device (pflash0) by additionally passing ``-bios |
| 78 | none``, as in |
| 79 | |
| 80 | .. code-block:: bash |
| 81 | |
| 82 | $ qemu-system-riscv64 \ |
| 83 | -bios none \ |
| 84 | -blockdev node-name=pflash0,driver=file,read-only=on,filename=<m_mode_code> \ |
| 85 | -M virt,pflash0=pflash0 \ |
| 86 | ... other args .... |
| 87 | |
| 88 | Firmware images used for pflash must be exactly 32 MiB in size. |
| 89 | |
| 90 | riscv-iommu support |
| 91 | ------------------- |
| 92 | |
| 93 | The board has support for the riscv-iommu-pci device by using the following |
| 94 | command line: |
| 95 | |
| 96 | .. code-block:: bash |
| 97 | |
| 98 | $ qemu-system-riscv64 -M virt -device riscv-iommu-pci (...) |
| 99 | |
| 100 | It also has support for the riscv-iommu-sys platform device: |
| 101 | |
| 102 | .. code-block:: bash |
| 103 | |
| 104 | $ qemu-system-riscv64 -M virt,iommu-sys=on (...) |
| 105 | |
| 106 | Refer to :ref:`riscv-iommu` for more information on how the RISC-V IOMMU support |
| 107 | works. |
| 108 | |
| 109 | Machine-specific options |
| 110 | ------------------------ |
| 111 | |
| 112 | The following machine-specific options are supported: |
| 113 | |
| 114 | - aclint=[on|off] |
| 115 | |
| 116 | When this option is "on", ACLINT devices will be emulated instead of |
| 117 | SiFive CLINT. When not specified, this option is assumed to be "off". |
| 118 | This option is restricted to the TCG accelerator. |
| 119 | |
| 120 | - acpi=[on|off|auto] |
| 121 | |
| 122 | When this option is "on" (which is the default), ACPI tables are generated and |
| 123 | exposed as firmware tables etc/acpi/rsdp and etc/acpi/tables. |
| 124 | |
| 125 | - aia=[none|aplic|aplic-imsic] |
| 126 | |
| 127 | This option allows selecting interrupt controller defined by the AIA |
| 128 | (advanced interrupt architecture) specification. The "aia=aplic" selects |
| 129 | APLIC (advanced platform level interrupt controller) to handle wired |
| 130 | interrupts whereas the "aia=aplic-imsic" selects APLIC and IMSIC (incoming |
| 131 | message signaled interrupt controller) to handle both wired interrupts and |
| 132 | MSIs. When not specified, this option is assumed to be "none" which selects |
| 133 | SiFive PLIC to handle wired interrupts. |
| 134 | |
| 135 | This option also interacts with '-accel kvm'. When using "aia=aplic-imsic" |
| 136 | with KVM, it is possible to set the use of the kernel irqchip in split mode |
| 137 | by using "-accel kvm,kernel-irqchip=split". In this case the ``virt`` machine |
| 138 | will emulate the APLIC controller instead of using the APLIC controller from |
| 139 | the irqchip. See :ref:`riscv-aia` for more details on all available AIA |
| 140 | modes. |
| 141 | |
| 142 | - aia-guests=nnn |
| 143 | |
| 144 | The number of per-HART VS-level AIA IMSIC pages to be emulated for a guest |
| 145 | having AIA IMSIC (i.e. "aia=aplic-imsic" selected). When not specified, |
| 146 | the default number of per-HART VS-level AIA IMSIC pages is 0. |
| 147 | |
| 148 | - iommu-sys=[on|off] |
| 149 | |
| 150 | Enables the riscv-iommu-sys platform device. Defaults to 'off'. |
| 151 | |
| 152 | Running Linux kernel |
| 153 | -------------------- |
| 154 | |
| 155 | Linux mainline v5.12 release is tested at the time of writing. To build a |
| 156 | Linux mainline kernel that can be booted by the ``virt`` machine in |
| 157 | 64-bit mode, simply configure the kernel using the defconfig configuration: |
| 158 | |
| 159 | .. code-block:: bash |
| 160 | |
| 161 | $ export ARCH=riscv |
| 162 | $ export CROSS_COMPILE=riscv64-linux- |
| 163 | $ make defconfig |
| 164 | $ make |
| 165 | |
| 166 | To boot the newly built Linux kernel in QEMU with the ``virt`` machine: |
| 167 | |
| 168 | .. code-block:: bash |
| 169 | |
| 170 | $ qemu-system-riscv64 -M virt -smp 4 -m 2G \ |
| 171 | -display none -serial stdio \ |
| 172 | -kernel arch/riscv/boot/Image \ |
| 173 | -initrd /path/to/rootfs.cpio \ |
| 174 | -append "root=/dev/ram" |
| 175 | |
| 176 | To build a Linux mainline kernel that can be booted by the ``virt`` machine |
| 177 | in 32-bit mode, use the rv32_defconfig configuration. A patch is required to |
| 178 | fix the 32-bit boot issue for Linux kernel v5.12. |
| 179 | |
| 180 | .. code-block:: bash |
| 181 | |
| 182 | $ export ARCH=riscv |
| 183 | $ export CROSS_COMPILE=riscv64-linux- |
| 184 | $ curl https://patchwork.kernel.org/project/linux-riscv/patch/20210627135117.28641-1-bmeng.cn@gmail.com/mbox/ > riscv.patch |
| 185 | $ git am riscv.patch |
| 186 | $ make rv32_defconfig |
| 187 | $ make |
| 188 | |
| 189 | Replace ``qemu-system-riscv64`` with ``qemu-system-riscv32`` in the command |
| 190 | line above to boot the 32-bit Linux kernel. A rootfs image containing 32-bit |
| 191 | applications shall be used in order for kernel to boot to user space. |
| 192 | |
| 193 | Running U-Boot |
| 194 | -------------- |
| 195 | |
| 196 | U-Boot mainline v2021.04 release is tested at the time of writing. To build an |
| 197 | S-mode U-Boot bootloader that can be booted by the ``virt`` machine, use |
| 198 | the qemu-riscv64_smode_defconfig with similar commands as described above for Linux: |
| 199 | |
| 200 | .. code-block:: bash |
| 201 | |
| 202 | $ export CROSS_COMPILE=riscv64-linux- |
| 203 | $ make qemu-riscv64_smode_defconfig |
| 204 | |
| 205 | Boot the 64-bit U-Boot S-mode image directly: |
| 206 | |
| 207 | .. code-block:: bash |
| 208 | |
| 209 | $ qemu-system-riscv64 -M virt -smp 4 -m 2G \ |
| 210 | -display none -serial stdio \ |
| 211 | -kernel /path/to/u-boot.bin |
| 212 | |
| 213 | To test booting U-Boot SPL which in M-mode, which in turn loads a FIT image |
| 214 | that bundles OpenSBI fw_dynamic firmware and U-Boot proper (S-mode) together, |
| 215 | build the U-Boot images using riscv64_spl_defconfig: |
| 216 | |
| 217 | .. code-block:: bash |
| 218 | |
| 219 | $ export CROSS_COMPILE=riscv64-linux- |
| 220 | $ export OPENSBI=/path/to/opensbi-riscv64-generic-fw_dynamic.bin |
| 221 | $ make qemu-riscv64_spl_defconfig |
| 222 | |
| 223 | The minimal QEMU commands to run U-Boot SPL are: |
| 224 | |
| 225 | .. code-block:: bash |
| 226 | |
| 227 | $ qemu-system-riscv64 -M virt -smp 4 -m 2G \ |
| 228 | -display none -serial stdio \ |
| 229 | -bios /path/to/u-boot-spl \ |
| 230 | -device loader,file=/path/to/u-boot.itb,addr=0x80200000 |
| 231 | |
| 232 | To test 32-bit U-Boot images, switch to use qemu-riscv32_smode_defconfig and |
| 233 | riscv32_spl_defconfig builds, and replace ``qemu-system-riscv64`` with |
| 234 | ``qemu-system-riscv32`` in the command lines above to boot the 32-bit U-Boot. |
| 235 | |
| 236 | Enabling TPM |
| 237 | ------------ |
| 238 | |
| 239 | A TPM device can be connected to the virt board by following the steps below. |
| 240 | |
| 241 | First launch the TPM emulator: |
| 242 | |
| 243 | .. code-block:: bash |
| 244 | |
| 245 | $ swtpm socket --tpm2 -t -d --tpmstate dir=/tmp/tpm \ |
| 246 | --ctrl type=unixio,path=swtpm-sock |
| 247 | |
| 248 | Then launch QEMU with some additional arguments to link a TPM device to the backend: |
| 249 | |
| 250 | .. code-block:: bash |
| 251 | |
| 252 | $ qemu-system-riscv64 \ |
| 253 | ... other args .... \ |
| 254 | -chardev socket,id=chrtpm,path=swtpm-sock \ |
| 255 | -tpmdev emulator,id=tpm0,chardev=chrtpm \ |
| 256 | -device tpm-tis-device,tpmdev=tpm0 |
| 257 | |
| 258 | The TPM device can be seen in the memory tree and the generated device |
| 259 | tree and should be accessible from the guest software. |