This project was developed by Chiara Iorio, Sara Braidotti and Matteo Pani during the Computer Architectures and Operating Systems course of the Master's degree in Cybersecurity at Politecnico di Torino.
The goal of this project is to emulate the NXP S32K3X8EVB board, based on the 32-bit Arm®Cortex®-M7 S32K358 MCU (NXP website).
To generate a custom QEMU version to emulate this board (its CPU, memory map, UART and timers) please refer to the following steps.
To read the whole documentation of the project click here. The presentation is to be visualized with patat, a feature-rich presentation tool that runs in the terminal. The references and the description of the files in the docs folder can be found here.
First of all, you need to install git and some other dependencies. For the list of the necessary dependencies look at the official Qemu documentation. Then we get the code from the QEMU's GitHub repository, checkout to a stable branch and check if the build configuration works correctly:
git clone https://github.com/qemu/qemu.git
cd qemu
git checkout stable-9.1
git submodule init
git submodule update --recursive
./configureAfterwards, we create and give the necessary permissions to the folder in which the QEMU binary file containing the new board will be installed:
sudo install --directory --owner $(id --user) --group $(id --group) /opt/qemu-9.1.0The easiest way to add the support for the board in QEMU is by applying the patch. Copy the file qemu.patch in the QEMU folder and apply it:
cd qemu
git apply < qemu.patchOtherwise, you can manually add the board by following the subsequent steps. The source files can be found in the src folder.
- Go to directory
qemu/hw/arm - Copy the file
s32k358.c - At the end of the
Kconfigfile add the code necessary to tell the peripherals needed by the board:
config S32K358
bool
default y
depends on TCG && ARM
select ARMSSE
select UNIMP
select S32K358_TIMER
select S32K358_UART
- At the end of the
meson.buildfile (that coordinates the configuration and build of all executables) add:
arm_ss.add(when: 'CONFIG_S32K358', if_true: files('s32k358.c'))
- Go to directory
qemu/hw/char - Copy the file
s32k358_uart.c - At the end of the
Kconfigfile add:
config S32K358_UART
bool
- At the end of the
meson.buildfile add:
specific_ss.add(when: 'CONFIG_S32K358_UART', if_true: files('s32k358_uart.c'))
- Go to
qemu/include/hw/char/and copy the files32k358_uart.h
- Go to directory
qemu/hw/timer - Copy the file
s32k358_timer.c - At the end of the
Kconfigfile add:
config S32K358_TIMER
bool
select PTIMER
- At the end of the
meson.buildfile add:
specific_ss.add(when: 'CONFIG_S32K358_TIMER', if_true: files('s32k358_timer.c'))
- Go to
qemu/include/hw/timer/and copy the files32k358_timer.h
┌─────────────┐ add ┌────────────────────────────────────────────────────────────────┐
qemu/hw/ ┌──┤ meson.build ├─────────┤ arm_ss.add(when: 'CONFIG_S32K358', if_true: files('s32k358.c'))│
│ └─────────────┘ └────────────────────────────────────────────────────────────────┘
│ │
│ │ ┌─────────────────────────────┐
│ ./arm │ ┌───────────┐ │ config S32K358 │
├────────────┼──┤ s32k358.c │ │ bool │
│ │ └───────────┘ │ default y │
│ │ ┌─────────┐ add │ depends on TCG && ARM │
│ └──│ Kconfig ├─────────────┤ select ARMSSE │
│ └─────────┘ │ select UNIMP │
│ │ select S32K358_TIMER │
│ │ select S32K358_UART │
│ └─────────────────────────────┘
│ ./char
│ ┌────────────────┐
├────────────┬───┤ s32k358_uart.c │
│ │ └────────────────┘ ┌───────────────────────────┐
│ │ ┌─────────┐ add │ config S32K358_UART │
│ ├───┤ Kconfig ├────────────┤ bool │
│ │ └─────────┘ └───────────────────────────┘
│ │ ┌─────────────┐ add ┌───────────────────────────────────────────────────────────────────────────────┐
│ └───┤ meson.build ├────────┤ specific_ss.add(when:F'CONFIG_S32K358_UART',fif_true:2files('s32k358_uart.c'))│
│ └─────────────┘ └───────────────────────────────────────────────────────────────────────────────┘
│ ./timer
│ ┌────────────────┐
└────────────┬───┤ s32k358_timer.c│ ┌───────────────────────────┐
│ └────────────────┘ │ config S32K358_TIMER │
│ ┌─────────┐ add │ bool │
├───┤ Kconfig ├────────────┤ select PTIMER │
│ └─────────┘ └───────────────────────────┘
│ ┌─────────────┐ add ┌─────────────────────────────────────────────────────────────────────────────────┐
└───┤ meson.build ├────────┤ specific_ss.add(when:F'CONFIG_S32K358_TIMER',fif_true:2files('s32k358_timer.c)) │
└─────────────┘ └─────────────────────────────────────────────────────────────────────────────────┘
qemu/include/hw/
│ ./char ┌────────────────┐
├────────────────┤ s32k358_uart.h │
│ └────────────────┘
│ ./timer ┌────────────────┐
└────────────────┤ s32k358_timer.h│
└────────────────┘
After adding the support for the new board, we need to recompile QEMU:
./configure \
--target-list=arm-softmmu,arm-linux-user \
--prefix=/opt/qemu-9.1.0/
make
make installNow we can test FreeRTOS on our custom machine. Therefore, the first step is to clone the FreeRTOS repository using the following command:
git clone https://github.com/FreeRTOS/FreeRTOS.git --recurse-submodulesAt this point, we can try to run the demo application (Demo folder). Compile the code with the NXP toolchain by typing make and then make qemu_start to launch the application. Try to type something and press enter to experience the LPUART receive functionality!
Remember to put the correct directory for your FreeRTOS folder in the Makefile.
This project is distributed under the CC-BY_NC 4.0 - copyright (c) 2025 Braidotti Sara, Iorio Chiara, Pani Matteo.
You can view additional details on this page.