Emulate memory-mapped peripherals (GPIO, UART/char, SPI, I2C, timers, DMA, interrupt controllers, flash, …) so MCU firmware runs against realistic hardware. Peripherals are instantiated from a YAML profile naming which peripheral class sits at which MMIO base address. Only active in bare-metal (MCU) mode. Mature released infrastructure; maturity-based status.
done — exercised by tests/test_mcu.py against STM32F1/F4 and GD32VF1
firmware images (UART echo, freertos, blink, crc, dma_clock, i2c/spi/lcd).
| File | Role |
|---|---|
qiling/hw/hw.py |
QlHwManager: creates peripherals from profile, maps MMIO, steps them each tick |
qiling/hw/peripheral.py |
Base QlPeripheral (+ QlPeripheralUtils) |
qiling/hw/analog/ char/ dma/ flash/ gpio/ i2c/ intc/ math/ mem/ misc/ net/ power/ sd/ spi/ timer/ |
One directory per peripheral class, chip-specific implementations inside |
qiling/hw/const/ |
Register layout constants per chip family |
qiling/hw/connectivity.py, external_device/ |
External-interface plumbing (e.g. connecting a fake device to a bus) |
qiling/extensions/mcu/ |
Board/chip definitions (stm32f4xx, gd32vf1, nxp, atmel, bes): memory maps naming peripheral class + base address, passed as env= to Qiling |
qiling/hw/hw.py:60-QlHwManager- available asql.hw; created by core only whenql.baremetal(qiling/core.py:191).qiling/hw/hw.py:67-QlHwManager.create(label, struct, base)- instantiates a peripheral from the profile entry and maps its MMIO region.qiling/hw/hw.py:135-QlHwManager.step()- advances every peripheral one tick; called from the MCU run loop.qiling/hw/peripheral.py:132-QlPeripheral(QlPeripheralUtils)- base class: a ctypes register struct + read/write handlers on the MMIO region.qiling/extensions/mcu/stm32f4/stm32f407.py(and siblings) - chipenvdicts consumed atQiling(..., env=...)construction.
- Created by core.md for bare-metal targets; driven by the MCU run loop in os-baremetal.md (
QlHwManager.step()between execution slices). - Interrupt controller peripherals (
intc/) raise exceptions delivered throughQlInterruptContextin arch.md. - MMIO regions are mapped through
QlMemoryManager(os-base.md). - Profile parsing (YAML) is in
profile_setup(core.md,qiling/utils.py:419).
cd tests && python3 test_mcu.py # pass = unittest "OK", exit 0- Exercises GPIO, UART, EXTI, I2C, SPI, DMA, CRC, RTC, watchdog peripherals on real firmware from
examples/rootfs/mcu/.
- Peripheral fidelity is demand-driven: registers behave as observed firmware needs, not per full datasheets.
- Chip coverage limited to families under
qiling/extensions/mcu/; adding a chip means writing its memory map + any missing peripheral classes.