Create the seven GPIO ports GPIOA..GPIOG by name via qdev_new() and map
them at their APB2 base addresses, removing the corresponding
unimplemented-device stubs so the real devices back that range.

The Rust GPIO type is only present in a Rust-enabled build, so the ports
are created behind an object_class_by_name() check; with --disable-rust
the type is absent and the range is simply left unbacked.

Signed-off-by: Jack Wang <[email protected]>
---
 hw/arm/Kconfig                 |  1 +
 hw/arm/stm32f103_board.c       |  2 +-
 hw/arm/stm32f103_soc.c         | 54 +++++++++++++++++++++++++++++-----
 include/hw/arm/stm32f103_soc.h |  9 ++++++
 4 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 66aed6edd7..7aa194c64a 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -410,6 +410,7 @@ config STM32F103_SOC
     select STM32F2XX_USART
     select STM32F2XX_SPI
     select STM32F1XX_ADC
+    select STM32F1XX_GPIO if HAVE_RUST
 
 config B_L475E_IOT01A
     bool
diff --git a/hw/arm/stm32f103_board.c b/hw/arm/stm32f103_board.c
index a740483575..fb5041e484 100644
--- a/hw/arm/stm32f103_board.c
+++ b/hw/arm/stm32f103_board.c
@@ -26,7 +26,7 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
-#include "hw/boards.h"
+#include "hw/core/boards.h"
 #include "hw/core/qdev-properties.h"
 #include "hw/core/qdev-clock.h"
 #include "qemu/error-report.h"
diff --git a/hw/arm/stm32f103_soc.c b/hw/arm/stm32f103_soc.c
index e76640ec03..75fc99a554 100644
--- a/hw/arm/stm32f103_soc.c
+++ b/hw/arm/stm32f103_soc.c
@@ -24,12 +24,16 @@
 
 #include "qemu/osdep.h"
 #include "qapi/error.h"
+#include "qom/object.h"
 #include "system/address-spaces.h"
 #include "system/system.h"
 #include "hw/arm/stm32f103_soc.h"
 #include "hw/core/qdev-clock.h"
 #include "hw/misc/unimp.h"
 
+/* QOM type name of the Rust GPIO device (rust/hw/gpio/src/gpio.rs) */
+#define TYPE_STM32F1XX_GPIO_RUST "stm32f1xx-gpio-rust"
+
 #define RCC_ADDR 0x40021000
 
 /* USART addresses: USART1, USART2, USART3, UART4, UART5 */
@@ -47,6 +51,12 @@ static const uint32_t adc_addr[] = {
     0x40012400, 0x40012800, 0x40013C00
 };
 
+/* GPIO addresses: GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG */
+static const uint32_t gpio_addr[] = {
+    0x40010800, 0x40010C00, 0x40011000, 0x40011400, 0x40011800, 0x40011C00,
+    0x40012000
+};
+
 static const int usart_irq[] = { 37, 38, 39, 52, 53 };
 static const int spi_irq[]   = { 35, 36, 51 };
 #define ADC_IRQ 18
@@ -199,6 +209,37 @@ static void stm32f103_soc_realize(DeviceState *dev_soc, 
Error **errp)
                            qdev_get_gpio_in(DEVICE(&s->adc_irqs), i));
     }
 
+    /*
+     * GPIO ports GPIOA..GPIOG.
+     *
+     * These are implemented by the Rust device "stm32f1xx-gpio-rust", created
+     * by name with qdev_new() and mapped at its APB2 base address.  On STM32F1
+     * a GPIO port has no dedicated NVIC line of its own: pin-change interrupts
+     * are delivered through the EXTI controller (not yet modelled), so no
+     * sysbus_connect_irq() to the NVIC is done here.
+     *
+     * The GPIO port is only provided by the Rust build; when QEMU is built
+     * with --disable-rust the type is not registered, so skip creating the
+     * ports and leave the address range unbacked.
+     */
+    if (object_class_by_name(TYPE_STM32F1XX_GPIO_RUST)) {
+        for (i = 0; i < STM32F103_NUM_GPIOS; i++) {
+            g_autofree char *name = g_strdup_printf("gpio%c", 'a' + i);
+            s->gpio[i] = qdev_new(TYPE_STM32F1XX_GPIO_RUST);
+            /*
+             * Give each port a stable QOM name ("/machine/soc/gpioa"..) so
+             * tests and the monitor can reach it and its gpio-out lines by
+             * path.
+             */
+            object_property_add_child(OBJECT(s), name, OBJECT(s->gpio[i]));
+            busdev = SYS_BUS_DEVICE(s->gpio[i]);
+            if (!sysbus_realize_and_unref(busdev, errp)) {
+                return;
+            }
+            sysbus_mmio_map(busdev, 0, gpio_addr[i]);
+        }
+    }
+
     /*
      * Unimplemented peripherals -- STM32F103 devices that do not yet
      * have QEMU models.
@@ -231,13 +272,12 @@ static void stm32f103_soc_realize(DeviceState *dev_soc, 
Error **errp)
     /* APB2 peripherals */
     create_unimplemented_device("AFIO",        0x40010000, 0x400);
     create_unimplemented_device("EXTI",        0x40010400, 0x400);
-    create_unimplemented_device("GPIOA",       0x40010800, 0x400);
-    create_unimplemented_device("GPIOB",       0x40010C00, 0x400);
-    create_unimplemented_device("GPIOC",       0x40011000, 0x400);
-    create_unimplemented_device("GPIOD",       0x40011400, 0x400);
-    create_unimplemented_device("GPIOE",       0x40011800, 0x400);
-    create_unimplemented_device("GPIOF",       0x40011C00, 0x400);
-    create_unimplemented_device("GPIOG",       0x40012000, 0x400);
+    /*
+     * GPIOA..GPIOG (0x40010800..0x40012000) are real devices mapped in the
+     * GPIO loop above when the Rust build is used, so they must NOT be
+     * registered as unimplemented devices here: overlapping MemoryRegions at
+     * the same address abort at runtime.
+     */
     create_unimplemented_device("timer[1]",    0x40012C00, 0x400);
     create_unimplemented_device("timer[8]",    0x40013400, 0x400);
     create_unimplemented_device("timer[9]",    0x40014C00, 0x400);
diff --git a/include/hw/arm/stm32f103_soc.h b/include/hw/arm/stm32f103_soc.h
index 260f3695c0..8d78360ce0 100644
--- a/include/hw/arm/stm32f103_soc.h
+++ b/include/hw/arm/stm32f103_soc.h
@@ -40,6 +40,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(STM32F103State, STM32F103_SOC)
 #define STM32F103_NUM_USARTS 5
 #define STM32F103_NUM_SPIS 3
 #define STM32F103_NUM_ADCS 3
+#define STM32F103_NUM_GPIOS 7
 
 /* High-density STM32F103: 512 KB Flash, 64 KB SRAM */
 #define STM32F103_FLASH_BASE_ADDRESS 0x08000000
@@ -58,6 +59,14 @@ struct STM32F103State {
     OrIRQState adc_irqs;
     STM32F1XXADCState adc[STM32F103_NUM_ADCS];
 
+    /*
+     * GPIOA..GPIOG are implemented by the Rust device "stm32f1xx-gpio-rust".
+     * That device is created by name via qdev_new() (pointer-based mounting)
+     * rather than embedded by value, so no C struct definition is required
+     * here and no struct-size coupling with the Rust side is needed.
+     */
+    DeviceState *gpio[STM32F103_NUM_GPIOS];
+
     MemoryRegion sram;
     MemoryRegion flash;
     MemoryRegion flash_alias;
-- 
2.53.0


Reply via email to