| 1 | SiFive HiFive Unleashed (``sifive_u``) |
| 2 | ====================================== |
| 3 | |
| 4 | SiFive HiFive Unleashed Development Board is the ultimate RISC-V development |
| 5 | board featuring the Freedom U540 multi-core RISC-V processor. |
| 6 | |
| 7 | Supported devices |
| 8 | ----------------- |
| 9 | |
| 10 | The ``sifive_u`` machine supports the following devices: |
| 11 | |
| 12 | * 1 E51 / E31 core |
| 13 | * Up to 4 U54 / U34 cores |
| 14 | * Core Local Interruptor (CLINT) |
| 15 | * Platform-Level Interrupt Controller (PLIC) |
| 16 | * Power, Reset, Clock, Interrupt (PRCI) |
| 17 | * L2 Loosely Integrated Memory (L2-LIM) |
| 18 | * DDR memory controller |
| 19 | * 2 UARTs |
| 20 | * 1 GEM Ethernet controller |
| 21 | * 1 GPIO controller |
| 22 | * 1 One-Time Programmable (OTP) memory with stored serial number |
| 23 | * 1 DMA controller |
| 24 | * 2 QSPI controllers |
| 25 | * 1 ISSI 25WP256 flash |
| 26 | * 1 SD card in SPI mode |
| 27 | * PWM0 and PWM1 |
| 28 | |
| 29 | Please note the real world HiFive Unleashed board has a fixed configuration of |
| 30 | 1 E51 core and 4 U54 core combination and the RISC-V core boots in 64-bit mode. |
| 31 | With QEMU, one can create a machine with 1 E51 core and up to 4 U54 cores. It |
| 32 | is also possible to create a 32-bit variant with the same peripherals except |
| 33 | that the RISC-V cores are replaced by the 32-bit ones (E31 and U34), to help |
| 34 | testing of 32-bit guest software. |
| 35 | |
| 36 | Hardware configuration information |
| 37 | ---------------------------------- |
| 38 | |
| 39 | The ``sifive_u`` machine automatically generates a device tree blob ("dtb") |
| 40 | which it passes to the guest, if there is no ``-dtb`` option. This provides |
| 41 | information about the addresses, interrupt lines and other configuration of |
| 42 | the various devices in the system. Guest software should discover the devices |
| 43 | that are present in the generated DTB instead of using a DTB for the real |
| 44 | hardware, as some of the devices are not modeled by QEMU and trying to access |
| 45 | these devices may cause unexpected behavior. |
| 46 | |
| 47 | If users want to provide their own DTB, they can use the ``-dtb`` option. |
| 48 | These DTBs should have the following requirements: |
| 49 | |
| 50 | * The /cpus node should contain at least one subnode for E51 and the number |
| 51 | of subnodes should match QEMU's ``-smp`` option |
| 52 | * The /memory reg size should match QEMU’s selected ram_size via ``-m`` |
| 53 | * Should contain a node for the CLINT device with a compatible string |
| 54 | "riscv,clint0" if using with OpenSBI BIOS images |
| 55 | |
| 56 | Boot options |
| 57 | ------------ |
| 58 | |
| 59 | The ``sifive_u`` machine can start using the standard -kernel functionality |
| 60 | for loading a Linux kernel, a VxWorks kernel, a modified U-Boot bootloader |
| 61 | (S-mode) or ELF executable with the default OpenSBI firmware image as the |
| 62 | -bios. It also supports booting the unmodified U-Boot bootloader using the |
| 63 | standard -bios functionality. |
| 64 | |
| 65 | Machine-specific options |
| 66 | ------------------------ |
| 67 | |
| 68 | The following machine-specific options are supported: |
| 69 | |
| 70 | - serial=nnn |
| 71 | |
| 72 | The board serial number. When not given, the default serial number 1 is used. |
| 73 | |
| 74 | SiFive reserves the first 1 KiB of the 16 KiB OTP memory for internal use. |
| 75 | The current usage is only used to store the serial number of the board at |
| 76 | offset 0xfc. U-Boot reads the serial number from the OTP memory, and uses |
| 77 | it to generate a unique MAC address to be programmed to the on-chip GEM |
| 78 | Ethernet controller. When multiple QEMU ``sifive_u`` machines are created |
| 79 | and connected to the same subnet, they all have the same MAC address hence |
| 80 | it creates an unusable network. In such scenario, user should give different |
| 81 | values to serial= when creating different ``sifive_u`` machines. |
| 82 | |
| 83 | - start-in-flash |
| 84 | |
| 85 | When given, QEMU's ROM codes jump to QSPI memory-mapped flash directly. |
| 86 | Otherwise QEMU will jump to DRAM or L2LIM depending on the msel= value. |
| 87 | When not given, it defaults to direct DRAM booting. |
| 88 | |
| 89 | - msel=[6|11] |
| 90 | |
| 91 | Mode Select (MSEL[3:0]) pins value, used to control where to boot from. |
| 92 | |
| 93 | The FU540 SoC supports booting from several sources, which are controlled |
| 94 | using the Mode Select pins on the chip. Typically, the boot process runs |
| 95 | through several stages before it begins execution of user-provided programs. |
| 96 | These stages typically include the following: |
| 97 | |
| 98 | 1. Zeroth Stage Boot Loader (ZSBL), which is contained in an on-chip mask |
| 99 | ROM and provided by QEMU. Note QEMU implemented ROM codes are not the |
| 100 | same as what is programmed in the hardware. The QEMU one is a simplified |
| 101 | version, but it provides the same functionality as the hardware. |
| 102 | 2. First Stage Boot Loader (FSBL), which brings up PLLs and DDR memory. |
| 103 | This is U-Boot SPL. |
| 104 | 3. Second Stage Boot Loader (SSBL), which further initializes additional |
| 105 | peripherals as needed. This is U-Boot proper combined with an OpenSBI |
| 106 | fw_dynamic firmware image. |
| 107 | |
| 108 | msel=6 means FSBL and SSBL are both on the QSPI flash. msel=11 means FSBL |
| 109 | and SSBL are both on the SD card. |
| 110 | |
| 111 | Running Linux kernel |
| 112 | -------------------- |
| 113 | |
| 114 | Linux mainline v5.10 release is tested at the time of writing. To build a |
| 115 | Linux mainline kernel that can be booted by the ``sifive_u`` machine in |
| 116 | 64-bit mode, simply configure the kernel using the defconfig configuration: |
| 117 | |
| 118 | .. code-block:: bash |
| 119 | |
| 120 | $ export ARCH=riscv |
| 121 | $ export CROSS_COMPILE=riscv64-linux- |
| 122 | $ make defconfig |
| 123 | $ make |
| 124 | |
| 125 | To boot the newly built Linux kernel in QEMU with the ``sifive_u`` machine: |
| 126 | |
| 127 | .. code-block:: bash |
| 128 | |
| 129 | $ qemu-system-riscv64 -M sifive_u -smp 5 -m 2G \ |
| 130 | -display none -serial stdio \ |
| 131 | -kernel arch/riscv/boot/Image \ |
| 132 | -initrd /path/to/rootfs.ext4 \ |
| 133 | -append "root=/dev/ram" |
| 134 | |
| 135 | Alternatively, we can use a custom DTB to boot the machine by inserting a CLINT |
| 136 | node in fu540-c000.dtsi in the Linux kernel, |
| 137 | |
| 138 | .. code-block:: none |
| 139 | |
| 140 | clint: clint@2000000 { |
| 141 | compatible = "riscv,clint0"; |
| 142 | interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7 |
| 143 | &cpu1_intc 3 &cpu1_intc 7 |
| 144 | &cpu2_intc 3 &cpu2_intc 7 |
| 145 | &cpu3_intc 3 &cpu3_intc 7 |
| 146 | &cpu4_intc 3 &cpu4_intc 7>; |
| 147 | reg = <0x00 0x2000000 0x00 0x10000>; |
| 148 | }; |
| 149 | |
| 150 | with the following command line options: |
| 151 | |
| 152 | .. code-block:: bash |
| 153 | |
| 154 | $ qemu-system-riscv64 -M sifive_u -smp 5 -m 8G \ |
| 155 | -display none -serial stdio \ |
| 156 | -kernel arch/riscv/boot/Image \ |
| 157 | -dtb arch/riscv/boot/dts/sifive/hifive-unleashed-a00.dtb \ |
| 158 | -initrd /path/to/rootfs.ext4 \ |
| 159 | -append "root=/dev/ram" |
| 160 | |
| 161 | To build a Linux mainline kernel that can be booted by the ``sifive_u`` machine |
| 162 | in 32-bit mode, use the rv32_defconfig configuration. A patch is required to |
| 163 | fix the 32-bit boot issue for Linux kernel v5.10. |
| 164 | |
| 165 | .. code-block:: bash |
| 166 | |
| 167 | $ export ARCH=riscv |
| 168 | $ export CROSS_COMPILE=riscv64-linux- |
| 169 | $ curl https://patchwork.kernel.org/project/linux-riscv/patch/20201219001356.2887782-1-atish.patra@wdc.com/mbox/ > riscv.patch |
| 170 | $ git am riscv.patch |
| 171 | $ make rv32_defconfig |
| 172 | $ make |
| 173 | |
| 174 | Replace ``qemu-system-riscv64`` with ``qemu-system-riscv32`` in the command |
| 175 | line above to boot the 32-bit Linux kernel. A rootfs image containing 32-bit |
| 176 | applications shall be used in order for kernel to boot to user space. |
| 177 | |
| 178 | Running VxWorks kernel |
| 179 | ---------------------- |
| 180 | |
| 181 | VxWorks 7 SR0650 release is tested at the time of writing. To build a 64-bit |
| 182 | VxWorks mainline kernel that can be booted by the ``sifive_u`` machine, simply |
| 183 | create a VxWorks source build project based on the sifive_generic BSP, and a |
| 184 | VxWorks image project to generate the bootable VxWorks image, by following the |
| 185 | BSP documentation instructions. |
| 186 | |
| 187 | A pre-built 64-bit VxWorks 7 image for HiFive Unleashed board is available as |
| 188 | part of the VxWorks SDK for testing as well. Instructions to download the SDK: |
| 189 | |
| 190 | .. code-block:: bash |
| 191 | |
| 192 | $ wget https://labs.windriver.com/downloads/wrsdk-vxworks7-sifive-hifive-1.01.tar.bz2 |
| 193 | $ tar xvf wrsdk-vxworks7-sifive-hifive-1.01.tar.bz2 |
| 194 | $ ls bsps/sifive_generic_1_0_0_0/uboot/uVxWorks |
| 195 | |
| 196 | To boot the VxWorks kernel in QEMU with the ``sifive_u`` machine, use: |
| 197 | |
| 198 | .. code-block:: bash |
| 199 | |
| 200 | $ qemu-system-riscv64 -M sifive_u -smp 5 -m 2G \ |
| 201 | -display none -serial stdio \ |
| 202 | -nic tap,ifname=tap0,script=no,downscript=no \ |
| 203 | -kernel /path/to/vxWorks \ |
| 204 | -append "gem(0,0)host:vxWorks h=192.168.200.1 e=192.168.200.2:ffffff00 u=target pw=vxTarget f=0x01" |
| 205 | |
| 206 | It is also possible to test 32-bit VxWorks on the ``sifive_u`` machine. Create |
| 207 | a 32-bit project to build the 32-bit VxWorks image, and use exact the same |
| 208 | command line options with ``qemu-system-riscv32``. |
| 209 | |
| 210 | Running U-Boot |
| 211 | -------------- |
| 212 | |
| 213 | U-Boot mainline v2024.01 release is tested at the time of writing. To build a |
| 214 | U-Boot mainline bootloader that can be booted by the ``sifive_u`` machine, use |
| 215 | the sifive_unleashed_defconfig with similar commands as described above for |
| 216 | Linux: |
| 217 | |
| 218 | .. code-block:: bash |
| 219 | |
| 220 | $ export CROSS_COMPILE=riscv64-linux- |
| 221 | $ export OPENSBI=/path/to/opensbi-riscv64-generic-fw_dynamic.bin |
| 222 | $ make sifive_unleashed_defconfig |
| 223 | |
| 224 | You will get spl/u-boot-spl.bin and u-boot.itb file in the build tree. |
| 225 | |
| 226 | To start U-Boot using the ``sifive_u`` machine, prepare an SPI flash image, or |
| 227 | SD card image that is properly partitioned and populated with correct contents. |
| 228 | genimage_ can be used to generate these images. |
| 229 | |
| 230 | A sample configuration file for a 128 MiB SD card image is: |
| 231 | |
| 232 | .. code-block:: bash |
| 233 | |
| 234 | $ cat genimage_sdcard.cfg |
| 235 | image sdcard.img { |
| 236 | size = 128M |
| 237 | |
| 238 | hdimage { |
| 239 | gpt = true |
| 240 | } |
| 241 | |
| 242 | partition u-boot-spl { |
| 243 | image = "u-boot-spl.bin" |
| 244 | offset = 17K |
| 245 | partition-type-uuid = 5B193300-FC78-40CD-8002-E86C45580B47 |
| 246 | } |
| 247 | |
| 248 | partition u-boot { |
| 249 | image = "u-boot.itb" |
| 250 | offset = 1041K |
| 251 | partition-type-uuid = 2E54B353-1271-4842-806F-E436D6AF6985 |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | SPI flash image has slightly different partition offsets, and the size has to |
| 256 | be 32 MiB to match the ISSI 25WP256 flash on the real board: |
| 257 | |
| 258 | .. code-block:: bash |
| 259 | |
| 260 | $ cat genimage_spi-nor.cfg |
| 261 | image spi-nor.img { |
| 262 | size = 32M |
| 263 | |
| 264 | hdimage { |
| 265 | gpt = true |
| 266 | } |
| 267 | |
| 268 | partition u-boot-spl { |
| 269 | image = "u-boot-spl.bin" |
| 270 | offset = 20K |
| 271 | partition-type-uuid = 5B193300-FC78-40CD-8002-E86C45580B47 |
| 272 | } |
| 273 | |
| 274 | partition u-boot { |
| 275 | image = "u-boot.itb" |
| 276 | offset = 1044K |
| 277 | partition-type-uuid = 2E54B353-1271-4842-806F-E436D6AF6985 |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | Assume U-Boot binaries are put in the same directory as the config file, |
| 282 | we can generate the image by: |
| 283 | |
| 284 | .. code-block:: bash |
| 285 | |
| 286 | $ genimage --config genimage_<boot_src>.cfg --inputpath . |
| 287 | |
| 288 | Boot U-Boot from SD card, by specifying msel=11 and pass the SD card image |
| 289 | to QEMU ``sifive_u`` machine: |
| 290 | |
| 291 | .. code-block:: bash |
| 292 | |
| 293 | $ qemu-system-riscv64 -M sifive_u,msel=11 -smp 5 -m 8G \ |
| 294 | -display none -serial stdio \ |
| 295 | -bios /path/to/u-boot-spl.bin \ |
| 296 | -drive file=/path/to/sdcard.img,if=sd |
| 297 | |
| 298 | Changing msel= value to 6, allows booting U-Boot from the SPI flash: |
| 299 | |
| 300 | .. code-block:: bash |
| 301 | |
| 302 | $ qemu-system-riscv64 -M sifive_u,msel=6 -smp 5 -m 8G \ |
| 303 | -display none -serial stdio \ |
| 304 | -bios /path/to/u-boot-spl.bin \ |
| 305 | -drive file=/path/to/spi-nor.img,if=mtd |
| 306 | |
| 307 | Note when testing U-Boot, QEMU automatically generated device tree blob is |
| 308 | not used because U-Boot itself embeds device tree blobs for U-Boot SPL and |
| 309 | U-Boot proper. Hence the number of cores and size of memory have to match |
| 310 | the real hardware, ie: 5 cores (-smp 5) and 8 GiB memory (-m 8G). |
| 311 | |
| 312 | Above use case is to run upstream U-Boot for the SiFive HiFive Unleashed |
| 313 | board on QEMU ``sifive_u`` machine out of the box. This allows users to |
| 314 | develop and test the recommended RISC-V boot flow with a real world use |
| 315 | case: ZSBL (in QEMU) loads U-Boot SPL from SD card or SPI flash to L2LIM, |
| 316 | then U-Boot SPL loads the combined payload image of OpenSBI fw_dynamic |
| 317 | firmware and U-Boot proper. |
| 318 | |
| 319 | However sometimes we want to have a quick test of booting U-Boot on QEMU |
| 320 | without the needs of preparing the SPI flash or SD card images, an alternate |
| 321 | way can be used, which is to create a U-Boot S-mode image by modifying the |
| 322 | configuration of U-Boot: |
| 323 | |
| 324 | .. code-block:: bash |
| 325 | |
| 326 | $ export CROSS_COMPILE=riscv64-linux- |
| 327 | $ make sifive_unleashed_defconfig |
| 328 | $ ./scripts/config --enable OF_BOARD |
| 329 | $ ./scripts/config --disable BINMAN_FDT |
| 330 | $ ./scripts/config --disable SPL |
| 331 | $ make olddefconfig |
| 332 | |
| 333 | This changes U-Boot to use the QEMU generated device tree blob, and bypass |
| 334 | running the U-Boot SPL stage. |
| 335 | |
| 336 | Boot the 64-bit U-Boot S-mode image directly: |
| 337 | |
| 338 | .. code-block:: bash |
| 339 | |
| 340 | $ qemu-system-riscv64 -M sifive_u -smp 5 -m 2G \ |
| 341 | -display none -serial stdio \ |
| 342 | -kernel /path/to/u-boot.bin |
| 343 | |
| 344 | It's possible to create a 32-bit U-Boot S-mode image as well. |
| 345 | |
| 346 | .. code-block:: bash |
| 347 | |
| 348 | $ export CROSS_COMPILE=riscv64-linux- |
| 349 | $ make sifive_unleashed_defconfig |
| 350 | $ ./scripts/config --disable ARCH_RV64I |
| 351 | $ ./scripts/config --enable ARCH_RV32I |
| 352 | $ ./scripts/config --set-val TEXT_BASE 0x80400000 |
| 353 | $ ./scripts/config --enable OF_BOARD |
| 354 | $ ./scripts/config --disable BINMAN_FDT |
| 355 | $ ./scripts/config --disable SPL |
| 356 | $ make olddefconfig |
| 357 | |
| 358 | Use the same command line options to boot the 32-bit U-Boot S-mode image: |
| 359 | |
| 360 | .. code-block:: bash |
| 361 | |
| 362 | $ qemu-system-riscv32 -M sifive_u -smp 5 -m 2G \ |
| 363 | -display none -serial stdio \ |
| 364 | -kernel /path/to/u-boot.bin |
| 365 | |
| 366 | .. _genimage: https://github.com/pengutronix/genimage |