diff options
73 files changed, 2001 insertions, 694 deletions
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 58802f7..5603192 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2937,22 +2937,32 @@ void kvm_cpu_synchronize_state(CPUState *cpu) } } -static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) +static bool kvm_cpu_synchronize_put(CPUState *cpu, KvmPutState state, + const char *desc) { Error *err = NULL; - int ret = kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE, &err); + int ret = kvm_arch_put_registers(cpu, state, &err); if (ret) { if (err) { - error_reportf_err(err, "Restoring resisters after reset: "); + error_reportf_err(err, "Restoring resisters %s: ", desc); } else { - error_report("Failed to put registers after reset: %s", + error_report("Failed to put registers %s: %s", desc, strerror(-ret)); } - cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); - vm_stop(RUN_STATE_INTERNAL_ERROR); + return false; } cpu->vcpu_dirty = false; + + return true; +} + +static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) +{ + if (!kvm_cpu_synchronize_put(cpu, KVM_PUT_RESET_STATE, "after reset")) { + cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); + vm_stop(RUN_STATE_INTERNAL_ERROR); + } } void kvm_cpu_synchronize_post_reset(CPUState *cpu) @@ -2966,19 +2976,9 @@ void kvm_cpu_synchronize_post_reset(CPUState *cpu) static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) { - Error *err = NULL; - int ret = kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE, &err); - if (ret) { - if (err) { - error_reportf_err(err, "Putting registers after init: "); - } else { - error_report("Failed to put registers after init: %s", - strerror(-ret)); - } + if (!kvm_cpu_synchronize_put(cpu, KVM_PUT_FULL_STATE, "after init")) { exit(1); } - - cpu->vcpu_dirty = false; } void kvm_cpu_synchronize_post_init(CPUState *cpu) @@ -3168,20 +3168,11 @@ int kvm_cpu_exec(CPUState *cpu) MemTxAttrs attrs; if (cpu->vcpu_dirty) { - Error *err = NULL; - ret = kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE, &err); - if (ret) { - if (err) { - error_reportf_err(err, "Putting registers after init: "); - } else { - error_report("Failed to put registers after init: %s", - strerror(-ret)); - } + if (!kvm_cpu_synchronize_put(cpu, KVM_PUT_RUNTIME_STATE, + "at runtime")) { ret = -1; break; } - - cpu->vcpu_dirty = false; } kvm_arch_pre_run(cpu, run); diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 67e5277..98361f5 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -285,6 +285,33 @@ and serves as the initial engineering sample rather than a production version. A newer revision, A1, is now supported, and the ``ast2700a1-evb`` should replace the older A0 version. +Arm ``sonorapass-bmc`` machine (since 10.2) +''''''''''''''''''''''''''''''''''''''''''' + +The ``sonorapass-bmc`` machine represents a lab server that never +entered production. Since it does not rely on any specific device +models, it can be replaced by the ``ast2500-evb`` machine using the +``fmc-model`` option to specify the flash type. The I2C devices +connected to the board can be defined via the QEMU command line. + +Arm ``qcom-dc-scm-v1-bmc`` and ``qcom-firework-bmc`` machine (since 10.2) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +The ``qcom-dc-scm-v1-bmc`` and ``qcom-firework-bmc`` represent lab +servers that never entered production. Since they do not rely on any +specific device models, they can be replaced by the ``ast2600-evb`` +machine using the ``fmc-model`` option to specify the flash type. The +I2C devices connected to the board can be defined via the QEMU command +line. + +Arm ``fp5280g2-bmc`` machine (since 10.2) +''''''''''''''''''''''''''''''''''''''''''' + +The ``fp5280g2-bmc`` machine does not rely on any specific device +models, it can be replaced by the ``ast2500-evb`` machine using the +``fmc-model`` option to specify the flash type. The I2C devices +connected to the board can be defined via the QEMU command line. + RISC-V default machine option (since 10.0) '''''''''''''''''''''''''''''''''''''''''' diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 2f0ab2e..79c26d9 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -155,6 +155,7 @@ module status ``hwcore::irq`` complete ``hwcore::qdev`` stable ``hwcore::sysbus`` stable +``migration::migratable`` proof of concept ``migration::vmstate`` stable ``qom`` stable ``system::memory`` stable diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index eaaa880..25b4aed 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -271,12 +271,12 @@ ERST .name = "accel", .args_type = "", .params = "", - .help = "show accelerator info", + .help = "show accelerator statistics", }, SRST ``info accel`` - Show accelerator info. + Show accelerator statistics. ERST SRST @@ -308,16 +308,21 @@ SRST ERST { - .name = "mshv", + .name = "accelerators", .args_type = "", .params = "", - .help = "show MSHV information", - .cmd = hmp_info_mshv, + .help = "show present and enabled information", + .cmd = hmp_info_accelerators, }, SRST - ``info mshv`` - Show MSHV information. + ``info accelerators`` + Show which accelerators are compiled into a QEMU binary, and what accelerator + is in use. For example:: + + kvm qtest [tcg] + + indicates that TCG in use, and that KVM and qtest are also available. ERST { diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 6046ec0..21ee62f 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -299,12 +299,14 @@ static void connect_serial_hds_to_uarts(AspeedMachineState *bmc) AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default; - aspeed_soc_uart_set_chr(s, uart_chosen, serial_hd(0)); + aspeed_soc_uart_set_chr(s->uart, uart_chosen, sc->uarts_base, + sc->uarts_num, serial_hd(0)); for (int i = 1, uart = sc->uarts_base; i < sc->uarts_num; uart++) { if (uart == uart_chosen) { continue; } - aspeed_soc_uart_set_chr(s, uart, serial_hd(i++)); + aspeed_soc_uart_set_chr(s->uart, uart, sc->uarts_base, sc->uarts_num, + serial_hd(i++)); } } @@ -1310,8 +1312,8 @@ static void aspeed_set_bmc_console(Object *obj, const char *value, Error **errp) AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc); AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(amc->soc_name)); int val; - int uart_first = aspeed_uart_first(sc); - int uart_last = aspeed_uart_last(sc); + int uart_first = aspeed_uart_first(sc->uarts_base); + int uart_last = aspeed_uart_last(sc->uarts_base, sc->uarts_num); if (sscanf(value, "uart%u", &val) != 1) { error_setg(errp, "Bad value for \"uart\" property"); @@ -1418,7 +1420,6 @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, amc->spi_model = "mx25l25635f"; amc->num_cs = 1; amc->i2c_init = palmetto_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 256 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1436,7 +1437,6 @@ static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, amc->spi_model = "mx25l25635e"; amc->num_cs = 1; amc->i2c_init = quanta_q71l_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 128 * MiB; aspeed_machine_class_init_cpus_defaults(mc); } @@ -1455,7 +1455,6 @@ static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc, amc->num_cs = 1; amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = palmetto_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 256 * MiB; aspeed_machine_class_init_cpus_defaults(mc); } @@ -1474,7 +1473,6 @@ static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc, amc->num_cs = 1; amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = palmetto_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 512 * MiB; aspeed_machine_class_init_cpus_defaults(mc); } @@ -1492,7 +1490,6 @@ static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, amc->spi_model = "mx25l25635f"; amc->num_cs = 1; amc->i2c_init = ast2500_evb_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 512 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1511,7 +1508,6 @@ static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, amc->spi_model = "mx25l25635e"; amc->num_cs = 2; amc->i2c_init = yosemitev2_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 512 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1529,7 +1525,6 @@ static void aspeed_machine_romulus_class_init(ObjectClass *oc, amc->spi_model = "mx66l1g45g"; amc->num_cs = 2; amc->i2c_init = romulus_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 512 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1548,7 +1543,6 @@ static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, amc->spi_model = "mx25l25635e"; amc->num_cs = 2; amc->i2c_init = tiogapass_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1560,13 +1554,13 @@ static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "OCP SonoraPass BMC (ARM1176)"; + mc->deprecation_reason = "use 'ast2500-evb' instead"; amc->soc_name = "ast2500-a1"; amc->hw_strap1 = SONORAPASS_BMC_HW_STRAP1; amc->fmc_model = "mx66l1g45g"; amc->spi_model = "mx66l1g45g"; amc->num_cs = 2; amc->i2c_init = sonorapass_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 512 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1584,7 +1578,6 @@ static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, amc->spi_model = "mx66l1g45g"; amc->num_cs = 2; amc->i2c_init = witherspoon_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 512 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1606,7 +1599,6 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, ASPEED_MAC3_ON; amc->sdhci_wp_inverted = true; amc->i2c_init = ast2600_evb_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); aspeed_machine_ast2600_class_emmc_init(oc); @@ -1625,7 +1617,6 @@ static void aspeed_machine_g220a_class_init(ObjectClass *oc, const void *data) amc->num_cs = 2; amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = g220a_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 1024 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1637,6 +1628,7 @@ static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "Inspur FP5280G2 BMC (ARM1176)"; + mc->deprecation_reason = "use 'ast2500-evb' instead"; amc->soc_name = "ast2500-a1"; amc->hw_strap1 = FP5280G2_BMC_HW_STRAP1; amc->fmc_model = "n25q512a"; @@ -1644,7 +1636,6 @@ static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, amc->num_cs = 2; amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON; amc->i2c_init = fp5280g2_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 512 * MiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1663,7 +1654,6 @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, const void *data) amc->num_cs = 2; amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc->i2c_init = rainier_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); aspeed_machine_ast2600_class_emmc_init(oc); @@ -1686,7 +1676,6 @@ static void aspeed_machine_fuji_class_init(ObjectClass *oc, const void *data) amc->macs_mask = ASPEED_MAC3_ON; amc->i2c_init = fuji_bmc_i2c_init; amc->uart_default = ASPEED_DEV_UART1; - mc->auto_create_sdcard = true; mc->default_ram_size = FUJI_BMC_RAM_SIZE; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1708,7 +1697,6 @@ static void aspeed_machine_bletchley_class_init(ObjectClass *oc, amc->num_cs = 2; amc->macs_mask = ASPEED_MAC2_ON; amc->i2c_init = bletchley_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = BLETCHLEY_BMC_RAM_SIZE; aspeed_machine_class_init_cpus_defaults(mc); } @@ -1728,7 +1716,6 @@ static void aspeed_machine_catalina_class_init(ObjectClass *oc, amc->num_cs = 2; amc->macs_mask = ASPEED_MAC2_ON; amc->i2c_init = catalina_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = CATALINA_BMC_RAM_SIZE; aspeed_machine_class_init_cpus_defaults(mc); aspeed_machine_ast2600_class_emmc_init(oc); @@ -1796,7 +1783,6 @@ static void aspeed_machine_fby35_class_init(ObjectClass *oc, const void *data) amc->num_cs = 2; amc->macs_mask = ASPEED_MAC3_ON; amc->i2c_init = fby35_i2c_init; - mc->auto_create_sdcard = true; /* FIXME: Replace this macro with something more general */ mc->default_ram_size = FUJI_BMC_RAM_SIZE; aspeed_machine_class_init_cpus_defaults(mc); @@ -1909,7 +1895,6 @@ static void aspeed_machine_ast2700a0_evb_class_init(ObjectClass *oc, amc->uart_default = ASPEED_DEV_UART12; amc->i2c_init = ast2700_evb_i2c_init; amc->vbootrom = true; - mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); } @@ -1932,7 +1917,6 @@ static void aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc, amc->uart_default = ASPEED_DEV_UART12; amc->i2c_init = ast2700_evb_i2c_init; amc->vbootrom = true; - mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); } @@ -1945,6 +1929,7 @@ static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "Qualcomm DC-SCM V1 BMC (Cortex A7)"; + mc->deprecation_reason = "use 'ast2600-evb' instead"; amc->soc_name = "ast2600-a3"; amc->hw_strap1 = QCOM_DC_SCM_V1_BMC_HW_STRAP1; amc->hw_strap2 = QCOM_DC_SCM_V1_BMC_HW_STRAP2; @@ -1953,7 +1938,6 @@ static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, amc->num_cs = 2; amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc->i2c_init = qcom_dc_scm_bmc_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); }; @@ -1965,6 +1949,7 @@ static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc, AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); mc->desc = "Qualcomm DC-SCM V1/Firework BMC (Cortex A7)"; + mc->deprecation_reason = "use 'ast2600-evb' instead"; amc->soc_name = "ast2600-a3"; amc->hw_strap1 = QCOM_DC_SCM_V1_BMC_HW_STRAP1; amc->hw_strap2 = QCOM_DC_SCM_V1_BMC_HW_STRAP2; @@ -1973,7 +1958,6 @@ static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc, amc->num_cs = 2; amc->macs_mask = ASPEED_MAC2_ON | ASPEED_MAC3_ON; amc->i2c_init = qcom_dc_scm_firework_i2c_init; - mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); }; diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index c446e70..7f49c13 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -192,6 +192,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); DeviceState *armv7m; Error *err = NULL; + int uart; int i; g_autofree char *sram_name = NULL; @@ -201,17 +202,20 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) } /* General I/O memory space to catch all unimplemented device */ - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->iomem), + "aspeed.io", sc->memmap[ASPEED_DEV_IOMEM], ASPEED_SOC_IOMEM_SIZE); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->sbc_unimplemented), + aspeed_mmio_map_unimplemented(s->memory, + SYS_BUS_DEVICE(&s->sbc_unimplemented), "aspeed.sbc", sc->memmap[ASPEED_DEV_SBC], 0x40000); /* AST1030 CPU Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); - qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc)); + qdev_prop_set_string(armv7m, "cpu-type", + aspeed_soc_cpu_type(sc->valid_cpu_types)); qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); object_property_set_link(OBJECT(&a->armv7m), "memory", OBJECT(s->memory), &error_abort); @@ -241,7 +245,8 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scu), 0, + sc->memmap[ASPEED_DEV_SCU]); /* I2C */ @@ -250,7 +255,8 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->i2c), 0, + sc->memmap[ASPEED_DEV_I2C]); for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) { qemu_irq irq = qdev_get_gpio_in(DEVICE(&a->armv7m), sc->irqmap[ASPEED_DEV_I2C] + i); @@ -262,7 +268,8 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i3c), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->i3c), 0, + sc->memmap[ASPEED_DEV_I3C]); for (i = 0; i < ASPEED_I3C_NR_DEVICES; i++) { qemu_irq irq = qdev_get_gpio_in(DEVICE(&a->armv7m), sc->irqmap[ASPEED_DEV_I3C] + i); @@ -274,20 +281,21 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->peci), 0, sc->memmap[ASPEED_DEV_PECI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_PECI)); + aspeed_soc_ast1030_get_irq(s, ASPEED_DEV_PECI)); /* LPC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->lpc), 0, + sc->memmap[ASPEED_DEV_LPC]); /* Connect the LPC IRQ to the GIC. It is otherwise unused. */ sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_LPC)); + aspeed_soc_ast1030_get_irq(s, ASPEED_DEV_LPC)); /* * On the AST1030 LPC subdevice IRQs are connected straight to the GIC. @@ -309,8 +317,13 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) sc->irqmap[ASPEED_DEV_KCS] + aspeed_lpc_kcs_4)); /* UART */ - if (!aspeed_soc_uart_realize(s, errp)) { - return; + for (i = 0, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) { + if (!aspeed_soc_uart_realize(s->memory, &s->uart[i], + sc->memmap[uart], errp)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + aspeed_soc_ast1030_get_irq(s, uart)); } /* Timer */ @@ -319,10 +332,10 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->timerctrl), 0, sc->memmap[ASPEED_DEV_TIMER1]); for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); + qemu_irq irq = aspeed_soc_ast1030_get_irq(s, ASPEED_DEV_TIMER1 + i); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } @@ -330,9 +343,10 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->adc), 0, + sc->memmap[ASPEED_DEV_ADC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); + aspeed_soc_ast1030_get_irq(s, ASPEED_DEV_ADC)); /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(&s->sram), @@ -340,11 +354,12 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 0, + sc->memmap[ASPEED_DEV_FMC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_FMC)); + aspeed_soc_ast1030_get_irq(s, ASPEED_DEV_FMC)); /* SPI */ for (i = 0; i < sc->spis_num; i++) { @@ -353,9 +368,9 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI1 + i]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 1, ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } @@ -363,7 +378,8 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sbc), 0, + sc->memmap[ASPEED_DEV_SBC]); /* HACE */ object_property_set_link(OBJECT(&s->hace), "dram", OBJECT(&s->sram), @@ -371,10 +387,10 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); + aspeed_soc_ast1030_get_irq(s, ASPEED_DEV_HACE)); /* Watch dog */ for (i = 0; i < sc->wdts_num; i++) { @@ -386,32 +402,38 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); } /* GPIO */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); + aspeed_soc_ast1030_get_irq(s, ASPEED_DEV_GPIO)); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->pwm), "aspeed.pwm", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->pwm), + "aspeed.pwm", sc->memmap[ASPEED_DEV_PWM], 0x100); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->espi), "aspeed.espi", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->espi), + "aspeed.espi", sc->memmap[ASPEED_DEV_ESPI], 0x800); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->udc), "aspeed.udc", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->udc), + "aspeed.udc", sc->memmap[ASPEED_DEV_UDC], 0x1000); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->sgpiom), "aspeed.sgpiom", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->sgpiom), + "aspeed.sgpiom", sc->memmap[ASPEED_DEV_SGPIOM], 0x100); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->jtag[0]), "aspeed.jtag", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->jtag[0]), + "aspeed.jtag", sc->memmap[ASPEED_DEV_JTAG0], 0x20); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->jtag[1]), "aspeed.jtag", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->jtag[1]), + "aspeed.jtag", sc->memmap[ASPEED_DEV_JTAG1], 0x20); } @@ -441,7 +463,6 @@ static void aspeed_soc_ast1030_class_init(ObjectClass *klass, const void *data) sc->irqmap = aspeed_soc_ast1030_irqmap; sc->memmap = aspeed_soc_ast1030_memmap; sc->num_cpus = 1; - sc->get_irq = aspeed_soc_ast1030_get_irq; } static const TypeInfo aspeed_soc_ast10x0_types[] = { diff --git a/hw/arm/aspeed_ast2400.c b/hw/arm/aspeed_ast2400.c index c7b0f21..b1b826b 100644 --- a/hw/arm/aspeed_ast2400.c +++ b/hw/arm/aspeed_ast2400.c @@ -157,7 +157,7 @@ static void aspeed_ast2400_soc_init(Object *obj) for (i = 0; i < sc->num_cpus; i++) { object_initialize_child(obj, "cpu[*]", &a->cpu[i], - aspeed_soc_cpu_type(sc)); + aspeed_soc_cpu_type(sc->valid_cpu_types)); } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); @@ -251,6 +251,7 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) AspeedSoCState *s = ASPEED_SOC(dev); AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); g_autofree char *sram_name = NULL; + int uart; /* Default boot region (SPI memory or ROMs) */ memory_region_init(&s->spi_boot_container, OBJECT(s), @@ -259,12 +260,14 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) &s->spi_boot_container); /* IO space */ - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->iomem), + "aspeed.io", sc->memmap[ASPEED_DEV_IOMEM], ASPEED_SOC_IOMEM_SIZE); /* Video engine stub */ - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->video), "aspeed.video", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->video), + "aspeed.video", sc->memmap[ASPEED_DEV_VIDEO], 0x1000); /* CPU */ @@ -289,13 +292,15 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scu), 0, + sc->memmap[ASPEED_DEV_SCU]); /* VIC */ if (!sysbus_realize(SYS_BUS_DEVICE(&a->vic), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->vic), 0, sc->memmap[ASPEED_DEV_VIC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->vic), 0, + sc->memmap[ASPEED_DEV_VIC]); sysbus_connect_irq(SYS_BUS_DEVICE(&a->vic), 0, qdev_get_gpio_in(DEVICE(&a->cpu), ARM_CPU_IRQ)); sysbus_connect_irq(SYS_BUS_DEVICE(&a->vic), 1, @@ -305,9 +310,10 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->rtc), 0, + sc->memmap[ASPEED_DEV_RTC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_RTC)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_RTC)); /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), @@ -315,10 +321,10 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->timerctrl), 0, sc->memmap[ASPEED_DEV_TIMER1]); for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - qemu_irq irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); + qemu_irq irq = aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_TIMER1 + i); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } @@ -326,13 +332,19 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->adc), 0, + sc->memmap[ASPEED_DEV_ADC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_ADC)); /* UART */ - if (!aspeed_soc_uart_realize(s, errp)) { - return; + for (i = 0, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) { + if (!aspeed_soc_uart_realize(s->memory, &s->uart[i], + sc->memmap[uart], errp)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + aspeed_soc_ast2400_get_irq(s, uart)); } /* I2C */ @@ -341,18 +353,19 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->i2c), 0, + sc->memmap[ASPEED_DEV_I2C]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_I2C)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_I2C)); /* PECI */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->peci), 0, sc->memmap[ASPEED_DEV_PECI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_PECI)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_PECI)); /* FMC, The number of CS is set at the board level */ object_property_set_link(OBJECT(&s->fmc), "dram", OBJECT(s->dram_mr), @@ -360,11 +373,12 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 0, + sc->memmap[ASPEED_DEV_FMC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_FMC)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_FMC)); /* Set up an alias on the FMC CE0 region (boot default) */ MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio; @@ -377,9 +391,9 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI1 + i]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 1, ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } @@ -388,17 +402,18 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->ehci[i]), 0, sc->memmap[ASPEED_DEV_EHCI1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i)); + aspeed_soc_ast2400_get_irq(s, + ASPEED_DEV_EHCI1 + i)); } /* SDMC - SDRAM Memory Controller */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_DEV_SDMC]); /* Watch dog */ @@ -411,7 +426,7 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); } /* RAM */ @@ -426,48 +441,49 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, sc->memmap[ASPEED_DEV_ETH1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_ETH1 + i)); } /* XDMA */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->xdma), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->xdma), 0, sc->memmap[ASPEED_DEV_XDMA]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_XDMA)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_XDMA)); /* GPIO */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_GPIO)); /* SDHCI */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sdhci), 0, sc->memmap[ASPEED_DEV_SDHCI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_SDHCI)); /* LPC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->lpc), 0, + sc->memmap[ASPEED_DEV_LPC]); /* Connect the LPC IRQ to the VIC */ sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_LPC)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_LPC)); /* * On the AST2400 and AST2500 the one LPC IRQ is shared between all of the @@ -496,10 +512,10 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); + aspeed_soc_ast2400_get_irq(s, ASPEED_DEV_HACE)); } static void aspeed_soc_ast2400_class_init(ObjectClass *oc, const void *data) @@ -527,7 +543,6 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, const void *data) sc->irqmap = aspeed_soc_ast2400_irqmap; sc->memmap = aspeed_soc_ast2400_memmap; sc->num_cpus = 1; - sc->get_irq = aspeed_soc_ast2400_get_irq; } static void aspeed_soc_ast2500_class_init(ObjectClass *oc, const void *data) @@ -555,7 +570,6 @@ static void aspeed_soc_ast2500_class_init(ObjectClass *oc, const void *data) sc->irqmap = aspeed_soc_ast2500_irqmap; sc->memmap = aspeed_soc_ast2500_memmap; sc->num_cpus = 1; - sc->get_irq = aspeed_soc_ast2400_get_irq; } static const TypeInfo aspeed_soc_ast2400_types[] = { diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 03e5df9..498d1ec 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -167,7 +167,7 @@ static void aspeed_soc_ast2600_init(Object *obj) for (i = 0; i < sc->num_cpus; i++) { object_initialize_child(obj, "cpu[*]", &a->cpu[i], - aspeed_soc_cpu_type(sc)); + aspeed_soc_cpu_type(sc->valid_cpu_types)); } snprintf(typename, sizeof(typename), "aspeed.scu-%s", socname); @@ -324,7 +324,7 @@ static bool aspeed_soc_ast2600_pcie_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy[0]), errp)) { return false; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie_phy[0]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->pcie_phy[0]), 0, sc->memmap[ASPEED_DEV_PCIE_PHY1]); object_property_set_int(OBJECT(&s->pcie[0]), "dram-base", @@ -335,7 +335,7 @@ static bool aspeed_soc_ast2600_pcie_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie[0]), errp)) { return false; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie[0]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->pcie[0]), 0, sc->memmap[ASPEED_DEV_PCIE0]); irq = qdev_get_gpio_in(DEVICE(&a->a7mpcore), @@ -362,6 +362,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); qemu_irq irq; g_autofree char *sram_name = NULL; + int uart; /* Default boot region (SPI memory or ROMs) */ memory_region_init(&s->spi_boot_container, OBJECT(s), @@ -370,16 +371,19 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) &s->spi_boot_container); /* IO space */ - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), "aspeed.io", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->iomem), + "aspeed.io", sc->memmap[ASPEED_DEV_IOMEM], ASPEED_SOC_IOMEM_SIZE); /* Video engine stub */ - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->video), "aspeed.video", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->video), + "aspeed.video", sc->memmap[ASPEED_DEV_VIDEO], 0x1000); /* eMMC Boot Controller stub */ - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->emmc_boot_controller), + aspeed_mmio_map_unimplemented(s->memory, + SYS_BUS_DEVICE(&s->emmc_boot_controller), "aspeed.emmc-boot-controller", sc->memmap[ASPEED_DEV_EMMC_BC], 0x1000); @@ -414,7 +418,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) &error_abort); sysbus_realize(SYS_BUS_DEVICE(&a->a7mpcore), &error_abort); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->a7mpcore), 0, ASPEED_A7MPCORE_ADDR); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->a7mpcore), 0, + ASPEED_A7MPCORE_ADDR); for (i = 0; i < sc->num_cpus; i++) { SysBusDevice *sbd = SYS_BUS_DEVICE(&a->a7mpcore); @@ -440,7 +445,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) sc->memmap[ASPEED_DEV_SRAM], &s->sram); /* DPMCU */ - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu), "aspeed.dpmcu", + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->dpmcu), + "aspeed.dpmcu", sc->memmap[ASPEED_DEV_DPMCU], ASPEED_SOC_DPMCU_SIZE); @@ -448,15 +454,17 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scu), 0, + sc->memmap[ASPEED_DEV_SCU]); /* RTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->rtc), 0, + sc->memmap[ASPEED_DEV_RTC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_RTC)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_RTC)); /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), @@ -464,10 +472,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->timerctrl), 0, sc->memmap[ASPEED_DEV_TIMER1]); for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); + irq = aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_TIMER1 + i); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } @@ -475,13 +483,19 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->adc), 0, + sc->memmap[ASPEED_DEV_ADC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_ADC)); /* UART */ - if (!aspeed_soc_uart_realize(s, errp)) { - return; + for (i = 0, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) { + if (!aspeed_soc_uart_realize(s->memory, &s->uart[i], + sc->memmap[uart], errp)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + aspeed_soc_ast2600_get_irq(s, uart)); } /* I2C */ @@ -490,7 +504,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->i2c), 0, + sc->memmap[ASPEED_DEV_I2C]); for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) { irq = qdev_get_gpio_in(DEVICE(&a->a7mpcore), sc->irqmap[ASPEED_DEV_I2C] + i); @@ -502,10 +517,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->peci), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->peci), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->peci), 0, sc->memmap[ASPEED_DEV_PECI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->peci), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_PECI)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_PECI)); /* PCIe Root Complex (RC) */ if (!aspeed_soc_ast2600_pcie_realize(dev, errp)) { @@ -518,11 +533,12 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 0, + sc->memmap[ASPEED_DEV_FMC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_FMC)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_FMC)); /* Set up an alias on the FMC CE0 region (boot default) */ MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio; @@ -537,9 +553,9 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI1 + i]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 1, ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } @@ -548,17 +564,18 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->ehci[i]), 0, sc->memmap[ASPEED_DEV_EHCI1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i)); + aspeed_soc_ast2600_get_irq(s, + ASPEED_DEV_EHCI1 + i)); } /* SDMC - SDRAM Memory Controller */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_DEV_SDMC]); /* Watch dog */ @@ -571,7 +588,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); } /* RAM */ @@ -586,10 +603,10 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, sc->memmap[ASPEED_DEV_ETH1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_ETH1 + i)); object_property_set_link(OBJECT(&s->mii[i]), "nic", OBJECT(&s->ftgmac100[i]), &error_abort); @@ -597,7 +614,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->mii[i]), 0, sc->memmap[ASPEED_DEV_MII1 + i]); } @@ -605,55 +622,56 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->xdma), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->xdma), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->xdma), 0, sc->memmap[ASPEED_DEV_XDMA]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->xdma), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_XDMA)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_XDMA)); /* GPIO */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_GPIO)); if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio_1_8v), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio_1_8v), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->gpio_1_8v), 0, sc->memmap[ASPEED_DEV_GPIO_1_8V]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio_1_8v), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_GPIO_1_8V)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_GPIO_1_8V)); /* SDHCI */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sdhci), 0, sc->memmap[ASPEED_DEV_SDHCI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_SDHCI)); /* eMMC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->emmc), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->emmc), 0, sc->memmap[ASPEED_DEV_EMMC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_EMMC)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_EMMC)); /* LPC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->lpc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->lpc), 0, sc->memmap[ASPEED_DEV_LPC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->lpc), 0, + sc->memmap[ASPEED_DEV_LPC]); /* Connect the LPC IRQ to the GIC. It is otherwise unused. */ sysbus_connect_irq(SYS_BUS_DEVICE(&s->lpc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_LPC)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_LPC)); /* * On the AST2600 LPC subdevice IRQs are connected straight to the GIC. @@ -685,16 +703,17 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_HACE)); /* I3C */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->i3c), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i3c), 0, sc->memmap[ASPEED_DEV_I3C]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->i3c), 0, + sc->memmap[ASPEED_DEV_I3C]); for (i = 0; i < ASPEED_I3C_NR_DEVICES; i++) { irq = qdev_get_gpio_in(DEVICE(&a->a7mpcore), sc->irqmap[ASPEED_DEV_I3C] + i); @@ -706,17 +725,18 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sbc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sbc), 0, sc->memmap[ASPEED_DEV_SBC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sbc), 0, + sc->memmap[ASPEED_DEV_SBC]); /* FSI */ for (i = 0; i < ASPEED_FSI_NUM; i++) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->fsi[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fsi[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fsi[i]), 0, sc->memmap[ASPEED_DEV_FSI1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fsi[i]), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_FSI1 + i)); + aspeed_soc_ast2600_get_irq(s, ASPEED_DEV_FSI1 + i)); } } @@ -752,7 +772,6 @@ static void aspeed_soc_ast2600_class_init(ObjectClass *oc, const void *data) sc->irqmap = aspeed_soc_ast2600_irqmap; sc->memmap = aspeed_soc_ast2600_memmap; sc->num_cpus = 2; - sc->get_irq = aspeed_soc_ast2600_get_irq; sc->boot_from_emmc = aspeed_soc_ast2600_boot_from_emmc; } diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index 2e16a03..a61ecff 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -21,7 +21,7 @@ #include "hw/loader.h" #include "hw/arm/boot.h" #include "hw/block/flash.h" - +#include "hw/arm/aspeed_coprocessor.h" #define TYPE_AST2700A1FC MACHINE_TYPE_NAME("ast2700fc") OBJECT_DECLARE_SIMPLE_TYPE(Ast2700FCState, AST2700A1FC); @@ -42,8 +42,8 @@ struct Ast2700FCState { Clock *tsp_sysclk; Aspeed27x0SoCState ca35; - Aspeed27x0SSPSoCState ssp; - Aspeed27x0TSPSoCState tsp; + Aspeed27x0CoprocessorState ssp; + Aspeed27x0CoprocessorState tsp; bool mmio_exec; }; @@ -91,7 +91,8 @@ static bool ast2700fc_ca35_init(MachineState *machine, Error **errp) AST2700FC_HW_STRAP1, &error_abort); object_property_set_int(OBJECT(&s->ca35), "hw-strap2", AST2700FC_HW_STRAP2, &error_abort); - aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART12, serial_hd(0)); + aspeed_soc_uart_set_chr(soc->uart, ASPEED_DEV_UART12, sc->uarts_base, + sc->uarts_num, serial_hd(0)); if (!qdev_realize(DEVICE(&s->ca35), NULL, errp)) { return false; } @@ -114,12 +115,14 @@ static bool ast2700fc_ca35_init(MachineState *machine, Error **errp) static bool ast2700fc_ssp_init(MachineState *machine, Error **errp) { - AspeedSoCState *soc; + AspeedCoprocessorState *soc; + AspeedCoprocessorClass *sc; Ast2700FCState *s = AST2700A1FC(machine); s->ssp_sysclk = clock_new(OBJECT(s), "SSP_SYSCLK"); clock_set_hz(s->ssp_sysclk, 200000000ULL); - object_initialize_child(OBJECT(s), "ssp", &s->ssp, TYPE_ASPEED27X0SSP_SOC); + object_initialize_child(OBJECT(s), "ssp", &s->ssp, + TYPE_ASPEED27X0SSP_COPROCESSOR); memory_region_init(&s->ssp_memory, OBJECT(&s->ssp), "ssp-memory", UINT64_MAX); @@ -127,8 +130,10 @@ static bool ast2700fc_ssp_init(MachineState *machine, Error **errp) object_property_set_link(OBJECT(&s->ssp), "memory", OBJECT(&s->ssp_memory), &error_abort); - soc = ASPEED_SOC(&s->ssp); - aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART4, serial_hd(1)); + soc = ASPEED_COPROCESSOR(&s->ssp); + sc = ASPEED_COPROCESSOR_GET_CLASS(soc); + aspeed_soc_uart_set_chr(soc->uart, ASPEED_DEV_UART4, sc->uarts_base, + sc->uarts_num, serial_hd(1)); if (!qdev_realize(DEVICE(&s->ssp), NULL, errp)) { return false; } @@ -138,12 +143,14 @@ static bool ast2700fc_ssp_init(MachineState *machine, Error **errp) static bool ast2700fc_tsp_init(MachineState *machine, Error **errp) { - AspeedSoCState *soc; + AspeedCoprocessorState *soc; + AspeedCoprocessorClass *sc; Ast2700FCState *s = AST2700A1FC(machine); s->tsp_sysclk = clock_new(OBJECT(s), "TSP_SYSCLK"); clock_set_hz(s->tsp_sysclk, 200000000ULL); - object_initialize_child(OBJECT(s), "tsp", &s->tsp, TYPE_ASPEED27X0TSP_SOC); + object_initialize_child(OBJECT(s), "tsp", &s->tsp, + TYPE_ASPEED27X0TSP_COPROCESSOR); memory_region_init(&s->tsp_memory, OBJECT(&s->tsp), "tsp-memory", UINT64_MAX); @@ -151,8 +158,10 @@ static bool ast2700fc_tsp_init(MachineState *machine, Error **errp) object_property_set_link(OBJECT(&s->tsp), "memory", OBJECT(&s->tsp_memory), &error_abort); - soc = ASPEED_SOC(&s->tsp); - aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART7, serial_hd(2)); + soc = ASPEED_COPROCESSOR(&s->tsp); + sc = ASPEED_COPROCESSOR_GET_CLASS(soc); + aspeed_soc_uart_set_chr(soc->uart, ASPEED_DEV_UART7, sc->uarts_base, + sc->uarts_num, serial_hd(2)); if (!qdev_realize(DEVICE(&s->tsp), NULL, errp)) { return false; } diff --git a/hw/arm/aspeed_ast27x0-ssp.c b/hw/arm/aspeed_ast27x0-ssp.c index 80ec599..936c7c7 100644 --- a/hw/arm/aspeed_ast27x0-ssp.c +++ b/hw/arm/aspeed_ast27x0-ssp.c @@ -1,5 +1,5 @@ /* - * ASPEED Ast27x0 SSP SoC + * ASPEED Ast27x0 SSP Coprocessor * * Copyright (C) 2025 ASPEED Technology Inc. * @@ -14,6 +14,7 @@ #include "hw/qdev-clock.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" +#include "hw/arm/aspeed_coprocessor.h" #define AST2700_SSP_RAM_SIZE (32 * MiB) @@ -104,10 +105,11 @@ static struct nvic_intc_irq_info ast2700_ssp_intcmap[] = { {136, 0, 9, NULL}, }; -static qemu_irq aspeed_soc_ast27x0ssp_get_irq(AspeedSoCState *s, int dev) +static qemu_irq aspeed_soc_ast27x0ssp_get_irq(AspeedCoprocessorState *s, + int dev) { - Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(s); - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + Aspeed27x0CoprocessorState *a = ASPEED27X0SSP_COPROCESSOR(s); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_GET_CLASS(s); int or_idx; int idx; @@ -128,9 +130,9 @@ static qemu_irq aspeed_soc_ast27x0ssp_get_irq(AspeedSoCState *s, int dev) static void aspeed_soc_ast27x0ssp_init(Object *obj) { - Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(obj); - AspeedSoCState *s = ASPEED_SOC(obj); - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + Aspeed27x0CoprocessorState *a = ASPEED27X0SSP_COPROCESSOR(obj); + AspeedCoprocessorState *s = ASPEED_COPROCESSOR(obj); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_GET_CLASS(s); int i; object_initialize_child(obj, "armv7m", &a->armv7m, TYPE_ARMV7M); @@ -159,11 +161,12 @@ static void aspeed_soc_ast27x0ssp_init(Object *obj) static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) { - Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(dev_soc); - AspeedSoCState *s = ASPEED_SOC(dev_soc); - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + Aspeed27x0CoprocessorState *a = ASPEED27X0SSP_COPROCESSOR(dev_soc); + AspeedCoprocessorState *s = ASPEED_COPROCESSOR(dev_soc); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_GET_CLASS(s); DeviceState *armv7m; g_autofree char *sram_name = NULL; + int uart; int i; if (!clock_has_source(s->sysclk)) { @@ -174,7 +177,8 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) /* AST27X0 SSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); - qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc)); + qdev_prop_set_string(armv7m, "cpu-type", + aspeed_soc_cpu_type(sc->valid_cpu_types)); qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); object_property_set_link(OBJECT(&a->armv7m), "memory", OBJECT(s->memory), &error_abort); @@ -183,8 +187,8 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) sram_name = g_strdup_printf("aspeed.dram.%d", CPU(a->armv7m.cpu)->cpu_index); - if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, - errp)) { + if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, + AST2700_SSP_RAM_SIZE, errp)) { return; } memory_region_add_subregion(s->memory, @@ -195,14 +199,15 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scu), 0, + sc->memmap[ASPEED_DEV_SCU]); /* INTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->intc[0]), 0, sc->memmap[ASPEED_DEV_INTC]); /* INTCIO */ @@ -210,7 +215,7 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->intc[1]), 0, sc->memmap[ASPEED_DEV_INTCIO]); /* irq source orgates -> INTC0 */ @@ -235,57 +240,56 @@ static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) qdev_get_gpio_in(DEVICE(&a->intc[0].orgates[0]), i)); } /* UART */ - if (!aspeed_soc_uart_realize(s, errp)) { - return; + for (i = 0, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) { + if (!aspeed_soc_uart_realize(s->memory, &s->uart[i], + sc->memmap[uart], errp)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + aspeed_soc_ast27x0ssp_get_irq(s, uart)); } - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->timerctrl), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->timerctrl), "aspeed.timerctrl", sc->memmap[ASPEED_DEV_TIMER1], 0x200); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[0]), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->ipc[0]), "aspeed.ipc0", sc->memmap[ASPEED_DEV_IPC0], 0x1000); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[1]), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->ipc[1]), "aspeed.ipc1", sc->memmap[ASPEED_DEV_IPC1], 0x1000); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->scuio), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->scuio), "aspeed.scuio", sc->memmap[ASPEED_DEV_SCUIO], 0x1000); } -static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, const void *data) +static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, + const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO: cortex-m4f */ NULL }; DeviceClass *dc = DEVICE_CLASS(klass); - AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_CLASS(dc); - /* Reason: The Aspeed SoC can only be instantiated from a board */ + /* Reason: The Aspeed Coprocessor can only be instantiated from a board */ dc->user_creatable = false; dc->realize = aspeed_soc_ast27x0ssp_realize; sc->valid_cpu_types = valid_cpu_types; sc->silicon_rev = AST2700_A1_SILICON_REV; - sc->sram_size = AST2700_SSP_RAM_SIZE; - sc->spis_num = 0; - sc->ehcis_num = 0; - sc->wdts_num = 0; - sc->macs_num = 0; sc->uarts_num = 13; sc->uarts_base = ASPEED_DEV_UART0; sc->irqmap = aspeed_soc_ast27x0ssp_irqmap; sc->memmap = aspeed_soc_ast27x0ssp_memmap; - sc->num_cpus = 1; - sc->get_irq = aspeed_soc_ast27x0ssp_get_irq; } static const TypeInfo aspeed_soc_ast27x0ssp_types[] = { { - .name = TYPE_ASPEED27X0SSP_SOC, - .parent = TYPE_ASPEED_SOC, - .instance_size = sizeof(Aspeed27x0SSPSoCState), + .name = TYPE_ASPEED27X0SSP_COPROCESSOR, + .parent = TYPE_ASPEED_COPROCESSOR, + .instance_size = sizeof(Aspeed27x0CoprocessorState), .instance_init = aspeed_soc_ast27x0ssp_init, .class_init = aspeed_soc_ast27x0ssp_class_init, }, diff --git a/hw/arm/aspeed_ast27x0-tsp.c b/hw/arm/aspeed_ast27x0-tsp.c index 4e0efae..9318f8c 100644 --- a/hw/arm/aspeed_ast27x0-tsp.c +++ b/hw/arm/aspeed_ast27x0-tsp.c @@ -1,5 +1,5 @@ /* - * ASPEED Ast27x0 TSP SoC + * ASPEED Ast27x0 TSP Coprocessor * * Copyright (C) 2025 ASPEED Technology Inc. * @@ -14,6 +14,7 @@ #include "hw/qdev-clock.h" #include "hw/misc/unimp.h" #include "hw/arm/aspeed_soc.h" +#include "hw/arm/aspeed_coprocessor.h" #define AST2700_TSP_RAM_SIZE (32 * MiB) @@ -104,10 +105,11 @@ static struct nvic_intc_irq_info ast2700_tsp_intcmap[] = { {136, 0, 9, NULL}, }; -static qemu_irq aspeed_soc_ast27x0tsp_get_irq(AspeedSoCState *s, int dev) +static qemu_irq aspeed_soc_ast27x0tsp_get_irq(AspeedCoprocessorState *s, + int dev) { - Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(s); - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + Aspeed27x0CoprocessorState *a = ASPEED27X0TSP_COPROCESSOR(s); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_GET_CLASS(s); int or_idx; int idx; @@ -128,9 +130,9 @@ static qemu_irq aspeed_soc_ast27x0tsp_get_irq(AspeedSoCState *s, int dev) static void aspeed_soc_ast27x0tsp_init(Object *obj) { - Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(obj); - AspeedSoCState *s = ASPEED_SOC(obj); - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + Aspeed27x0CoprocessorState *a = ASPEED27X0TSP_COPROCESSOR(obj); + AspeedCoprocessorState *s = ASPEED_COPROCESSOR(obj); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_GET_CLASS(s); int i; object_initialize_child(obj, "armv7m", &a->armv7m, TYPE_ARMV7M); @@ -159,11 +161,12 @@ static void aspeed_soc_ast27x0tsp_init(Object *obj) static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) { - Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(dev_soc); - AspeedSoCState *s = ASPEED_SOC(dev_soc); - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + Aspeed27x0CoprocessorState *a = ASPEED27X0TSP_COPROCESSOR(dev_soc); + AspeedCoprocessorState *s = ASPEED_COPROCESSOR(dev_soc); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_GET_CLASS(s); DeviceState *armv7m; g_autofree char *sram_name = NULL; + int uart; int i; if (!clock_has_source(s->sysclk)) { @@ -174,7 +177,8 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) /* AST27X0 TSP Core */ armv7m = DEVICE(&a->armv7m); qdev_prop_set_uint32(armv7m, "num-irq", 256); - qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc)); + qdev_prop_set_string(armv7m, "cpu-type", + aspeed_soc_cpu_type(sc->valid_cpu_types)); qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); object_property_set_link(OBJECT(&a->armv7m), "memory", OBJECT(s->memory), &error_abort); @@ -183,8 +187,8 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) sram_name = g_strdup_printf("aspeed.dram.%d", CPU(a->armv7m.cpu)->cpu_index); - if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, - errp)) { + if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, + AST2700_TSP_RAM_SIZE, errp)) { return; } memory_region_add_subregion(s->memory, @@ -195,14 +199,15 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scu), 0, + sc->memmap[ASPEED_DEV_SCU]); /* INTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->intc[0]), 0, sc->memmap[ASPEED_DEV_INTC]); /* INTCIO */ @@ -210,7 +215,7 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->intc[1]), 0, sc->memmap[ASPEED_DEV_INTCIO]); /* irq source orgates -> INTC */ @@ -235,57 +240,56 @@ static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) qdev_get_gpio_in(DEVICE(&a->intc[0].orgates[0]), i)); } /* UART */ - if (!aspeed_soc_uart_realize(s, errp)) { - return; + for (i = 0, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) { + if (!aspeed_soc_uart_realize(s->memory, &s->uart[i], + sc->memmap[uart], errp)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + aspeed_soc_ast27x0tsp_get_irq(s, uart)); } - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->timerctrl), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->timerctrl), "aspeed.timerctrl", sc->memmap[ASPEED_DEV_TIMER1], 0x200); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[0]), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->ipc[0]), "aspeed.ipc0", sc->memmap[ASPEED_DEV_IPC0], 0x1000); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[1]), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->ipc[1]), "aspeed.ipc1", sc->memmap[ASPEED_DEV_IPC1], 0x1000); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->scuio), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&a->scuio), "aspeed.scuio", sc->memmap[ASPEED_DEV_SCUIO], 0x1000); } -static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, const void *data) +static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, + const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO cortex-m4f */ NULL }; DeviceClass *dc = DEVICE_CLASS(klass); - AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc); + AspeedCoprocessorClass *sc = ASPEED_COPROCESSOR_CLASS(dc); - /* Reason: The Aspeed SoC can only be instantiated from a board */ + /* Reason: The Aspeed Coprocessor can only be instantiated from a board */ dc->user_creatable = false; dc->realize = aspeed_soc_ast27x0tsp_realize; sc->valid_cpu_types = valid_cpu_types; sc->silicon_rev = AST2700_A1_SILICON_REV; - sc->sram_size = AST2700_TSP_RAM_SIZE; - sc->spis_num = 0; - sc->ehcis_num = 0; - sc->wdts_num = 0; - sc->macs_num = 0; sc->uarts_num = 13; sc->uarts_base = ASPEED_DEV_UART0; sc->irqmap = aspeed_soc_ast27x0tsp_irqmap; sc->memmap = aspeed_soc_ast27x0tsp_memmap; - sc->num_cpus = 1; - sc->get_irq = aspeed_soc_ast27x0tsp_get_irq; } static const TypeInfo aspeed_soc_ast27x0tsp_types[] = { { - .name = TYPE_ASPEED27X0TSP_SOC, - .parent = TYPE_ASPEED_SOC, - .instance_size = sizeof(Aspeed27x0TSPSoCState), + .name = TYPE_ASPEED27X0TSP_COPROCESSOR, + .parent = TYPE_ASPEED_COPROCESSOR, + .instance_size = sizeof(Aspeed27x0CoprocessorState), .instance_init = aspeed_soc_ast27x0tsp_init, .class_init = aspeed_soc_ast27x0tsp_class_init, }, diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 8533391..c484bcd 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -436,7 +436,7 @@ static void aspeed_soc_ast2700_init(Object *obj) for (i = 0; i < sc->num_cpus; i++) { object_initialize_child(obj, "cpu[*]", &a->cpu[i], - aspeed_soc_cpu_type(sc)); + aspeed_soc_cpu_type(sc->valid_cpu_types)); } object_initialize_child(obj, "gic", &a->gic, gicv3_class_name()); @@ -589,9 +589,9 @@ static bool aspeed_soc_ast2700_gic_realize(DeviceState *dev, Error **errp) return false; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->gic), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->gic), 0, sc->memmap[ASPEED_GIC_DIST]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->gic), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->gic), 1, sc->memmap[ASPEED_GIC_REDIST]); for (i = 0; i < sc->num_cpus; i++) { @@ -647,7 +647,7 @@ static bool aspeed_soc_ast2700_pcie_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie_phy[i]), errp)) { return false; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie_phy[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->pcie_phy[i]), 0, sc->memmap[ASPEED_DEV_PCIE_PHY0 + i]); object_property_set_int(OBJECT(&s->pcie[i]), "dram-base", @@ -658,9 +658,9 @@ static bool aspeed_soc_ast2700_pcie_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->pcie[i]), errp)) { return false; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->pcie[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->pcie[i]), 0, sc->memmap[ASPEED_DEV_PCIE0 + i]); - irq = aspeed_soc_get_irq(s, ASPEED_DEV_PCIE0 + i); + irq = aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_PCIE0 + i); sysbus_connect_irq(SYS_BUS_DEVICE(&s->pcie[i].rc), 0, irq); mmio_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->pcie[i].rc), 1); @@ -687,6 +687,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) AspeedINTCClass *icio = ASPEED_INTC_GET_CLASS(&a->intc[1]); g_autofree char *name = NULL; qemu_irq irq; + int uart; /* Default boot region (SPI memory or ROMs) */ memory_region_init(&s->spi_boot_container, OBJECT(s), @@ -719,7 +720,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->intc[0]), 0, sc->memmap[ASPEED_DEV_INTC]); /* INTCIO */ @@ -727,7 +728,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&a->intc[1]), 0, sc->memmap[ASPEED_DEV_INTCIO]); /* irq sources -> orgates -> INTC */ @@ -777,18 +778,24 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scu), 0, + sc->memmap[ASPEED_DEV_SCU]); /* SCU1 */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->scuio), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scuio), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->scuio), 0, sc->memmap[ASPEED_DEV_SCUIO]); /* UART */ - if (!aspeed_soc_uart_realize(s, errp)) { - return; + for (i = 0, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) { + if (!aspeed_soc_uart_realize(s->memory, &s->uart[i], + sc->memmap[uart], errp)) { + return; + } + sysbus_connect_irq(SYS_BUS_DEVICE(&s->uart[i]), 0, + aspeed_soc_ast2700_get_irq(s, uart)); } /* FMC, The number of CS is set at the board level */ @@ -800,11 +807,12 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->fmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->fmc), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 0, + sc->memmap[ASPEED_DEV_FMC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->fmc), 1, ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_FMC)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_FMC)); /* Set up an alias on the FMC CE0 region (boot default) */ MemoryRegion *fmc0_mmio = &s->fmc.flashes[0].mmio; @@ -819,9 +827,9 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->spi[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 0, sc->memmap[ASPEED_DEV_SPI0 + i]); - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->spi[i]), 1, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->spi[i]), 1, ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } @@ -830,10 +838,11 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->ehci[i]), 0, sc->memmap[ASPEED_DEV_EHCI1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i)); + aspeed_soc_ast2700_get_irq(s, + ASPEED_DEV_EHCI1 + i)); } /* @@ -848,7 +857,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdmc), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sdmc), 0, sc->memmap[ASPEED_DEV_SDMC]); /* RAM */ @@ -865,10 +874,10 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->ftgmac100[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, sc->memmap[ASPEED_DEV_ETH1 + i]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_ETH1 + i)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_ETH1 + i)); object_property_set_link(OBJECT(&s->mii[i]), "nic", OBJECT(&s->ftgmac100[i]), &error_abort); @@ -876,7 +885,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->mii[i]), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->mii[i]), 0, sc->memmap[ASPEED_DEV_MII1 + i]); } @@ -890,28 +899,30 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->wdt[i]), 0, wdt_offset); } /* SLI */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sli), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sli), 0, sc->memmap[ASPEED_DEV_SLI]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sli), 0, + sc->memmap[ASPEED_DEV_SLI]); if (!sysbus_realize(SYS_BUS_DEVICE(&s->sliio), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sliio), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sliio), 0, sc->memmap[ASPEED_DEV_SLIIO]); /* ADC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->adc), 0, + sc->memmap[ASPEED_DEV_ADC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_ADC)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_ADC)); /* I2C */ object_property_set_link(OBJECT(&s->i2c), "dram", OBJECT(s->dram_mr), @@ -919,7 +930,8 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->i2c), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->i2c), 0, sc->memmap[ASPEED_DEV_I2C]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->i2c), 0, + sc->memmap[ASPEED_DEV_I2C]); for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) { /* * The AST2700 I2C controller has one source INTC per bus. @@ -948,36 +960,37 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->gpio), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->gpio), 0, sc->memmap[ASPEED_DEV_GPIO]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_GPIO)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_GPIO)); /* RTC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->rtc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->rtc), 0, sc->memmap[ASPEED_DEV_RTC]); + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->rtc), 0, + sc->memmap[ASPEED_DEV_RTC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->rtc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_RTC)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_RTC)); /* SDHCI */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->sdhci), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->sdhci), 0, sc->memmap[ASPEED_DEV_SDHCI]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_SDHCI)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_SDHCI)); /* eMMC */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->emmc), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->emmc), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->emmc), 0, sc->memmap[ASPEED_DEV_EMMC]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->emmc), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_EMMC)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_EMMC)); /* Timer */ object_property_set_link(OBJECT(&s->timerctrl), "scu", OBJECT(&s->scu), @@ -985,10 +998,10 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->timerctrl), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->timerctrl), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->timerctrl), 0, sc->memmap[ASPEED_DEV_TIMER1]); for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) { - irq = aspeed_soc_get_irq(s, ASPEED_DEV_TIMER1 + i); + irq = aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_TIMER1 + i); sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); } @@ -998,33 +1011,33 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(SYS_BUS_DEVICE(&s->hace), errp)) { return; } - aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->hace), 0, + aspeed_mmio_map(s->memory, SYS_BUS_DEVICE(&s->hace), 0, sc->memmap[ASPEED_DEV_HACE]); sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, - aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); + aspeed_soc_ast2700_get_irq(s, ASPEED_DEV_HACE)); /* PCIe Root Complex (RC) */ if (!aspeed_soc_ast2700_pcie_realize(dev, errp)) { return; } - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->dpmcu), "aspeed.dpmcu", sc->memmap[ASPEED_DEV_DPMCU], AST2700_SOC_DPMCU_SIZE); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->ltpi), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->ltpi), "aspeed.ltpi", sc->memmap[ASPEED_DEV_LTPI], AST2700_SOC_LTPI_SIZE); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->iomem), "aspeed.io", sc->memmap[ASPEED_DEV_IOMEM], AST2700_SOC_IO_SIZE); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem0), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->iomem0), "aspeed.iomem0", sc->memmap[ASPEED_DEV_IOMEM0], AST2700_SOC_IOMEM_SIZE); - aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem1), + aspeed_mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->iomem1), "aspeed.iomem1", sc->memmap[ASPEED_DEV_IOMEM1], AST2700_SOC_IOMEM_SIZE); @@ -1056,7 +1069,6 @@ static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, const void *data) sc->uarts_base = ASPEED_DEV_UART0; sc->irqmap = aspeed_soc_ast2700a0_irqmap; sc->memmap = aspeed_soc_ast2700_memmap; - sc->get_irq = aspeed_soc_ast2700_get_irq; } static void aspeed_soc_ast2700a1_class_init(ObjectClass *oc, const void *data) @@ -1085,7 +1097,6 @@ static void aspeed_soc_ast2700a1_class_init(ObjectClass *oc, const void *data) sc->uarts_base = ASPEED_DEV_UART0; sc->irqmap = aspeed_soc_ast2700a1_irqmap; sc->memmap = aspeed_soc_ast2700_memmap; - sc->get_irq = aspeed_soc_ast2700_get_irq; } static const TypeInfo aspeed_soc_ast27x0_types[] = { diff --git a/hw/arm/aspeed_coprocessor_common.c b/hw/arm/aspeed_coprocessor_common.c new file mode 100644 index 0000000..8a94b44 --- /dev/null +++ b/hw/arm/aspeed_coprocessor_common.c @@ -0,0 +1,49 @@ +/* + * ASPEED Coprocessor + * + * Copyright (C) 2025 ASPEED Technology Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "system/memory.h" +#include "hw/qdev-properties.h" +#include "hw/arm/aspeed_coprocessor.h" + +static void aspeed_coprocessor_realize(DeviceState *dev, Error **errp) +{ + AspeedCoprocessorState *s = ASPEED_COPROCESSOR(dev); + + if (!s->memory) { + error_setg(errp, "'memory' link is not set"); + return; + } +} + +static const Property aspeed_coprocessor_properties[] = { + DEFINE_PROP_LINK("memory", AspeedCoprocessorState, memory, + TYPE_MEMORY_REGION, MemoryRegion *), +}; + +static void aspeed_coprocessor_class_init(ObjectClass *oc, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = aspeed_coprocessor_realize; + device_class_set_props(dc, aspeed_coprocessor_properties); +} + +static const TypeInfo aspeed_coprocessor_types[] = { + { + .name = TYPE_ASPEED_COPROCESSOR, + .parent = TYPE_DEVICE, + .instance_size = sizeof(AspeedCoprocessorState), + .class_size = sizeof(AspeedCoprocessorClass), + .class_init = aspeed_coprocessor_class_init, + .abstract = true, + }, +}; + +DEFINE_TYPES(aspeed_coprocessor_types) diff --git a/hw/arm/aspeed_soc_common.c b/hw/arm/aspeed_soc_common.c index bc70e86..78b6ae1 100644 --- a/hw/arm/aspeed_soc_common.c +++ b/hw/arm/aspeed_soc_common.c @@ -22,52 +22,39 @@ #include "qemu/datadir.h" -const char *aspeed_soc_cpu_type(AspeedSoCClass *sc) +const char *aspeed_soc_cpu_type(const char * const *valid_cpu_types) { - assert(sc->valid_cpu_types); - assert(sc->valid_cpu_types[0]); - assert(!sc->valid_cpu_types[1]); - return sc->valid_cpu_types[0]; + assert(valid_cpu_types); + assert(valid_cpu_types[0]); + assert(!valid_cpu_types[1]); + return valid_cpu_types[0]; } -qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev) +bool aspeed_soc_uart_realize(MemoryRegion *memory, SerialMM *smm, + const hwaddr addr, Error **errp) { - return ASPEED_SOC_GET_CLASS(s)->get_irq(s, dev); -} - -bool aspeed_soc_uart_realize(AspeedSoCState *s, Error **errp) -{ - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - SerialMM *smm; - - for (int i = 0, uart = sc->uarts_base; i < sc->uarts_num; i++, uart++) { - smm = &s->uart[i]; - - /* Chardev property is set by the machine. */ - qdev_prop_set_uint8(DEVICE(smm), "regshift", 2); - qdev_prop_set_uint32(DEVICE(smm), "baudbase", 38400); - qdev_set_legacy_instance_id(DEVICE(smm), sc->memmap[uart], 2); - qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN); - if (!sysbus_realize(SYS_BUS_DEVICE(smm), errp)) { - return false; - } - - sysbus_connect_irq(SYS_BUS_DEVICE(smm), 0, aspeed_soc_get_irq(s, uart)); - aspeed_mmio_map(s, SYS_BUS_DEVICE(smm), 0, sc->memmap[uart]); + /* Chardev property is set by the machine. */ + qdev_prop_set_uint8(DEVICE(smm), "regshift", 2); + qdev_prop_set_uint32(DEVICE(smm), "baudbase", 38400); + qdev_set_legacy_instance_id(DEVICE(smm), addr, 2); + qdev_prop_set_uint8(DEVICE(smm), "endianness", DEVICE_LITTLE_ENDIAN); + if (!sysbus_realize(SYS_BUS_DEVICE(smm), errp)) { + return false; } + aspeed_mmio_map(memory, SYS_BUS_DEVICE(smm), 0, addr); return true; } -void aspeed_soc_uart_set_chr(AspeedSoCState *s, int dev, Chardev *chr) +void aspeed_soc_uart_set_chr(SerialMM *uart, int dev, int uarts_base, + int uarts_num, Chardev *chr) { - AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); - int uart_first = aspeed_uart_first(sc); + int uart_first = aspeed_uart_first(uarts_base); int uart_index = aspeed_uart_index(dev); int i = uart_index - uart_first; - g_assert(0 <= i && i < ARRAY_SIZE(s->uart) && i < sc->uarts_num); - qdev_prop_set_chr(DEVICE(&s->uart[i]), "chardev", chr); + g_assert(0 <= i && i < ASPEED_UARTS_NUM && i < uarts_num); + qdev_prop_set_chr(DEVICE(&uart[i]), "chardev", chr); } /* @@ -111,20 +98,20 @@ bool aspeed_soc_dram_init(AspeedSoCState *s, Error **errp) return true; } -void aspeed_mmio_map(AspeedSoCState *s, SysBusDevice *dev, int n, hwaddr addr) +void aspeed_mmio_map(MemoryRegion *memory, SysBusDevice *dev, int n, + hwaddr addr) { - memory_region_add_subregion(s->memory, addr, - sysbus_mmio_get_region(dev, n)); + memory_region_add_subregion(memory, addr, sysbus_mmio_get_region(dev, n)); } -void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev, +void aspeed_mmio_map_unimplemented(MemoryRegion *memory, SysBusDevice *dev, const char *name, hwaddr addr, uint64_t size) { qdev_prop_set_string(DEVICE(dev), "name", name); qdev_prop_set_uint64(DEVICE(dev), "size", size); sysbus_realize(dev, &error_abort); - memory_region_add_subregion_overlap(s->memory, addr, + memory_region_add_subregion_overlap(memory, addr, sysbus_mmio_get_region(dev, 0), -1000); } diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c index c14fc2e..5a94c84 100644 --- a/hw/arm/fby35.c +++ b/hw/arm/fby35.c @@ -71,9 +71,11 @@ static void fby35_bmc_write_boot_rom(DriveInfo *dinfo, MemoryRegion *mr, static void fby35_bmc_init(Fby35State *s) { AspeedSoCState *soc; + AspeedSoCClass *sc; object_initialize_child(OBJECT(s), "bmc", &s->bmc, "ast2600-a3"); soc = ASPEED_SOC(&s->bmc); + sc = ASPEED_SOC_GET_CLASS(soc); memory_region_init(&s->bmc_memory, OBJECT(&s->bmc), "bmc-memory", UINT64_MAX); @@ -91,7 +93,8 @@ static void fby35_bmc_init(Fby35State *s) &error_abort); object_property_set_int(OBJECT(&s->bmc), "hw-strap2", 0x00000003, &error_abort); - aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART5, serial_hd(0)); + aspeed_soc_uart_set_chr(soc->uart, ASPEED_DEV_UART5, sc->uarts_base, + sc->uarts_num, serial_hd(0)); qdev_realize(DEVICE(&s->bmc), NULL, &error_abort); aspeed_board_init_flashes(&soc->fmc, "n25q00", 2, 0); @@ -118,12 +121,14 @@ static void fby35_bmc_init(Fby35State *s) static void fby35_bic_init(Fby35State *s) { AspeedSoCState *soc; + AspeedSoCClass *sc; s->bic_sysclk = clock_new(OBJECT(s), "SYSCLK"); clock_set_hz(s->bic_sysclk, 200000000ULL); object_initialize_child(OBJECT(s), "bic", &s->bic, "ast1030-a1"); soc = ASPEED_SOC(&s->bic); + sc = ASPEED_SOC_GET_CLASS(soc); memory_region_init(&s->bic_memory, OBJECT(&s->bic), "bic-memory", UINT64_MAX); @@ -131,7 +136,8 @@ static void fby35_bic_init(Fby35State *s) qdev_connect_clock_in(DEVICE(&s->bic), "sysclk", s->bic_sysclk); object_property_set_link(OBJECT(&s->bic), "memory", OBJECT(&s->bic_memory), &error_abort); - aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART5, serial_hd(1)); + aspeed_soc_uart_set_chr(soc->uart, ASPEED_DEV_UART5, sc->uarts_base, + sc->uarts_num, serial_hd(1)); qdev_realize(DEVICE(&s->bic), NULL, &error_abort); aspeed_board_init_flashes(&soc->fmc, "sst25vf032b", 2, 2); diff --git a/hw/arm/meson.build b/hw/arm/meson.build index dc683913..b88b5b0 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -45,14 +45,15 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_soc_common.c', 'aspeed_ast2400.c', 'aspeed_ast2600.c', - 'aspeed_ast27x0-ssp.c', - 'aspeed_ast27x0-tsp.c', 'aspeed_ast10x0.c', 'aspeed_eeprom.c', 'fby35.c')) arm_common_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files( 'aspeed_ast27x0.c', - 'aspeed_ast27x0-fc.c',)) + 'aspeed_ast27x0-fc.c', + 'aspeed_ast27x0-ssp.c', + 'aspeed_ast27x0-tsp.c', + 'aspeed_coprocessor_common.c')) arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c')) arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c')) arm_common_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c')) diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c index 682ed9f..74a5660 100644 --- a/hw/core/machine-hmp-cmds.c +++ b/hw/core/machine-hmp-cmds.c @@ -163,19 +163,22 @@ void hmp_info_kvm(Monitor *mon, const QDict *qdict) qapi_free_KvmInfo(info); } -void hmp_info_mshv(Monitor *mon, const QDict *qdict) +void hmp_info_accelerators(Monitor *mon, const QDict *qdict) { - MshvInfo *info; - - info = qmp_query_mshv(NULL); - monitor_printf(mon, "mshv support: "); - if (info->present) { - monitor_printf(mon, "%s\n", info->enabled ? "enabled" : "disabled"); - } else { - monitor_printf(mon, "not compiled\n"); + AcceleratorInfo *info; + AcceleratorList *accel; + + info = qmp_query_accelerators(NULL); + for (accel = info->present; accel; accel = accel->next) { + char trail = accel->next ? ' ' : '\n'; + if (info->enabled == accel->value) { + monitor_printf(mon, "[%s]%c", Accelerator_str(accel->value), trail); + } else { + monitor_printf(mon, "%s%c", Accelerator_str(accel->value), trail); + } } - qapi_free_MshvInfo(info); + qapi_free_AcceleratorInfo(info); } void hmp_info_uuid(Monitor *mon, const QDict *qdict) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index e24bf0d..51d5c23 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -31,15 +31,25 @@ #include <sys/stat.h> /* - * QMP query for MSHV + * QMP query for enabled and present accelerators */ -MshvInfo *qmp_query_mshv(Error **errp) +AcceleratorInfo *qmp_query_accelerators(Error **errp) { - MshvInfo *info = g_malloc0(sizeof(*info)); - - info->enabled = mshv_enabled(); - info->present = accel_find("mshv"); - + AcceleratorInfo *info = g_malloc0(sizeof(*info)); + AccelClass *current_class = ACCEL_GET_CLASS(current_accel()); + int i; + + for (i = ACCELERATOR__MAX; i-- > 0; ) { + const char *s = Accelerator_str(i); + AccelClass *this_class = accel_find(s); + + if (this_class) { + QAPI_LIST_PREPEND(info->present, i); + if (this_class == current_class) { + info->enabled = i; + } + } + } return info; } diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c index 22822fe..164fd0b 100644 --- a/hw/display/xenfb.c +++ b/hw/display/xenfb.c @@ -283,8 +283,7 @@ static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src, scale = surface_height(surface) - 1; break; default: - scale = 0x8000; - break; + g_assert_not_reached(); } xenfb->axis[move->axis] = move->value * scale / 0x7fff; } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index dacedc5..cddca69 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -36,6 +36,13 @@ #include "net/net.h" #include "qemu/log.h" +#define TYPE_HPPA_COMMON_MACHINE MACHINE_TYPE_NAME("hppa-common") +OBJECT_DECLARE_SIMPLE_TYPE(HppaMachineState, HPPA_COMMON_MACHINE) + +struct HppaMachineState { + MachineState parent_obj; +}; + #define MIN_SEABIOS_HPPA_VERSION 12 /* require at least this fw version */ #define HPA_POWER_BUTTON (FIRMWARE_END - 0x10) @@ -345,16 +352,11 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, TranslateFn *translate) { const char *kernel_filename = machine->kernel_filename; - const char *kernel_cmdline = machine->kernel_cmdline; - const char *initrd_filename = machine->initrd_filename; - const char *firmware = machine->firmware; MachineClass *mc = MACHINE_GET_CLASS(machine); DeviceState *dev; PCIDevice *pci_dev; - char *firmware_filename; - uint64_t firmware_low, firmware_high; long size; - uint64_t kernel_entry = 0, kernel_low, kernel_high; + uint64_t kernel_entry = 0; MemoryRegion *addr_space = get_system_memory(); MemoryRegion *rom_region; SysBusDevice *s; @@ -424,6 +426,10 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, firmware on 64-bit machines by default if not specified on command line. */ if (!qtest_enabled()) { + const char *firmware = machine->firmware; + uint64_t firmware_low, firmware_high; + char *firmware_filename; + if (!firmware) { firmware = lasi_dev ? "hppa-firmware.img" : "hppa-firmware64.img"; } @@ -460,6 +466,10 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus, /* Load kernel */ if (kernel_filename) { + const char *kernel_cmdline = machine->kernel_cmdline; + const char *initrd_filename = machine->initrd_filename; + uint64_t kernel_low, kernel_high; + size = load_elf(kernel_filename, NULL, linux_kernel_virt_to_phys, NULL, &kernel_entry, &kernel_low, &kernel_high, NULL, ELFDATA2MSB, EM_PARISC, 0, 0); @@ -683,6 +693,22 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) } } +static void hppa_machine_common_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + NMIClass *nc = NMI_CLASS(oc); + + mc->reset = hppa_machine_reset; + mc->block_default_type = IF_SCSI; + mc->default_cpus = 1; + mc->max_cpus = HPPA_MAX_CPUS; + mc->default_boot_order = "cd"; + mc->default_ram_id = "ram"; + mc->default_nic = "tulip"; + + nc->nmi_monitor_handler = hppa_nmi; +} + static void HP_B160L_machine_init_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { @@ -690,35 +716,15 @@ static void HP_B160L_machine_init_class_init(ObjectClass *oc, const void *data) NULL }; MachineClass *mc = MACHINE_CLASS(oc); - NMIClass *nc = NMI_CLASS(oc); mc->desc = "HP B160L workstation"; mc->default_cpu_type = TYPE_HPPA_CPU; mc->valid_cpu_types = valid_cpu_types; mc->init = machine_HP_B160L_init; - mc->reset = hppa_machine_reset; - mc->block_default_type = IF_SCSI; - mc->max_cpus = HPPA_MAX_CPUS; - mc->default_cpus = 1; mc->is_default = true; mc->default_ram_size = 512 * MiB; - mc->default_boot_order = "cd"; - mc->default_ram_id = "ram"; - mc->default_nic = "tulip"; - - nc->nmi_monitor_handler = hppa_nmi; } -static const TypeInfo HP_B160L_machine_init_typeinfo = { - .name = MACHINE_TYPE_NAME("B160L"), - .parent = TYPE_MACHINE, - .class_init = HP_B160L_machine_init_class_init, - .interfaces = (const InterfaceInfo[]) { - { TYPE_NMI }, - { } - }, -}; - static void HP_C3700_machine_init_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { @@ -726,39 +732,35 @@ static void HP_C3700_machine_init_class_init(ObjectClass *oc, const void *data) NULL }; MachineClass *mc = MACHINE_CLASS(oc); - NMIClass *nc = NMI_CLASS(oc); mc->desc = "HP C3700 workstation"; mc->default_cpu_type = TYPE_HPPA64_CPU; mc->valid_cpu_types = valid_cpu_types; mc->init = machine_HP_C3700_init; - mc->reset = hppa_machine_reset; - mc->block_default_type = IF_SCSI; mc->max_cpus = HPPA_MAX_CPUS; - mc->default_cpus = 1; - mc->is_default = false; mc->default_ram_size = 1024 * MiB; - mc->default_boot_order = "cd"; - mc->default_ram_id = "ram"; - mc->default_nic = "tulip"; - - nc->nmi_monitor_handler = hppa_nmi; } -static const TypeInfo HP_C3700_machine_init_typeinfo = { - .name = MACHINE_TYPE_NAME("C3700"), - .parent = TYPE_MACHINE, - .class_init = HP_C3700_machine_init_class_init, - .interfaces = (const InterfaceInfo[]) { - { TYPE_NMI }, - { } +static const TypeInfo hppa_machine_types[] = { + { + .name = TYPE_HPPA_COMMON_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(HppaMachineState), + .class_init = hppa_machine_common_class_init, + .abstract = true, + .interfaces = (const InterfaceInfo[]) { + { TYPE_NMI }, + { } + }, + }, { + .name = MACHINE_TYPE_NAME("B160L"), + .parent = TYPE_HPPA_COMMON_MACHINE, + .class_init = HP_B160L_machine_init_class_init, + }, { + .name = MACHINE_TYPE_NAME("C3700"), + .parent = TYPE_HPPA_COMMON_MACHINE, + .class_init = HP_C3700_machine_init_class_init, }, }; -static void hppa_machine_init_register_types(void) -{ - type_register_static(&HP_B160L_machine_init_typeinfo); - type_register_static(&HP_C3700_machine_init_typeinfo); -} - -type_init(hppa_machine_init_register_types) +DEFINE_TYPES(hppa_machine_types) diff --git a/hw/intc/apic.c b/hw/intc/apic.c index 6d78596..c768033 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -646,8 +646,6 @@ void apic_sipi(DeviceState *dev) { APICCommonState *s = APIC(dev); - cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); - if (!s->wait_for_sipi) return; cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector); diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index a516415..3dd48cb 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -306,7 +306,7 @@ static ram_addr_t alloc_initrd_memory(struct loongarch_boot_info *info, static int64_t load_kernel_info(struct loongarch_boot_info *info) { uint64_t kernel_entry, kernel_low, kernel_high, initrd_offset = 0; - ssize_t kernel_size, initrd_size; + ssize_t kernel_size; kernel_size = load_elf(info->kernel_filename, NULL, cpu_loongarch_virt_to_phys, NULL, @@ -328,7 +328,8 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) } if (info->initrd_filename) { - initrd_size = get_image_size(info->initrd_filename); + ssize_t initrd_size = get_image_size(info->initrd_filename); + if (initrd_size > 0) { initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); initrd_offset = alloc_initrd_memory(info, initrd_offset, @@ -337,7 +338,7 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) initrd_offset, initrd_size); } - if (initrd_size == (target_ulong)-1) { + if (initrd_size == -1) { error_report("could not load initial ram disk '%s'", info->initrd_filename); exit(1); diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c index 3eb1119..3433486 100644 --- a/hw/net/can/xlnx-versal-canfd.c +++ b/hw/net/can/xlnx-versal-canfd.c @@ -35,12 +35,8 @@ #include "hw/irq.h" #include "hw/register.h" #include "qapi/error.h" -#include "qemu/bitops.h" #include "qemu/log.h" -#include "qemu/cutils.h" -#include "qemu/event_notifier.h" #include "hw/qdev-properties.h" -#include "qom/object_interfaces.h" #include "migration/vmstate.h" #include "hw/net/xlnx-versal-canfd.h" #include "trace.h" diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c index 2310f62..bc70e50 100644 --- a/hw/ppc/ppce500_spin.c +++ b/hw/ppc/ppce500_spin.c @@ -99,8 +99,7 @@ static void spin_kick(CPUState *cs, run_on_cpu_data data) cs->halted = 0; cs->exception_index = -1; - cs->stopped = false; - qemu_cpu_kick(cs); + cpu_resume(cs); } static void spin_write(void *opaque, hwaddr addr, uint64_t value, diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 51e88ba..8602a56 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -306,6 +306,7 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) g_autofree SCCB *work_sccb = NULL; AddressSpace *as = CPU(cpu)->as; const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; + MemTxResult ret; /* first some basic checks on program checks */ if (env->psw.mask & PSW_MASK_PSTATE) { @@ -320,7 +321,10 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) } /* the header contains the actual length of the sccb */ - address_space_read(as, sccb, attrs, &header, sizeof(SCCBHeader)); + ret = address_space_read(as, sccb, attrs, &header, sizeof(SCCBHeader)); + if (ret != MEMTX_OK) { + return -PGM_ADDRESSING; + } /* Valid sccb sizes */ if (be16_to_cpu(header.length) < sizeof(SCCBHeader)) { @@ -333,7 +337,11 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) * the host has checked the values */ work_sccb = g_malloc0(be16_to_cpu(header.length)); - address_space_read(as, sccb, attrs, work_sccb, be16_to_cpu(header.length)); + ret = address_space_read(as, sccb, attrs, + work_sccb, be16_to_cpu(header.length)); + if (ret != MEMTX_OK) { + return -PGM_ADDRESSING; + } if (!sclp_command_code_valid(code)) { work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); @@ -347,7 +355,11 @@ int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code) sclp_c->execute(sclp, work_sccb, code); out_write: - address_space_write(as, sccb, attrs, work_sccb, be16_to_cpu(header.length)); + ret = address_space_write(as, sccb, attrs, + work_sccb, be16_to_cpu(header.length)); + if (ret != MEMTX_OK) { + return -PGM_PROTECTION; + } sclp_c->service_interrupt(sclp, sccb); diff --git a/hw/sparc/leon3.c b/hw/sparc/leon3.c index 0aeaad3..09d2cec 100644 --- a/hw/sparc/leon3.c +++ b/hw/sparc/leon3.c @@ -192,7 +192,7 @@ static void leon3_cache_control_int(CPUSPARCState *env) static void leon3_irq_ack(CPUSPARCState *env, int intno) { - CPUState *cpu = CPU(env_cpu(env)); + CPUState *cpu = env_cpu(env); grlib_irqmp_ack(env->irq_manager, cpu->cpu_index, intno); } diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c index 16e6110..1e4365f 100644 --- a/hw/vmapple/vmapple.c +++ b/hw/vmapple/vmapple.c @@ -51,6 +51,8 @@ #include "system/reset.h" #include "system/runstate.h" #include "system/system.h" +#include "target/arm/gtimer.h" +#include "target/arm/cpu.h" struct VMAppleMachineState { MachineState parent; diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 6efffae..55de1a7 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -268,7 +268,7 @@ static void xtfpga_init(const XtfpgaBoardDesc *board, MachineState *machine) /* Need MMU initialized prior to ELF loading, * so that ELF gets loaded into virtual addresses */ - cpu_reset(CPU(cpu)); + reset_mmu(cenv); } if (smp_cpus > 1) { extints = xtensa_mx_pic_get_extints(mx_pic); diff --git a/include/hw/arm/aspeed_coprocessor.h b/include/hw/arm/aspeed_coprocessor.h new file mode 100644 index 0000000..d77655d --- /dev/null +++ b/include/hw/arm/aspeed_coprocessor.h @@ -0,0 +1,61 @@ +/* + * ASPEED Coprocessor + * + * Copyright (C) 2025 ASPEED Technology Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ASPEED_COPROCESSOR_H +#define ASPEED_COPROCESSOR_H + +#include "qom/object.h" +#include "hw/arm/aspeed_soc.h" + +struct AspeedCoprocessorState { + DeviceState parent; + + MemoryRegion *memory; + MemoryRegion sram; + Clock *sysclk; + + AspeedSCUState scu; + AspeedSCUState scuio; + AspeedTimerCtrlState timerctrl; + SerialMM uart[ASPEED_UARTS_NUM]; +}; + +#define TYPE_ASPEED_COPROCESSOR "aspeed-coprocessor" +OBJECT_DECLARE_TYPE(AspeedCoprocessorState, AspeedCoprocessorClass, + ASPEED_COPROCESSOR) + +struct AspeedCoprocessorClass { + DeviceClass parent_class; + + /** valid_cpu_types: NULL terminated array of a single CPU type. */ + const char * const *valid_cpu_types; + uint32_t silicon_rev; + const hwaddr *memmap; + const int *irqmap; + int uarts_base; + int uarts_num; +}; + +struct Aspeed27x0CoprocessorState { + AspeedCoprocessorState parent; + AspeedINTCState intc[2]; + UnimplementedDeviceState ipc[2]; + UnimplementedDeviceState scuio; + + ARMv7MState armv7m; +}; + +#define TYPE_ASPEED27X0SSP_COPROCESSOR "aspeed27x0ssp-coprocessor" +OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0CoprocessorState, + ASPEED27X0SSP_COPROCESSOR) + +#define TYPE_ASPEED27X0TSP_COPROCESSOR "aspeed27x0tsp-coprocessor" +DECLARE_OBJ_CHECKERS(Aspeed27x0CoprocessorState, AspeedCoprocessorClass, + ASPEED27X0TSP_COPROCESSOR, TYPE_ASPEED27X0TSP_COPROCESSOR) + +#endif /* ASPEED_COPROCESSOR_H */ diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index ed32efb..4b8e599 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -153,30 +153,6 @@ struct Aspeed10x0SoCState { ARMv7MState armv7m; }; -struct Aspeed27x0SSPSoCState { - AspeedSoCState parent; - AspeedINTCState intc[2]; - UnimplementedDeviceState ipc[2]; - UnimplementedDeviceState scuio; - - ARMv7MState armv7m; -}; - -#define TYPE_ASPEED27X0SSP_SOC "aspeed27x0ssp-soc" -OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SSPSoCState, ASPEED27X0SSP_SOC) - -struct Aspeed27x0TSPSoCState { - AspeedSoCState parent; - AspeedINTCState intc[2]; - UnimplementedDeviceState ipc[2]; - UnimplementedDeviceState scuio; - - ARMv7MState armv7m; -}; - -#define TYPE_ASPEED27X0TSP_SOC "aspeed27x0tsp-soc" -OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0TSPSoCState, ASPEED27X0TSP_SOC) - #define TYPE_ASPEED10X0_SOC "aspeed10x0-soc" OBJECT_DECLARE_SIMPLE_TYPE(Aspeed10x0SoCState, ASPEED10X0_SOC) @@ -198,12 +174,9 @@ struct AspeedSoCClass { const int *irqmap; const hwaddr *memmap; uint32_t num_cpus; - qemu_irq (*get_irq)(AspeedSoCState *s, int dev); bool (*boot_from_emmc)(AspeedSoCState *s); }; -const char *aspeed_soc_cpu_type(AspeedSoCClass *sc); - enum { ASPEED_DEV_VBOOTROM, ASPEED_DEV_SPI_BOOT, @@ -304,12 +277,15 @@ enum { ASPEED_DEV_IPC1, }; -qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev); -bool aspeed_soc_uart_realize(AspeedSoCState *s, Error **errp); -void aspeed_soc_uart_set_chr(AspeedSoCState *s, int dev, Chardev *chr); +const char *aspeed_soc_cpu_type(const char * const *valid_cpu_types); +bool aspeed_soc_uart_realize(MemoryRegion *memory, SerialMM *smm, + const hwaddr addr, Error **errp); +void aspeed_soc_uart_set_chr(SerialMM *uart, int dev, int uarts_base, + int uarts_num, Chardev *chr); bool aspeed_soc_dram_init(AspeedSoCState *s, Error **errp); -void aspeed_mmio_map(AspeedSoCState *s, SysBusDevice *dev, int n, hwaddr addr); -void aspeed_mmio_map_unimplemented(AspeedSoCState *s, SysBusDevice *dev, +void aspeed_mmio_map(MemoryRegion *memory, SysBusDevice *dev, int n, + hwaddr addr); +void aspeed_mmio_map_unimplemented(MemoryRegion *memory, SysBusDevice *dev, const char *name, hwaddr addr, uint64_t size); void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, @@ -326,14 +302,14 @@ static inline int aspeed_uart_index(int uart_dev) return uart_dev - ASPEED_DEV_UART0; } -static inline int aspeed_uart_first(AspeedSoCClass *sc) +static inline int aspeed_uart_first(int uarts_base) { - return aspeed_uart_index(sc->uarts_base); + return aspeed_uart_index(uarts_base); } -static inline int aspeed_uart_last(AspeedSoCClass *sc) +static inline int aspeed_uart_last(int uarts_base, int uarts_num) { - return aspeed_uart_first(sc) + sc->uarts_num - 1; + return aspeed_uart_first(uarts_base) + uarts_num - 1; } #endif /* ASPEED_SOC_H */ diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h index 31bd812..897dfaa 100644 --- a/include/monitor/hmp.h +++ b/include/monitor/hmp.h @@ -24,7 +24,7 @@ strList *hmp_split_at_comma(const char *str); void hmp_info_name(Monitor *mon, const QDict *qdict); void hmp_info_version(Monitor *mon, const QDict *qdict); void hmp_info_kvm(Monitor *mon, const QDict *qdict); -void hmp_info_mshv(Monitor *mon, const QDict *qdict); +void hmp_info_accelerators(Monitor *mon, const QDict *qdict); void hmp_info_status(Monitor *mon, const QDict *qdict); void hmp_info_uuid(Monitor *mon, const QDict *qdict); void hmp_info_chardev(Monitor *mon, const QDict *qdict); diff --git a/include/qemu/timer.h b/include/qemu/timer.h index abd2204..aec730a 100644 --- a/include/qemu/timer.h +++ b/include/qemu/timer.h @@ -699,7 +699,7 @@ void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time); * * Returns: true if the timer is pending */ -bool timer_pending(QEMUTimer *ts); +bool timer_pending(const QEMUTimer *ts); /** * timer_expired: @@ -710,7 +710,7 @@ bool timer_pending(QEMUTimer *ts); * * Returns: true if the timer has expired */ -bool timer_expired(QEMUTimer *timer_head, int64_t current_time); +bool timer_expired(const QEMUTimer *timer_head, int64_t current_time); /** * timer_expire_time_ns: @@ -720,7 +720,7 @@ bool timer_expired(QEMUTimer *timer_head, int64_t current_time); * * Returns: the expiry time in nanoseconds */ -uint64_t timer_expire_time_ns(QEMUTimer *ts); +uint64_t timer_expire_time_ns(const QEMUTimer *ts); /** * timer_get: diff --git a/include/system/kvm.h b/include/system/kvm.h index 4fc09e3..8f9eecf 100644 --- a/include/system/kvm.h +++ b/include/system/kvm.h @@ -340,14 +340,16 @@ int kvm_arch_process_async_events(CPUState *cpu); int kvm_arch_get_registers(CPUState *cpu, Error **errp); -/* state subset only touched by the VCPU itself during runtime */ -#define KVM_PUT_RUNTIME_STATE 1 -/* state subset modified during VCPU reset */ -#define KVM_PUT_RESET_STATE 2 -/* full state set, modified during initialization or on vmload */ -#define KVM_PUT_FULL_STATE 3 - -int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp); +typedef enum kvm_put_state { + /* state subset only touched by the VCPU itself during runtime */ + KVM_PUT_RUNTIME_STATE = 1, + /* state subset modified during VCPU reset */ + KVM_PUT_RESET_STATE = 2, + /* full state set, modified during initialization or on vmload */ + KVM_PUT_FULL_STATE = 3, +} KvmPutState; + +int kvm_arch_put_registers(CPUState *cpu, KvmPutState level, Error **errp); int kvm_arch_get_default_type(MachineState *ms); diff --git a/qapi/accelerator.json b/qapi/accelerator.json index 664e027..2b92060 100644 --- a/qapi/accelerator.json +++ b/qapi/accelerator.json @@ -56,30 +56,55 @@ 'features': [ 'unstable' ] } ## -# @MshvInfo: +# @Accelerator: # # Information about support for MSHV acceleration # -# @enabled: true if MSHV acceleration is active +# @hvf: Apple Hypervisor.framework # -# @present: true if MSHV acceleration is built into this executable +# @kvm: KVM +# +# @mshv: Hyper-V +# +# @nvmm: NetBSD NVMM +# +# @qtest: QTest (dummy accelerator) +# +# @tcg: TCG (dynamic translation) +# +# @whpx: Windows Hypervisor Platform +# +# @xen: Xen +# +# Since: 10.2.0 +## +{ 'enum': 'Accelerator', 'data': ['hvf', 'kvm', 'mshv', 'nvmm', 'qtest', 'tcg', 'whpx', 'xen'] } + +## +# @AcceleratorInfo: +# +# Information about support for various accelerators +# +# @enabled: the accelerator that is in use +# +# @present: the list of accelerators that are built into this executable # # Since: 10.2.0 ## -{ 'struct': 'MshvInfo', 'data': {'enabled': 'bool', 'present': 'bool'} } +{ 'struct': 'AcceleratorInfo', 'data': {'enabled': 'Accelerator', 'present': ['Accelerator']} } ## -# @query-mshv: +# @query-accelerators: # -# Return information about MSHV acceleration +# Return information about accelerators # -# Returns: @MshvInfo +# Returns: @AcceleratorInfo # -# Since: 10.0.92 +# Since: 10.2.0 # # .. qmp-example:: # -# -> { "execute": "query-mshv" } -# <- { "return": { "enabled": true, "present": true } } +# -> { "execute": "query-accelerators" } +# <- { "return": { "enabled": "mshv", "present": ["kvm", "mshv", "qtest", "tcg"] } } ## -{ 'command': 'query-mshv', 'returns': 'MshvInfo' } +{ 'command': 'query-accelerators', 'returns': 'AcceleratorInfo' } diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 1108513..0c1df62 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -59,7 +59,6 @@ name = "bql" version = "0.1.0" dependencies = [ "glib-sys", - "migration", ] [[package]] @@ -198,8 +197,10 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" name = "migration" version = "0.1.0" dependencies = [ + "bql", "common", "glib-sys", + "qemu_macros", "util", ] diff --git a/rust/bql/Cargo.toml b/rust/bql/Cargo.toml index d5177e5..8fd8131 100644 --- a/rust/bql/Cargo.toml +++ b/rust/bql/Cargo.toml @@ -13,7 +13,6 @@ repository.workspace = true rust-version.workspace = true [dependencies] -migration = { path = "../migration" } glib-sys.workspace = true [features] diff --git a/rust/bql/meson.build b/rust/bql/meson.build index 22d7c9b..091372d 100644 --- a/rust/bql/meson.build +++ b/rust/bql/meson.build @@ -37,7 +37,6 @@ _bql_rs = static_library( override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_abi: 'rust', rust_args: _bql_cfg, - link_with: [_migration_rs], dependencies: [glib_sys_rs], ) diff --git a/rust/bql/src/cell.rs b/rust/bql/src/cell.rs index 24ab294..8ade7db 100644 --- a/rust/bql/src/cell.rs +++ b/rust/bql/src/cell.rs @@ -151,8 +151,6 @@ use std::{ ptr::NonNull, }; -use migration::impl_vmstate_transparent; - /// A mutable memory location that is protected by the Big QEMU Lock. /// /// # Memory layout @@ -364,8 +362,6 @@ impl<T: Default> BqlCell<T> { } } -impl_vmstate_transparent!(crate::cell::BqlCell<T> where T: VMState); - /// A mutable memory location with dynamically checked borrow rules, /// protected by the Big QEMU Lock. /// @@ -580,6 +576,23 @@ impl<T> BqlRefCell<T> { } } + /// Returns a mutable reference to the underlying data in this cell, + /// while the owner already has a mutable reference to the cell. + /// + /// # Examples + /// + /// ``` + /// use bql::BqlRefCell; + /// + /// let mut c = BqlRefCell::new(5); + /// + /// *c.get_mut() = 10; + /// ``` + #[inline] + pub const fn get_mut(&mut self) -> &mut T { + self.value.get_mut() + } + /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples @@ -674,8 +687,6 @@ impl<T> From<T> for BqlRefCell<T> { } } -impl_vmstate_transparent!(crate::cell::BqlRefCell<T> where T: VMState); - struct BorrowRef<'b> { borrow: &'b Cell<BorrowFlag>, } diff --git a/rust/hw/char/pl011/src/registers.rs b/rust/hw/char/pl011/src/registers.rs index 0c3a4d7..fa57281 100644 --- a/rust/hw/char/pl011/src/registers.rs +++ b/rust/hw/char/pl011/src/registers.rs @@ -255,6 +255,7 @@ pub enum Mode { #[bitsize(2)] #[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)] +#[allow(clippy::enum_variant_names)] /// `WLEN` Word length, field of [Line Control register](LineControl). /// /// These bits indicate the number of data bits transmitted or received in a diff --git a/rust/hw/timer/hpet/src/fw_cfg.rs b/rust/hw/timer/hpet/src/fw_cfg.rs index e569b57..bb4ea89 100644 --- a/rust/hw/timer/hpet/src/fw_cfg.rs +++ b/rust/hw/timer/hpet/src/fw_cfg.rs @@ -40,7 +40,7 @@ impl HPETFwConfig { assert!(bql::is_locked()); // SAFETY: all accesses go through these methods, which guarantee // that the accesses are protected by the BQL. - let mut fw_cfg = unsafe { *addr_of_mut!(hpet_fw_cfg) }; + let fw_cfg = unsafe { &mut *addr_of_mut!(hpet_fw_cfg) }; if fw_cfg.count == u8::MAX { // first instance @@ -60,7 +60,7 @@ impl HPETFwConfig { assert!(bql::is_locked()); // SAFETY: all accesses go through these methods, which guarantee // that the accesses are protected by the BQL. - let mut fw_cfg = unsafe { *addr_of_mut!(hpet_fw_cfg) }; + let fw_cfg = unsafe { &mut *addr_of_mut!(hpet_fw_cfg) }; fw_cfg.hpet[hpet_id].event_timer_block_id = timer_block_id; fw_cfg.hpet[hpet_id].address = address; diff --git a/rust/meson.build b/rust/meson.build index 6ba075c..76e1069 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -29,8 +29,8 @@ subdir('qemu-macros') subdir('common') subdir('bits') subdir('util') -subdir('migration') subdir('bql') +subdir('migration') subdir('qom') subdir('system') subdir('chardev') diff --git a/rust/migration/Cargo.toml b/rust/migration/Cargo.toml index 94504f3..4154574 100644 --- a/rust/migration/Cargo.toml +++ b/rust/migration/Cargo.toml @@ -13,7 +13,9 @@ repository.workspace = true rust-version.workspace = true [dependencies] +bql = { path = "../bql" } common = { path = "../common" } +qemu_macros = { path = "../qemu-macros" } util = { path = "../util" } glib-sys.workspace = true diff --git a/rust/migration/meson.build b/rust/migration/meson.build index 18be65c..4444947 100644 --- a/rust/migration/meson.build +++ b/rust/migration/meson.build @@ -31,18 +31,19 @@ _migration_rs = static_library( [ 'src/lib.rs', 'src/bindings.rs', + 'src/migratable.rs', 'src/vmstate.rs', ], {'.' : _migration_bindings_inc_rs}, ), override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_abi: 'rust', - link_with: [_util_rs], - dependencies: [common_rs, glib_sys_rs], + link_with: [_util_rs, _bql_rs], + dependencies: [common_rs, glib_sys_rs, qemu_macros], ) migration_rs = declare_dependency(link_with: [_migration_rs], - dependencies: [migration, qemuutil]) + dependencies: [bql_rs, migration, qemuutil]) # Doctests are essentially integration tests, so they need the same dependencies. # Note that running them requires the object files for C code, so place them diff --git a/rust/migration/src/lib.rs b/rust/migration/src/lib.rs index 5f51dde..c9bdf0d 100644 --- a/rust/migration/src/lib.rs +++ b/rust/migration/src/lib.rs @@ -2,5 +2,10 @@ pub mod bindings; +pub use qemu_macros::ToMigrationState; + +pub mod migratable; +pub use migratable::*; + pub mod vmstate; pub use vmstate::*; diff --git a/rust/migration/src/migratable.rs b/rust/migration/src/migratable.rs new file mode 100644 index 0000000..ded6fe8 --- /dev/null +++ b/rust/migration/src/migratable.rs @@ -0,0 +1,442 @@ +// Copyright 2025 Red Hat, Inc. +// Author(s): Paolo Bonzini <pbonzini@redhat.com> +// SPDX-License-Identifier: GPL-2.0-or-later + +use std::{ + fmt, + mem::size_of, + ptr::{self, addr_of, NonNull}, + sync::{Arc, Mutex}, +}; + +use bql::{BqlCell, BqlRefCell}; +use common::Zeroable; + +use crate::{ + bindings, vmstate_fields_ref, vmstate_of, InvalidError, VMState, VMStateDescriptionBuilder, +}; + +/// Enables QEMU migration support even when a type is wrapped with +/// synchronization primitives (like `Mutex`) that the C migration +/// code cannot directly handle. The trait provides methods to +/// extract essential state for migration and restore it after +/// migration completes. +/// +/// On top of extracting data from synchronization wrappers during save +/// and restoring it during load, it's also possible to use `ToMigrationState` +/// to convert runtime representations to migration-safe formats. +/// +/// # Examples +/// +/// ``` +/// use bql::BqlCell; +/// use migration::{InvalidError, ToMigrationState, VMState}; +/// # use migration::VMStateField; +/// +/// # #[derive(Debug, PartialEq, Eq)] +/// struct DeviceState { +/// counter: BqlCell<u32>, +/// enabled: bool, +/// } +/// +/// # #[derive(Debug)] +/// #[derive(Default)] +/// struct DeviceMigrationState { +/// counter: u32, +/// enabled: bool, +/// } +/// +/// # unsafe impl VMState for DeviceMigrationState { +/// # const BASE: VMStateField = ::common::Zeroable::ZERO; +/// # } +/// impl ToMigrationState for DeviceState { +/// type Migrated = DeviceMigrationState; +/// +/// fn snapshot_migration_state( +/// &self, +/// target: &mut Self::Migrated, +/// ) -> Result<(), InvalidError> { +/// target.counter = self.counter.get(); +/// target.enabled = self.enabled; +/// Ok(()) +/// } +/// +/// fn restore_migrated_state_mut( +/// &mut self, +/// source: Self::Migrated, +/// _version_id: u8, +/// ) -> Result<(), InvalidError> { +/// self.counter.set(source.counter); +/// self.enabled = source.enabled; +/// Ok(()) +/// } +/// } +/// # bql::start_test(); +/// # let dev = DeviceState { counter: 10.into(), enabled: true }; +/// # let mig = dev.to_migration_state().unwrap(); +/// # assert!(matches!(*mig, DeviceMigrationState { counter: 10, enabled: true })); +/// # let mut dev2 = DeviceState { counter: 42.into(), enabled: false }; +/// # dev2.restore_migrated_state_mut(*mig, 1).unwrap(); +/// # assert_eq!(dev2, dev); +/// ``` +/// +/// More commonly, the trait is derived through the +/// [`derive(ToMigrationState)`](qemu_macros::ToMigrationState) procedural +/// macro. +pub trait ToMigrationState { + /// The type used to represent the migrated state. + type Migrated: Default + VMState; + + /// Capture the current state into a migration-safe format, failing + /// if the state cannot be migrated. + fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError>; + + /// Restores state from a migrated representation, failing if the + /// state cannot be restored. + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError>; + + /// Convenience method to combine allocation and state capture + /// into a single operation. + fn to_migration_state(&self) -> Result<Box<Self::Migrated>, InvalidError> { + let mut migrated = Box::<Self::Migrated>::default(); + self.snapshot_migration_state(&mut migrated)?; + Ok(migrated) + } +} + +// Implementations for primitive types. Do not use a blanket implementation +// for all Copy types, because [T; N] is Copy if T is Copy; that would conflict +// with the below implementation for arrays. +macro_rules! impl_for_primitive { + ($($t:ty),*) => { + $( + impl ToMigrationState for $t { + type Migrated = Self; + + fn snapshot_migration_state( + &self, + target: &mut Self::Migrated, + ) -> Result<(), InvalidError> { + *target = *self; + Ok(()) + } + + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + _version_id: u8, + ) -> Result<(), InvalidError> { + *self = source; + Ok(()) + } + } + )* + }; +} + +impl_for_primitive!(u8, u16, u32, u64, i8, i16, i32, i64, bool); + +impl<T: ToMigrationState, const N: usize> ToMigrationState for [T; N] +where + [T::Migrated; N]: Default, +{ + type Migrated = [T::Migrated; N]; + + fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { + for (item, target_item) in self.iter().zip(target.iter_mut()) { + item.snapshot_migration_state(target_item)?; + } + Ok(()) + } + + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + for (item, source_item) in self.iter_mut().zip(source) { + item.restore_migrated_state_mut(source_item, version_id)?; + } + Ok(()) + } +} + +impl<T: ToMigrationState> ToMigrationState for Mutex<T> { + type Migrated = T::Migrated; + + fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { + self.lock().unwrap().snapshot_migration_state(target) + } + + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + self.get_mut() + .unwrap() + .restore_migrated_state_mut(source, version_id) + } +} + +impl<T: ToMigrationState> ToMigrationState for BqlRefCell<T> { + type Migrated = T::Migrated; + + fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { + self.borrow().snapshot_migration_state(target) + } + + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + self.get_mut() + .restore_migrated_state_mut(source, version_id) + } +} + +/// Extension trait for types that support migration state restoration +/// through interior mutability. +/// +/// This trait extends [`ToMigrationState`] for types that can restore +/// their state without requiring mutable access. While user structs +/// will generally use `ToMigrationState`, the device will have multiple +/// references and therefore the device struct has to employ an interior +/// mutability wrapper like [`Mutex`] or [`BqlRefCell`]. +/// +/// Anything that implements this trait can in turn be used within +/// [`Migratable<T>`], which makes no assumptions on how to achieve mutable +/// access to the runtime state. +/// +/// # Examples +/// +/// ``` +/// use std::sync::Mutex; +/// +/// use migration::ToMigrationStateShared; +/// +/// let device_state = Mutex::new(42); +/// // Can restore without &mut access +/// device_state.restore_migrated_state(100, 1).unwrap(); +/// assert_eq!(*device_state.lock().unwrap(), 100); +/// ``` +pub trait ToMigrationStateShared: ToMigrationState { + /// Restores state from a migrated representation to an interior-mutable + /// object. Similar to `restore_migrated_state_mut`, but requires a + /// shared reference; therefore it can be used to restore a device's + /// state even though devices have multiple references to them. + fn restore_migrated_state( + &self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError>; +} + +impl<T: ToMigrationStateShared, const N: usize> ToMigrationStateShared for [T; N] +where + [T::Migrated; N]: Default, +{ + fn restore_migrated_state( + &self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + for (item, source_item) in self.iter().zip(source) { + item.restore_migrated_state(source_item, version_id)?; + } + Ok(()) + } +} + +// Arc requires the contained object to be interior-mutable +impl<T: ToMigrationStateShared> ToMigrationState for Arc<T> { + type Migrated = T::Migrated; + + fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), InvalidError> { + (**self).snapshot_migration_state(target) + } + + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + (**self).restore_migrated_state(source, version_id) + } +} + +impl<T: ToMigrationStateShared> ToMigrationStateShared for Arc<T> { + fn restore_migrated_state( + &self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + (**self).restore_migrated_state(source, version_id) + } +} + +// Interior-mutable types. Note how they only require ToMigrationState for +// the inner type! + +impl<T: ToMigrationState> ToMigrationStateShared for Mutex<T> { + fn restore_migrated_state( + &self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + self.lock() + .unwrap() + .restore_migrated_state_mut(source, version_id) + } +} + +impl<T: ToMigrationState> ToMigrationStateShared for BqlRefCell<T> { + fn restore_migrated_state( + &self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), InvalidError> { + self.borrow_mut() + .restore_migrated_state_mut(source, version_id) + } +} + +/// A wrapper that enables QEMU migration for types with shared state. +/// +/// `Migratable<T>` provides a bridge between Rust types that use interior +/// mutability (like `Mutex<T>`) and QEMU's C-based migration infrastructure. +/// It manages the lifecycle of migration state and provides automatic +/// conversion between runtime and migration representations. +/// +/// ``` +/// # use std::sync::Mutex; +/// # use migration::{Migratable, ToMigrationState, VMState, VMStateField}; +/// +/// #[derive(ToMigrationState)] +/// pub struct DeviceRegs { +/// status: u32, +/// } +/// # unsafe impl VMState for DeviceRegsMigration { +/// # const BASE: VMStateField = ::common::Zeroable::ZERO; +/// # } +/// +/// pub struct SomeDevice { +/// // ... +/// registers: Migratable<Mutex<DeviceRegs>>, +/// } +/// ``` +#[repr(C)] +pub struct Migratable<T: ToMigrationStateShared> { + /// Pointer to migration state, valid only during migration operations. + /// C vmstate does not support NULL pointers, so no `Option<Box<>>`. + migration_state: BqlCell<*mut T::Migrated>, + + /// The runtime state that can be accessed during normal operation + runtime_state: T, +} + +impl<T: ToMigrationStateShared> std::ops::Deref for Migratable<T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.runtime_state + } +} + +impl<T: ToMigrationStateShared> std::ops::DerefMut for Migratable<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.runtime_state + } +} + +impl<T: ToMigrationStateShared> Migratable<T> { + /// Creates a new `Migratable` wrapper around the given runtime state. + /// + /// # Returns + /// A new `Migratable` instance ready for use and migration + pub fn new(runtime_state: T) -> Self { + Self { + migration_state: BqlCell::new(ptr::null_mut()), + runtime_state, + } + } + + fn pre_save(&self) -> Result<(), InvalidError> { + let state = self.runtime_state.to_migration_state()?; + self.migration_state.set(Box::into_raw(state)); + Ok(()) + } + + fn post_save(&self) -> Result<(), InvalidError> { + let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) }; + drop(state); + Ok(()) + } + + fn pre_load(&self) -> Result<(), InvalidError> { + self.migration_state + .set(Box::into_raw(Box::<T::Migrated>::default())); + Ok(()) + } + + fn post_load(&self, version_id: u8) -> Result<(), InvalidError> { + let state = unsafe { Box::from_raw(self.migration_state.replace(ptr::null_mut())) }; + self.runtime_state + .restore_migrated_state(*state, version_id) + } +} + +impl<T: ToMigrationStateShared + fmt::Debug> fmt::Debug for Migratable<T> +where + T::Migrated: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut struct_f = f.debug_struct("Migratable"); + struct_f.field("runtime_state", &self.runtime_state); + + let state = NonNull::new(self.migration_state.get()).map(|x| unsafe { x.as_ref() }); + struct_f.field("migration_state", &state); + struct_f.finish() + } +} + +impl<T: ToMigrationStateShared + Default> Default for Migratable<T> { + fn default() -> Self { + Self::new(T::default()) + } +} + +impl<T: 'static + ToMigrationStateShared> Migratable<T> { + const FIELD: bindings::VMStateField = vmstate_of!(Self, migration_state); + + const FIELDS: &[bindings::VMStateField] = vmstate_fields_ref! { + Migratable::<T>::FIELD + }; + + const VMSD: &'static bindings::VMStateDescription = VMStateDescriptionBuilder::<Self>::new() + .version_id(1) + .minimum_version_id(1) + .pre_save(&Self::pre_save) + .pre_load(&Self::pre_load) + .post_save(&Self::post_save) + .post_load(&Self::post_load) + .fields(Self::FIELDS) + .build() + .as_ref(); +} + +unsafe impl<T: 'static + ToMigrationStateShared> VMState for Migratable<T> { + const BASE: bindings::VMStateField = { + bindings::VMStateField { + vmsd: addr_of!(*Self::VMSD), + size: size_of::<Self>(), + flags: bindings::VMStateFlags::VMS_STRUCT, + ..Zeroable::ZERO + } + }; +} diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs index e04b19b..42e5df8d 100644 --- a/rust/migration/src/vmstate.rs +++ b/rust/migration/src/vmstate.rs @@ -72,6 +72,7 @@ macro_rules! call_func_with_field { ($func:expr, $typ:ty, $($field:tt).+) => { $func(loop { #![allow(unreachable_code)] + #![allow(unused_variables)] const fn phantom__<T>(_: &T) -> ::core::marker::PhantomData<T> { ::core::marker::PhantomData } // Unreachable code is exempt from checks on uninitialized values. // Use that trick to infer the type of this PhantomData. @@ -275,6 +276,8 @@ macro_rules! impl_vmstate_transparent { }; } +impl_vmstate_transparent!(bql::BqlCell<T> where T: VMState); +impl_vmstate_transparent!(bql::BqlRefCell<T> where T: VMState); impl_vmstate_transparent!(std::cell::Cell<T> where T: VMState); impl_vmstate_transparent!(std::cell::UnsafeCell<T> where T: VMState); impl_vmstate_transparent!(std::pin::Pin<T> where T: VMState); @@ -293,6 +296,25 @@ macro_rules! impl_vmstate_bitsized { as ::bilge::prelude::Number>::UnderlyingType as $crate::vmstate::VMState>::VARRAY_FLAG; } + + impl $crate::migratable::ToMigrationState for $type { + type Migrated = <<$type as ::bilge::prelude::Bitsized>::ArbitraryInt + as ::bilge::prelude::Number>::UnderlyingType; + + fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), $crate::InvalidError> { + *target = Self::Migrated::from(*self); + Ok(()) + } + + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + version_id: u8, + ) -> Result<(), $crate::InvalidError> { + *self = Self::from(source); + Ok(()) + } + } }; } @@ -411,20 +433,31 @@ macro_rules! vmstate_exist_fn { }}; } +/// Add a terminator to the fields in the arguments, and return +/// a reference to the resulting array of values. +#[macro_export] +macro_rules! vmstate_fields_ref { + ($($field:expr),*$(,)*) => { + &[ + $($field),*, + $crate::bindings::VMStateField { + flags: $crate::bindings::VMStateFlags::VMS_END, + ..::common::zeroable::Zeroable::ZERO + } + ] + } +} + /// Helper macro to declare a list of /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and return /// a pointer to the array of values it created. #[macro_export] macro_rules! vmstate_fields { ($($field:expr),*$(,)*) => {{ - static _FIELDS: &[$crate::bindings::VMStateField] = &[ + static _FIELDS: &[$crate::bindings::VMStateField] = $crate::vmstate_fields_ref!( $($field),*, - $crate::bindings::VMStateField { - flags: $crate::bindings::VMStateFlags::VMS_END, - ..::common::zeroable::Zeroable::ZERO - } - ]; - _FIELDS.as_ptr() + ); + _FIELDS }} } @@ -469,33 +502,21 @@ macro_rules! impl_vmstate_struct { }; } -/// A transparent wrapper type for the `subsections` field of -/// [`VMStateDescription`]. -/// -/// This is necessary to be able to declare subsection descriptions as statics, -/// because the only way to implement `Sync` for a foreign type (and `*const` -/// pointers are foreign types in Rust) is to create a wrapper struct and -/// `unsafe impl Sync` for it. -/// -/// This struct is used in the -/// [`vm_state_subsections`](crate::vmstate_subsections) macro implementation. -#[repr(transparent)] -pub struct VMStateSubsectionsWrapper(pub &'static [*const crate::bindings::VMStateDescription]); - -unsafe impl Sync for VMStateSubsectionsWrapper {} +/// The type returned by [`vmstate_subsections!`](crate::vmstate_subsections). +pub type VMStateSubsections = &'static [Option<&'static crate::bindings::VMStateDescription>]; /// Helper macro to declare a list of subsections ([`VMStateDescription`]) /// into a static and return a pointer to the array of pointers it created. #[macro_export] macro_rules! vmstate_subsections { ($($subsection:expr),*$(,)*) => {{ - static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = $crate::vmstate::VMStateSubsectionsWrapper(&[ + static _SUBSECTIONS: $crate::vmstate::VMStateSubsections = &[ $({ static _SUBSECTION: $crate::bindings::VMStateDescription = $subsection.get(); - ::core::ptr::addr_of!(_SUBSECTION) + Some(&_SUBSECTION) }),*, - ::core::ptr::null() - ]); + None, + ]; &_SUBSECTIONS }} } @@ -676,14 +697,21 @@ impl<T> VMStateDescriptionBuilder<T> { } #[must_use] - pub const fn fields(mut self, fields: *const VMStateField) -> Self { - self.0.fields = fields; + pub const fn fields(mut self, fields: &'static [VMStateField]) -> Self { + if fields[fields.len() - 1].flags.0 != VMStateFlags::VMS_END.0 { + panic!("fields are not terminated, use vmstate_fields!"); + } + self.0.fields = fields.as_ptr(); self } #[must_use] - pub const fn subsections(mut self, subs: &'static VMStateSubsectionsWrapper) -> Self { - self.0.subsections = subs.0.as_ptr(); + pub const fn subsections(mut self, subs: &'static VMStateSubsections) -> Self { + if subs[subs.len() - 1].is_some() { + panic!("subsections are not terminated, use vmstate_subsections!"); + } + let subs: *const Option<&bindings::VMStateDescription> = subs.as_ptr(); + self.0.subsections = subs.cast::<*const bindings::VMStateDescription>(); self } diff --git a/rust/qemu-macros/src/lib.rs b/rust/qemu-macros/src/lib.rs index 3e21b67..50239f2 100644 --- a/rust/qemu-macros/src/lib.rs +++ b/rust/qemu-macros/src/lib.rs @@ -13,9 +13,13 @@ use syn::{ Attribute, Data, DeriveInput, Error, Field, Fields, FieldsUnnamed, Ident, Meta, Path, Token, Variant, }; + mod bits; use bits::BitsConstInternal; +mod migration_state; +use migration_state::MigrationStateDerive; + #[cfg(test)] mod tests; @@ -401,7 +405,98 @@ pub fn bits_const_internal(ts: TokenStream) -> TokenStream { let ts = proc_macro2::TokenStream::from(ts); let mut it = ts.into_iter(); - BitsConstInternal::parse(&mut it) + let out = BitsConstInternal::parse(&mut it).unwrap_or_else(syn::Error::into_compile_error); + + // https://github.com/rust-lang/rust-clippy/issues/15852 + quote! { + { + #[allow(clippy::double_parens)] + #out + } + } + .into() +} + +/// Derive macro for generating migration state structures and trait +/// implementations. +/// +/// This macro generates a migration state struct and implements the +/// `ToMigrationState` trait for the annotated struct, enabling state +/// serialization and restoration. Note that defining a `VMStateDescription` +/// for the migration state struct is left to the user. +/// +/// # Container attributes +/// +/// The following attributes can be applied to the struct: +/// +/// - `#[migration_state(rename = CustomName)]` - Customizes the name of the +/// generated migration struct. By default, the generated struct is named +/// `{OriginalName}Migration`. +/// +/// # Field attributes +/// +/// The following attributes can be applied to individual fields: +/// +/// - `#[migration_state(omit)]` - Excludes the field from the migration state +/// entirely. +/// +/// - `#[migration_state(into(Type))]` - Converts the field using `.into()` +/// during both serialization and restoration. +/// +/// - `#[migration_state(try_into(Type))]` - Converts the field using +/// `.try_into()` during both serialization and restoration. Returns +/// `InvalidError` on conversion failure. +/// +/// - `#[migration_state(clone)]` - Clones the field value. +/// +/// Fields without any attributes use `ToMigrationState` recursively; note that +/// this is a simple copy for types that implement `Copy`. +/// +/// # Attribute compatibility +/// +/// - `omit` cannot be used with any other attributes +/// - only one of `into(Type)`, `try_into(Type)` can be used, but they can be +/// coupled with `clone`. +/// +/// # Examples +/// +/// Basic usage: +/// ```ignore +/// #[derive(ToMigrationState)] +/// struct MyStruct { +/// field1: u32, +/// field2: Timer, +/// } +/// ``` +/// +/// With attributes: +/// ```ignore +/// #[derive(ToMigrationState)] +/// #[migration_state(rename = CustomMigration)] +/// struct MyStruct { +/// #[migration_state(omit)] +/// runtime_field: u32, +/// +/// #[migration_state(clone)] +/// shared_data: String, +/// +/// #[migration_state(into(Cow<'static, str>), clone)] +/// converted_field: String, +/// +/// #[migration_state(try_into(i8))] +/// fallible_field: u32, +/// +/// // Default: use ToMigrationState trait recursively +/// nested_field: NestedStruct, +/// +/// // Primitive types have a default implementation of ToMigrationState +/// simple_field: u32, +/// } +/// ``` +#[proc_macro_derive(ToMigrationState, attributes(migration_state))] +pub fn derive_to_migration_state(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + MigrationStateDerive::expand(input) .unwrap_or_else(syn::Error::into_compile_error) .into() } diff --git a/rust/qemu-macros/src/migration_state.rs b/rust/qemu-macros/src/migration_state.rs new file mode 100644 index 0000000..5edf0ef --- /dev/null +++ b/rust/qemu-macros/src/migration_state.rs @@ -0,0 +1,298 @@ +use std::borrow::Cow; + +use proc_macro2::TokenStream; +use quote::{format_ident, quote, ToTokens}; +use syn::{spanned::Spanned, DeriveInput, Error, Field, Ident, Result, Type}; + +use crate::get_fields; + +#[derive(Debug, Default)] +enum ConversionMode { + #[default] + None, + Omit, + Into(Type), + TryInto(Type), + ToMigrationState, +} + +impl ConversionMode { + fn target_type(&self, original_type: &Type) -> TokenStream { + match self { + ConversionMode::Into(ty) | ConversionMode::TryInto(ty) => ty.to_token_stream(), + ConversionMode::ToMigrationState => { + quote! { <#original_type as ToMigrationState>::Migrated } + } + _ => original_type.to_token_stream(), + } + } +} + +#[derive(Debug, Default)] +struct ContainerAttrs { + rename: Option<Ident>, +} + +impl ContainerAttrs { + fn parse_from(&mut self, attrs: &[syn::Attribute]) -> Result<()> { + use attrs::{set, with, Attrs}; + Attrs::new() + .once("rename", with::eq(set::parse(&mut self.rename))) + .parse_attrs("migration_state", attrs)?; + Ok(()) + } + + fn parse(attrs: &[syn::Attribute]) -> Result<Self> { + let mut container_attrs = Self::default(); + container_attrs.parse_from(attrs)?; + Ok(container_attrs) + } +} + +#[derive(Debug, Default)] +struct FieldAttrs { + conversion: ConversionMode, + clone: bool, +} + +impl FieldAttrs { + fn parse_from(&mut self, attrs: &[syn::Attribute]) -> Result<()> { + let mut omit_flag = false; + let mut into_type: Option<Type> = None; + let mut try_into_type: Option<Type> = None; + + use attrs::{set, with, Attrs}; + Attrs::new() + .once("omit", set::flag(&mut omit_flag)) + .once("into", with::paren(set::parse(&mut into_type))) + .once("try_into", with::paren(set::parse(&mut try_into_type))) + .once("clone", set::flag(&mut self.clone)) + .parse_attrs("migration_state", attrs)?; + + self.conversion = match (omit_flag, into_type, try_into_type, self.clone) { + // Valid combinations of attributes first... + (true, None, None, false) => ConversionMode::Omit, + (false, Some(ty), None, _) => ConversionMode::Into(ty), + (false, None, Some(ty), _) => ConversionMode::TryInto(ty), + (false, None, None, true) => ConversionMode::None, // clone without conversion + (false, None, None, false) => ConversionMode::ToMigrationState, // default behavior + + // ... then the error cases + (true, _, _, _) => { + return Err(Error::new( + attrs[0].span(), + "ToMigrationState: omit cannot be used with other attributes", + )); + } + (_, Some(_), Some(_), _) => { + return Err(Error::new( + attrs[0].span(), + "ToMigrationState: into and try_into attributes cannot be used together", + )); + } + }; + + Ok(()) + } + + fn parse(attrs: &[syn::Attribute]) -> Result<Self> { + let mut field_attrs = Self::default(); + field_attrs.parse_from(attrs)?; + Ok(field_attrs) + } +} + +#[derive(Debug)] +struct MigrationStateField { + name: Ident, + original_type: Type, + attrs: FieldAttrs, +} + +impl MigrationStateField { + fn maybe_clone(&self, mut value: TokenStream) -> TokenStream { + if self.attrs.clone { + value = quote! { #value.clone() }; + } + value + } + + fn generate_migration_state_field(&self) -> TokenStream { + let name = &self.name; + let field_type = self.attrs.conversion.target_type(&self.original_type); + + quote! { + pub #name: #field_type, + } + } + + fn generate_snapshot_field(&self) -> TokenStream { + let name = &self.name; + let value = self.maybe_clone(quote! { self.#name }); + + match &self.attrs.conversion { + ConversionMode::Omit => { + unreachable!("Omitted fields are filtered out during processing") + } + ConversionMode::None => quote! { + target.#name = #value; + }, + ConversionMode::Into(_) => quote! { + target.#name = #value.into(); + }, + ConversionMode::TryInto(_) => quote! { + target.#name = #value.try_into().map_err(|_| migration::InvalidError)?; + }, + ConversionMode::ToMigrationState => quote! { + self.#name.snapshot_migration_state(&mut target.#name)?; + }, + } + } + + fn generate_restore_field(&self) -> TokenStream { + let name = &self.name; + + match &self.attrs.conversion { + ConversionMode::Omit => { + unreachable!("Omitted fields are filtered out during processing") + } + ConversionMode::None => quote! { + self.#name = #name; + }, + ConversionMode::Into(_) => quote! { + self.#name = #name.into(); + }, + ConversionMode::TryInto(_) => quote! { + self.#name = #name.try_into().map_err(|_| migration::InvalidError)?; + }, + ConversionMode::ToMigrationState => quote! { + self.#name.restore_migrated_state_mut(#name, _version_id)?; + }, + } + } +} + +#[derive(Debug)] +pub struct MigrationStateDerive { + input: DeriveInput, + fields: Vec<MigrationStateField>, + container_attrs: ContainerAttrs, +} + +impl MigrationStateDerive { + fn parse(input: DeriveInput) -> Result<Self> { + let container_attrs = ContainerAttrs::parse(&input.attrs)?; + let fields = get_fields(&input, "ToMigrationState")?; + let fields = Self::process_fields(fields)?; + + Ok(Self { + input, + fields, + container_attrs, + }) + } + + fn process_fields( + fields: &syn::punctuated::Punctuated<Field, syn::token::Comma>, + ) -> Result<Vec<MigrationStateField>> { + let processed = fields + .iter() + .map(|field| { + let attrs = FieldAttrs::parse(&field.attrs)?; + Ok((field, attrs)) + }) + .collect::<Result<Vec<_>>>()? + .into_iter() + .filter(|(_, attrs)| !matches!(attrs.conversion, ConversionMode::Omit)) + .map(|(field, attrs)| MigrationStateField { + name: field.ident.as_ref().unwrap().clone(), + original_type: field.ty.clone(), + attrs, + }) + .collect(); + + Ok(processed) + } + + fn migration_state_name(&self) -> Cow<'_, Ident> { + match &self.container_attrs.rename { + Some(rename) => Cow::Borrowed(rename), + None => Cow::Owned(format_ident!("{}Migration", &self.input.ident)), + } + } + + fn generate_migration_state_struct(&self) -> TokenStream { + let name = self.migration_state_name(); + let fields = self + .fields + .iter() + .map(MigrationStateField::generate_migration_state_field); + + quote! { + #[derive(Default)] + pub struct #name { + #(#fields)* + } + } + } + + fn generate_snapshot_migration_state(&self) -> TokenStream { + let fields = self + .fields + .iter() + .map(MigrationStateField::generate_snapshot_field); + + quote! { + fn snapshot_migration_state(&self, target: &mut Self::Migrated) -> Result<(), migration::InvalidError> { + #(#fields)* + Ok(()) + } + } + } + + fn generate_restore_migrated_state(&self) -> TokenStream { + let names: Vec<_> = self.fields.iter().map(|f| &f.name).collect(); + let fields = self + .fields + .iter() + .map(MigrationStateField::generate_restore_field); + + // version_id could be used or not depending on conversion attributes + quote! { + #[allow(clippy::used_underscore_binding)] + fn restore_migrated_state_mut(&mut self, source: Self::Migrated, _version_id: u8) -> Result<(), migration::InvalidError> { + let Self::Migrated { #(#names),* } = source; + #(#fields)* + Ok(()) + } + } + } + + fn generate(&self) -> TokenStream { + let struct_name = &self.input.ident; + let generics = &self.input.generics; + + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let name = self.migration_state_name(); + let migration_state_struct = self.generate_migration_state_struct(); + let snapshot_impl = self.generate_snapshot_migration_state(); + let restore_impl = self.generate_restore_migrated_state(); + + quote! { + #migration_state_struct + + impl #impl_generics ToMigrationState for #struct_name #ty_generics #where_clause { + type Migrated = #name; + + #snapshot_impl + + #restore_impl + } + } + } + + pub fn expand(input: DeriveInput) -> Result<TokenStream> { + let tokens = Self::parse(input)?.generate(); + Ok(tokens) + } +} diff --git a/rust/qemu-macros/src/tests.rs b/rust/qemu-macros/src/tests.rs index ac998d2..6569141 100644 --- a/rust/qemu-macros/src/tests.rs +++ b/rust/qemu-macros/src/tests.rs @@ -7,7 +7,7 @@ use quote::quote; use super::*; macro_rules! derive_compile_fail { - ($derive_fn:ident, $input:expr, $($error_msg:expr),+ $(,)?) => {{ + ($derive_fn:path, $input:expr, $($error_msg:expr),+ $(,)?) => {{ let input: proc_macro2::TokenStream = $input; let error_msg = &[$( quote! { ::core::compile_error! { $error_msg } } ),*]; let derive_fn: fn(input: syn::DeriveInput) -> Result<proc_macro2::TokenStream, syn::Error> = @@ -24,7 +24,7 @@ macro_rules! derive_compile_fail { } macro_rules! derive_compile { - ($derive_fn:ident, $input:expr, $($expected:tt)*) => {{ + ($derive_fn:path, $input:expr, $($expected:tt)*) => {{ let input: proc_macro2::TokenStream = $input; let expected: proc_macro2::TokenStream = $($expected)*; let derive_fn: fn(input: syn::DeriveInput) -> Result<proc_macro2::TokenStream, syn::Error> = @@ -345,3 +345,112 @@ fn test_derive_tryinto() { } ); } + +#[test] +fn test_derive_to_migration_state() { + derive_compile_fail!( + MigrationStateDerive::expand, + quote! { + struct MyStruct { + #[migration_state(omit, clone)] + bad: u32, + } + }, + "ToMigrationState: omit cannot be used with other attributes" + ); + derive_compile_fail!( + MigrationStateDerive::expand, + quote! { + struct MyStruct { + #[migration_state(into)] + bad: u32, + } + }, + "unexpected end of input, expected parentheses" + ); + derive_compile_fail!( + MigrationStateDerive::expand, + quote! { + struct MyStruct { + #[migration_state(into(String), try_into(String))] + bad: &'static str, + } + }, + "ToMigrationState: into and try_into attributes cannot be used together" + ); + derive_compile!( + MigrationStateDerive::expand, + quote! { + #[migration_state(rename = CustomMigration)] + struct MyStruct { + #[migration_state(omit)] + runtime_field: u32, + + #[migration_state(clone)] + shared_data: String, + + #[migration_state(into(Cow<'static, str>), clone)] + converted_field: String, + + #[migration_state(try_into(i8))] + fallible_field: u32, + + nested_field: NestedStruct, + simple_field: u32, + } + }, + quote! { + #[derive(Default)] + pub struct CustomMigration { + pub shared_data: String, + pub converted_field: Cow<'static, str>, + pub fallible_field: i8, + pub nested_field: <NestedStruct as ToMigrationState>::Migrated, + pub simple_field: <u32 as ToMigrationState>::Migrated, + } + impl ToMigrationState for MyStruct { + type Migrated = CustomMigration; + fn snapshot_migration_state( + &self, + target: &mut Self::Migrated + ) -> Result<(), migration::InvalidError> { + target.shared_data = self.shared_data.clone(); + target.converted_field = self.converted_field.clone().into(); + target.fallible_field = self + .fallible_field + .try_into() + .map_err(|_| migration::InvalidError)?; + self.nested_field + .snapshot_migration_state(&mut target.nested_field)?; + self.simple_field + .snapshot_migration_state(&mut target.simple_field)?; + Ok(()) + } + #[allow(clippy::used_underscore_binding)] + fn restore_migrated_state_mut( + &mut self, + source: Self::Migrated, + _version_id: u8 + ) -> Result<(), migration::InvalidError> { + let Self::Migrated { + shared_data, + converted_field, + fallible_field, + nested_field, + simple_field + } = source; + self.shared_data = shared_data; + self.converted_field = converted_field.into(); + self.fallible_field = fallible_field + .try_into() + .map_err(|_| migration::InvalidError)?; + self.nested_field + .restore_migrated_state_mut(nested_field, _version_id)?; + self.simple_field + .restore_migrated_state_mut(simple_field, _version_id)?; + Ok(()) + } + } + } + ); +} diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 4f769d6..0d57081 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -2123,7 +2123,7 @@ static int kvm_arch_put_sve(CPUState *cs) return 0; } -int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) +int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { uint64_t val; uint32_t fpr; diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ab18de8..455caff 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1397,7 +1397,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .type = CPUID_FEATURE_WORD, .feat_names = { "no-nested-data-bp", "fs-gs-base-ns", "lfence-always-serializing", NULL, - NULL, NULL, "null-sel-clr-base", NULL, + NULL, "verw-clear", "null-sel-clr-base", NULL, "auto-ibrs", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1415,6 +1415,22 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { .tcg_features = 0, .unmigratable_flags = 0, }, + [FEAT_8000_0021_ECX] = { + .type = CPUID_FEATURE_WORD, + .feat_names = { + NULL, "tsa-sq-no", "tsa-l1-no", NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + }, + .cpuid = { .eax = 0x80000021, .reg = R_ECX, }, + .tcg_features = 0, + .unmigratable_flags = 0, + }, [FEAT_8000_0022_EAX] = { .type = CPUID_FEATURE_WORD, .feat_names = { @@ -8526,6 +8542,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, *eax = *ebx = *ecx = *edx = 0; *eax = env->features[FEAT_8000_0021_EAX]; *ebx = env->features[FEAT_8000_0021_EBX]; + *ecx = env->features[FEAT_8000_0021_ECX]; break; case 0x80000022: *eax = *ebx = *ecx = *edx = 0; @@ -8632,7 +8649,11 @@ static void x86_cpu_reset_hold(Object *obj, ResetType type) env->idt.limit = 0xffff; env->gdt.limit = 0xffff; +#if defined(CONFIG_USER_ONLY) + env->ldt.limit = 0; +#else env->ldt.limit = 0xffff; +#endif env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT); env->tr.limit = 0xffff; env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT); diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 8b7c173..ce94886 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -643,6 +643,7 @@ typedef enum FeatureWord { FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */ FEAT_8000_0021_EAX, /* CPUID[8000_0021].EAX */ FEAT_8000_0021_EBX, /* CPUID[8000_0021].EBX */ + FEAT_8000_0021_ECX, /* CPUID[8000_0021].ECX */ FEAT_8000_0022_EAX, /* CPUID[8000_0022].EAX */ FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */ FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */ @@ -1103,6 +1104,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); #define CPUID_8000_0021_EAX_FS_GS_BASE_NS (1U << 1) /* LFENCE is always serializing */ #define CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING (1U << 2) +/* Memory form of VERW mitigates TSA */ +#define CPUID_8000_0021_EAX_VERW_CLEAR (1U << 5) /* Null Selector Clears Base */ #define CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE (1U << 6) /* Automatic IBRS */ @@ -1126,6 +1129,11 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); */ #define CPUID_8000_0021_EBX_RAPSIZE (8U << 16) +/* CPU is not vulnerable TSA SA-SQ attack */ +#define CPUID_8000_0021_ECX_TSA_SQ_NO (1U << 1) +/* CPU is not vulnerable TSA SA-L1 attack */ +#define CPUID_8000_0021_ECX_TSA_L1_NO (1U << 2) + /* Performance Monitoring Version 2 */ #define CPUID_8000_0022_EAX_PERFMON_V2 (1U << 0) diff --git a/target/i386/helper.c b/target/i386/helper.c index 651041c..72b2e19 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -621,6 +621,10 @@ void do_cpu_init(X86CPU *cpu) void do_cpu_sipi(X86CPU *cpu) { + CPUX86State *env = &cpu->env; + if (env->hflags & HF_SMM_MASK) { + return; + } apic_sipi(cpu->apic_state); } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index db40caa..309f043 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -653,6 +653,23 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index) must_be_one = (uint32_t)value; can_be_one = (uint32_t)(value >> 32); return can_be_one & ~must_be_one; + case MSR_IA32_ARCH_CAPABILITIES: + /* + * Special handling for fb-clear bit in ARCH_CAPABILITIES MSR. + * KVM will only report the bit if it is enabled in the host, + * but, for live migration capability purposes, we want to + * expose the bit to the guest even if it is disabled in the + * host, as long as the host itself is not vulnerable to + * the issue that the fb-clear bit is meant to mitigate. + */ + if ((value & MSR_ARCH_CAP_MDS_NO) && + (value & MSR_ARCH_CAP_TAA_NO) && + (value & MSR_ARCH_CAP_SBDR_SSDP_NO) && + (value & MSR_ARCH_CAP_FBSDP_NO) && + (value & MSR_ARCH_CAP_PSDP_NO)) { + value |= MSR_ARCH_CAP_FB_CLEAR; + } + return value; default: return value; @@ -3907,7 +3924,7 @@ static void kvm_init_msrs(X86CPU *cpu) assert(kvm_buf_set_msrs(cpu) == 0); } -static int kvm_put_msrs(X86CPU *cpu, int level) +static int kvm_put_msrs(X86CPU *cpu, KvmPutState level) { CPUX86State *env = &cpu->env; int i; @@ -5027,7 +5044,7 @@ static int kvm_get_apic(X86CPU *cpu) return 0; } -static int kvm_put_vcpu_events(X86CPU *cpu, int level) +static int kvm_put_vcpu_events(X86CPU *cpu, KvmPutState level) { CPUState *cs = CPU(cpu); CPUX86State *env = &cpu->env; @@ -5270,7 +5287,7 @@ static int kvm_get_nested_state(X86CPU *cpu) return ret; } -int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp) +int kvm_arch_put_registers(CPUState *cpu, KvmPutState level, Error **errp) { X86CPU *x86_cpu = X86_CPU(cpu); int ret; diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index 5103865..a50f57d 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -1541,7 +1541,7 @@ static void decode_group4_5(DisasContext *s, CPUX86State *env, X86OpEntry *entry [0x0b] = X86_OP_ENTRYr(CALLF_m, M,p), [0x0c] = X86_OP_ENTRYr(JMP_m, E,f64, zextT0), [0x0d] = X86_OP_ENTRYr(JMPF_m, M,p), - [0x0e] = X86_OP_ENTRYr(PUSH, E,f64), + [0x0e] = X86_OP_ENTRYr(PUSH, E,d64), }; int w = (*b & 1); diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 071f3fb..f49fe85 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -456,7 +456,7 @@ static void switch_tss_ra(CPUX86State *env, int tss_selector, new_segs[i] = access_ldw(&new, tss_base + (0x48 + i * 4)); } new_ldt = access_ldw(&new, tss_base + 0x60); - new_trap = access_ldl(&new, tss_base + 0x64); + new_trap = access_ldw(&new, tss_base + 0x64) & 1; } else { /* 16 bit */ new_cr3 = 0; diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c index 50040f6..f622b5d 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -592,7 +592,8 @@ static bool get_physical_address(CPUX86State *env, vaddr addr, if (sext != 0 && sext != -1) { *err = (TranslateFault){ .exception_index = EXCP0D_GPF, - .cr2 = addr, + /* non-canonical #GP doesn't change CR2 */ + .cr2 = env->cr[2], }; return false; } diff --git a/target/i386/tcg/system/seg_helper.c b/target/i386/tcg/system/seg_helper.c index 38072e5..8c7856b 100644 --- a/target/i386/tcg/system/seg_helper.c +++ b/target/i386/tcg/system/seg_helper.c @@ -182,6 +182,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request) apic_poll_irq(cpu->apic_state); break; case CPU_INTERRUPT_SIPI: + cpu_reset_interrupt(cs, CPU_INTERRUPT_SIPI); do_cpu_sipi(cpu); break; case CPU_INTERRUPT_SMI: diff --git a/target/i386/tcg/system/smm_helper.c b/target/i386/tcg/system/smm_helper.c index 251eb78..fb028a8 100644 --- a/target/i386/tcg/system/smm_helper.c +++ b/target/i386/tcg/system/smm_helper.c @@ -168,7 +168,7 @@ void do_smm_enter(X86CPU *cpu) env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK)); cpu_x86_update_cr4(env, 0); - env->dr[7] = 0x00000400; + helper_set_dr(env, 7, 0x00000400); cpu_x86_load_seg_cache(env, R_CS, (env->smbase >> 4) & 0xffff, env->smbase, 0xffffffff, @@ -233,8 +233,8 @@ void helper_rsm(CPUX86State *env) env->eip = x86_ldq_phys(cs, sm_state + 0x7f78); cpu_load_eflags(env, x86_ldl_phys(cs, sm_state + 0x7f70), ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); - env->dr[6] = x86_ldl_phys(cs, sm_state + 0x7f68); - env->dr[7] = x86_ldl_phys(cs, sm_state + 0x7f60); + helper_set_dr(env, 6, x86_ldl_phys(cs, sm_state + 0x7f68)); + helper_set_dr(env, 7, x86_ldl_phys(cs, sm_state + 0x7f60)); cpu_x86_update_cr4(env, x86_ldl_phys(cs, sm_state + 0x7f48)); cpu_x86_update_cr3(env, x86_ldq_phys(cs, sm_state + 0x7f50)); @@ -268,8 +268,8 @@ void helper_rsm(CPUX86State *env) env->regs[R_EDX] = x86_ldl_phys(cs, sm_state + 0x7fd8); env->regs[R_ECX] = x86_ldl_phys(cs, sm_state + 0x7fd4); env->regs[R_EAX] = x86_ldl_phys(cs, sm_state + 0x7fd0); - env->dr[6] = x86_ldl_phys(cs, sm_state + 0x7fcc); - env->dr[7] = x86_ldl_phys(cs, sm_state + 0x7fc8); + helper_set_dr(env, 6, x86_ldl_phys(cs, sm_state + 0x7fcc)); + helper_set_dr(env, 7, x86_ldl_phys(cs, sm_state + 0x7fc8)); env->tr.selector = x86_ldl_phys(cs, sm_state + 0x7fc4) & 0xffff; env->tr.base = x86_ldl_phys(cs, sm_state + 0x7f64); diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index e5ea2db..4e4f4e7 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -325,7 +325,7 @@ static int kvm_loongarch_get_csr(CPUState *cs) return ret; } -static int kvm_loongarch_put_csr(CPUState *cs, int level) +static int kvm_loongarch_put_csr(CPUState *cs, KvmPutState level) { int ret = 0; CPULoongArchState *env = cpu_env(cs); @@ -763,7 +763,7 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp) return ret; } -int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) +int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { int ret; static int once; diff --git a/target/mips/kvm.c b/target/mips/kvm.c index 450947c..912cd5d 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -590,7 +590,7 @@ static void kvm_mips_update_state(void *opaque, bool running, RunState state) } } -static int kvm_mips_put_fpu_registers(CPUState *cs, int level) +static int kvm_mips_put_fpu_registers(CPUState *cs, KvmPutState level) { CPUMIPSState *env = cpu_env(cs); int err, ret = 0; @@ -749,7 +749,7 @@ static int kvm_mips_get_fpu_registers(CPUState *cs) } -static int kvm_mips_put_cp0_registers(CPUState *cs, int level) +static int kvm_mips_put_cp0_registers(CPUState *cs, KvmPutState level) { CPUMIPSState *env = cpu_env(cs); int err, ret = 0; @@ -1177,7 +1177,7 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) return ret; } -int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) +int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { CPUMIPSState *env = cpu_env(cs); struct kvm_regs regs; diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 2521ff6..cd60893 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -907,7 +907,7 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu) return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs); } -int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) +int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { PowerPCCPU *cpu = POWERPC_CPU(cs); CPUPPCState *env = &cpu->env; diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 187c2c9..75ca3fb 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1369,7 +1369,7 @@ int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state) return 0; } -int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) +int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { int ret = 0; diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 491cc5f..916dac1 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -468,7 +468,7 @@ static int can_sync_regs(CPUState *cs, int regs) #define KVM_SYNC_REQUIRED_REGS (KVM_SYNC_GPRS | KVM_SYNC_ACRS | \ KVM_SYNC_CRS | KVM_SYNC_PREFIX) -int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) +int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) { CPUS390XState *env = cpu_env(cs); struct kvm_fpu fpu = {}; diff --git a/tests/functional/aarch64/test_aspeed_ast2700.py b/tests/functional/aarch64/test_aspeed_ast2700.py index a3db267..0ced1a2 100755 --- a/tests/functional/aarch64/test_aspeed_ast2700.py +++ b/tests/functional/aarch64/test_aspeed_ast2700.py @@ -37,26 +37,21 @@ class AST2x00MachineSDK(QemuSystemTest): wait_for_console_pattern(self, 'done') wait_for_console_pattern(self, 'Jumping to BL31 (Trusted Firmware-A)') - def verify_openbmc_boot_and_login(self, name): + def verify_openbmc_boot_start(self): wait_for_console_pattern(self, 'U-Boot 2023.10') wait_for_console_pattern(self, '## Loading kernel from FIT Image') - wait_for_console_pattern(self, 'Starting kernel ...') + wait_for_console_pattern(self, 'Linux version ') + + def verify_openbmc_boot_and_login(self, name): + self.verify_openbmc_boot_start() wait_for_console_pattern(self, f'{name} login:') exec_command_and_wait_for_pattern(self, 'root', 'Password:') exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') - ASSET_SDK_V906_AST2700 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-a0-default-obmc.tar.gz', - '7247b6f19dbfb700686f8d9f723ac23f3eb229226c0589cb9b06b80d1b61f3cb') - - ASSET_SDK_V906_AST2700A1 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-default-obmc.tar.gz', - 'f1d53e0be8a404ecce3e105f72bc50fa4e090ad13160ffa91b10a6e0233a9dc6') - - ASSET_SDK_V907_AST2700A1_VBOOROM = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.07/ast2700-default-obmc.tar.gz', - '6e9e0c4b13e0f26040eca3f4a7f17cf09fc0f5c37c820500ff79370cc3c44add') + ASSET_SDK_V908_AST2700A1 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.08/ast2700-default-obmc.tar.gz', + 'eac3dc409b7ea3cd4b03d4792d3cebd469792ad893cb51e1d15f0fc20bd1e2cd') def do_ast2700_i2c_test(self): exec_command_and_wait_for_pattern(self, @@ -69,6 +64,19 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '18000') + def do_ast2700_pcie_test(self): + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:00:00.0', + '0002:00:00.0 PCI bridge: ' + 'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge') + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:01:00.0', + '0002:01:00.0 Ethernet controller: ' + 'Intel Corporation 82574L Gigabit Network Connection') + exec_command_and_wait_for_pattern(self, + 'ip addr show dev eth2', + 'inet 10.0.2.15/24') + def start_ast2700_test(self, name): num_cpu = 4 uboot_size = os.path.getsize(self.scratch_file(name, @@ -115,30 +123,28 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc')) - def test_aarch64_ast2700a0_evb_sdk_v09_06(self): - self.set_machine('ast2700a0-evb') - - self.archive_extract(self.ASSET_SDK_V906_AST2700) - self.start_ast2700_test('ast2700-a0-default') - self.verify_openbmc_boot_and_login('ast2700-a0-default') - self.do_ast2700_i2c_test() - - def test_aarch64_ast2700a1_evb_sdk_v09_06(self): + def test_aarch64_ast2700a1_evb_sdk_v09_08(self): self.set_machine('ast2700a1-evb') + self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V906_AST2700A1) + self.archive_extract(self.ASSET_SDK_V908_AST2700A1) + self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') + self.vm.add_args('-netdev', 'user,id=net1') self.start_ast2700_test('ast2700-default') self.verify_openbmc_boot_and_login('ast2700-default') self.do_ast2700_i2c_test() + self.do_ast2700_pcie_test() - def test_aarch64_ast2700a1_evb_sdk_vbootrom_v09_07(self): + def test_aarch64_ast2700a1_evb_sdk_vbootrom_v09_08(self): self.set_machine('ast2700a1-evb') + self.require_netdev('user') - self.archive_extract(self.ASSET_SDK_V907_AST2700A1_VBOOROM) + self.archive_extract(self.ASSET_SDK_V908_AST2700A1) + self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') + self.vm.add_args('-netdev', 'user,id=net1') self.start_ast2700_test_vbootrom('ast2700-default') self.verify_vbootrom_firmware_flow() - self.verify_openbmc_boot_and_login('ast2700-default') - self.do_ast2700_i2c_test() + self.verify_openbmc_boot_start() if __name__ == '__main__': QemuSystemTest.main() diff --git a/tests/functional/aarch64/test_aspeed_ast2700fc.py b/tests/functional/aarch64/test_aspeed_ast2700fc.py index b85370e..28b6661 100755 --- a/tests/functional/aarch64/test_aspeed_ast2700fc.py +++ b/tests/functional/aarch64/test_aspeed_ast2700fc.py @@ -20,6 +20,8 @@ class AST2x00MachineSDK(QemuSystemTest): self.vm.set_console() self.vm.add_args('-device', 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test') + self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.2') + self.vm.add_args('-netdev', 'user,id=net1') self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', '-net', 'nic', '-net', 'user', '-snapshot') @@ -49,6 +51,16 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '18000') + def do_ast2700_pcie_test(self): + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:00:00.0', + '0002:00:00.0 PCI bridge: ' + 'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge') + exec_command_and_wait_for_pattern(self, + 'lspci -s 0002:01:00.0', + '0002:01:00.0 Ethernet controller: ' + 'Intel Corporation 82574L Gigabit Network Connection') + def do_ast2700fc_ssp_test(self): self.vm.shutdown() self.vm.set_console(console_index=1) @@ -128,6 +140,7 @@ class AST2x00MachineSDK(QemuSystemTest): self.start_ast2700fc_test('ast2700-default') self.verify_openbmc_boot_and_login('ast2700-default') self.do_ast2700_i2c_test() + self.do_ast2700_pcie_test() self.do_ast2700fc_ssp_test() self.do_ast2700fc_tsp_test() diff --git a/tests/functional/arm/meson.build b/tests/functional/arm/meson.build index e4e7dba..d1ed076 100644 --- a/tests/functional/arm/meson.build +++ b/tests/functional/arm/meson.build @@ -5,7 +5,8 @@ test_arm_timeouts = { 'aspeed_romulus' : 120, 'aspeed_witherspoon' : 120, 'aspeed_ast2500' : 720, - 'aspeed_ast2600' : 1200, + 'aspeed_ast2600_buildroot' : 720, + 'aspeed_ast2600_sdk' : 1200, 'aspeed_bletchley' : 480, 'aspeed_catalina' : 480, 'aspeed_gb200nvl_bmc' : 480, @@ -31,7 +32,8 @@ tests_arm_system_thorough = [ 'aspeed_romulus', 'aspeed_witherspoon', 'aspeed_ast2500', - 'aspeed_ast2600', + 'aspeed_ast2600_buildroot', + 'aspeed_ast2600_sdk', 'aspeed_bletchley', 'aspeed_catalina', 'aspeed_gb200nvl_bmc', diff --git a/tests/functional/arm/test_aspeed_ast1030.py b/tests/functional/arm/test_aspeed_ast1030.py index e47b597..60e2b02 100755 --- a/tests/functional/arm/test_aspeed_ast1030.py +++ b/tests/functional/arm/test_aspeed_ast1030.py @@ -13,17 +13,17 @@ from qemu_test import exec_command_and_wait_for_pattern class AST1030Machine(AspeedTest): - ASSET_ZEPHYR_3_02 = Asset( + ASSET_ZEPHYR_3_03 = Asset( ('https://github.com/AspeedTech-BMC' - '/zephyr/releases/download/v00.03.02/ast1030-evb-demo.zip'), - '1ec83caab3ddd5d09481772801be7210e222cb015ce22ec6fffb8a76956dcd4f') + '/zephyr/releases/download/v00.03.03/ast1030-evb-demo.zip'), + '27cd73cdee6374bceb4ee58b3ace87989fa3f0684f4e612510804b588b24d4e0') - def test_arm_ast1030_zephyros_3_02(self): + def test_arm_ast1030_zephyros_3_03(self): self.set_machine('ast1030-evb') - kernel_name = "ast1030-evb-demo-3/zephyr.elf" + kernel_name = "ast1030-evb-demo/zephyr.elf" kernel_file = self.archive_extract( - self.ASSET_ZEPHYR_3_02, member=kernel_name) + self.ASSET_ZEPHYR_3_03, member=kernel_name) self.vm.set_console() self.vm.add_args('-kernel', kernel_file, '-nographic') @@ -72,8 +72,9 @@ class AST1030Machine(AspeedTest): def test_arm_ast1030_otp_blockdev_device(self): self.vm.set_machine("ast1030-evb") - kernel_name = "ast1030-evb-demo-3/zephyr.elf" - kernel_file = self.archive_extract(self.ASSET_ZEPHYR_3_02, member=kernel_name) + kernel_name = "ast1030-evb-demo/zephyr.elf" + kernel_file = self.archive_extract(self.ASSET_ZEPHYR_3_03, + member=kernel_name) otp_img = self.generate_otpmem_image() self.vm.set_console() diff --git a/tests/functional/arm/test_aspeed_ast2500.py b/tests/functional/arm/test_aspeed_ast2500.py index 4fdd81e..5efd104 100755 --- a/tests/functional/arm/test_aspeed_ast2500.py +++ b/tests/functional/arm/test_aspeed_ast2500.py @@ -37,14 +37,14 @@ class AST2500Machine(AspeedTest): self.do_test_arm_aspeed_buildroot_poweroff() - ASSET_SDK_V907_AST2500 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.07/ast2500-default-obmc.tar.gz', - 'd52bcc279a37c8d7679b3e4ef22cc77c36f0f6624c687b37334f798828afb077') + ASSET_SDK_V908_AST2500 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.08/ast2500-default-obmc.tar.gz', + 'c0a2ba169efd19be5eb77c50ec2a6afd9d826e196a0be3432f969fc72d4b7c0e') def test_arm_ast2500_evb_sdk(self): self.set_machine('ast2500-evb') - self.archive_extract(self.ASSET_SDK_V907_AST2500) + self.archive_extract(self.ASSET_SDK_V908_AST2500) self.do_test_arm_aspeed_sdk_start( self.scratch_file("ast2500-default", "image-bmc")) diff --git a/tests/functional/arm/test_aspeed_ast2600.py b/tests/functional/arm/test_aspeed_ast2600_buildroot.py index f655c0b..51f2676 100755 --- a/tests/functional/arm/test_aspeed_ast2600.py +++ b/tests/functional/arm/test_aspeed_ast2600_buildroot.py @@ -97,80 +97,6 @@ class AST2600Machine(AspeedTest): self.do_test_arm_aspeed_buildroot_poweroff() - ASSET_SDK_V907_AST2600 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.07/ast2600-default-obmc.tar.gz', - 'cb6c08595bcbba1672ce716b068ba4e48eda1ed9abe78a07b30392ba2278feba') - - def do_ast2600_pcie_test(self): - exec_command_and_wait_for_pattern(self, - 'lspci -s 80:00.0', - '80:00.0 Host bridge: ' - 'ASPEED Technology, Inc. Device 2600') - exec_command_and_wait_for_pattern(self, - 'lspci -s 80:08.0', - '80:08.0 PCI bridge: ' - 'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge') - exec_command_and_wait_for_pattern(self, - 'lspci -s 81:00.0', - '81:00.0 Ethernet controller: ' - 'Intel Corporation 82574L Gigabit Network Connection') - exec_command_and_wait_for_pattern(self, - 'ip addr show dev eth4', - 'inet 10.0.2.15/24') - - def test_arm_ast2600_evb_sdk(self): - self.set_machine('ast2600-evb') - self.require_netdev('user') - - self.archive_extract(self.ASSET_SDK_V907_AST2600) - - self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test') - self.vm.add_args('-device', - 'ds1338,bus=aspeed.i2c.bus.5,address=0x32') - self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.0') - self.vm.add_args('-netdev', 'user,id=net1') - self.do_test_arm_aspeed_sdk_start( - self.scratch_file("ast2600-default", "image-bmc")) - - self.wait_for_console_pattern('ast2600-default login:') - - exec_command_and_wait_for_pattern(self, 'root', 'Password:') - exec_command_and_wait_for_pattern(self, '0penBmc', - 'root@ast2600-default:~#') - - exec_command_and_wait_for_pattern(self, - 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device', - 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d') - exec_command_and_wait_for_pattern(self, - 'cat /sys/class/hwmon/hwmon19/temp1_input', '0') - self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000) - exec_command_and_wait_for_pattern(self, - 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000') - - exec_command_and_wait_for_pattern(self, - 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device', - 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32') - year = time.strftime("%Y") - exec_command_and_wait_for_pattern(self, - '/sbin/hwclock -f /dev/rtc1', year) - self.do_ast2600_pcie_test() - - def test_arm_ast2600_otp_blockdev_device(self): - self.vm.set_machine("ast2600-evb") - - image_path = self.archive_extract(self.ASSET_SDK_V907_AST2600) - otp_img = self.generate_otpmem_image() - - self.vm.set_console() - self.vm.add_args( - "-blockdev", f"driver=file,filename={otp_img},node-name=otp", - "-global", "aspeed-otp.drive=otp", - ) - self.do_test_arm_aspeed_sdk_start( - self.scratch_file("ast2600-default", "image-bmc")) - self.wait_for_console_pattern("ast2600-default login:") if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/arm/test_aspeed_ast2600_sdk.py b/tests/functional/arm/test_aspeed_ast2600_sdk.py new file mode 100755 index 0000000..e3d4ed0 --- /dev/null +++ b/tests/functional/arm/test_aspeed_ast2600_sdk.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# +# Functional test that boots the ASPEED machines +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os +import time + +from qemu_test import Asset +from aspeed import AspeedTest +from qemu_test import exec_command_and_wait_for_pattern + + +class AST2600Machine(AspeedTest): + + ASSET_SDK_V908_AST2600 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.08/ast2600-default-obmc.tar.gz', + 'a0414f14ad696550efe083c2156dbeda855c08cc9ae7f40fe1b41bf292295f82') + + def do_ast2600_pcie_test(self): + exec_command_and_wait_for_pattern(self, + 'lspci -s 80:00.0', + '80:00.0 Host bridge: ' + 'ASPEED Technology, Inc. Device 2600') + exec_command_and_wait_for_pattern(self, + 'lspci -s 80:08.0', + '80:08.0 PCI bridge: ' + 'ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge') + exec_command_and_wait_for_pattern(self, + 'lspci -s 81:00.0', + '81:00.0 Ethernet controller: ' + 'Intel Corporation 82574L Gigabit Network Connection') + exec_command_and_wait_for_pattern(self, + 'ip addr show dev eth4', + 'inet 10.0.2.15/24') + + def test_arm_ast2600_evb_sdk(self): + self.set_machine('ast2600-evb') + self.require_netdev('user') + + self.archive_extract(self.ASSET_SDK_V908_AST2600) + + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test') + self.vm.add_args('-device', + 'ds1338,bus=aspeed.i2c.bus.5,address=0x32') + self.vm.add_args('-device', 'e1000e,netdev=net1,bus=pcie.0') + self.vm.add_args('-netdev', 'user,id=net1') + self.do_test_arm_aspeed_sdk_start( + self.scratch_file("ast2600-default", "image-bmc")) + + self.wait_for_console_pattern('ast2600-default login:') + + exec_command_and_wait_for_pattern(self, 'root', 'Password:') + exec_command_and_wait_for_pattern(self, '0penBmc', + 'root@ast2600-default:~#') + + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device', + 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d') + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon19/temp1_input', '0') + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000) + exec_command_and_wait_for_pattern(self, + 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000') + + exec_command_and_wait_for_pattern(self, + 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device', + 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32') + year = time.strftime("%Y") + exec_command_and_wait_for_pattern(self, + '/sbin/hwclock -f /dev/rtc1', year) + self.do_ast2600_pcie_test() + + def test_arm_ast2600_otp_blockdev_device(self): + self.vm.set_machine("ast2600-evb") + + image_path = self.archive_extract(self.ASSET_SDK_V908_AST2600) + otp_img = self.generate_otpmem_image() + + self.vm.set_console() + self.vm.add_args( + "-blockdev", f"driver=file,filename={otp_img},node-name=otp", + "-global", "aspeed-otp.drive=otp", + ) + self.do_test_arm_aspeed_sdk_start( + self.scratch_file("ast2600-default", "image-bmc")) + self.wait_for_console_pattern("ast2600-default login:") + + +if __name__ == '__main__': + AspeedTest.main() diff --git a/util/async.c b/util/async.c index 2719c62..a736d2c 100644 --- a/util/async.c +++ b/util/async.c @@ -256,8 +256,9 @@ static int64_t aio_compute_bh_timeout(BHList *head, int timeout) QEMUBH *bh; QSLIST_FOREACH_RCU(bh, head, next) { - if ((bh->flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { - if (bh->flags & BH_IDLE) { + int flags = qatomic_load_acquire(&bh->flags); + if ((flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { + if (flags & BH_IDLE) { /* idle bottom halves will be polled at least * every 10ms */ timeout = 10000000; @@ -335,14 +336,16 @@ aio_ctx_check(GSource *source) aio_notify_accept(ctx); QSLIST_FOREACH_RCU(bh, &ctx->bh_list, next) { - if ((bh->flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { + int flags = qatomic_load_acquire(&bh->flags); + if ((flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { return true; } } QSIMPLEQ_FOREACH(s, &ctx->bh_slice_list, next) { QSLIST_FOREACH_RCU(bh, &s->bh_list, next) { - if ((bh->flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { + int flags = qatomic_load_acquire(&bh->flags); + if ((flags & (BH_SCHEDULED | BH_DELETED)) == BH_SCHEDULED) { return true; } } diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 1fb48be..56f11b6 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -89,7 +89,7 @@ static inline QEMUClock *qemu_clock_ptr(QEMUClockType type) return &qemu_clocks[type]; } -static bool timer_expired_ns(QEMUTimer *timer_head, int64_t current_time) +static bool timer_expired_ns(const QEMUTimer *timer_head, int64_t current_time) { return timer_head && (timer_head->expire_time <= current_time); } @@ -475,12 +475,12 @@ void timer_mod_anticipate(QEMUTimer *ts, int64_t expire_time) timer_mod_anticipate_ns(ts, expire_time * ts->scale); } -bool timer_pending(QEMUTimer *ts) +bool timer_pending(const QEMUTimer *ts) { return ts->expire_time >= 0; } -bool timer_expired(QEMUTimer *timer_head, int64_t current_time) +bool timer_expired(const QEMUTimer *timer_head, int64_t current_time) { return timer_expired_ns(timer_head, current_time * timer_head->scale); } @@ -649,7 +649,7 @@ void init_clocks(QEMUTimerListNotifyCB *notify_cb) #endif } -uint64_t timer_expire_time_ns(QEMUTimer *ts) +uint64_t timer_expire_time_ns(const QEMUTimer *ts) { return timer_pending(ts) ? ts->expire_time : -1; } |