Adding a custom ARM platform to QEMU 5.2.0
The SoC is being developed by the ASIC team, but the software team wants to develop the software concurrently for the hardware that is not yet available, at least not for another 3 months or longer. In this situation what do you do ?
In the early phase of SoC development you don't usually have hardware available, but you want to develop the software concurrently with the ASIC development. One option is to find the platform with the closest architecture and develop the software based on that platform, but it not always that easy to find. If you could, why would you want to continue with your SoC development ? You are already steps behind your competitors. This option will also come with a lot of clean-up work later on. The other option is to software emulated your platform such that we can develop and test your software implementation to its nearest target platform. This is what QEMU comes in to play. This blog is one of two parts series. One is to add new ARM platform into QEMU to emulate the hardware while the other part is to port FreeRTOS to support the new platform.
An open source, QEMU from qemu.org is a generic machine emulator and virtualizer that supports various CPU architectures and platforms. QEMU runs on most mainstream OS, Linux, Windows, and MacOS. Since it is an open source, you can customize by adding the new platform into this package, build, install and use it. This blogs documents about how I add a custom ARM Cortex R-5 platform in to the existing package. I call it real-time experimental SoC, rtx-soc platform. This platform will be added to the supported ARM CPU architectur the QEMU.
Components
Two main components needed: QEMU package (and other s/w dependencies required by this package) and the host PC (Linux). The software packages required by QEMU are listed in its respective QEMU site for building the QEMU. It is most likely that the needed dependencies are met if you fully installed the Linux distribution. If not, only minimal effort is needed. I choose the latest release version qemu-5.2.0 of early 2021 since I find it to be easier than the earlier version for adding new target. I have actually done this with version qemu-5.1.0 and found that the latest version is easier to port.
The host PC is for building and running the QEMU to virtualize/emulate the h/w platform. For my case I use Linux x64 Slackware with kernel built to support virtualization. The PC BIOS should have virtualization enable as well. They may not be the requirements of the host platform for QEMU.
QEMU
-
QEMU
version: qemu-5.2.0, which is the latest as of Jan 2021.
Emulation: ARM and AARCH64 on Linux x64 host.
-
SoC target plaform to be added:
ARM Cortex-R5 with 4MB on-chip RAM (OCR).
APB peripherals: UART, Timer, I2C
GICv2 Interrupt controller
Flash and others
Before you begin the work, you might as well test build the stock release as-is for the ARM emulation. If all the dependencies are met the package should build successfully. To build as-is for ARM, extract the package then cd qemu-5.2.0 to configure and build,
./configure --target-list=arm-softmmu,arm-linux-user,aarch64-softmmu,aarch64-linux-user --prefix=/opt/qemu-5.2.0/
This configure for ARMv7 and ARMv8 and install to /opt/qemu-5.2.0 when you do make install. The output of the built QEMU is in its build/ directory. You can as well run QEMU from this directory without having to install it to the desired location.
Check the machines supported by this build,
qemu-system-aarch64 -M help
Will list the ARM platforms supported, for examples,
Supported machines are: akita Sharp SL-C1000 (Akita) PDA (PXA270) ast2500-evb Aspeed AST2500 EVB (ARM1176) ast2600-evb Aspeed AST2600 EVB (Cortex A7) borzoi Sharp SL-C3100 (Borzoi) PDA (PXA270) canon-a1100 Canon PowerShot A1100 IS cheetah Palm Tungsten|E aka. Cheetah PDA (OMAP310) collie Sharp SL-5500 (Collie) PDA (SA-1110) connex Gumstix Connex (PXA255) ..
You can find images of the supported platforms that you could run with QEMU in their respective websites with the instructions on what specific command parameters you need to supply. The images can be just the boot code images or full disk images completed with OS.
Adding platform to QEMU
In QEMU directories structure, I only need to work in two directories, hw/arm/ and default-configs/devices/ to add the new target platform and to modified the existing configuration incorporating new platform.
Adding rtx-soc to configuration
1) Specify QEMU platform and what the platform needs for its basic peripherals. To do this, add config RTX_SOC block which is a custom platform to hw/arm/Kconfig by editing this file (line 8-15),
The components chosen by select are the peripherals that my platform needs to instantiate on board bring-up. They are the QEMU objects to be invoked in the source code so they too need to be configured as default devices. More peripherals can be added in the future, but it is adequate for my need at the time being.
2) Adding to CONFIG_RTX_SOC to default-configs/devices/arm-softmmu.mak file for the above configuration. QEMU will build RTX_SOC platform as a default supported platform among others (line 3).
3) Add file name rtx-soc.c to be compiled to QEMU 5.2.0's hw/arm/meson.build script. This is the emulated Cortex-R5 RTX_SOC target platform (line 3).
The configuration part of this package is complete. Next is to add platform machine file.
Creating and adding platform file
rtx-soc.c is source file to describe the ARM Cortex-R5 platform to be added to the supported platform as described in the section above. The Cortex-R5 CPU support is in target/arm directory of the QEMU. There is no need to do anything with respect to this directory or any subdirectory in target/. All other peripheral components are in hw/ subdirectories, for example, hw/char/ (serial port), hw/net/ (Ethernet network), /hw/block/ (flash) etc... You can explore the subdirectories of hw/ to find out what you need to add them to your platform.
Simply create rtx-soc.c source file in QEMU's /hw/arm/ directory. The edited configuration already made as described above will compile this source into QEMU to support this platform.
Implementation of RTX platform Cortex-R5
Instead of creating rtx-soc.c from scratch, it is best to clone it from the one of the existing file in hw/arm/ directory. Browsing through these files, I choose ARM Versatile Express emulation, vexpress.c, as the base line and clone it to be rtx-soc.c because it has many similar peripherals that I need and having the content that is easier to understand. The vexpress is based on Cortex-A9 and Cortex-A15 multicore h/w platform. I will replace these ARM cores in rtx-soc.c for Cortex-R5. The components that do not exist in my platform will be removed and the components that I need will be added.
Steps involved
Copy vexpress.c to rtx-soc.c - start off with this cloned file.
-
Edit the clone file, rtx-soc.c :
Create the hwaddr structure that defines my platform need to be created to match the phyiscal addresses of the memory and peripheral devices. I can edit the existing structure to fit my need,
More elements can be added as needed.
Create/edit VEDBoardInfo structure for this platform and specify to use motherboard map as defined above,
Create/edit the rtx-soc machine classes and information structures for initialization. For machine state, use VexpressMachineState since it is not necessary to rename it.
Create/edit type_init() macro to invoke machine initialization for this platform.
static void rtx_soc_machine_init(void)
{
type_register_static(&rtx_soc_info);
type_register_static(&rtx_soc_r5_info);
}
type_init(rtx_soc_machine_init);
Define the machine type and object macros used in the structures above,
Line 2 defines the name of the emulated platform, rtx-r5. The QEMU's '-M help' option will list it in its supported platform list.
When machine class is initialized, rtx_soc_common_init() function is called so we need to implement this function. The vexpress_common_init() is renamed and edited to become this function. This function is for instantiating devices defined for the target platform. For RTX platform, the clocks and voltage sensors remain the same as the Vexpress's. MMC, Keyboard, VRAM devices are commented out. Only one UART0 is used so UART1-3 are not instantiated.
Configure and build QEMU at top directory to populate the build directory by cmake.
qemu-5.2.0/$./configure --target-list=arm-softmmu,arm-linux-user,aarch64-softmmu,aarch64-linux-user --prefix=/opt/qemu-5.2.0/ qemu-5.2.0/$make && make install
More elements can be added as needed.*make install* to install the s/w binaries into the directory in /opt/qemu-5.2.0. QEMU binary can also be run within build/ directory. The successfully created platform would show up on the supported list of ARM machines (line 8),
Testing
Once the built is complete and installed, I can use it to emulate the hardware platform to test my FreeRTOS port for this RTX SoC. The freertos-nga is the ELF binary of the ported RTOS for this platform. Porting the FreeRTOS will be in another post of this two parts series. Here is the console output where QEMU emulates rtx-r5 with 2MB of on-chip RAM running FreeRTOS,
qemu-system-aarch64 -M rtx-r5 -m 2m -nographic -no-reboot -kernel build/freertos-nga machine cpu_type cortex-r5f-arm-cpu UART base 0x58000000 created for serial0. main: Entering main(265) init_console, line 222 current state: standby, last_state initialize Entering app_main(33686018), 3.141590 nga> tasks Task Name Status Prio HWM Task Number app_main X 1 323 3 IDLE R 0 478 6 uart_rx_poll B 1 471 4 Tmr Svc B 4 451 7 TX B 2 472 2 Rx B 1 468 1 regi_state_mon B 2 335 5 Timer ulCount : 62 nga>
QEMU can be use along with GDB such as arm-eabi-gdb to debug the OS port. The '-s -S' options use with QEMU is to single step and connect to GDB, for example,
$ qemu-system-aarch64 -M rtx-r5 -m 2m -nographic -no-reboot -kernel build/freertos-nga -s -S machine cpu_type cortex-r5f-arm-cpu UART base 0x58000000 created for serial0.
At this stage, QEMU is waiting for GDB connection. To connect, open another shell and start GDB,
$ arm-eabi-gdb build/freertos-nga GNU gdb (GDB) 9.2 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-pc-linux-gnu --target=arm-eabi". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from build/freertos-nga... (gdb) target remote :1234 Remote debugging using :1234 _freertos_vector_table () at /home/user/NGA/freertos-nga/platform/FreeRTOS_asm_vectors.S:82 82 B _boot (gdb) b main Breakpoint 1 at 0xd8c: file /home/user/NGA/freertos-nga/app/main.c, line 246. (gdb) c Continuing. Breakpoint 1, main () at /home/user/NGA/freertos-nga/app/main.c:246 246 xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) ); (gdb)
Conclusion
Without hardware available, I can use QEMU to emulate a virtual hardware with almost everything, CPU and peripherals that I need to get going for software development. For a faster Linux host, the clock cycles for slower ARM core frequency ~20MHZ -40MHZ is probably very close to the physical hardware although I did not take any measurement. QEMU is a powerful software tool and more than adequate for majority of software work such as board bring up and low-level firmware development. Its MMU support is very machine accurate. It can emulate PC to run the full blown OS such as Windows or Linux without problem.
Citations
- 1
-
https://qemu.org QEMU portal
- 2
-
ARM Ltd, for all ARM Architecture.