diff options
Diffstat (limited to 'hw/i386')
| -rw-r--r-- | hw/i386/Kconfig | 1 | ||||
| -rw-r--r-- | hw/i386/acpi-build.c | 281 | ||||
| -rw-r--r-- | hw/i386/acpi-common.c | 7 | ||||
| -rw-r--r-- | hw/i386/acpi-microvm.c | 3 | ||||
| -rw-r--r-- | hw/i386/microvm.c | 15 | ||||
| -rw-r--r-- | hw/i386/pc_q35.c | 5 | ||||
| -rw-r--r-- | hw/i386/x86.c | 52 |
7 files changed, 210 insertions, 154 deletions
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index c4fb5b49bd..1bf47b0b0b 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -58,6 +58,7 @@ config PC_ACPI select ACPI_X86 select ACPI_CPU_HOTPLUG select ACPI_MEMORY_HOTPLUG + select ACPI_PCI_BRIDGE select ACPI_VIOT select SMBUS_EEPROM select PFLASH_CFI01 diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 127c4e2d50..145389aa58 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -117,8 +117,6 @@ typedef struct AcpiMiscInfo { #ifdef CONFIG_TPM TPMVersion tpm_version; #endif - const unsigned char *dsdt_code; - unsigned dsdt_size; } AcpiMiscInfo; typedef struct FwCfgTPMConfig { @@ -385,151 +383,185 @@ static void build_append_pcihp_notify_entry(Aml *method, int slot) aml_append(method, if_ctx); } -static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus, - bool pcihp_bridge_en) +static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus) { - Aml *dev, *notify_method = NULL, *method; - QObject *bsel; - PCIBus *sec; - int devfn; + const PCIDevice *pdev = bus->devices[devfn]; - bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); - if (bsel) { - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); + if (PCI_FUNC(devfn)) { + if (IS_PCI_BRIDGE(pdev)) { + /* + * Ignore only hotplugged PCI bridges on !0 functions, but + * allow describing cold plugged bridges on all functions + */ + if (DEVICE(pdev)->hotplugged) { + return true; + } + } else if (!get_dev_aml_func(DEVICE(pdev))) { + /* + * Ignore all other devices on !0 functions unless they + * have AML description (i.e have get_dev_aml_func() != 0) + */ + return true; + } + } + return false; +} - aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); - notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); +static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus) +{ + PCIDevice *pdev = bus->devices[devfn]; + if (pdev) { + return is_devfn_ignored_generic(devfn, bus) || + !DEVICE_GET_CLASS(pdev)->hotpluggable || + /* Cold plugged bridges aren't themselves hot-pluggable */ + (IS_PCI_BRIDGE(pdev) && !DEVICE(pdev)->hotplugged); + } else { /* non populated slots */ + /* + * hotplug is supported only for non-multifunction device + * so generate device description only for function 0 + */ + if (PCI_FUNC(devfn) || + (pci_bus_is_express(bus) && PCI_SLOT(devfn) > 0)) { + return true; + } } + return false; +} - for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { - DeviceClass *dc; - PCIDevice *pdev = bus->devices[devfn]; - int slot = PCI_SLOT(devfn); - int func = PCI_FUNC(devfn); - /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ - int adr = slot << 16 | func; - bool hotpluggbale_slot = false; - bool bridge_in_acpi = false; - bool cold_plugged_bridge = false; +static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus, + QObject *bsel) +{ + int devfn; + Aml *dev, *notify_method = NULL, *method; + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - if (pdev) { - dc = DEVICE_GET_CLASS(pdev); + aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val))); + notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED); - /* - * Cold plugged bridges aren't themselves hot-pluggable. - * Hotplugged bridges *are* hot-pluggable. - */ - cold_plugged_bridge = IS_PCI_BRIDGE(pdev) && - !DEVICE(pdev)->hotplugged; - bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + int slot = PCI_SLOT(devfn); + int adr = slot << 16 | PCI_FUNC(devfn); - hotpluggbale_slot = bsel && dc->hotpluggable && - !cold_plugged_bridge; + if (is_devfn_ignored_hotplug(devfn, bus)) { + continue; + } - /* - * allow describing coldplugged bridges in ACPI even if they are not - * on function 0, as they are not unpluggable, for all other devices - * generate description only for function 0 per slot, and for other - * functions if device on function provides its own AML - */ - if (func && !bridge_in_acpi && !get_dev_aml_func(DEVICE(pdev))) { - continue; - } + if (bus->devices[devfn]) { + dev = aml_scope("S%.02X", devfn); } else { - /* - * hotplug is supported only for non-multifunction device - * so generate device description only for function 0 - */ - if (bsel && !func) { - if (pci_bus_is_express(bus) && slot > 0) { - break; - } - /* mark it as empty hotpluggable slot */ - hotpluggbale_slot = true; - } else { - continue; - } + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); } - /* start to compose PCI device descriptor */ - dev = aml_device("S%.02X", devfn); - aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); + /* + * Can't declare _SUN here for every device as it changes 'slot' + * enumeration order in linux kernel, so use another variable for it + */ + aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); + aml_append(dev, aml_pci_device_dsm()); - if (bsel) { - /* - * Can't declare _SUN here for every device as it changes 'slot' - * enumeration order in linux kernel, so use another variable for it - */ - aml_append(dev, aml_name_decl("ASUN", aml_int(slot))); - aml_append(dev, aml_pci_device_dsm()); - } + aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); + /* add _EJ0 to make slot hotpluggable */ + method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); + aml_append(method, + aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) + ); + aml_append(dev, method); - call_dev_aml_func(DEVICE(pdev), dev); + build_append_pcihp_notify_entry(notify_method, slot); - bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en; - if (bridge_in_acpi) { - /* - * device is coldplugged bridge, - * add child device descriptions into its scope - */ - PCIBus *sec_bus = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev)); + /* device descriptor has been composed, add it into parent context */ + aml_append(parent_scope, dev); + } + aml_append(parent_scope, notify_method); +} - build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en); - } +void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus) +{ + QObject *bsel; + int devfn; + Aml *dev; - if (hotpluggbale_slot) { - aml_append(dev, aml_name_decl("_SUN", aml_int(slot))); - /* add _EJ0 to make slot hotpluggable */ - method = aml_method("_EJ0", 1, AML_NOTSERIALIZED); - aml_append(method, - aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN")) - ); - aml_append(dev, method); + bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); - build_append_pcihp_notify_entry(notify_method, slot); + for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) { + /* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */ + int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn); + PCIDevice *pdev = bus->devices[devfn]; + + if (!pdev || is_devfn_ignored_generic(devfn, bus)) { + continue; } + /* start to compose PCI device descriptor */ + dev = aml_device("S%.02X", devfn); + aml_append(dev, aml_name_decl("_ADR", aml_int(adr))); + + call_dev_aml_func(DEVICE(bus->devices[devfn]), dev); + /* device descriptor has been composed, add it into parent context */ aml_append(parent_scope, dev); } if (bsel) { - aml_append(parent_scope, notify_method); + build_append_pcihp_slots(parent_scope, bus, bsel); } - /* Append PCNT method to notify about events on local and child buses. - * Add this method for root bus only when hotplug is enabled since DSDT - * expects it. - */ - if (bsel || pcihp_bridge_en) { - method = aml_method("PCNT", 0, AML_NOTSERIALIZED); - - /* If bus supports hotplug select it and notify about local events */ - if (bsel) { - uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); - - aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); - aml_append(method, aml_call2("DVNT", aml_name("PCIU"), - aml_int(1))); /* Device Check */ - aml_append(method, aml_call2("DVNT", aml_name("PCID"), - aml_int(3))); /* Eject Request */ + qobject_unref(bsel); +} + +static bool build_append_notfication_callback(Aml *parent_scope, + const PCIBus *bus) +{ + Aml *method; + PCIBus *sec; + QObject *bsel; + int nr_notifiers = 0; + + QLIST_FOREACH(sec, &bus->child, sibling) { + Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn); + if (pci_bus_is_root(sec) || + !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { + continue; } + nr_notifiers = nr_notifiers + + build_append_notfication_callback(br_scope, sec); + aml_append(parent_scope, br_scope); + } - /* Notify about child bus events in any case */ - if (pcihp_bridge_en) { - QLIST_FOREACH(sec, &bus->child, sibling) { - if (pci_bus_is_root(sec)) { - continue; - } + /* + * Append PCNT method to notify about events on local and child buses. + * ps: hostbridge might not have hotplug (bsel) enabled but might have + * child bridges that do have bsel. + */ + method = aml_method("PCNT", 0, AML_NOTSERIALIZED); - aml_append(method, aml_name("^S%.02X.PCNT", - sec->parent_dev->devfn)); - } + /* If bus supports hotplug select it and notify about local events */ + bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL); + if (bsel) { + uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel)); + + aml_append(method, aml_store(aml_int(bsel_val), aml_name("BNUM"))); + aml_append(method, aml_call2("DVNT", aml_name("PCIU"), + aml_int(1))); /* Device Check */ + aml_append(method, aml_call2("DVNT", aml_name("PCID"), + aml_int(3))); /* Eject Request */ + nr_notifiers++; + } + + /* Notify about child bus events in any case */ + QLIST_FOREACH(sec, &bus->child, sibling) { + if (pci_bus_is_root(sec) || + !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) { + continue; } - aml_append(parent_scope, method); + aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn)); } + + aml_append(parent_scope, method); qobject_unref(bsel); + return !!nr_notifiers; } static Aml *aml_pci_pdsm(void) @@ -1678,7 +1710,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; Aml *scope = aml_scope("PCI0"); /* Scan all PCI buses. Generate tables to support hotplug. */ - build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); + build_append_pci_bus_devices(scope, bus); aml_append(sb_scope, scope); } } @@ -1728,13 +1760,26 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, aml_append(dsdt, sb_scope); if (pm->pcihp_bridge_en || pm->pcihp_root_en) { + bool has_pcnt; + + Object *pci_host = acpi_get_i386_pci_host(); + PCIBus *bus = PCI_HOST_BRIDGE(pci_host)->bus; + + scope = aml_scope("\\_SB.PCI0"); + has_pcnt = build_append_notfication_callback(scope, bus); + if (has_pcnt) { + aml_append(dsdt, scope); + } + scope = aml_scope("_GPE"); { method = aml_method("_E01", 0, AML_NOTSERIALIZED); - aml_append(method, - aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); - aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); - aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + if (has_pcnt) { + aml_append(method, + aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF)); + aml_append(method, aml_call0("\\_SB.PCI0.PCNT")); + aml_append(method, aml_release(aml_name("\\_SB.PCI0.BLCK"))); + } aml_append(scope, method); } aml_append(dsdt, scope); diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 4aaafbdd7b..52e5c1439a 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -33,9 +33,8 @@ #include "acpi-build.h" #include "acpi-common.h" -void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, - const CPUArchIdList *apic_ids, GArray *entry, - bool force_enabled) +void pc_madt_cpu_entry(int uid, const CPUArchIdList *apic_ids, + GArray *entry, bool force_enabled) { uint32_t apic_id = apic_ids->cpus[uid].arch_id; /* Flags – Local APIC Flags */ @@ -112,7 +111,7 @@ void acpi_build_madt(GArray *table_data, BIOSLinker *linker, build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */ for (i = 0; i < apic_ids->len; i++) { - adevc->madt_cpu(adev, i, apic_ids, table_data, false); + adevc->madt_cpu(i, apic_ids, table_data, false); if (apic_ids->cpus[i].arch_id > 254) { x2apic_mode = true; } diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index fb09185cbd..a075360d85 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -26,6 +26,7 @@ #include "exec/memory.h" #include "hw/acpi/acpi.h" +#include "hw/acpi/acpi_aml_interface.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/generic_event_device.h" @@ -129,7 +130,7 @@ build_dsdt_microvm(GArray *table_data, BIOSLinker *linker, sb_scope = aml_scope("_SB"); fw_cfg_add_acpi_dsdt(sb_scope, x86ms->fw_cfg); - isa_build_aml(ISA_BUS(isabus), sb_scope); + qbus_build_aml(BUS(isabus), sb_scope); build_ged_aml(sb_scope, GED_DEVICE, x86ms->acpi_dev, GED_MMIO_IRQ, AML_SYSTEM_MEMORY, GED_MMIO_BASE); acpi_dsdt_add_power_button(sb_scope); diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 170a331e3f..29f30dd6d3 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -378,7 +378,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) MicrovmMachineState *mms = MICROVM_MACHINE(machine); BusState *bus; BusChild *kid; - char *cmdline; + char *cmdline, *existing_cmdline; + size_t len; /* * Find MMIO transports with attached devices, and add them to the kernel @@ -387,7 +388,8 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) * Yes, this is a hack, but one that heavily improves the UX without * introducing any significant issues. */ - cmdline = g_strdup(machine->kernel_cmdline); + existing_cmdline = fw_cfg_read_bytes_ptr(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA); + cmdline = g_strdup(existing_cmdline); bus = sysbus_get_default(); QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; @@ -411,9 +413,12 @@ static void microvm_fix_kernel_cmdline(MachineState *machine) } } - fw_cfg_modify_i32(x86ms->fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(cmdline) + 1); - fw_cfg_modify_string(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA, cmdline); - + len = strlen(cmdline); + if (len > VIRTIO_CMDLINE_TOTAL_MAX_LEN + strlen(existing_cmdline)) { + fprintf(stderr, "qemu: virtio mmio cmdline too large, skipping\n"); + } else { + memcpy(existing_cmdline, cmdline, len + 1); + } g_free(cmdline); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 83c57c6eb1..66cd718b70 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -257,8 +257,9 @@ static void pc_q35_init(MachineState *machine) NULL); if (!keep_pci_slot_hpc && acpi_pcihp) { - object_register_sugar_prop(TYPE_PCIE_SLOT, "x-native-hotplug", - "false", true); + object_register_sugar_prop(TYPE_PCIE_SLOT, + "x-do-not-expose-native-hotplug-cap", + "true", true); } /* irq lines */ diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 78cc131926..eaff4227bd 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -50,6 +50,7 @@ #include "hw/intc/i8259.h" #include "hw/rtc/mc146818rtc.h" #include "target/i386/sev.h" +#include "hw/i386/microvm.h" #include "hw/acpi/cpu_hotplug.h" #include "hw/irq.h" @@ -813,12 +814,18 @@ void x86_load_linux(X86MachineState *x86ms, const char *kernel_filename = machine->kernel_filename; const char *initrd_filename = machine->initrd_filename; const char *dtb_filename = machine->dtb; - const char *kernel_cmdline = machine->kernel_cmdline; + char *kernel_cmdline; SevKernelLoaderContext sev_load_ctx = {}; enum { RNG_SEED_LENGTH = 32 }; - /* Align to 16 bytes as a paranoia measure */ - cmdline_size = (strlen(kernel_cmdline) + 16) & ~15; + /* + * Add the NUL terminator, some padding for the microvm cmdline fiddling + * hack, and then align to 16 bytes as a paranoia measure + */ + cmdline_size = (strlen(machine->kernel_cmdline) + 1 + + VIRTIO_CMDLINE_TOTAL_MAX_LEN + 16) & ~15; + /* Make a copy, since we might append arbitrary bytes to it later. */ + kernel_cmdline = g_strndup(machine->kernel_cmdline, cmdline_size); /* load the kernel header */ f = fopen(kernel_filename, "rb"); @@ -959,12 +966,6 @@ void x86_load_linux(X86MachineState *x86ms, initrd_max = x86ms->below_4g_mem_size - acpi_data_size - 1; } - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); - fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1); - fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); - sev_load_ctx.cmdline_data = (char *)kernel_cmdline; - sev_load_ctx.cmdline_size = strlen(kernel_cmdline) + 1; - if (protocol >= 0x202) { stl_p(header + 0x228, cmdline_addr); } else { @@ -1091,27 +1092,24 @@ void x86_load_linux(X86MachineState *x86ms, exit(1); } - setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(SetupData) + dtb_size; - kernel = g_realloc(kernel, kernel_size); - - - setup_data = (SetupData *)(kernel + setup_data_offset); + setup_data_offset = cmdline_size; + cmdline_size += sizeof(SetupData) + dtb_size; + kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size); + setup_data = (void *)kernel_cmdline + setup_data_offset; setup_data->next = cpu_to_le64(first_setup_data); - first_setup_data = prot_addr + setup_data_offset; + first_setup_data = cmdline_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_DTB); setup_data->len = cpu_to_le32(dtb_size); - load_image_size(dtb_filename, setup_data->data, dtb_size); } - if (!legacy_no_rng_seed) { - setup_data_offset = QEMU_ALIGN_UP(kernel_size, 16); - kernel_size = setup_data_offset + sizeof(SetupData) + RNG_SEED_LENGTH; - kernel = g_realloc(kernel, kernel_size); - setup_data = (SetupData *)(kernel + setup_data_offset); + if (!legacy_no_rng_seed && protocol >= 0x209) { + setup_data_offset = cmdline_size; + cmdline_size += sizeof(SetupData) + RNG_SEED_LENGTH; + kernel_cmdline = g_realloc(kernel_cmdline, cmdline_size); + setup_data = (void *)kernel_cmdline + setup_data_offset; setup_data->next = cpu_to_le64(first_setup_data); - first_setup_data = prot_addr + setup_data_offset; + first_setup_data = cmdline_addr + setup_data_offset; setup_data->type = cpu_to_le32(SETUP_RNG_SEED); setup_data->len = cpu_to_le32(RNG_SEED_LENGTH); qemu_guest_getrandom_nofail(setup_data->data, RNG_SEED_LENGTH); @@ -1122,6 +1120,12 @@ void x86_load_linux(X86MachineState *x86ms, fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size); } + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, cmdline_size); + fw_cfg_add_bytes(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline, cmdline_size); + sev_load_ctx.cmdline_data = (char *)kernel_cmdline; + sev_load_ctx.cmdline_size = cmdline_size; + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); sev_load_ctx.kernel_data = (char *)kernel; @@ -1134,7 +1138,7 @@ void x86_load_linux(X86MachineState *x86ms, * kernel on the other side of the fw_cfg interface matches the hash of the * file the user passed in. */ - if (!sev_enabled()) { + if (!sev_enabled() && first_setup_data) { SetupDataFixup *fixup = g_malloc(sizeof(*fixup)); memcpy(setup, header, MIN(sizeof(header), setup_size)); |