2004-03-14 15:20:30 +03:00
|
|
|
/*
|
|
|
|
* QEMU PC System Emulator
|
2007-09-17 01:08:06 +04:00
|
|
|
*
|
2004-03-14 15:20:30 +03:00
|
|
|
* Copyright (c) 2003-2004 Fabrice Bellard
|
2007-09-17 01:08:06 +04:00
|
|
|
*
|
2004-03-14 15:20:30 +03:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
2018-02-01 14:18:31 +03:00
|
|
|
|
2016-01-26 21:17:03 +03:00
|
|
|
#include "qemu/osdep.h"
|
2018-06-29 17:22:13 +03:00
|
|
|
#include "qemu/units.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/i386/pc.h"
|
|
|
|
#include "hw/char/serial.h"
|
2018-03-09 01:39:22 +03:00
|
|
|
#include "hw/char/parallel.h"
|
2023-08-24 00:36:35 +03:00
|
|
|
#include "hw/hyperv/hv-balloon.h"
|
2019-04-22 19:58:21 +03:00
|
|
|
#include "hw/i386/fw_cfg.h"
|
2020-03-12 19:54:22 +03:00
|
|
|
#include "hw/i386/vmport.h"
|
2014-12-19 04:43:35 +03:00
|
|
|
#include "sysemu/cpus.h"
|
2024-02-20 11:55:05 +03:00
|
|
|
#include "hw/ide/ide-bus.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/timer/hpet.h"
|
2013-02-04 18:40:22 +04:00
|
|
|
#include "hw/loader.h"
|
2019-10-04 02:03:53 +03:00
|
|
|
#include "hw/rtc/mc146818rtc.h"
|
2019-12-12 19:15:43 +03:00
|
|
|
#include "hw/intc/i8259.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/timer/i8254.h"
|
2018-03-09 01:39:24 +03:00
|
|
|
#include "hw/input/i8042.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/audio/pcspk.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/sysemu.h"
|
2020-05-08 13:02:22 +03:00
|
|
|
#include "sysemu/xen.h"
|
2019-08-12 08:23:38 +03:00
|
|
|
#include "sysemu/reset.h"
|
2020-12-12 18:55:08 +03:00
|
|
|
#include "kvm/kvm_i386.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/xen/xen.h"
|
2023-11-09 20:42:30 +03:00
|
|
|
#include "qapi/qmp/qlist.h"
|
2015-03-17 20:29:20 +03:00
|
|
|
#include "qemu/error-report.h"
|
2014-03-14 23:33:51 +04:00
|
|
|
#include "hw/acpi/cpu_hotplug.h"
|
i386: ACPI table generation code from seabios
This adds C code for generating ACPI tables at runtime,
imported from seabios git tree
commit 51684b7ced75fb76776e8ee84833fcfb6ecf12dd
Although ACPI tables come from a system BIOS on real hw,
it makes sense that the ACPI tables are coupled with the
virtual machine, since they have to abstract the x86 machine to
the OS's.
This is widely desired as a way to avoid the churn
and proliferation of QEMU-specific interfaces
associated with ACPI tables in bios code.
Notes:
As BIOS can reprogram devices prior to loading
ACPI tables, we pre-format ACPI tables but defer loading
hardware configuration there until tables are loaded.
The code structure was intentionally kept as close
to the seabios original as possible, to simplify
comparison and making sure we didn't lose anything
in translation.
Minor code duplication results, to help ensure there are no functional
regressions, I think it's better to merge it like this and do more code
changes in follow-up patches.
Cross-version compatibility concerns have been addressed:
ACPI tables are exposed to guest as FW_CFG entries.
When running with -M 1.5 and older, this patch disables ACPI
table generation, and doesn't expose ACPI
tables to guest.
As table content is likely to change over time,
the following measures are taken to simplify
cross-version migration:
- All tables besides the RSDP are packed in a single FW CFG entry.
This entry size is currently 23K. We round it up to 64K
to avoid too much churn there.
- Tables are placed in special ROM blob (not mapped into guest memory)
which is automatically migrated together with the guest, same
as BIOS code.
- Offsets where hardware configuration is loaded in ACPI tables
are also migrated, this is in case future ACPI changes make us
rearrange the tables in memory.
This patch reuses some code from SeaBIOS, which was originally under
LGPLv2 and then relicensed to GPLv3 or LGPLv3, in QEMU under GPLv2+. This
relicensing has been acked by all contributors that had contributed to the
code since the v2->v3 relicense. ACKs approving the v2+ relicensing are
listed below. The list might include ACKs from people not holding
copyright on any parts of the reused code, but it's better to err on the
side of caution and include them.
Affected SeaBIOS files (GPLv2+ license headers added)
<http://thread.gmane.org/gmane.comp.bios.coreboot.seabios/5949>:
src/acpi-dsdt-cpu-hotplug.dsl
src/acpi-dsdt-dbug.dsl
src/acpi-dsdt-hpet.dsl
src/acpi-dsdt-isa.dsl
src/acpi-dsdt-pci-crs.dsl
src/acpi.c
src/acpi.h
src/ssdt-misc.dsl
src/ssdt-pcihp.dsl
src/ssdt-proc.dsl
tools/acpi_extract.py
tools/acpi_extract_preprocess.py
Each one of the listed people agreed to the following:
> If you allow the use of your contribution in QEMU under the
> terms of GPLv2 or later as proposed by this patch,
> please respond to this mail including the line:
>
> Acked-by: Name <email address>
Acked-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Jan Kiszka <jan.kiszka@siemens.com>
Acked-by: Jason Baron <jbaron@akamai.com>
Acked-by: David Woodhouse <David.Woodhouse@intel.com>
Acked-by: Gleb Natapov <gleb@redhat.com>
Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
Acked-by: Dave Frodin <dave.frodin@se-eng.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Acked-by: Kevin O'Connor <kevin@koconnor.net>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Acked-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Acked-by: Isaku Yamahata <yamahata@valinux.co.jp>
Acked-by: Magnus Christensson <magnus.christensson@intel.com>
Acked-by: Hu Tao <hutao@cn.fujitsu.com>
Acked-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Tested-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Tested-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2013-07-24 19:56:14 +04:00
|
|
|
#include "acpi-build.h"
|
hw/i386: Include "hw/mem/nvdimm.h"
All this files use methods/definitions declared in the NVDIMM
device header. Include it.
This fixes (when modifying unrelated headers):
hw/i386/acpi-build.c:2733:9: error: implicit declaration of function 'nvdimm_build_acpi' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
^
hw/i386/pc.c:1996:61: error: use of undeclared identifier 'TYPE_NVDIMM'
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
^
hw/i386/pc.c:2032:55: error: use of undeclared identifier 'TYPE_NVDIMM'
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
^
hw/i386/pc.c:2040:9: error: implicit declaration of function 'nvdimm_plug' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
nvdimm_plug(ms->nvdimms_state);
^
hw/i386/pc.c:2040:9: error: this function declaration is not a prototype [-Werror,-Wstrict-prototypes]
nvdimm_plug(ms->nvdimms_state);
^
hw/i386/pc.c:2065:42: error: use of undeclared identifier 'TYPE_NVDIMM'
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
^
hw/i386/pc_i440fx.c:307:9: error: implicit declaration of function 'nvdimm_init_acpi_state' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
^
hw/i386/pc_q35.c:332:9: error: implicit declaration of function 'nvdimm_init_acpi_state' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
nvdimm_init_acpi_state(machine->nvdimms_state, system_io,
^
Acked-by: John Snow <jsnow@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20200228114649.12818-17-philmd@redhat.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
2020-02-28 14:46:47 +03:00
|
|
|
#include "hw/mem/nvdimm.h"
|
2022-06-08 17:54:33 +03:00
|
|
|
#include "hw/cxl/cxl_host.h"
|
2018-12-12 20:57:53 +03:00
|
|
|
#include "hw/usb.h"
|
2016-10-19 15:05:42 +03:00
|
|
|
#include "hw/i386/intel_iommu.h"
|
2017-10-17 19:44:22 +03:00
|
|
|
#include "hw/net/ne2000-isa.h"
|
2021-10-26 21:20:23 +03:00
|
|
|
#include "hw/virtio/virtio-iommu.h"
|
2023-07-11 18:34:40 +03:00
|
|
|
#include "hw/virtio/virtio-md-pci.h"
|
2022-12-13 02:40:45 +03:00
|
|
|
#include "hw/i386/kvm/xen_overlay.h"
|
2022-12-16 17:02:29 +03:00
|
|
|
#include "hw/i386/kvm/xen_evtchn.h"
|
2022-12-16 18:50:26 +03:00
|
|
|
#include "hw/i386/kvm/xen_gnttab.h"
|
2022-12-23 20:39:23 +03:00
|
|
|
#include "hw/i386/kvm/xen_xenstore.h"
|
2023-08-24 00:36:35 +03:00
|
|
|
#include "hw/mem/memory-device.h"
|
2019-08-19 01:54:01 +03:00
|
|
|
#include "e820_memory_layout.h"
|
2019-12-13 13:50:57 +03:00
|
|
|
#include "trace.h"
|
2024-05-30 14:16:39 +03:00
|
|
|
#include "sev.h"
|
2020-02-03 13:42:03 +03:00
|
|
|
#include CONFIG_DEVICES
|
2010-05-30 00:23:49 +04:00
|
|
|
|
2023-02-15 18:10:00 +03:00
|
|
|
#ifdef CONFIG_XEN_EMU
|
|
|
|
#include "hw/xen/xen-legacy-backend.h"
|
|
|
|
#include "hw/xen/xen-bus.h"
|
|
|
|
#endif
|
|
|
|
|
2022-05-20 21:01:02 +03:00
|
|
|
/*
|
|
|
|
* Helper for setting model-id for CPU models that changed model-id
|
|
|
|
* depending on QEMU versions up to QEMU 2.4.
|
|
|
|
*/
|
|
|
|
#define PC_CPU_MODEL_IDS(v) \
|
|
|
|
{ "qemu32-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
|
|
|
|
{ "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\
|
|
|
|
{ "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },
|
|
|
|
|
2024-03-18 18:53:36 +03:00
|
|
|
GlobalProperty pc_compat_9_0[] = {
|
2024-04-24 18:49:13 +03:00
|
|
|
{ TYPE_X86_CPU, "x-l1-cache-per-thread", "false" },
|
2024-03-18 18:53:36 +03:00
|
|
|
{ TYPE_X86_CPU, "guest-phys-bits", "0" },
|
2024-04-10 02:07:43 +03:00
|
|
|
{ "sev-guest", "legacy-vm-type", "true" },
|
target/i386: Fix CPUID encoding of Fn8000001E_ECX
Observed the following failure while booting the SEV-SNP guest and the
guest fails to boot with the smp parameters:
"-smp 192,sockets=1,dies=12,cores=8,threads=2".
qemu-system-x86_64: sev_snp_launch_update: SNP_LAUNCH_UPDATE ret=-5 fw_error=22 'Invalid parameter'
qemu-system-x86_64: SEV-SNP: CPUID validation failed for function 0x8000001e, index: 0x0.
provided: eax:0x00000000, ebx: 0x00000100, ecx: 0x00000b00, edx: 0x00000000
expected: eax:0x00000000, ebx: 0x00000100, ecx: 0x00000300, edx: 0x00000000
qemu-system-x86_64: SEV-SNP: failed update CPUID page
Reason for the failure is due to overflowing of bits used for "Node per
processor" in CPUID Fn8000001E_ECX. This field's width is 3 bits wide and
can hold maximum value 0x7. With dies=12 (0xB), it overflows and spills
over into the reserved bits. In the case of SEV-SNP, this causes CPUID
enforcement failure and guest fails to boot.
The PPR documentation for CPUID_Fn8000001E_ECX [Node Identifiers]
=================================================================
Bits Description
31:11 Reserved.
10:8 NodesPerProcessor: Node per processor. Read-only.
ValidValues:
Value Description
0h 1 node per processor.
7h-1h Reserved.
7:0 NodeId: Node ID. Read-only. Reset: Fixed,XXh.
=================================================================
As in the spec, the valid value for "node per processor" is 0 and rest
are reserved.
Looking back at the history of decoding of CPUID_Fn8000001E_ECX, noticed
that there were cases where "node per processor" can be more than 1. It
is valid only for pre-F17h (pre-EPYC) architectures. For EPYC or later
CPUs, the linux kernel does not use this information to build the L3
topology.
Also noted that the CPUID Function 0x8000001E_ECX is available only when
TOPOEXT feature is enabled. This feature is enabled only for EPYC(F17h)
or later processors. So, previous generation of processors do not not
enumerate 0x8000001E_ECX leaf.
There could be some corner cases where the older guests could enable the
TOPOEXT feature by running with -cpu host, in which case legacy guests
might notice the topology change. To address those cases introduced a
new CPU property "legacy-multi-node". It will be true for older machine
types to maintain compatibility. By default, it will be false, so new
decoding will be used going forward.
The documentation is taken from Preliminary Processor Programming
Reference (PPR) for AMD Family 19h Model 11h, Revision B1 Processors 55901
Rev 0.25 - Oct 6, 2022.
Cc: qemu-stable@nongnu.org
Fixes: 31ada106d891 ("Simplify CPUID_8000_001E for AMD")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Babu Moger <babu.moger@amd.com>
Message-ID: <0ee4b0a8293188a53970a2b0e4f4ef713425055e.1714757834.git.babu.moger@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-05-03 20:46:30 +03:00
|
|
|
{ TYPE_X86_CPU, "legacy-multi-node", "on" },
|
2024-03-18 18:53:36 +03:00
|
|
|
};
|
2024-03-25 17:01:51 +03:00
|
|
|
const size_t pc_compat_9_0_len = G_N_ELEMENTS(pc_compat_9_0);
|
|
|
|
|
2023-11-20 12:42:59 +03:00
|
|
|
GlobalProperty pc_compat_8_2[] = {};
|
|
|
|
const size_t pc_compat_8_2_len = G_N_ELEMENTS(pc_compat_8_2);
|
|
|
|
|
2023-07-18 17:22:35 +03:00
|
|
|
GlobalProperty pc_compat_8_1[] = {};
|
|
|
|
const size_t pc_compat_8_1_len = G_N_ELEMENTS(pc_compat_8_1);
|
|
|
|
|
2023-05-03 21:23:52 +03:00
|
|
|
GlobalProperty pc_compat_8_0[] = {
|
|
|
|
{ "virtio-mem", "unplugged-inaccessible", "auto" },
|
|
|
|
};
|
2023-03-14 20:30:09 +03:00
|
|
|
const size_t pc_compat_8_0_len = G_N_ELEMENTS(pc_compat_8_0);
|
|
|
|
|
hw/isa: enable TCO watchdog reboot pin strap by default
The TCO watchdog implementation default behaviour from POV of the
guest OS relies on the initial values for two I/O ports:
* TCO1_CNT == 0x0
Since bit 11 (TCO Timer Halt) is clear, the watchdog state
is considered to be initially running
* GCS == 0x20
Since bit 5 (No Reboot) is set, the watchdog will not trigger
when the timer expires
This is a safe default, because the No Reboot bit will prevent the
watchdog from triggering if the guest OS is unaware of its existance,
or is slow in configuring it. When a Linux guest initializes the TCO
watchdog, it will attempt to clear the "No Reboot" flag, and read the
value back. If the clear was honoured, the driver will treat this as
an indicator that the watchdog is functional and create the guest
watchdog device.
QEMU implements a second "no reboot" flag, however, via pin straps
which overrides the behaviour of the guest controlled "no reboot"
flag:
commit 5add35bec1e249bb5345a47008c8f298d4760be4
Author: Paulo Alcantara <pcacjr@gmail.com>
Date: Sun Jun 28 14:58:58 2015 -0300
ich9: implement strap SPKR pin logic
This second 'noreboot' pin was defaulted to high, which also inhibits
triggering of the requested watchdog actions, unless QEMU is launched
with the magic flag "-global ICH9-LPC.noreboot=false".
This is a bad default as we are exposing a watchdog to every guest OS
using the q35 machine type, but preventing it from actually doing what
it is designed to do. What is worse is that the guest OS and its apps
have no way to know that the watchdog is never going to fire, due to
this second 'noreboot' pin.
If a guest OS had no watchdog device at all, then apps whose operation
and/or data integrity relies on a watchdog can refuse to launch, and
alert the administrator of the problematic deployment. With Q35 machines
unconditionally exposing a watchdog though, apps will think their
deployment is correct but in fact have no protection at all.
This patch flips the default of the second 'no reboot' flag, so that
configured watchdog actions will be honoured out of the box for the
7.2 Q35 machine type onwards, if the guest enables use of the watchdog.
See also related bug reports
https://bugzilla.redhat.com/show_bug.cgi?id=2080207
https://bugzilla.redhat.com/show_bug.cgi?id=2136889
https://bugzilla.redhat.com/show_bug.cgi?id=2137346
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20221216125749.596075-5-berrange@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2022-12-16 15:57:48 +03:00
|
|
|
GlobalProperty pc_compat_7_2[] = {
|
|
|
|
{ "ICH9-LPC", "noreboot", "true" },
|
|
|
|
};
|
2022-12-12 18:21:44 +03:00
|
|
|
const size_t pc_compat_7_2_len = G_N_ELEMENTS(pc_compat_7_2);
|
|
|
|
|
2022-07-27 15:17:55 +03:00
|
|
|
GlobalProperty pc_compat_7_1[] = {};
|
|
|
|
const size_t pc_compat_7_1_len = G_N_ELEMENTS(pc_compat_7_1);
|
|
|
|
|
2022-03-16 17:55:21 +03:00
|
|
|
GlobalProperty pc_compat_7_0[] = {};
|
|
|
|
const size_t pc_compat_7_0_len = G_N_ELEMENTS(pc_compat_7_0);
|
|
|
|
|
2021-12-17 16:40:39 +03:00
|
|
|
GlobalProperty pc_compat_6_2[] = {
|
|
|
|
{ "virtio-mem", "unplugged-inaccessible", "off" },
|
|
|
|
};
|
2021-12-17 17:39:48 +03:00
|
|
|
const size_t pc_compat_6_2_len = G_N_ELEMENTS(pc_compat_6_2);
|
|
|
|
|
2021-09-02 12:35:30 +03:00
|
|
|
GlobalProperty pc_compat_6_1[] = {
|
|
|
|
{ TYPE_X86_CPU, "hv-version-id-build", "0x1bbc" },
|
|
|
|
{ TYPE_X86_CPU, "hv-version-id-major", "0x0006" },
|
|
|
|
{ TYPE_X86_CPU, "hv-version-id-minor", "0x0001" },
|
2021-11-12 14:08:54 +03:00
|
|
|
{ "ICH9-LPC", "x-keep-pci-slot-hpc", "false" },
|
2021-09-02 12:35:30 +03:00
|
|
|
};
|
2021-08-31 04:54:26 +03:00
|
|
|
const size_t pc_compat_6_1_len = G_N_ELEMENTS(pc_compat_6_1);
|
|
|
|
|
2021-05-07 16:36:49 +03:00
|
|
|
GlobalProperty pc_compat_6_0[] = {
|
|
|
|
{ "qemu64" "-" TYPE_X86_CPU, "family", "6" },
|
|
|
|
{ "qemu64" "-" TYPE_X86_CPU, "model", "6" },
|
|
|
|
{ "qemu64" "-" TYPE_X86_CPU, "stepping", "3" },
|
2021-07-08 03:36:23 +03:00
|
|
|
{ TYPE_X86_CPU, "x-vendor-cpuid-only", "off" },
|
2021-08-16 11:32:14 +03:00
|
|
|
{ "ICH9-LPC", ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, "off" },
|
2021-11-12 14:08:54 +03:00
|
|
|
{ "ICH9-LPC", "x-keep-pci-slot-hpc", "true" },
|
2021-05-07 16:36:49 +03:00
|
|
|
};
|
2021-03-31 14:19:00 +03:00
|
|
|
const size_t pc_compat_6_0_len = G_N_ELEMENTS(pc_compat_6_0);
|
|
|
|
|
2020-12-07 17:07:39 +03:00
|
|
|
GlobalProperty pc_compat_5_2[] = {
|
|
|
|
{ "ICH9-LPC", "x-smi-cpu-hotunplug", "off" },
|
|
|
|
};
|
2020-11-09 20:39:28 +03:00
|
|
|
const size_t pc_compat_5_2_len = G_N_ELEMENTS(pc_compat_5_2);
|
|
|
|
|
2020-09-23 12:46:40 +03:00
|
|
|
GlobalProperty pc_compat_5_1[] = {
|
|
|
|
{ "ICH9-LPC", "x-smi-cpu-hotplug", "off" },
|
2020-10-05 17:18:19 +03:00
|
|
|
{ TYPE_X86_CPU, "kvm-msi-ext-dest-id", "off" },
|
2020-09-23 12:46:40 +03:00
|
|
|
};
|
2020-08-19 17:40:16 +03:00
|
|
|
const size_t pc_compat_5_1_len = G_N_ELEMENTS(pc_compat_5_1);
|
|
|
|
|
hw/pci-host: save/restore pci host config register
The pci host config register is used to save PCI address for
read/write config data. If guest writes a value to config register,
and then QEMU pauses the vcpu to migrate, after the migration, the guest
will continue to write pci config data, and the write data will be ignored
because of new qemu process losing the config register state.
To trigger the bug:
1. guest is booting in seabios.
2. guest enables the SMRAM in seabios:piix4_apmc_smm_setup, and then
expects to disable the SMRAM by pci_config_writeb.
3. after guest writes the pci host config register, QEMU pauses vcpu
to finish migration.
4. guest write of config data(0x0A) fails to disable the SMRAM because
the config register state is lost.
5. guest continues to boot and crashes in ipxe option ROM due to SMRAM
in enabled state.
Example Reproducer:
step 1. Make modifications to seabios and qemu for increase reproduction
efficiency, write 0xf0 to 0x402 port notify qemu to stop vcpu after
0x0cf8 port wrote i440 configure register. qemu stop vcpu when catch
0x402 port wrote 0xf0.
seabios:/src/hw/pci.c
@@ -52,6 +52,11 @@ void pci_config_writeb(u16 bdf, u32 addr, u8 val)
writeb(mmconfig_addr(bdf, addr), val);
} else {
outl(ioconfig_cmd(bdf, addr), PORT_PCI_CMD);
+ if (bdf == 0 && addr == 0x72 && val == 0xa) {
+ dprintf(1, "stop vcpu\n");
+ outb(0xf0, 0x402); // notify qemu to stop vcpu
+ dprintf(1, "resume vcpu\n");
+ }
outb(val, PORT_PCI_DATA + (addr & 3));
}
}
qemu:hw/char/debugcon.c
@@ -60,6 +61,9 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val,
printf(" [debugcon: write addr=0x%04" HWADDR_PRIx " val=0x%02" PRIx64 "]\n", addr, val);
#endif
+ if (ch == 0xf0) {
+ vm_stop(RUN_STATE_PAUSED);
+ }
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
qemu_chr_fe_write_all(&s->chr, &ch, 1);
step 2. start vm1 by the following command line, and then vm stopped.
$ qemu-system-x86_64 -machine pc-i440fx-5.0,accel=kvm\
-netdev tap,ifname=tap-test,id=hostnet0,vhost=on,downscript=no,script=no\
-device virtio-net-pci,netdev=hostnet0,id=net0,bus=pci.0,addr=0x13,bootindex=3\
-device cirrus-vga,id=video0,vgamem_mb=16,bus=pci.0,addr=0x2\
-chardev file,id=seabios,path=/var/log/test.seabios,append=on\
-device isa-debugcon,iobase=0x402,chardev=seabios\
-monitor stdio
step 3. start vm2 to accept vm1 state.
$ qemu-system-x86_64 -machine pc-i440fx-5.0,accel=kvm\
-netdev tap,ifname=tap-test1,id=hostnet0,vhost=on,downscript=no,script=no\
-device virtio-net-pci,netdev=hostnet0,id=net0,bus=pci.0,addr=0x13,bootindex=3\
-device cirrus-vga,id=video0,vgamem_mb=16,bus=pci.0,addr=0x2\
-chardev file,id=seabios,path=/var/log/test.seabios,append=on\
-device isa-debugcon,iobase=0x402,chardev=seabios\
-monitor stdio \
-incoming tcp:127.0.0.1:8000
step 4. execute the following qmp command in vm1 to migrate.
(qemu) migrate tcp:127.0.0.1:8000
step 5. execute the following qmp command in vm2 to resume vcpu.
(qemu) cont
Before this patch, we get KVM "emulation failure" error on vm2.
This patch fixes it.
Cc: qemu-stable@nongnu.org
Signed-off-by: Hogan Wang <hogan.wang@huawei.com>
Message-Id: <20200727084621.3279-1-hogan.wang@huawei.com>
Reported-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2020-07-27 11:46:20 +03:00
|
|
|
GlobalProperty pc_compat_5_0[] = {
|
|
|
|
};
|
2020-04-29 17:46:05 +03:00
|
|
|
const size_t pc_compat_5_0_len = G_N_ELEMENTS(pc_compat_5_0);
|
|
|
|
|
2019-12-09 16:08:55 +03:00
|
|
|
GlobalProperty pc_compat_4_2[] = {
|
|
|
|
{ "mch", "smbase-smram", "off" },
|
|
|
|
};
|
2019-11-12 13:48:11 +03:00
|
|
|
const size_t pc_compat_4_2_len = G_N_ELEMENTS(pc_compat_4_2);
|
|
|
|
|
2019-07-24 13:35:24 +03:00
|
|
|
GlobalProperty pc_compat_4_1[] = {};
|
|
|
|
const size_t pc_compat_4_1_len = G_N_ELEMENTS(pc_compat_4_1);
|
|
|
|
|
2019-04-11 13:20:25 +03:00
|
|
|
GlobalProperty pc_compat_4_0[] = {};
|
|
|
|
const size_t pc_compat_4_0_len = G_N_ELEMENTS(pc_compat_4_0);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_3_1[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ "intel-iommu", "dma-drain", "off" },
|
2018-12-20 15:07:32 +03:00
|
|
|
{ "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "off" },
|
|
|
|
{ "Opteron_G4" "-" TYPE_X86_CPU, "rdtscp", "off" },
|
2019-01-21 18:50:51 +03:00
|
|
|
{ "Opteron_G4" "-" TYPE_X86_CPU, "npt", "off" },
|
|
|
|
{ "Opteron_G4" "-" TYPE_X86_CPU, "nrip-save", "off" },
|
2018-12-20 15:07:32 +03:00
|
|
|
{ "Opteron_G5" "-" TYPE_X86_CPU, "rdtscp", "off" },
|
2019-01-21 18:50:51 +03:00
|
|
|
{ "Opteron_G5" "-" TYPE_X86_CPU, "npt", "off" },
|
|
|
|
{ "Opteron_G5" "-" TYPE_X86_CPU, "nrip-save", "off" },
|
|
|
|
{ "EPYC" "-" TYPE_X86_CPU, "npt", "off" },
|
|
|
|
{ "EPYC" "-" TYPE_X86_CPU, "nrip-save", "off" },
|
|
|
|
{ "EPYC-IBPB" "-" TYPE_X86_CPU, "npt", "off" },
|
|
|
|
{ "EPYC-IBPB" "-" TYPE_X86_CPU, "nrip-save", "off" },
|
2018-12-20 15:11:00 +03:00
|
|
|
{ "Skylake-Client" "-" TYPE_X86_CPU, "mpx", "on" },
|
|
|
|
{ "Skylake-Client-IBRS" "-" TYPE_X86_CPU, "mpx", "on" },
|
|
|
|
{ "Skylake-Server" "-" TYPE_X86_CPU, "mpx", "on" },
|
|
|
|
{ "Skylake-Server-IBRS" "-" TYPE_X86_CPU, "mpx", "on" },
|
|
|
|
{ "Cascadelake-Server" "-" TYPE_X86_CPU, "mpx", "on" },
|
|
|
|
{ "Icelake-Client" "-" TYPE_X86_CPU, "mpx", "on" },
|
|
|
|
{ "Icelake-Server" "-" TYPE_X86_CPU, "mpx", "on" },
|
2018-12-27 05:43:03 +03:00
|
|
|
{ "Cascadelake-Server" "-" TYPE_X86_CPU, "stepping", "5" },
|
2019-01-30 02:52:59 +03:00
|
|
|
{ TYPE_X86_CPU, "x-intel-pt-auto-level", "off" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_3_1_len = G_N_ELEMENTS(pc_compat_3_1);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_3_0[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ TYPE_X86_CPU, "x-hv-synic-kvm-only", "on" },
|
|
|
|
{ "Skylake-Server" "-" TYPE_X86_CPU, "pku", "off" },
|
|
|
|
{ "Skylake-Server-IBRS" "-" TYPE_X86_CPU, "pku", "off" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_3_0_len = G_N_ELEMENTS(pc_compat_3_0);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_12[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ TYPE_X86_CPU, "legacy-cache", "on" },
|
|
|
|
{ TYPE_X86_CPU, "topoext", "off" },
|
|
|
|
{ "EPYC-" TYPE_X86_CPU, "xlevel", "0x8000000a" },
|
|
|
|
{ "EPYC-IBPB-" TYPE_X86_CPU, "xlevel", "0x8000000a" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_12_len = G_N_ELEMENTS(pc_compat_2_12);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_11[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ TYPE_X86_CPU, "x-migrate-smi-count", "off" },
|
|
|
|
{ "Skylake-Server" "-" TYPE_X86_CPU, "clflushopt", "off" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_11_len = G_N_ELEMENTS(pc_compat_2_11);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_10[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ TYPE_X86_CPU, "x-hv-max-vps", "0x40" },
|
|
|
|
{ "i440FX-pcihost", "x-pci-hole64-fix", "off" },
|
|
|
|
{ "q35-pcihost", "x-pci-hole64-fix", "off" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_10_len = G_N_ELEMENTS(pc_compat_2_10);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_9[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ "mch", "extended-tseg-mbytes", "0" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_9_len = G_N_ELEMENTS(pc_compat_2_9);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_8[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ TYPE_X86_CPU, "tcg-cpuid", "off" },
|
|
|
|
{ "kvmclock", "x-mach-use-reliable-get-clock", "off" },
|
|
|
|
{ "ICH9-LPC", "x-smi-broadcast", "off" },
|
|
|
|
{ TYPE_X86_CPU, "vmware-cpuid-freq", "off" },
|
|
|
|
{ "Haswell-" TYPE_X86_CPU, "stepping", "1" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_8_len = G_N_ELEMENTS(pc_compat_2_8);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_7[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ TYPE_X86_CPU, "l3-cache", "off" },
|
|
|
|
{ TYPE_X86_CPU, "full-cpuid-auto-level", "off" },
|
|
|
|
{ "Opteron_G3" "-" TYPE_X86_CPU, "family", "15" },
|
|
|
|
{ "Opteron_G3" "-" TYPE_X86_CPU, "model", "6" },
|
|
|
|
{ "Opteron_G3" "-" TYPE_X86_CPU, "stepping", "1" },
|
|
|
|
{ "isa-pcspk", "migrate", "off" },
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_7_len = G_N_ELEMENTS(pc_compat_2_7);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_6[] = {
|
2019-01-07 22:30:20 +03:00
|
|
|
{ TYPE_X86_CPU, "cpuid-0xb", "off" },
|
|
|
|
{ "vmxnet3", "romfile", "" },
|
|
|
|
{ TYPE_X86_CPU, "fill-mtrr-mask", "off" },
|
|
|
|
{ "apic-common", "legacy-instance-id", "on", }
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_6_len = G_N_ELEMENTS(pc_compat_2_6);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_5[] = {};
|
|
|
|
const size_t pc_compat_2_5_len = G_N_ELEMENTS(pc_compat_2_5);
|
|
|
|
|
2018-12-12 18:36:30 +03:00
|
|
|
GlobalProperty pc_compat_2_4[] = {
|
|
|
|
PC_CPU_MODEL_IDS("2.4.0")
|
2019-01-07 22:30:20 +03:00
|
|
|
{ "Haswell-" TYPE_X86_CPU, "abm", "off" },
|
|
|
|
{ "Haswell-noTSX-" TYPE_X86_CPU, "abm", "off" },
|
|
|
|
{ "Broadwell-" TYPE_X86_CPU, "abm", "off" },
|
|
|
|
{ "Broadwell-noTSX-" TYPE_X86_CPU, "abm", "off" },
|
|
|
|
{ "host" "-" TYPE_X86_CPU, "host-cache-info", "on" },
|
|
|
|
{ TYPE_X86_CPU, "check", "off" },
|
|
|
|
{ "qemu64" "-" TYPE_X86_CPU, "sse4a", "on" },
|
|
|
|
{ "qemu64" "-" TYPE_X86_CPU, "abm", "on" },
|
|
|
|
{ "qemu64" "-" TYPE_X86_CPU, "popcnt", "on" },
|
|
|
|
{ "qemu32" "-" TYPE_X86_CPU, "popcnt", "on" },
|
|
|
|
{ "Opteron_G2" "-" TYPE_X86_CPU, "rdtscp", "on" },
|
|
|
|
{ "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "on" },
|
|
|
|
{ "Opteron_G4" "-" TYPE_X86_CPU, "rdtscp", "on" },
|
|
|
|
{ "Opteron_G5" "-" TYPE_X86_CPU, "rdtscp", "on", }
|
2018-12-12 18:36:30 +03:00
|
|
|
};
|
|
|
|
const size_t pc_compat_2_4_len = G_N_ELEMENTS(pc_compat_2_4);
|
|
|
|
|
2019-10-18 16:59:06 +03:00
|
|
|
GSIState *pc_gsi_create(qemu_irq **irqs, bool pci_enabled)
|
|
|
|
{
|
|
|
|
GSIState *s;
|
|
|
|
|
|
|
|
s = g_new0(GSIState, 1);
|
|
|
|
if (kvm_ioapic_in_kernel()) {
|
|
|
|
kvm_pc_setup_irq_routing(pci_enabled);
|
|
|
|
}
|
2023-02-13 20:30:30 +03:00
|
|
|
*irqs = qemu_allocate_irqs(gsi_handler, s, IOAPIC_NUM_PINS);
|
2019-10-18 16:59:06 +03:00
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2012-09-19 15:50:08 +04:00
|
|
|
static void ioport80_write(void *opaque, hwaddr addr, uint64_t data,
|
|
|
|
unsigned size)
|
2004-03-14 15:20:30 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-01-09 22:10:22 +04:00
|
|
|
static uint64_t ioport80_read(void *opaque, hwaddr addr, unsigned size)
|
|
|
|
{
|
2013-01-11 20:41:43 +04:00
|
|
|
return 0xffffffffffffffffULL;
|
2013-01-09 22:10:22 +04:00
|
|
|
}
|
|
|
|
|
2023-07-14 14:16:12 +03:00
|
|
|
/* MS-DOS compatibility mode FPU exception support */
|
2012-09-19 15:50:08 +04:00
|
|
|
static void ioportF0_write(void *opaque, hwaddr addr, uint64_t data,
|
|
|
|
unsigned size)
|
2004-05-09 01:03:41 +04:00
|
|
|
{
|
2019-10-16 11:18:10 +03:00
|
|
|
if (tcg_enabled()) {
|
2019-10-16 11:34:39 +03:00
|
|
|
cpu_set_ignne();
|
2019-10-16 11:18:10 +03:00
|
|
|
}
|
2004-05-09 01:03:41 +04:00
|
|
|
}
|
|
|
|
|
2013-01-09 22:10:22 +04:00
|
|
|
static uint64_t ioportF0_read(void *opaque, hwaddr addr, unsigned size)
|
|
|
|
{
|
2013-01-11 20:41:43 +04:00
|
|
|
return 0xffffffffffffffffULL;
|
2013-01-09 22:10:22 +04:00
|
|
|
}
|
|
|
|
|
2004-03-31 22:58:38 +04:00
|
|
|
/* PC cmos mappings */
|
|
|
|
|
2004-03-14 15:20:30 +03:00
|
|
|
#define REG_EQUIPMENT_BYTE 0x14
|
|
|
|
|
2023-02-11 02:17:51 +03:00
|
|
|
static void cmos_init_hd(MC146818RtcState *s, int type_ofs, int info_ofs,
|
2012-07-10 13:12:38 +04:00
|
|
|
int16_t cylinders, int8_t heads, int8_t sectors)
|
2004-10-09 20:47:59 +04:00
|
|
|
{
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, type_ofs, 47);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs, cylinders);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 1, cylinders >> 8);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 2, heads);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 3, 0xff);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 4, 0xff);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 6, cylinders);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 7, cylinders >> 8);
|
|
|
|
mc146818rtc_set_cmos_data(s, info_ofs + 8, sectors);
|
2004-10-09 20:47:59 +04:00
|
|
|
}
|
|
|
|
|
2007-10-31 04:54:04 +03:00
|
|
|
/* convert boot_device letter to something recognizable by the bios */
|
|
|
|
static int boot_device2nibble(char boot_device)
|
|
|
|
{
|
|
|
|
switch(boot_device) {
|
|
|
|
case 'a':
|
|
|
|
case 'b':
|
|
|
|
return 0x01; /* floppy boot */
|
|
|
|
case 'c':
|
|
|
|
return 0x02; /* hard drive boot */
|
|
|
|
case 'd':
|
|
|
|
return 0x03; /* CD-ROM boot */
|
|
|
|
case 'n':
|
|
|
|
return 0x04; /* Network boot */
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-02-13 12:56:56 +03:00
|
|
|
static void set_boot_dev(PCMachineState *pcms, MC146818RtcState *s,
|
|
|
|
const char *boot_device, Error **errp)
|
2008-05-05 00:11:34 +04:00
|
|
|
{
|
|
|
|
#define PC_MAX_BOOT_DEVICES 3
|
|
|
|
int nbds, bds[3] = { 0, };
|
|
|
|
int i;
|
|
|
|
|
|
|
|
nbds = strlen(boot_device);
|
|
|
|
if (nbds > PC_MAX_BOOT_DEVICES) {
|
2014-12-03 22:04:02 +03:00
|
|
|
error_setg(errp, "Too many boot devices for PC");
|
|
|
|
return;
|
2008-05-05 00:11:34 +04:00
|
|
|
}
|
|
|
|
for (i = 0; i < nbds; i++) {
|
|
|
|
bds[i] = boot_device2nibble(boot_device[i]);
|
|
|
|
if (bds[i] == 0) {
|
2014-12-03 22:04:02 +03:00
|
|
|
error_setg(errp, "Invalid boot device for PC: '%c'",
|
|
|
|
boot_device[i]);
|
|
|
|
return;
|
2008-05-05 00:11:34 +04:00
|
|
|
}
|
|
|
|
}
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x3d, (bds[1] << 4) | bds[0]);
|
2024-02-13 12:56:56 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x38, (bds[2] << 4) | !pcms->fd_bootchk);
|
2008-05-05 00:11:34 +04:00
|
|
|
}
|
|
|
|
|
2014-12-03 22:04:02 +03:00
|
|
|
static void pc_boot_set(void *opaque, const char *boot_device, Error **errp)
|
2010-02-17 20:07:48 +03:00
|
|
|
{
|
2024-03-03 21:53:30 +03:00
|
|
|
PCMachineState *pcms = opaque;
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(pcms);
|
2024-02-13 12:56:56 +03:00
|
|
|
|
2024-03-03 21:53:30 +03:00
|
|
|
set_boot_dev(pcms, MC146818_RTC(x86ms->rtc), boot_device, errp);
|
2010-02-17 20:07:48 +03:00
|
|
|
}
|
|
|
|
|
2023-02-11 02:17:51 +03:00
|
|
|
static void pc_cmos_init_floppy(MC146818RtcState *rtc_state, ISADevice *floppy)
|
2015-06-25 16:35:05 +03:00
|
|
|
{
|
2024-04-25 21:43:13 +03:00
|
|
|
int val, nb;
|
2016-01-22 23:50:56 +03:00
|
|
|
FloppyDriveType fd_type[2] = { FLOPPY_DRIVE_TYPE_NONE,
|
|
|
|
FLOPPY_DRIVE_TYPE_NONE };
|
2015-06-25 16:35:05 +03:00
|
|
|
|
2024-04-25 21:43:13 +03:00
|
|
|
#ifdef CONFIG_FDC_ISA
|
2015-06-25 16:35:05 +03:00
|
|
|
/* floppy type */
|
|
|
|
if (floppy) {
|
2024-04-25 21:43:13 +03:00
|
|
|
for (int i = 0; i < 2; i++) {
|
2015-06-25 16:35:05 +03:00
|
|
|
fd_type[i] = isa_fdc_get_drive_type(floppy, i);
|
|
|
|
}
|
|
|
|
}
|
2024-04-25 21:43:13 +03:00
|
|
|
#endif
|
|
|
|
|
2015-06-25 16:35:05 +03:00
|
|
|
val = (cmos_get_fd_drive_type(fd_type[0]) << 4) |
|
|
|
|
cmos_get_fd_drive_type(fd_type[1]);
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(rtc_state, 0x10, val);
|
2015-06-25 16:35:05 +03:00
|
|
|
|
2023-02-11 02:18:53 +03:00
|
|
|
val = mc146818rtc_get_cmos_data(rtc_state, REG_EQUIPMENT_BYTE);
|
2015-06-25 16:35:05 +03:00
|
|
|
nb = 0;
|
2016-01-22 23:50:56 +03:00
|
|
|
if (fd_type[0] != FLOPPY_DRIVE_TYPE_NONE) {
|
2015-06-25 16:35:05 +03:00
|
|
|
nb++;
|
|
|
|
}
|
2016-01-22 23:50:56 +03:00
|
|
|
if (fd_type[1] != FLOPPY_DRIVE_TYPE_NONE) {
|
2015-06-25 16:35:05 +03:00
|
|
|
nb++;
|
|
|
|
}
|
|
|
|
switch (nb) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
val |= 0x01; /* 1 drive, ready for boot */
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
val |= 0x41; /* 2 drives, ready for boot */
|
|
|
|
break;
|
|
|
|
}
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(rtc_state, REG_EQUIPMENT_BYTE, val);
|
2015-06-25 16:35:05 +03:00
|
|
|
}
|
|
|
|
|
hw/i386/pc: reflect any FDC @ ioport 0x3f0 in the CMOS
With the pc-q35-2.4 machine type, if the user creates an ISA FDC manually:
-device isa-fdc,driveA=drive-fdc0-0-0 \
-drive file=...,if=none,id=drive-fdc0-0-0,format=raw
then the board-default FDC will be skipped, and only the explicitly
requested FDC will exist. qtree-wise, this is correct; however such an FDC
is currently not registered in the CMOS, because that code is only reached
for the board-default FDC.
The pc_cmos_init_late() one-shot reset handler -- one-shot because the
CMOS is not reprogrammed during warm reset -- should search for any ISA
FDC devices, created implicitly (by board code) or explicitly, and set the
CMOS accordingly to the ISA FDC(s) with iobase=0x3f0:
- if there is no such FDC, report both drives absent,
- if there is exactly one such FDC, report its drives in the CMOS,
- if there are more than one such FDCs, then pick one (it is not specified
which one), and print a warning about the ambiguity.
Cc: Jan Tomko <jtomko@redhat.com>
Cc: John Snow <jsnow@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Reported-by: Jan Tomko <jtomko@redhat.com>
Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-25 16:35:06 +03:00
|
|
|
typedef struct check_fdc_state {
|
|
|
|
ISADevice *floppy;
|
|
|
|
bool multiple;
|
|
|
|
} CheckFdcState;
|
|
|
|
|
|
|
|
static int check_fdc(Object *obj, void *opaque)
|
|
|
|
{
|
|
|
|
CheckFdcState *state = opaque;
|
|
|
|
Object *fdc;
|
|
|
|
uint32_t iobase;
|
|
|
|
Error *local_err = NULL;
|
|
|
|
|
|
|
|
fdc = object_dynamic_cast(obj, TYPE_ISA_FDC);
|
|
|
|
if (!fdc) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-06-07 19:36:22 +03:00
|
|
|
iobase = object_property_get_uint(obj, "iobase", &local_err);
|
hw/i386/pc: reflect any FDC @ ioport 0x3f0 in the CMOS
With the pc-q35-2.4 machine type, if the user creates an ISA FDC manually:
-device isa-fdc,driveA=drive-fdc0-0-0 \
-drive file=...,if=none,id=drive-fdc0-0-0,format=raw
then the board-default FDC will be skipped, and only the explicitly
requested FDC will exist. qtree-wise, this is correct; however such an FDC
is currently not registered in the CMOS, because that code is only reached
for the board-default FDC.
The pc_cmos_init_late() one-shot reset handler -- one-shot because the
CMOS is not reprogrammed during warm reset -- should search for any ISA
FDC devices, created implicitly (by board code) or explicitly, and set the
CMOS accordingly to the ISA FDC(s) with iobase=0x3f0:
- if there is no such FDC, report both drives absent,
- if there is exactly one such FDC, report its drives in the CMOS,
- if there are more than one such FDCs, then pick one (it is not specified
which one), and print a warning about the ambiguity.
Cc: Jan Tomko <jtomko@redhat.com>
Cc: John Snow <jsnow@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Reported-by: Jan Tomko <jtomko@redhat.com>
Suggested-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2015-06-25 16:35:06 +03:00
|
|
|
if (local_err || iobase != 0x3f0) {
|
|
|
|
error_free(local_err);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->floppy) {
|
|
|
|
state->multiple = true;
|
|
|
|
} else {
|
|
|
|
state->floppy = ISA_DEVICE(obj);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char * const fdc_container_path[] = {
|
|
|
|
"/unattached", "/peripheral", "/peripheral-anon"
|
|
|
|
};
|
|
|
|
|
2015-12-30 23:11:51 +03:00
|
|
|
/*
|
|
|
|
* Locate the FDC at IO address 0x3f0, in order to configure the CMOS registers
|
|
|
|
* and ACPI objects.
|
|
|
|
*/
|
2022-05-20 21:01:03 +03:00
|
|
|
static ISADevice *pc_find_fdc0(void)
|
2015-12-30 23:11:51 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Object *container;
|
|
|
|
CheckFdcState state = { 0 };
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(fdc_container_path); i++) {
|
|
|
|
container = container_get(qdev_get_machine(), fdc_container_path[i]);
|
|
|
|
object_child_foreach(container, check_fdc, &state);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state.multiple) {
|
2017-07-12 16:57:41 +03:00
|
|
|
warn_report("multiple floppy disk controllers with "
|
|
|
|
"iobase=0x3f0 have been found");
|
2015-12-18 18:35:24 +03:00
|
|
|
error_printf("the one being picked for CMOS setup might not reflect "
|
2017-09-11 22:52:43 +03:00
|
|
|
"your intent");
|
2015-12-30 23:11:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return state.floppy;
|
|
|
|
}
|
|
|
|
|
2024-02-20 19:06:14 +03:00
|
|
|
static void pc_cmos_init_late(PCMachineState *pcms)
|
2010-06-24 21:58:20 +04:00
|
|
|
{
|
2024-02-20 19:06:14 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(pcms);
|
|
|
|
MC146818RtcState *s = MC146818_RTC(x86ms->rtc);
|
2012-07-10 13:12:38 +04:00
|
|
|
int16_t cylinders;
|
|
|
|
int8_t heads, sectors;
|
2010-06-24 21:58:20 +04:00
|
|
|
int val;
|
2012-07-10 13:12:53 +04:00
|
|
|
int i, trans;
|
2010-06-24 21:58:20 +04:00
|
|
|
|
2012-07-10 13:12:38 +04:00
|
|
|
val = 0;
|
2024-02-20 19:06:14 +03:00
|
|
|
if (pcms->idebus[0] &&
|
|
|
|
ide_get_geometry(pcms->idebus[0], 0,
|
|
|
|
&cylinders, &heads, §ors) >= 0) {
|
2012-07-10 13:12:38 +04:00
|
|
|
cmos_init_hd(s, 0x19, 0x1b, cylinders, heads, sectors);
|
|
|
|
val |= 0xf0;
|
|
|
|
}
|
2024-02-20 19:06:14 +03:00
|
|
|
if (pcms->idebus[0] &&
|
|
|
|
ide_get_geometry(pcms->idebus[0], 1,
|
|
|
|
&cylinders, &heads, §ors) >= 0) {
|
2012-07-10 13:12:38 +04:00
|
|
|
cmos_init_hd(s, 0x1a, 0x24, cylinders, heads, sectors);
|
|
|
|
val |= 0x0f;
|
|
|
|
}
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x12, val);
|
2010-06-24 21:58:20 +04:00
|
|
|
|
|
|
|
val = 0;
|
|
|
|
for (i = 0; i < 4; i++) {
|
2012-07-10 13:12:38 +04:00
|
|
|
/* NOTE: ide_get_geometry() returns the physical
|
|
|
|
geometry. It is always such that: 1 <= sects <= 63, 1
|
|
|
|
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
|
|
|
|
geometry can be different if a translation is done. */
|
2024-02-20 19:06:14 +03:00
|
|
|
BusState *idebus = pcms->idebus[i / 2];
|
|
|
|
if (idebus &&
|
|
|
|
ide_get_geometry(idebus, i % 2,
|
2012-07-10 13:12:38 +04:00
|
|
|
&cylinders, &heads, §ors) >= 0) {
|
2024-02-20 19:06:14 +03:00
|
|
|
trans = ide_get_bios_chs_trans(idebus, i % 2) - 1;
|
2012-07-10 13:12:53 +04:00
|
|
|
assert((trans & ~3) == 0);
|
|
|
|
val |= trans << (i * 2);
|
2010-06-24 21:58:20 +04:00
|
|
|
}
|
|
|
|
}
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x39, val);
|
2010-06-24 21:58:20 +04:00
|
|
|
|
2015-12-30 23:11:51 +03:00
|
|
|
pc_cmos_init_floppy(s, pc_find_fdc0());
|
2004-03-31 22:58:38 +04:00
|
|
|
|
|
|
|
/* various important CMOS locations needed by PC/Bochs bios */
|
2004-03-14 15:20:30 +03:00
|
|
|
|
|
|
|
/* memory size */
|
2012-08-15 15:12:20 +04:00
|
|
|
/* base memory (first MiB) */
|
2019-10-22 10:39:50 +03:00
|
|
|
val = MIN(x86ms->below_4g_mem_size / KiB, 640);
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x15, val);
|
|
|
|
mc146818rtc_set_cmos_data(s, 0x16, val >> 8);
|
2012-08-15 15:12:20 +04:00
|
|
|
/* extended memory (next 64MiB) */
|
2019-10-22 10:39:50 +03:00
|
|
|
if (x86ms->below_4g_mem_size > 1 * MiB) {
|
|
|
|
val = (x86ms->below_4g_mem_size - 1 * MiB) / KiB;
|
2012-08-15 15:12:20 +04:00
|
|
|
} else {
|
|
|
|
val = 0;
|
|
|
|
}
|
2004-03-14 15:20:30 +03:00
|
|
|
if (val > 65535)
|
|
|
|
val = 65535;
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x17, val);
|
|
|
|
mc146818rtc_set_cmos_data(s, 0x18, val >> 8);
|
|
|
|
mc146818rtc_set_cmos_data(s, 0x30, val);
|
|
|
|
mc146818rtc_set_cmos_data(s, 0x31, val >> 8);
|
2012-08-15 15:12:20 +04:00
|
|
|
/* memory between 16MiB and 4GiB */
|
2019-10-22 10:39:50 +03:00
|
|
|
if (x86ms->below_4g_mem_size > 16 * MiB) {
|
|
|
|
val = (x86ms->below_4g_mem_size - 16 * MiB) / (64 * KiB);
|
2012-08-15 15:12:20 +04:00
|
|
|
} else {
|
2004-06-26 19:53:17 +04:00
|
|
|
val = 0;
|
2012-08-15 15:12:20 +04:00
|
|
|
}
|
2004-03-14 15:20:30 +03:00
|
|
|
if (val > 65535)
|
|
|
|
val = 65535;
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x34, val);
|
|
|
|
mc146818rtc_set_cmos_data(s, 0x35, val >> 8);
|
2012-08-15 15:12:20 +04:00
|
|
|
/* memory above 4GiB */
|
2019-10-22 10:39:50 +03:00
|
|
|
val = x86ms->above_4g_mem_size / 65536;
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, 0x5b, val);
|
|
|
|
mc146818rtc_set_cmos_data(s, 0x5c, val >> 8);
|
|
|
|
mc146818rtc_set_cmos_data(s, 0x5d, val >> 16);
|
2007-09-17 12:09:54 +04:00
|
|
|
|
2004-03-31 22:58:38 +04:00
|
|
|
val = 0;
|
|
|
|
val |= 0x02; /* FPU is there */
|
|
|
|
val |= 0x04; /* PS/2 mouse installed */
|
2023-02-11 02:18:53 +03:00
|
|
|
mc146818rtc_set_cmos_data(s, REG_EQUIPMENT_BYTE, val);
|
2004-03-14 15:20:30 +03:00
|
|
|
}
|
|
|
|
|
2010-05-22 11:59:01 +04:00
|
|
|
static void handle_a20_line_change(void *opaque, int irq, int level)
|
2005-11-22 02:34:32 +03:00
|
|
|
{
|
2013-01-18 18:19:06 +04:00
|
|
|
X86CPU *cpu = opaque;
|
2004-04-06 00:26:03 +04:00
|
|
|
|
2010-05-22 11:59:01 +04:00
|
|
|
/* XXX: send to all CPUs ? */
|
2011-01-06 21:24:35 +03:00
|
|
|
/* XXX: add logic to handle multiple A20 line sources */
|
2013-01-18 18:19:06 +04:00
|
|
|
x86_cpu_set_a20(cpu, level);
|
2004-04-06 00:26:03 +04:00
|
|
|
}
|
|
|
|
|
2004-03-15 00:46:48 +03:00
|
|
|
#define NE2000_NB_MAX 6
|
|
|
|
|
2009-09-13 12:32:37 +04:00
|
|
|
static const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
|
|
|
|
0x280, 0x380 };
|
|
|
|
static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
|
2004-03-15 00:46:48 +03:00
|
|
|
|
2023-10-20 02:07:45 +03:00
|
|
|
static gboolean pc_init_ne2k_isa(ISABus *bus, NICInfo *nd, Error **errp)
|
2006-02-05 07:14:41 +03:00
|
|
|
{
|
|
|
|
static int nb_ne2k = 0;
|
|
|
|
|
2023-10-20 02:07:45 +03:00
|
|
|
if (nb_ne2k == NE2000_NB_MAX) {
|
|
|
|
error_setg(errp,
|
|
|
|
"maximum number of ISA NE2000 devices exceeded");
|
|
|
|
return false;
|
|
|
|
}
|
2011-12-16 01:09:51 +04:00
|
|
|
isa_ne2000_init(bus, ne2000_io[nb_ne2k],
|
2009-09-10 13:43:33 +04:00
|
|
|
ne2000_irq[nb_ne2k], nd);
|
2006-02-05 07:14:41 +03:00
|
|
|
nb_ne2k++;
|
2023-10-20 02:07:45 +03:00
|
|
|
return true;
|
2006-02-05 07:14:41 +03:00
|
|
|
}
|
|
|
|
|
2010-05-14 11:29:15 +04:00
|
|
|
void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
|
2010-03-29 23:23:52 +04:00
|
|
|
{
|
2013-01-18 18:03:43 +04:00
|
|
|
X86CPU *cpu = opaque;
|
2010-03-29 23:23:52 +04:00
|
|
|
|
|
|
|
if (level) {
|
2013-01-18 18:03:43 +04:00
|
|
|
cpu_interrupt(CPU(cpu), CPU_INTERRUPT_SMI);
|
2010-03-29 23:23:52 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-30 13:57:26 +04:00
|
|
|
static
|
2015-12-11 21:42:23 +03:00
|
|
|
void pc_machine_done(Notifier *notifier, void *data)
|
2013-05-30 13:57:26 +04:00
|
|
|
{
|
2015-12-11 21:42:23 +03:00
|
|
|
PCMachineState *pcms = container_of(notifier,
|
|
|
|
PCMachineState, machine_done);
|
2019-10-22 10:39:50 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(pcms);
|
2022-06-08 17:54:35 +03:00
|
|
|
|
2024-02-24 16:58:47 +03:00
|
|
|
cxl_hook_up_pxb_registers(pcms->pcibus, &pcms->cxl_devices_state,
|
2022-06-08 17:54:39 +03:00
|
|
|
&error_fatal);
|
|
|
|
|
|
|
|
if (pcms->cxl_devices_state.is_enabled) {
|
|
|
|
cxl_fmws_link_targets(&pcms->cxl_devices_state, &error_fatal);
|
2022-06-08 17:54:35 +03:00
|
|
|
}
|
2015-06-02 14:23:07 +03:00
|
|
|
|
2016-07-14 19:54:31 +03:00
|
|
|
/* set the number of CPUs */
|
2020-09-15 15:09:03 +03:00
|
|
|
x86_rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus);
|
2016-07-14 19:54:31 +03:00
|
|
|
|
2024-02-24 16:58:47 +03:00
|
|
|
fw_cfg_add_extra_pci_roots(pcms->pcibus, x86ms->fw_cfg);
|
2015-06-02 14:23:07 +03:00
|
|
|
|
2015-12-11 21:42:28 +03:00
|
|
|
acpi_setup();
|
2019-10-22 10:39:50 +03:00
|
|
|
if (x86ms->fw_cfg) {
|
2024-03-14 18:22:54 +03:00
|
|
|
fw_cfg_build_smbios(pcms, x86ms->fw_cfg, pcms->smbios_entry_point_type);
|
2019-10-22 10:39:50 +03:00
|
|
|
fw_cfg_build_feature_control(MACHINE(pcms), x86ms->fw_cfg);
|
2016-11-16 16:04:41 +03:00
|
|
|
/* update FW_CFG_NB_CPUS to account for -device added CPUs */
|
2019-10-22 10:39:50 +03:00
|
|
|
fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
2016-05-24 20:37:18 +03:00
|
|
|
}
|
2024-02-20 19:06:14 +03:00
|
|
|
|
|
|
|
pc_cmos_init_late(pcms);
|
2013-05-30 13:57:26 +04:00
|
|
|
}
|
|
|
|
|
2013-10-29 16:57:34 +04:00
|
|
|
/* setup pci memory address space mapping into system address space */
|
2023-01-05 20:38:26 +03:00
|
|
|
void pc_pci_as_mapping_init(MemoryRegion *system_memory,
|
2013-10-29 16:57:34 +04:00
|
|
|
MemoryRegion *pci_address_space)
|
2013-07-29 18:47:57 +04:00
|
|
|
{
|
2013-10-29 16:57:34 +04:00
|
|
|
/* Set to lower priority than RAM */
|
|
|
|
memory_region_add_subregion_overlap(system_memory, 0x0,
|
|
|
|
pci_address_space, -1);
|
2013-07-29 18:47:57 +04:00
|
|
|
}
|
|
|
|
|
2015-12-11 21:42:25 +03:00
|
|
|
void xen_load_linux(PCMachineState *pcms)
|
2014-07-07 10:34:35 +04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
FWCfgState *fw_cfg;
|
2019-09-30 18:26:29 +03:00
|
|
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
2019-10-22 10:39:50 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(pcms);
|
2014-07-07 10:34:35 +04:00
|
|
|
|
2015-08-07 22:55:53 +03:00
|
|
|
assert(MACHINE(pcms)->kernel_filename != NULL);
|
2014-07-07 10:34:35 +04:00
|
|
|
|
2021-04-26 06:47:10 +03:00
|
|
|
fw_cfg = fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4,
|
|
|
|
&address_space_memory);
|
2019-10-22 10:39:50 +03:00
|
|
|
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus);
|
2014-07-07 10:34:35 +04:00
|
|
|
rom_set_fw(fw_cfg);
|
|
|
|
|
2019-09-30 18:26:29 +03:00
|
|
|
x86_load_linux(x86ms, fw_cfg, pcmc->acpi_data_size,
|
2023-02-09 00:05:35 +03:00
|
|
|
pcmc->pvh_enabled);
|
2014-07-07 10:34:35 +04:00
|
|
|
for (i = 0; i < nb_option_roms; i++) {
|
|
|
|
assert(!strcmp(option_rom[i].name, "linuxboot.bin") ||
|
2016-05-23 21:11:33 +03:00
|
|
|
!strcmp(option_rom[i].name, "linuxboot_dma.bin") ||
|
2019-01-18 15:01:42 +03:00
|
|
|
!strcmp(option_rom[i].name, "pvh.bin") ||
|
2021-10-20 16:59:44 +03:00
|
|
|
!strcmp(option_rom[i].name, "multiboot.bin") ||
|
|
|
|
!strcmp(option_rom[i].name, "multiboot_dma.bin"));
|
2014-07-07 10:34:35 +04:00
|
|
|
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
|
|
|
|
}
|
2019-10-22 10:39:50 +03:00
|
|
|
x86ms->fw_cfg = fw_cfg;
|
2014-07-07 10:34:35 +04:00
|
|
|
}
|
|
|
|
|
2021-09-17 21:59:49 +03:00
|
|
|
#define PC_ROM_MIN_VGA 0xc0000
|
|
|
|
#define PC_ROM_MIN_OPTION 0xc8000
|
|
|
|
#define PC_ROM_MAX 0xe0000
|
|
|
|
#define PC_ROM_ALIGN 0x800
|
|
|
|
#define PC_ROM_SIZE (PC_ROM_MAX - PC_ROM_MIN_VGA)
|
|
|
|
|
2022-07-19 20:00:07 +03:00
|
|
|
static hwaddr pc_above_4g_end(PCMachineState *pcms)
|
|
|
|
{
|
|
|
|
X86MachineState *x86ms = X86_MACHINE(pcms);
|
|
|
|
|
|
|
|
if (pcms->sgx_epc.size != 0) {
|
|
|
|
return sgx_epc_above_4g_end(&pcms->sgx_epc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return x86ms->above_4g_mem_start + x86ms->above_4g_mem_size;
|
|
|
|
}
|
|
|
|
|
2022-07-19 20:00:11 +03:00
|
|
|
static void pc_get_device_memory_range(PCMachineState *pcms,
|
|
|
|
hwaddr *base,
|
|
|
|
ram_addr_t *device_mem_size)
|
2022-07-19 20:00:09 +03:00
|
|
|
{
|
|
|
|
MachineState *machine = MACHINE(pcms);
|
2022-07-19 20:00:11 +03:00
|
|
|
ram_addr_t size;
|
|
|
|
hwaddr addr;
|
|
|
|
|
|
|
|
size = machine->maxram_size - machine->ram_size;
|
|
|
|
addr = ROUND_UP(pc_above_4g_end(pcms), 1 * GiB);
|
|
|
|
|
2024-02-28 11:45:47 +03:00
|
|
|
/* size device region assuming 1G page max alignment per slot */
|
|
|
|
size += (1 * GiB) * machine->ram_slots;
|
2022-07-19 20:00:11 +03:00
|
|
|
|
|
|
|
*base = addr;
|
|
|
|
*device_mem_size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t pc_get_cxl_range_start(PCMachineState *pcms)
|
|
|
|
{
|
|
|
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
2023-10-11 13:53:35 +03:00
|
|
|
MachineState *ms = MACHINE(pcms);
|
2022-07-19 20:00:09 +03:00
|
|
|
hwaddr cxl_base;
|
2022-07-19 20:00:11 +03:00
|
|
|
ram_addr_t size;
|
2022-07-19 20:00:09 +03:00
|
|
|
|
2023-10-11 13:53:35 +03:00
|
|
|
if (pcmc->has_reserved_memory &&
|
|
|
|
(ms->ram_size < ms->maxram_size)) {
|
2022-07-19 20:00:11 +03:00
|
|
|
pc_get_device_memory_range(pcms, &cxl_base, &size);
|
|
|
|
cxl_base += size;
|
2022-07-19 20:00:09 +03:00
|
|
|
} else {
|
|
|
|
cxl_base = pc_above_4g_end(pcms);
|
|
|
|
}
|
|
|
|
|
|
|
|
return cxl_base;
|
|
|
|
}
|
|
|
|
|
2022-07-19 20:00:08 +03:00
|
|
|
static uint64_t pc_get_cxl_range_end(PCMachineState *pcms)
|
|
|
|
{
|
2022-07-19 20:00:10 +03:00
|
|
|
uint64_t start = pc_get_cxl_range_start(pcms) + MiB;
|
|
|
|
|
|
|
|
if (pcms->cxl_devices_state.fixed_windows) {
|
|
|
|
GList *it;
|
|
|
|
|
|
|
|
start = ROUND_UP(start, 256 * MiB);
|
|
|
|
for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
|
|
|
|
CXLFixedWindow *fw = it->data;
|
|
|
|
start += fw->size;
|
2022-07-19 20:00:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return start;
|
|
|
|
}
|
|
|
|
|
2022-07-19 20:00:12 +03:00
|
|
|
static hwaddr pc_max_used_gpa(PCMachineState *pcms, uint64_t pci_hole64_size)
|
|
|
|
{
|
|
|
|
X86CPU *cpu = X86_CPU(first_cpu);
|
hw/i386/pc: improve physical address space bound check for 32-bit x86 systems
32-bit x86 systems do not have a reserved memory for hole64. On those 32-bit
systems without PSE36 or PAE CPU features, hotplugging memory devices are not
supported by QEMU as QEMU always places hotplugged memory above 4 GiB boundary
which is beyond the physical address space of the processor. Linux guests also
does not support memory hotplug on those systems. Please see Linux
kernel commit b59d02ed08690 ("mm/memory_hotplug: disable the functionality
for 32b") for more details.
Therefore, the maximum limit of the guest physical address in the absence of
additional memory devices effectively coincides with the end of
"above 4G memory space" region for 32-bit x86 without PAE/PSE36. When users
configure additional memory devices, after properly accounting for the
additional device memory region to find the maximum value of the guest
physical address, the address will be outside the range of the processor's
physical address space.
This change adds improvements to take above into consideration.
For example, previously this was allowed:
$ ./qemu-system-x86_64 -cpu pentium -m size=10G
With this change now it is no longer allowed:
$ ./qemu-system-x86_64 -cpu pentium -m size=10G
qemu-system-x86_64: Address space limit 0xffffffff < 0x2bfffffff phys-bits too low (32)
However, the following are allowed since on both cases physical address
space of the processor is 36 bits:
$ ./qemu-system-x86_64 -cpu pentium2 -m size=10G
$ ./qemu-system-x86_64 -cpu pentium,pse36=on -m size=10G
For 32-bit, without PAE/PSE36, hotplugging additional memory is no longer allowed.
$ ./qemu-system-i386 -m size=1G,maxmem=3G,slots=2
qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32)
$ ./qemu-system-i386 -machine q35 -m size=1G,maxmem=3G,slots=2
qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32)
A new compatibility flag is introduced to make sure pc_max_used_gpa() keeps
returning the old value for machines 8.1 and older.
Therefore, the above is still allowed for older machine types in order to support
compatibility. Hence, the following still works:
$ ./qemu-system-i386 -machine pc-i440fx-8.1 -m size=1G,maxmem=3G,slots=2
$ ./qemu-system-i386 -machine pc-q35-8.1 -m size=1G,maxmem=3G,slots=2
Further, following is also allowed as with PSE36, the processor has 36-bit
address space:
$ ./qemu-system-i386 -cpu 486,pse36=on -m size=1G,maxmem=3G,slots=2
After calling CPUID with EAX=0x80000001, all AMD64 compliant processors
have the longmode-capable-bit turned on in the extended feature flags (bit 29)
in EDX. The absence of CPUID longmode can be used to differentiate between
32-bit and 64-bit processors and is the recommended approach. QEMU takes this
approach elsewhere (for example, please see x86_cpu_realizefn()), With
this change, pc_max_used_gpa() also uses the same method to detect 32-bit
processors.
Unit tests are modified to not run 32-bit x86 tests that use memory hotplug.
Suggested-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Ani Sinha <anisinha@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Message-Id: <20230922160413.165702-1-anisinha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2023-09-22 19:04:13 +03:00
|
|
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
|
|
|
MachineState *ms = MACHINE(pcms);
|
|
|
|
|
|
|
|
if (cpu->env.features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
|
|
|
|
/* 64-bit systems */
|
|
|
|
return pc_pci_hole64_start() + pci_hole64_size - 1;
|
|
|
|
}
|
2022-07-19 20:00:12 +03:00
|
|
|
|
hw/i386/pc: improve physical address space bound check for 32-bit x86 systems
32-bit x86 systems do not have a reserved memory for hole64. On those 32-bit
systems without PSE36 or PAE CPU features, hotplugging memory devices are not
supported by QEMU as QEMU always places hotplugged memory above 4 GiB boundary
which is beyond the physical address space of the processor. Linux guests also
does not support memory hotplug on those systems. Please see Linux
kernel commit b59d02ed08690 ("mm/memory_hotplug: disable the functionality
for 32b") for more details.
Therefore, the maximum limit of the guest physical address in the absence of
additional memory devices effectively coincides with the end of
"above 4G memory space" region for 32-bit x86 without PAE/PSE36. When users
configure additional memory devices, after properly accounting for the
additional device memory region to find the maximum value of the guest
physical address, the address will be outside the range of the processor's
physical address space.
This change adds improvements to take above into consideration.
For example, previously this was allowed:
$ ./qemu-system-x86_64 -cpu pentium -m size=10G
With this change now it is no longer allowed:
$ ./qemu-system-x86_64 -cpu pentium -m size=10G
qemu-system-x86_64: Address space limit 0xffffffff < 0x2bfffffff phys-bits too low (32)
However, the following are allowed since on both cases physical address
space of the processor is 36 bits:
$ ./qemu-system-x86_64 -cpu pentium2 -m size=10G
$ ./qemu-system-x86_64 -cpu pentium,pse36=on -m size=10G
For 32-bit, without PAE/PSE36, hotplugging additional memory is no longer allowed.
$ ./qemu-system-i386 -m size=1G,maxmem=3G,slots=2
qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32)
$ ./qemu-system-i386 -machine q35 -m size=1G,maxmem=3G,slots=2
qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32)
A new compatibility flag is introduced to make sure pc_max_used_gpa() keeps
returning the old value for machines 8.1 and older.
Therefore, the above is still allowed for older machine types in order to support
compatibility. Hence, the following still works:
$ ./qemu-system-i386 -machine pc-i440fx-8.1 -m size=1G,maxmem=3G,slots=2
$ ./qemu-system-i386 -machine pc-q35-8.1 -m size=1G,maxmem=3G,slots=2
Further, following is also allowed as with PSE36, the processor has 36-bit
address space:
$ ./qemu-system-i386 -cpu 486,pse36=on -m size=1G,maxmem=3G,slots=2
After calling CPUID with EAX=0x80000001, all AMD64 compliant processors
have the longmode-capable-bit turned on in the extended feature flags (bit 29)
in EDX. The absence of CPUID longmode can be used to differentiate between
32-bit and 64-bit processors and is the recommended approach. QEMU takes this
approach elsewhere (for example, please see x86_cpu_realizefn()), With
this change, pc_max_used_gpa() also uses the same method to detect 32-bit
processors.
Unit tests are modified to not run 32-bit x86 tests that use memory hotplug.
Suggested-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Ani Sinha <anisinha@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Message-Id: <20230922160413.165702-1-anisinha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2023-09-22 19:04:13 +03:00
|
|
|
/* 32-bit systems */
|
|
|
|
if (pcmc->broken_32bit_mem_addr_check) {
|
|
|
|
/* old value for compatibility reasons */
|
2022-07-19 20:00:12 +03:00
|
|
|
return ((hwaddr)1 << cpu->phys_bits) - 1;
|
|
|
|
}
|
|
|
|
|
hw/i386/pc: improve physical address space bound check for 32-bit x86 systems
32-bit x86 systems do not have a reserved memory for hole64. On those 32-bit
systems without PSE36 or PAE CPU features, hotplugging memory devices are not
supported by QEMU as QEMU always places hotplugged memory above 4 GiB boundary
which is beyond the physical address space of the processor. Linux guests also
does not support memory hotplug on those systems. Please see Linux
kernel commit b59d02ed08690 ("mm/memory_hotplug: disable the functionality
for 32b") for more details.
Therefore, the maximum limit of the guest physical address in the absence of
additional memory devices effectively coincides with the end of
"above 4G memory space" region for 32-bit x86 without PAE/PSE36. When users
configure additional memory devices, after properly accounting for the
additional device memory region to find the maximum value of the guest
physical address, the address will be outside the range of the processor's
physical address space.
This change adds improvements to take above into consideration.
For example, previously this was allowed:
$ ./qemu-system-x86_64 -cpu pentium -m size=10G
With this change now it is no longer allowed:
$ ./qemu-system-x86_64 -cpu pentium -m size=10G
qemu-system-x86_64: Address space limit 0xffffffff < 0x2bfffffff phys-bits too low (32)
However, the following are allowed since on both cases physical address
space of the processor is 36 bits:
$ ./qemu-system-x86_64 -cpu pentium2 -m size=10G
$ ./qemu-system-x86_64 -cpu pentium,pse36=on -m size=10G
For 32-bit, without PAE/PSE36, hotplugging additional memory is no longer allowed.
$ ./qemu-system-i386 -m size=1G,maxmem=3G,slots=2
qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32)
$ ./qemu-system-i386 -machine q35 -m size=1G,maxmem=3G,slots=2
qemu-system-i386: Address space limit 0xffffffff < 0x1ffffffff phys-bits too low (32)
A new compatibility flag is introduced to make sure pc_max_used_gpa() keeps
returning the old value for machines 8.1 and older.
Therefore, the above is still allowed for older machine types in order to support
compatibility. Hence, the following still works:
$ ./qemu-system-i386 -machine pc-i440fx-8.1 -m size=1G,maxmem=3G,slots=2
$ ./qemu-system-i386 -machine pc-q35-8.1 -m size=1G,maxmem=3G,slots=2
Further, following is also allowed as with PSE36, the processor has 36-bit
address space:
$ ./qemu-system-i386 -cpu 486,pse36=on -m size=1G,maxmem=3G,slots=2
After calling CPUID with EAX=0x80000001, all AMD64 compliant processors
have the longmode-capable-bit turned on in the extended feature flags (bit 29)
in EDX. The absence of CPUID longmode can be used to differentiate between
32-bit and 64-bit processors and is the recommended approach. QEMU takes this
approach elsewhere (for example, please see x86_cpu_realizefn()), With
this change, pc_max_used_gpa() also uses the same method to detect 32-bit
processors.
Unit tests are modified to not run 32-bit x86 tests that use memory hotplug.
Suggested-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Ani Sinha <anisinha@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Message-Id: <20230922160413.165702-1-anisinha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2023-09-22 19:04:13 +03:00
|
|
|
/*
|
|
|
|
* 32-bit systems don't have hole64 but they might have a region for
|
|
|
|
* memory devices. Even if additional hotplugged memory devices might
|
|
|
|
* not be usable by most guest OSes, we need to still consider them for
|
|
|
|
* calculating the highest possible GPA so that we can properly report
|
|
|
|
* if someone configures them on a CPU that cannot possibly address them.
|
|
|
|
*/
|
|
|
|
if (pcmc->has_reserved_memory &&
|
|
|
|
(ms->ram_size < ms->maxram_size)) {
|
|
|
|
hwaddr devmem_start;
|
|
|
|
ram_addr_t devmem_size;
|
|
|
|
|
|
|
|
pc_get_device_memory_range(pcms, &devmem_start, &devmem_size);
|
|
|
|
devmem_start += devmem_size;
|
|
|
|
return devmem_start - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* configuration without any memory hotplug */
|
|
|
|
return pc_above_4g_end(pcms) - 1;
|
2022-07-19 20:00:12 +03:00
|
|
|
}
|
|
|
|
|
i386/pc: relocate 4g start to 1T where applicable
It is assumed that the whole GPA space is available to be DMA
addressable, within a given address space limit, except for a
tiny region before the 4G. Since Linux v5.4, VFIO validates
whether the selected GPA is indeed valid i.e. not reserved by
IOMMU on behalf of some specific devices or platform-defined
restrictions, and thus failing the ioctl(VFIO_DMA_MAP) with
-EINVAL.
AMD systems with an IOMMU are examples of such platforms and
particularly may only have these ranges as allowed:
0000000000000000 - 00000000fedfffff (0 .. 3.982G)
00000000fef00000 - 000000fcffffffff (3.983G .. 1011.9G)
0000010000000000 - ffffffffffffffff (1Tb .. 16Pb[*])
We already account for the 4G hole, albeit if the guest is big
enough we will fail to allocate a guest with >1010G due to the
~12G hole at the 1Tb boundary, reserved for HyperTransport (HT).
[*] there is another reserved region unrelated to HT that exists
in the 256T boundary in Fam 17h according to Errata #1286,
documeted also in "Open-Source Register Reference for AMD Family
17h Processors (PUB)"
When creating the region above 4G, take into account that on AMD
platforms the HyperTransport range is reserved and hence it
cannot be used either as GPAs. On those cases rather than
establishing the start of ram-above-4g to be 4G, relocate instead
to 1Tb. See AMD IOMMU spec, section 2.1.2 "IOMMU Logical
Topology", for more information on the underlying restriction of
IOVAs.
After accounting for the 1Tb hole on AMD hosts, mtree should
look like:
0000000000000000-000000007fffffff (prio 0, i/o):
alias ram-below-4g @pc.ram 0000000000000000-000000007fffffff
0000010000000000-000001ff7fffffff (prio 0, i/o):
alias ram-above-4g @pc.ram 0000000080000000-000000ffffffffff
If the relocation is done or the address space covers it, we
also add the the reserved HT e820 range as reserved.
Default phys-bits on Qemu is TCG_PHYS_ADDR_BITS (40) which is enough
to address 1Tb (0xff ffff ffff). On AMD platforms, if a
ram-above-4g relocation is attempted and the CPU wasn't configured
with a big enough phys-bits, an error message will be printed
due to the maxphysaddr vs maxusedaddr check previously added.
Suggested-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20220719170014.27028-11-joao.m.martins@oracle.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2022-07-19 20:00:13 +03:00
|
|
|
/*
|
|
|
|
* AMD systems with an IOMMU have an additional hole close to the
|
|
|
|
* 1Tb, which are special GPAs that cannot be DMA mapped. Depending
|
|
|
|
* on kernel version, VFIO may or may not let you DMA map those ranges.
|
|
|
|
* Starting Linux v5.4 we validate it, and can't create guests on AMD machines
|
|
|
|
* with certain memory sizes. It's also wrong to use those IOVA ranges
|
|
|
|
* in detriment of leading to IOMMU INVALID_DEVICE_REQUEST or worse.
|
|
|
|
* The ranges reserved for Hyper-Transport are:
|
|
|
|
*
|
|
|
|
* FD_0000_0000h - FF_FFFF_FFFFh
|
|
|
|
*
|
|
|
|
* The ranges represent the following:
|
|
|
|
*
|
|
|
|
* Base Address Top Address Use
|
|
|
|
*
|
|
|
|
* FD_0000_0000h FD_F7FF_FFFFh Reserved interrupt address space
|
|
|
|
* FD_F800_0000h FD_F8FF_FFFFh Interrupt/EOI IntCtl
|
|
|
|
* FD_F900_0000h FD_F90F_FFFFh Legacy PIC IACK
|
|
|
|
* FD_F910_0000h FD_F91F_FFFFh System Management
|
|
|
|
* FD_F920_0000h FD_FAFF_FFFFh Reserved Page Tables
|
|
|
|
* FD_FB00_0000h FD_FBFF_FFFFh Address Translation
|
|
|
|
* FD_FC00_0000h FD_FDFF_FFFFh I/O Space
|
|
|
|
* FD_FE00_0000h FD_FFFF_FFFFh Configuration
|
|
|
|
* FE_0000_0000h FE_1FFF_FFFFh Extended Configuration/Device Messages
|
|
|
|
* FE_2000_0000h FF_FFFF_FFFFh Reserved
|
|
|
|
*
|
|
|
|
* See AMD IOMMU spec, section 2.1.2 "IOMMU Logical Topology",
|
|
|
|
* Table 3: Special Address Controls (GPA) for more information.
|
|
|
|
*/
|
|
|
|
#define AMD_HT_START 0xfd00000000UL
|
|
|
|
#define AMD_HT_END 0xffffffffffUL
|
|
|
|
#define AMD_ABOVE_1TB_START (AMD_HT_END + 1)
|
|
|
|
#define AMD_HT_SIZE (AMD_ABOVE_1TB_START - AMD_HT_START)
|
|
|
|
|
2015-12-11 21:42:24 +03:00
|
|
|
void pc_memory_init(PCMachineState *pcms,
|
|
|
|
MemoryRegion *system_memory,
|
|
|
|
MemoryRegion *rom_memory,
|
2022-07-19 20:00:06 +03:00
|
|
|
uint64_t pci_hole64_size)
|
2004-03-14 15:20:30 +03:00
|
|
|
{
|
2012-02-22 11:18:51 +04:00
|
|
|
int linux_boot, i;
|
2020-02-19 19:09:17 +03:00
|
|
|
MemoryRegion *option_rom_mr;
|
2011-07-26 15:26:17 +04:00
|
|
|
MemoryRegion *ram_below_4g, *ram_above_4g;
|
2013-04-16 04:24:08 +04:00
|
|
|
FWCfgState *fw_cfg;
|
2015-08-07 22:55:50 +03:00
|
|
|
MachineState *machine = MACHINE(pcms);
|
2019-08-19 01:54:06 +03:00
|
|
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
2015-12-02 01:58:06 +03:00
|
|
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
2019-10-22 10:39:50 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(pcms);
|
2022-07-19 20:00:12 +03:00
|
|
|
hwaddr maxphysaddr, maxusedaddr;
|
2022-04-29 17:41:00 +03:00
|
|
|
hwaddr cxl_base, cxl_resv_end = 0;
|
2022-07-19 20:00:12 +03:00
|
|
|
X86CPU *cpu = X86_CPU(first_cpu);
|
2005-07-23 23:05:37 +04:00
|
|
|
|
2019-10-22 10:39:50 +03:00
|
|
|
assert(machine->ram_size == x86ms->below_4g_mem_size +
|
|
|
|
x86ms->above_4g_mem_size);
|
2014-06-10 15:15:17 +04:00
|
|
|
|
|
|
|
linux_boot = (machine->kernel_filename != NULL);
|
2004-03-14 15:20:30 +03:00
|
|
|
|
i386/pc: relocate 4g start to 1T where applicable
It is assumed that the whole GPA space is available to be DMA
addressable, within a given address space limit, except for a
tiny region before the 4G. Since Linux v5.4, VFIO validates
whether the selected GPA is indeed valid i.e. not reserved by
IOMMU on behalf of some specific devices or platform-defined
restrictions, and thus failing the ioctl(VFIO_DMA_MAP) with
-EINVAL.
AMD systems with an IOMMU are examples of such platforms and
particularly may only have these ranges as allowed:
0000000000000000 - 00000000fedfffff (0 .. 3.982G)
00000000fef00000 - 000000fcffffffff (3.983G .. 1011.9G)
0000010000000000 - ffffffffffffffff (1Tb .. 16Pb[*])
We already account for the 4G hole, albeit if the guest is big
enough we will fail to allocate a guest with >1010G due to the
~12G hole at the 1Tb boundary, reserved for HyperTransport (HT).
[*] there is another reserved region unrelated to HT that exists
in the 256T boundary in Fam 17h according to Errata #1286,
documeted also in "Open-Source Register Reference for AMD Family
17h Processors (PUB)"
When creating the region above 4G, take into account that on AMD
platforms the HyperTransport range is reserved and hence it
cannot be used either as GPAs. On those cases rather than
establishing the start of ram-above-4g to be 4G, relocate instead
to 1Tb. See AMD IOMMU spec, section 2.1.2 "IOMMU Logical
Topology", for more information on the underlying restriction of
IOVAs.
After accounting for the 1Tb hole on AMD hosts, mtree should
look like:
0000000000000000-000000007fffffff (prio 0, i/o):
alias ram-below-4g @pc.ram 0000000000000000-000000007fffffff
0000010000000000-000001ff7fffffff (prio 0, i/o):
alias ram-above-4g @pc.ram 0000000080000000-000000ffffffffff
If the relocation is done or the address space covers it, we
also add the the reserved HT e820 range as reserved.
Default phys-bits on Qemu is TCG_PHYS_ADDR_BITS (40) which is enough
to address 1Tb (0xff ffff ffff). On AMD platforms, if a
ram-above-4g relocation is attempted and the CPU wasn't configured
with a big enough phys-bits, an error message will be printed
due to the maxphysaddr vs maxusedaddr check previously added.
Suggested-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20220719170014.27028-11-joao.m.martins@oracle.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2022-07-19 20:00:13 +03:00
|
|
|
/*
|
|
|
|
* The HyperTransport range close to the 1T boundary is unique to AMD
|
|
|
|
* hosts with IOMMUs enabled. Restrict the ram-above-4g relocation
|
2022-07-19 20:00:14 +03:00
|
|
|
* to above 1T to AMD vCPUs only. @enforce_amd_1tb_hole is only false in
|
|
|
|
* older machine types (<= 7.0) for compatibility purposes.
|
i386/pc: relocate 4g start to 1T where applicable
It is assumed that the whole GPA space is available to be DMA
addressable, within a given address space limit, except for a
tiny region before the 4G. Since Linux v5.4, VFIO validates
whether the selected GPA is indeed valid i.e. not reserved by
IOMMU on behalf of some specific devices or platform-defined
restrictions, and thus failing the ioctl(VFIO_DMA_MAP) with
-EINVAL.
AMD systems with an IOMMU are examples of such platforms and
particularly may only have these ranges as allowed:
0000000000000000 - 00000000fedfffff (0 .. 3.982G)
00000000fef00000 - 000000fcffffffff (3.983G .. 1011.9G)
0000010000000000 - ffffffffffffffff (1Tb .. 16Pb[*])
We already account for the 4G hole, albeit if the guest is big
enough we will fail to allocate a guest with >1010G due to the
~12G hole at the 1Tb boundary, reserved for HyperTransport (HT).
[*] there is another reserved region unrelated to HT that exists
in the 256T boundary in Fam 17h according to Errata #1286,
documeted also in "Open-Source Register Reference for AMD Family
17h Processors (PUB)"
When creating the region above 4G, take into account that on AMD
platforms the HyperTransport range is reserved and hence it
cannot be used either as GPAs. On those cases rather than
establishing the start of ram-above-4g to be 4G, relocate instead
to 1Tb. See AMD IOMMU spec, section 2.1.2 "IOMMU Logical
Topology", for more information on the underlying restriction of
IOVAs.
After accounting for the 1Tb hole on AMD hosts, mtree should
look like:
0000000000000000-000000007fffffff (prio 0, i/o):
alias ram-below-4g @pc.ram 0000000000000000-000000007fffffff
0000010000000000-000001ff7fffffff (prio 0, i/o):
alias ram-above-4g @pc.ram 0000000080000000-000000ffffffffff
If the relocation is done or the address space covers it, we
also add the the reserved HT e820 range as reserved.
Default phys-bits on Qemu is TCG_PHYS_ADDR_BITS (40) which is enough
to address 1Tb (0xff ffff ffff). On AMD platforms, if a
ram-above-4g relocation is attempted and the CPU wasn't configured
with a big enough phys-bits, an error message will be printed
due to the maxphysaddr vs maxusedaddr check previously added.
Suggested-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20220719170014.27028-11-joao.m.martins@oracle.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2022-07-19 20:00:13 +03:00
|
|
|
*/
|
2022-07-19 20:00:14 +03:00
|
|
|
if (IS_AMD_CPU(&cpu->env) && pcmc->enforce_amd_1tb_hole) {
|
i386/pc: relocate 4g start to 1T where applicable
It is assumed that the whole GPA space is available to be DMA
addressable, within a given address space limit, except for a
tiny region before the 4G. Since Linux v5.4, VFIO validates
whether the selected GPA is indeed valid i.e. not reserved by
IOMMU on behalf of some specific devices or platform-defined
restrictions, and thus failing the ioctl(VFIO_DMA_MAP) with
-EINVAL.
AMD systems with an IOMMU are examples of such platforms and
particularly may only have these ranges as allowed:
0000000000000000 - 00000000fedfffff (0 .. 3.982G)
00000000fef00000 - 000000fcffffffff (3.983G .. 1011.9G)
0000010000000000 - ffffffffffffffff (1Tb .. 16Pb[*])
We already account for the 4G hole, albeit if the guest is big
enough we will fail to allocate a guest with >1010G due to the
~12G hole at the 1Tb boundary, reserved for HyperTransport (HT).
[*] there is another reserved region unrelated to HT that exists
in the 256T boundary in Fam 17h according to Errata #1286,
documeted also in "Open-Source Register Reference for AMD Family
17h Processors (PUB)"
When creating the region above 4G, take into account that on AMD
platforms the HyperTransport range is reserved and hence it
cannot be used either as GPAs. On those cases rather than
establishing the start of ram-above-4g to be 4G, relocate instead
to 1Tb. See AMD IOMMU spec, section 2.1.2 "IOMMU Logical
Topology", for more information on the underlying restriction of
IOVAs.
After accounting for the 1Tb hole on AMD hosts, mtree should
look like:
0000000000000000-000000007fffffff (prio 0, i/o):
alias ram-below-4g @pc.ram 0000000000000000-000000007fffffff
0000010000000000-000001ff7fffffff (prio 0, i/o):
alias ram-above-4g @pc.ram 0000000080000000-000000ffffffffff
If the relocation is done or the address space covers it, we
also add the the reserved HT e820 range as reserved.
Default phys-bits on Qemu is TCG_PHYS_ADDR_BITS (40) which is enough
to address 1Tb (0xff ffff ffff). On AMD platforms, if a
ram-above-4g relocation is attempted and the CPU wasn't configured
with a big enough phys-bits, an error message will be printed
due to the maxphysaddr vs maxusedaddr check previously added.
Suggested-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20220719170014.27028-11-joao.m.martins@oracle.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2022-07-19 20:00:13 +03:00
|
|
|
/* Bail out if max possible address does not cross HT range */
|
|
|
|
if (pc_max_used_gpa(pcms, pci_hole64_size) >= AMD_HT_START) {
|
|
|
|
x86ms->above_4g_mem_start = AMD_ABOVE_1TB_START;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Advertise the HT region if address space covers the reserved
|
|
|
|
* region or if we relocate.
|
|
|
|
*/
|
|
|
|
if (cpu->phys_bits >= 40) {
|
|
|
|
e820_add_entry(AMD_HT_START, AMD_HT_SIZE, E820_RESERVED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-19 20:00:12 +03:00
|
|
|
/*
|
|
|
|
* phys-bits is required to be appropriately configured
|
|
|
|
* to make sure max used GPA is reachable.
|
|
|
|
*/
|
|
|
|
maxusedaddr = pc_max_used_gpa(pcms, pci_hole64_size);
|
|
|
|
maxphysaddr = ((hwaddr)1 << cpu->phys_bits) - 1;
|
|
|
|
if (maxphysaddr < maxusedaddr) {
|
|
|
|
error_report("Address space limit 0x%"PRIx64" < 0x%"PRIx64
|
|
|
|
" phys-bits too low (%u)",
|
|
|
|
maxphysaddr, maxusedaddr, cpu->phys_bits);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2020-02-19 19:09:17 +03:00
|
|
|
/*
|
|
|
|
* Split single memory region and use aliases to address portions of it,
|
|
|
|
* done for backwards compatibility with older qemus.
|
2011-07-26 15:26:17 +04:00
|
|
|
*/
|
2011-08-21 07:09:37 +04:00
|
|
|
ram_below_4g = g_malloc(sizeof(*ram_below_4g));
|
2020-02-19 19:09:17 +03:00
|
|
|
memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", machine->ram,
|
2019-10-22 10:39:50 +03:00
|
|
|
0, x86ms->below_4g_mem_size);
|
2011-07-26 15:26:17 +04:00
|
|
|
memory_region_add_subregion(system_memory, 0, ram_below_4g);
|
2019-10-22 10:39:50 +03:00
|
|
|
e820_add_entry(0, x86ms->below_4g_mem_size, E820_RAM);
|
|
|
|
if (x86ms->above_4g_mem_size > 0) {
|
2011-08-21 07:09:37 +04:00
|
|
|
ram_above_4g = g_malloc(sizeof(*ram_above_4g));
|
2020-02-19 19:09:17 +03:00
|
|
|
memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g",
|
|
|
|
machine->ram,
|
2019-10-22 10:39:50 +03:00
|
|
|
x86ms->below_4g_mem_size,
|
|
|
|
x86ms->above_4g_mem_size);
|
2022-07-19 20:00:04 +03:00
|
|
|
memory_region_add_subregion(system_memory, x86ms->above_4g_mem_start,
|
2011-07-26 15:26:17 +04:00
|
|
|
ram_above_4g);
|
2022-07-19 20:00:04 +03:00
|
|
|
e820_add_entry(x86ms->above_4g_mem_start, x86ms->above_4g_mem_size,
|
|
|
|
E820_RAM);
|
2010-07-06 20:37:17 +04:00
|
|
|
}
|
2008-09-15 20:01:01 +04:00
|
|
|
|
2021-07-19 14:21:21 +03:00
|
|
|
if (pcms->sgx_epc.size != 0) {
|
|
|
|
e820_add_entry(pcms->sgx_epc.base, pcms->sgx_epc.size, E820_RESERVED);
|
|
|
|
}
|
|
|
|
|
2015-12-11 21:42:28 +03:00
|
|
|
if (!pcmc->has_reserved_memory &&
|
2014-06-02 17:25:11 +04:00
|
|
|
(machine->ram_slots ||
|
2014-06-10 15:15:17 +04:00
|
|
|
(machine->maxram_size > machine->ram_size))) {
|
2014-06-02 17:25:11 +04:00
|
|
|
|
|
|
|
error_report("\"-memory 'slots|maxmem'\" is not supported by: %s",
|
|
|
|
mc->name);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2018-04-23 19:51:24 +03:00
|
|
|
/* initialize device memory address space */
|
2015-12-11 21:42:28 +03:00
|
|
|
if (pcmc->has_reserved_memory &&
|
2014-06-10 15:15:17 +04:00
|
|
|
(machine->ram_size < machine->maxram_size)) {
|
2022-07-19 20:00:11 +03:00
|
|
|
ram_addr_t device_mem_size;
|
2023-06-23 15:45:49 +03:00
|
|
|
hwaddr device_mem_base;
|
2014-06-02 17:25:08 +04:00
|
|
|
|
2014-06-02 17:25:09 +04:00
|
|
|
if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
|
|
|
|
error_report("unsupported amount of memory slots: %"PRIu64,
|
|
|
|
machine->ram_slots);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2015-01-29 16:48:41 +03:00
|
|
|
if (QEMU_ALIGN_UP(machine->maxram_size,
|
|
|
|
TARGET_PAGE_SIZE) != machine->maxram_size) {
|
|
|
|
error_report("maximum memory size must by aligned to multiple of "
|
|
|
|
"%d bytes", TARGET_PAGE_SIZE);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2023-06-23 15:45:49 +03:00
|
|
|
pc_get_device_memory_range(pcms, &device_mem_base, &device_mem_size);
|
pc: count in 1Gb hugepage alignment when sizing hotplug-memory container
if DIMMs with different size/alignment are interleaved
in creation order, it could lead to hotplug-memory
container fragmentation and following inability to use
all RAM upto maxmem.
For example:
-m 4G,slots=3,maxmem=7G
-object memory-backend-file,id=mem-1,size=256M,mem-path=/pagesize-2MB
-device pc-dimm,id=mem1,memdev=mem-1
-object memory-backend-file,id=mem-2,size=1G,mem-path=/pagesize-1GB
-device pc-dimm,id=mem2,memdev=mem-2
-object memory-backend-file,id=mem-3,size=256M,mem-path=/pagesize-2MB
-device pc-dimm,id=mem3,memdev=mem-3
fragments hotplug-memory container and doesn't allow
to use 1GB hugepage backend to consume remainig 1Gb.
To ease managment factor count in max 1Gb alignment for
each memory slot when sizing hotplug-memory region so
that regadless of fragmentaion it would be possible to
add max aligned DIMM.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2014-10-31 19:38:42 +03:00
|
|
|
|
2023-06-23 15:45:49 +03:00
|
|
|
if (device_mem_base + device_mem_size < device_mem_size) {
|
2014-06-02 17:25:08 +04:00
|
|
|
error_report("unsupported amount of maximum memory: " RAM_ADDR_FMT,
|
|
|
|
machine->maxram_size);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2023-06-23 15:45:49 +03:00
|
|
|
machine_memory_devices_init(machine, device_mem_base, device_mem_size);
|
2014-06-02 17:25:08 +04:00
|
|
|
}
|
2012-02-22 11:18:51 +04:00
|
|
|
|
2022-06-08 17:54:39 +03:00
|
|
|
if (pcms->cxl_devices_state.is_enabled) {
|
|
|
|
MemoryRegion *mr = &pcms->cxl_devices_state.host_mr;
|
2022-04-29 17:40:48 +03:00
|
|
|
hwaddr cxl_size = MiB;
|
|
|
|
|
2022-07-19 20:00:09 +03:00
|
|
|
cxl_base = pc_get_cxl_range_start(pcms);
|
2022-04-29 17:40:48 +03:00
|
|
|
memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size);
|
|
|
|
memory_region_add_subregion(system_memory, cxl_base, mr);
|
2022-04-29 17:41:00 +03:00
|
|
|
cxl_resv_end = cxl_base + cxl_size;
|
2022-06-08 17:54:39 +03:00
|
|
|
if (pcms->cxl_devices_state.fixed_windows) {
|
2022-04-29 17:41:00 +03:00
|
|
|
hwaddr cxl_fmw_base;
|
|
|
|
GList *it;
|
|
|
|
|
|
|
|
cxl_fmw_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB);
|
2022-06-08 17:54:39 +03:00
|
|
|
for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
|
2022-04-29 17:41:00 +03:00
|
|
|
CXLFixedWindow *fw = it->data;
|
|
|
|
|
|
|
|
fw->base = cxl_fmw_base;
|
|
|
|
memory_region_init_io(&fw->mr, OBJECT(machine), &cfmws_ops, fw,
|
|
|
|
"cxl-fixed-memory-region", fw->size);
|
|
|
|
memory_region_add_subregion(system_memory, fw->base, &fw->mr);
|
|
|
|
cxl_fmw_base += fw->size;
|
|
|
|
cxl_resv_end = cxl_fmw_base;
|
|
|
|
}
|
|
|
|
}
|
2022-04-29 17:40:48 +03:00
|
|
|
}
|
|
|
|
|
2012-02-22 11:18:51 +04:00
|
|
|
/* Initialize PC system firmware */
|
2019-03-08 16:14:43 +03:00
|
|
|
pc_system_firmware_init(pcms, rom_memory);
|
2011-07-26 15:26:17 +04:00
|
|
|
|
2011-08-21 07:09:37 +04:00
|
|
|
option_rom_mr = g_malloc(sizeof(*option_rom_mr));
|
2024-05-30 14:16:39 +03:00
|
|
|
if (machine_require_guest_memfd(machine)) {
|
|
|
|
memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom",
|
|
|
|
PC_ROM_SIZE, &error_fatal);
|
|
|
|
} else {
|
|
|
|
memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE,
|
|
|
|
&error_fatal);
|
|
|
|
if (pcmc->pci_enabled) {
|
|
|
|
memory_region_set_readonly(option_rom_mr, true);
|
|
|
|
}
|
pc: make 'pc.rom' readonly when machine has PCI enabled
looking at bios ROM mapping in QEMU it seems that only isapc
(i.e. not PCI enabled machine) requires ROM being mapped as
RW in other cases BIOS is mapped as RO. Do the same for option
ROM 'pc.rom' when machine has PCI enabled.
As useful side-effect pc.rom MemoryRegion stops being
put in vhost memory map (filtered out by vhost_section()),
which reduces number of entries by 1.
Coincidentally it fixes migration failure reported in
"[PATCH V2] vhost: fix a migration failed because of vhost region merge"
where following destination CLI with /sys/module/vhost/parameters/max_mem_regions = 8
export DIMMSCOUNT=6
QEMU -enable-kvm \
-netdev type=tap,id=guest0,vhost=on,script=no,vhostforce \
-device virtio-net-pci,netdev=guest0 \
-m 256,slots=256,maxmem=2G \
`i=0; while [ $i -lt $DIMMSCOUNT ]; do echo \
"-object memory-backend-ram,id=m$i,size=128M \
-device pc-dimm,id=d$i,memdev=m$i"; i=$(($i + 1)); \
done`
will fail to startup with error:
"-device pc-dimm,id=d5,memdev=m5: a used vhost backend has no free memory slots left"
while it's possible to add the 6th DIMM during hotplug
on source.
Issue is caused by the fact that number of entries in vhost map
is bigger on 1 entry, when -device is processed, than
after guest boots up, and that offending entry belongs to
'pc.rom', it's not like vhost intends to do IO in ROM range
so making it RO hides region from vhost and makes number
of entries in vhost memory map at -device/machine_done time
match number of entries after guest boots.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reported-by: Peng Hao <peng.hao2@zte.com.cn>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2017-07-28 12:09:05 +03:00
|
|
|
}
|
2011-09-21 22:49:29 +04:00
|
|
|
memory_region_add_subregion_overlap(rom_memory,
|
2011-07-26 15:26:17 +04:00
|
|
|
PC_ROM_MIN_VGA,
|
|
|
|
option_rom_mr,
|
|
|
|
1);
|
2009-04-10 00:59:05 +04:00
|
|
|
|
2019-09-16 13:42:42 +03:00
|
|
|
fw_cfg = fw_cfg_arch_create(machine,
|
2019-10-22 10:39:50 +03:00
|
|
|
x86ms->boot_cpus, x86ms->apic_id_limit);
|
2015-10-08 18:02:57 +03:00
|
|
|
|
2010-01-08 17:25:40 +03:00
|
|
|
rom_set_fw(fw_cfg);
|
2009-06-29 17:37:37 +04:00
|
|
|
|
2023-06-23 15:45:49 +03:00
|
|
|
if (machine->device_memory) {
|
2014-06-02 17:25:10 +04:00
|
|
|
uint64_t *val = g_malloc(sizeof(*val));
|
2018-04-23 19:51:17 +03:00
|
|
|
uint64_t res_mem_end = machine->device_memory->base;
|
2015-09-07 14:55:32 +03:00
|
|
|
|
|
|
|
if (!pcmc->broken_reserved_end) {
|
2018-04-23 19:51:17 +03:00
|
|
|
res_mem_end += memory_region_size(&machine->device_memory->mr);
|
2015-09-07 14:55:32 +03:00
|
|
|
}
|
2022-04-29 17:41:00 +03:00
|
|
|
|
2022-06-08 17:54:39 +03:00
|
|
|
if (pcms->cxl_devices_state.is_enabled) {
|
2022-04-29 17:41:00 +03:00
|
|
|
res_mem_end = cxl_resv_end;
|
|
|
|
}
|
2018-06-29 17:22:13 +03:00
|
|
|
*val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB));
|
2014-06-02 17:25:10 +04:00
|
|
|
fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
|
|
|
|
}
|
|
|
|
|
2009-04-10 00:59:05 +04:00
|
|
|
if (linux_boot) {
|
2019-09-30 18:26:29 +03:00
|
|
|
x86_load_linux(x86ms, fw_cfg, pcmc->acpi_data_size,
|
2023-02-09 00:05:35 +03:00
|
|
|
pcmc->pvh_enabled);
|
2009-04-10 00:59:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nb_option_roms; i++) {
|
2010-12-08 14:35:07 +03:00
|
|
|
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
|
2009-06-17 17:05:30 +04:00
|
|
|
}
|
2019-10-22 10:39:50 +03:00
|
|
|
x86ms->fw_cfg = fw_cfg;
|
2016-07-14 08:56:23 +03:00
|
|
|
|
|
|
|
/* Init default IOAPIC address space */
|
2019-10-22 10:39:50 +03:00
|
|
|
x86ms->ioapic_as = &address_space_memory;
|
2019-09-18 16:06:23 +03:00
|
|
|
|
|
|
|
/* Init ACPI memory hotplug IO base address */
|
|
|
|
pcms->memhp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
|
2010-05-14 11:29:11 +04:00
|
|
|
}
|
|
|
|
|
2017-11-11 18:25:00 +03:00
|
|
|
/*
|
|
|
|
* The 64bit pci hole starts after "above 4G RAM" and
|
|
|
|
* potentially the space reserved for memory hotplug.
|
|
|
|
*/
|
|
|
|
uint64_t pc_pci_hole64_start(void)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
|
|
|
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
2018-04-23 19:51:17 +03:00
|
|
|
MachineState *ms = MACHINE(pcms);
|
2017-11-11 18:25:00 +03:00
|
|
|
uint64_t hole64_start = 0;
|
2022-07-19 20:00:11 +03:00
|
|
|
ram_addr_t size = 0;
|
2017-11-11 18:25:00 +03:00
|
|
|
|
2022-07-19 20:00:08 +03:00
|
|
|
if (pcms->cxl_devices_state.is_enabled) {
|
|
|
|
hole64_start = pc_get_cxl_range_end(pcms);
|
2022-07-19 20:00:11 +03:00
|
|
|
} else if (pcmc->has_reserved_memory && (ms->ram_size < ms->maxram_size)) {
|
|
|
|
pc_get_device_memory_range(pcms, &hole64_start, &size);
|
2017-11-11 18:25:00 +03:00
|
|
|
if (!pcmc->broken_reserved_end) {
|
2022-07-19 20:00:11 +03:00
|
|
|
hole64_start += size;
|
2017-11-11 18:25:00 +03:00
|
|
|
}
|
|
|
|
} else {
|
2022-07-19 20:00:07 +03:00
|
|
|
hole64_start = pc_above_4g_end(pcms);
|
2017-11-11 18:25:00 +03:00
|
|
|
}
|
|
|
|
|
2018-06-29 17:22:13 +03:00
|
|
|
return ROUND_UP(hole64_start, 1 * GiB);
|
2017-11-11 18:25:00 +03:00
|
|
|
}
|
|
|
|
|
2011-12-16 01:09:51 +04:00
|
|
|
DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
|
2010-05-14 11:29:12 +04:00
|
|
|
{
|
2011-12-13 00:29:41 +04:00
|
|
|
DeviceState *dev = NULL;
|
|
|
|
|
2016-04-07 17:12:58 +03:00
|
|
|
rom_set_order_override(FW_CFG_ORDER_OVERRIDE_VGA);
|
2012-09-08 14:47:45 +04:00
|
|
|
if (pci_bus) {
|
|
|
|
PCIDevice *pcidev = pci_vga_init(pci_bus);
|
|
|
|
dev = pcidev ? &pcidev->qdev : NULL;
|
|
|
|
} else if (isa_bus) {
|
|
|
|
ISADevice *isadev = isa_vga_init(isa_bus);
|
2013-06-07 15:49:13 +04:00
|
|
|
dev = isadev ? DEVICE(isadev) : NULL;
|
2010-05-14 11:29:12 +04:00
|
|
|
}
|
2016-04-07 17:12:58 +03:00
|
|
|
rom_reset_order_override();
|
2011-12-13 00:29:41 +04:00
|
|
|
return dev;
|
2010-05-14 11:29:12 +04:00
|
|
|
}
|
|
|
|
|
2012-09-19 15:50:08 +04:00
|
|
|
static const MemoryRegionOps ioport80_io_ops = {
|
|
|
|
.write = ioport80_write,
|
2013-01-09 22:10:22 +04:00
|
|
|
.read = ioport80_read,
|
2012-09-19 15:50:08 +04:00
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
|
|
.impl = {
|
|
|
|
.min_access_size = 1,
|
|
|
|
.max_access_size = 1,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static const MemoryRegionOps ioportF0_io_ops = {
|
|
|
|
.write = ioportF0_write,
|
2013-01-09 22:10:22 +04:00
|
|
|
.read = ioportF0_read,
|
2012-09-19 15:50:08 +04:00
|
|
|
.endianness = DEVICE_NATIVE_ENDIAN,
|
|
|
|
.impl = {
|
|
|
|
.min_access_size = 1,
|
|
|
|
.max_access_size = 1,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2022-02-28 00:06:55 +03:00
|
|
|
static void pc_superio_init(ISABus *isa_bus, bool create_fdctrl,
|
|
|
|
bool create_i8042, bool no_vmport)
|
2018-03-09 01:39:46 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
DriveInfo *fd[MAX_FD];
|
|
|
|
qemu_irq *a20_line;
|
2024-04-25 21:43:13 +03:00
|
|
|
ISADevice *i8042, *port92, *vmmouse;
|
2018-03-09 01:39:46 +03:00
|
|
|
|
2018-04-20 17:52:46 +03:00
|
|
|
serial_hds_isa_init(isa_bus, 0, MAX_ISA_SERIAL_PORTS);
|
2018-03-09 01:39:46 +03:00
|
|
|
parallel_hds_isa_init(isa_bus, MAX_PARALLEL_PORTS);
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_FD; i++) {
|
|
|
|
fd[i] = drive_get(IF_FLOPPY, 0, i);
|
|
|
|
create_fdctrl |= !!fd[i];
|
|
|
|
}
|
|
|
|
if (create_fdctrl) {
|
2024-04-25 21:43:13 +03:00
|
|
|
#ifdef CONFIG_FDC_ISA
|
|
|
|
ISADevice *fdc = isa_new(TYPE_ISA_FDC);
|
2020-06-22 12:42:16 +03:00
|
|
|
if (fdc) {
|
|
|
|
isa_realize_and_unref(fdc, isa_bus, &error_fatal);
|
|
|
|
isa_fdc_init_drives(fdc, fd);
|
|
|
|
}
|
2024-04-25 21:43:13 +03:00
|
|
|
#endif
|
2018-03-09 01:39:46 +03:00
|
|
|
}
|
|
|
|
|
2022-02-28 00:06:55 +03:00
|
|
|
if (!create_i8042) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-20 21:01:00 +03:00
|
|
|
i8042 = isa_create_simple(isa_bus, TYPE_I8042);
|
2018-03-09 01:39:46 +03:00
|
|
|
if (!no_vmport) {
|
2020-05-04 11:33:39 +03:00
|
|
|
isa_create_simple(isa_bus, TYPE_VMPORT);
|
2020-06-10 08:32:09 +03:00
|
|
|
vmmouse = isa_try_new("vmmouse");
|
2018-03-09 01:39:46 +03:00
|
|
|
} else {
|
|
|
|
vmmouse = NULL;
|
|
|
|
}
|
|
|
|
if (vmmouse) {
|
2022-05-20 21:01:00 +03:00
|
|
|
object_property_set_link(OBJECT(vmmouse), TYPE_I8042, OBJECT(i8042),
|
qom: Put name parameter before value / visitor parameter
The object_property_set_FOO() setters take property name and value in
an unusual order:
void object_property_set_FOO(Object *obj, FOO_TYPE value,
const char *name, Error **errp)
Having to pass value before name feels grating. Swap them.
Same for object_property_set(), object_property_get(), and
object_property_parse().
Convert callers with this Coccinelle script:
@@
identifier fun = {
object_property_get, object_property_parse, object_property_set_str,
object_property_set_link, object_property_set_bool,
object_property_set_int, object_property_set_uint, object_property_set,
object_property_set_qobject
};
expression obj, v, name, errp;
@@
- fun(obj, v, name, errp)
+ fun(obj, name, v, errp)
Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error
message "no position information". Convert that one manually.
Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Convert manually.
Fails to convert hw/rx/rx-gdbsim.c, because Coccinelle gets confused
by RXCPU being used both as typedef and function-like macro there.
Convert manually. The other files using RXCPU that way don't need
conversion.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200707160613.848843-27-armbru@redhat.com>
[Straightforwad conflict with commit 2336172d9b "audio: set default
value for pcspk.iobase property" resolved]
2020-07-07 19:05:54 +03:00
|
|
|
&error_abort);
|
2020-06-10 08:32:09 +03:00
|
|
|
isa_realize_and_unref(vmmouse, isa_bus, &error_fatal);
|
2018-03-09 01:39:46 +03:00
|
|
|
}
|
2019-12-13 13:50:58 +03:00
|
|
|
port92 = isa_create_simple(isa_bus, TYPE_PORT92);
|
2018-03-09 01:39:46 +03:00
|
|
|
|
|
|
|
a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2);
|
2021-11-05 19:54:18 +03:00
|
|
|
qdev_connect_gpio_out_named(DEVICE(i8042),
|
|
|
|
I8042_A20_LINE, 0, a20_line[0]);
|
2019-12-13 13:50:59 +03:00
|
|
|
qdev_connect_gpio_out_named(DEVICE(port92),
|
|
|
|
PORT92_A20_LINE, 0, a20_line[1]);
|
2018-03-09 01:39:46 +03:00
|
|
|
g_free(a20_line);
|
|
|
|
}
|
|
|
|
|
2020-07-02 16:25:16 +03:00
|
|
|
void pc_basic_device_init(struct PCMachineState *pcms,
|
|
|
|
ISABus *isa_bus, qemu_irq *gsi,
|
2023-05-19 11:47:34 +03:00
|
|
|
ISADevice *rtc_state,
|
2015-05-28 23:04:08 +03:00
|
|
|
bool create_fdctrl,
|
2016-01-22 18:09:21 +03:00
|
|
|
uint32_t hpet_irqs)
|
2010-05-14 11:29:13 +04:00
|
|
|
{
|
|
|
|
int i;
|
2012-02-01 23:31:41 +04:00
|
|
|
DeviceState *hpet = NULL;
|
|
|
|
int pit_isa_irq = 0;
|
|
|
|
qemu_irq pit_alt_irq = NULL;
|
2018-03-09 01:39:46 +03:00
|
|
|
ISADevice *pit = NULL;
|
2012-09-19 15:50:08 +04:00
|
|
|
MemoryRegion *ioport80_io = g_new(MemoryRegion, 1);
|
|
|
|
MemoryRegion *ioportF0_io = g_new(MemoryRegion, 1);
|
2022-03-10 15:28:10 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(pcms);
|
2010-05-14 11:29:13 +04:00
|
|
|
|
2013-06-06 13:41:28 +04:00
|
|
|
memory_region_init_io(ioport80_io, NULL, &ioport80_io_ops, NULL, "ioport80", 1);
|
2012-09-19 15:50:08 +04:00
|
|
|
memory_region_add_subregion(isa_bus->address_space_io, 0x80, ioport80_io);
|
2010-05-14 11:29:13 +04:00
|
|
|
|
2013-06-06 13:41:28 +04:00
|
|
|
memory_region_init_io(ioportF0_io, NULL, &ioportF0_io_ops, NULL, "ioportF0", 1);
|
2012-09-19 15:50:08 +04:00
|
|
|
memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io);
|
2010-05-14 11:29:13 +04:00
|
|
|
|
2012-03-02 23:28:49 +04:00
|
|
|
/*
|
|
|
|
* Check if an HPET shall be created.
|
|
|
|
*/
|
2023-10-17 15:29:03 +03:00
|
|
|
if (pcms->hpet_enabled) {
|
2023-10-07 15:38:09 +03:00
|
|
|
qemu_irq rtc_irq;
|
|
|
|
|
2020-06-10 08:31:59 +03:00
|
|
|
hpet = qdev_try_new(TYPE_HPET);
|
2020-10-21 17:47:16 +03:00
|
|
|
if (!hpet) {
|
|
|
|
error_report("couldn't create HPET device");
|
|
|
|
exit(1);
|
|
|
|
}
|
2020-11-02 13:09:19 +03:00
|
|
|
/*
|
2023-09-15 14:57:11 +03:00
|
|
|
* For pc-piix-*, hpet's intcap is always IRQ2. For pc-q35-*,
|
|
|
|
* use IRQ16~23, IRQ8 and IRQ2. If the user has already set
|
|
|
|
* the property, use whatever mask they specified.
|
2020-11-02 13:09:19 +03:00
|
|
|
*/
|
2020-10-21 17:47:16 +03:00
|
|
|
uint8_t compat = object_property_get_uint(OBJECT(hpet),
|
|
|
|
HPET_INTCAP, NULL);
|
|
|
|
if (!compat) {
|
|
|
|
qdev_prop_set_uint32(hpet, HPET_INTCAP, hpet_irqs);
|
|
|
|
}
|
|
|
|
sysbus_realize_and_unref(SYS_BUS_DEVICE(hpet), &error_fatal);
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(hpet), 0, HPET_BASE);
|
2013-12-08 13:38:17 +04:00
|
|
|
|
2023-02-13 20:30:30 +03:00
|
|
|
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
2020-10-21 17:47:16 +03:00
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]);
|
2010-06-13 16:15:38 +04:00
|
|
|
}
|
2020-10-21 17:47:16 +03:00
|
|
|
pit_isa_irq = -1;
|
|
|
|
pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT);
|
|
|
|
rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
|
2023-05-19 11:47:33 +03:00
|
|
|
|
2023-10-07 15:38:18 +03:00
|
|
|
/* overwrite connection created by south bridge */
|
2023-05-19 11:47:34 +03:00
|
|
|
qdev_connect_gpio_out(DEVICE(rtc_state), 0, rtc_irq);
|
2023-05-19 11:47:33 +03:00
|
|
|
}
|
2023-10-07 15:38:09 +03:00
|
|
|
|
2023-05-19 11:47:34 +03:00
|
|
|
object_property_add_alias(OBJECT(pcms), "rtc-time", OBJECT(rtc_state),
|
2023-05-19 11:47:33 +03:00
|
|
|
"date");
|
2010-06-13 16:15:40 +04:00
|
|
|
|
hw/xen: Support HVM_PARAM_CALLBACK_TYPE_GSI callback
The GSI callback (and later PCI_INTX) is a level triggered interrupt. It
is asserted when an event channel is delivered to vCPU0, and is supposed
to be cleared when the vcpu_info->evtchn_upcall_pending field for vCPU0
is cleared again.
Thankfully, Xen does *not* assert the GSI if the guest sets its own
evtchn_upcall_pending field; we only need to assert the GSI when we
have delivered an event for ourselves. So that's the easy part, kind of.
There's a slight complexity in that we need to hold the BQL before we
can call qemu_set_irq(), and we definitely can't do that while holding
our own port_lock (because we'll need to take that from the qemu-side
functions that the PV backend drivers will call). So if we end up
wanting to set the IRQ in a context where we *don't* already hold the
BQL, defer to a BH.
However, we *do* need to poll for the evtchn_upcall_pending flag being
cleared. In an ideal world we would poll that when the EOI happens on
the PIC/IOAPIC. That's how it works in the kernel with the VFIO eventfd
pairs — one is used to trigger the interrupt, and the other works in the
other direction to 'resample' on EOI, and trigger the first eventfd
again if the line is still active.
However, QEMU doesn't seem to do that. Even VFIO level interrupts seem
to be supported by temporarily unmapping the device's BARs from the
guest when an interrupt happens, then trapping *all* MMIO to the device
and sending the 'resample' event on *every* MMIO access until the IRQ
is cleared! Maybe in future we'll plumb the 'resample' concept through
QEMU's irq framework but for now we'll do what Xen itself does: just
check the flag on every vmexit if the upcall GSI is known to be
asserted.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
2022-12-15 23:35:24 +03:00
|
|
|
#ifdef CONFIG_XEN_EMU
|
|
|
|
if (xen_mode == XEN_EMULATE) {
|
hw/xen: Simplify emulated Xen platform init
I initially put the basic platform init (overlay pages, grant tables,
event channels) into mc->kvm_type because that was the earliest place
that could sensibly test for xen_mode==XEN_EMULATE.
The intent was to do this early enough that we could then initialise the
XenBus and other parts which would have depended on them, from a generic
location for both Xen and KVM/Xen in the PC-specific code, as seen in
https://lore.kernel.org/qemu-devel/20230116221919.1124201-16-dwmw2@infradead.org/
However, then the Xen on Arm patches came along, and *they* wanted to
do the XenBus init from a 'generic' Xen-specific location instead:
https://lore.kernel.org/qemu-devel/20230210222729.957168-4-sstabellini@kernel.org/
Since there's no generic location that covers all three, I conceded to
do it for XEN_EMULATE mode in pc_basic_devices_init().
And now there's absolutely no point in having some of the platform init
done from pc_machine_kvm_type(); we can move it all up to live in a
single place in pc_basic_devices_init(). This has the added benefit that
we can drop the separate xen_evtchn_connect_gsis() function completely,
and pass just the system GSIs in directly to xen_evtchn_create().
While I'm at it, it does no harm to explicitly pass in the *number* of
said GSIs, because it does make me twitch a bit to pass an array of
impicit size. During the lifetime of the KVM/Xen patchset, that had
already changed (albeit just cosmetically) from GSI_NUM_PINS to
IOAPIC_NUM_PINS.
And document a bit better that this is for the *output* GSI for raising
CPU0's events when the per-CPU vector isn't available. The fact that
we create a whole set of them and then only waggle the one we're told
to, instead of having a single output and only *connecting* it to the
GSI that it should be connected to, is still non-intuitive for me.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
Message-Id: <20230412185102.441523-2-dwmw2@infradead.org>
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
2023-04-12 21:50:58 +03:00
|
|
|
xen_overlay_create();
|
|
|
|
xen_evtchn_create(IOAPIC_NUM_PINS, gsi);
|
|
|
|
xen_gnttab_create();
|
|
|
|
xen_xenstore_create();
|
2024-02-24 16:58:47 +03:00
|
|
|
if (pcms->pcibus) {
|
|
|
|
pci_create_simple(pcms->pcibus, -1, "xen-platform");
|
2023-01-17 16:51:22 +03:00
|
|
|
}
|
2023-10-17 19:53:58 +03:00
|
|
|
xen_bus_init();
|
hw/xen: Support HVM_PARAM_CALLBACK_TYPE_GSI callback
The GSI callback (and later PCI_INTX) is a level triggered interrupt. It
is asserted when an event channel is delivered to vCPU0, and is supposed
to be cleared when the vcpu_info->evtchn_upcall_pending field for vCPU0
is cleared again.
Thankfully, Xen does *not* assert the GSI if the guest sets its own
evtchn_upcall_pending field; we only need to assert the GSI when we
have delivered an event for ourselves. So that's the easy part, kind of.
There's a slight complexity in that we need to hold the BQL before we
can call qemu_set_irq(), and we definitely can't do that while holding
our own port_lock (because we'll need to take that from the qemu-side
functions that the PV backend drivers will call). So if we end up
wanting to set the IRQ in a context where we *don't* already hold the
BQL, defer to a BH.
However, we *do* need to poll for the evtchn_upcall_pending flag being
cleared. In an ideal world we would poll that when the EOI happens on
the PIC/IOAPIC. That's how it works in the kernel with the VFIO eventfd
pairs — one is used to trigger the interrupt, and the other works in the
other direction to 'resample' on EOI, and trigger the first eventfd
again if the line is still active.
However, QEMU doesn't seem to do that. Even VFIO level interrupts seem
to be supported by temporarily unmapping the device's BARs from the
guest when an interrupt happens, then trapping *all* MMIO to the device
and sending the 'resample' event on *every* MMIO access until the IRQ
is cleared! Maybe in future we'll plumb the 'resample' concept through
QEMU's irq framework but for now we'll do what Xen itself does: just
check the flag on every vmexit if the upcall GSI is known to be
asserted.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
2022-12-15 23:35:24 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-03-03 21:53:30 +03:00
|
|
|
qemu_register_boot_set(pc_boot_set, pcms);
|
2024-03-03 21:53:31 +03:00
|
|
|
set_boot_dev(pcms, MC146818_RTC(rtc_state),
|
|
|
|
MACHINE(pcms)->boot_config.order, &error_fatal);
|
2010-06-13 16:15:40 +04:00
|
|
|
|
2022-03-10 15:28:10 +03:00
|
|
|
if (!xen_enabled() &&
|
|
|
|
(x86ms->pit == ON_OFF_AUTO_AUTO || x86ms->pit == ON_OFF_AUTO_ON)) {
|
2015-12-17 19:16:08 +03:00
|
|
|
if (kvm_pit_in_kernel()) {
|
2011-11-14 19:07:01 +04:00
|
|
|
pit = kvm_pit_init(isa_bus, 0x40);
|
|
|
|
} else {
|
2017-10-17 19:44:15 +03:00
|
|
|
pit = i8254_pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
|
2011-11-14 19:07:01 +04:00
|
|
|
}
|
|
|
|
if (hpet) {
|
|
|
|
/* connect PIT to output control line of the HPET */
|
2013-06-07 15:49:13 +04:00
|
|
|
qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(DEVICE(pit), 0));
|
2011-11-14 19:07:01 +04:00
|
|
|
}
|
2023-10-16 13:12:39 +03:00
|
|
|
object_property_set_link(OBJECT(pcms->pcspk), "pit",
|
|
|
|
OBJECT(pit), &error_fatal);
|
|
|
|
isa_realize_and_unref(pcms->pcspk, isa_bus, &error_fatal);
|
2012-02-01 23:31:41 +04:00
|
|
|
}
|
2010-05-14 11:29:13 +04:00
|
|
|
|
2018-03-09 01:39:46 +03:00
|
|
|
/* Super I/O */
|
2022-02-28 00:06:55 +03:00
|
|
|
pc_superio_init(isa_bus, create_fdctrl, pcms->i8042_enabled,
|
|
|
|
pcms->vmport != ON_OFF_AUTO_ON);
|
2010-05-14 11:29:13 +04:00
|
|
|
}
|
|
|
|
|
2023-10-17 19:53:58 +03:00
|
|
|
void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus)
|
2012-11-15 00:54:01 +04:00
|
|
|
{
|
2023-05-10 21:46:21 +03:00
|
|
|
MachineClass *mc = MACHINE_CLASS(pcmc);
|
2023-10-20 02:07:45 +03:00
|
|
|
bool default_is_ne2k = g_str_equal(mc->default_nic, TYPE_ISA_NE2000);
|
|
|
|
NICInfo *nd;
|
2012-11-15 00:54:01 +04:00
|
|
|
|
2016-04-07 17:12:58 +03:00
|
|
|
rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC);
|
2012-11-15 00:54:01 +04:00
|
|
|
|
2023-10-20 02:07:45 +03:00
|
|
|
while ((nd = qemu_find_nic_info(TYPE_ISA_NE2000, default_is_ne2k, NULL))) {
|
|
|
|
pc_init_ne2k_isa(isa_bus, nd, &error_fatal);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Anything remaining should be a PCI NIC */
|
|
|
|
pci_init_nic_devices(pci_bus, mc->default_nic);
|
|
|
|
|
2016-04-07 17:12:58 +03:00
|
|
|
rom_reset_order_override();
|
2012-11-15 00:54:01 +04:00
|
|
|
}
|
|
|
|
|
2019-10-18 16:59:09 +03:00
|
|
|
void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs)
|
|
|
|
{
|
|
|
|
qemu_irq *i8259;
|
|
|
|
|
|
|
|
if (kvm_pic_in_kernel()) {
|
|
|
|
i8259 = kvm_i8259_init(isa_bus);
|
|
|
|
} else if (xen_enabled()) {
|
|
|
|
i8259 = xen_interrupt_controller_init();
|
|
|
|
} else {
|
2019-12-12 16:14:40 +03:00
|
|
|
i8259 = i8259_init(isa_bus, x86_allocate_cpu_irq());
|
2019-10-18 16:59:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < ISA_NUM_IRQS; i++) {
|
|
|
|
i8259_irqs[i] = i8259[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(i8259);
|
|
|
|
}
|
|
|
|
|
2018-06-19 16:41:34 +03:00
|
|
|
static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
|
|
Error **errp)
|
|
|
|
{
|
2020-09-15 15:09:02 +03:00
|
|
|
const X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
2019-03-08 21:20:53 +03:00
|
|
|
const MachineState *ms = MACHINE(hotplug_dev);
|
2018-06-19 16:41:34 +03:00
|
|
|
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
2019-04-07 12:23:14 +03:00
|
|
|
Error *local_err = NULL;
|
2018-06-19 16:41:34 +03:00
|
|
|
|
|
|
|
/*
|
2024-01-18 13:37:57 +03:00
|
|
|
* When "acpi=off" is used with the Q35 machine type, no ACPI is built,
|
2018-06-19 16:41:34 +03:00
|
|
|
* but pcms->acpi_dev is still created. Check !acpi_enabled in
|
|
|
|
* addition to cover this case.
|
|
|
|
*/
|
2020-09-15 15:09:02 +03:00
|
|
|
if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) {
|
2018-06-19 16:41:34 +03:00
|
|
|
error_setg(errp,
|
|
|
|
"memory hotplug is not enabled: missing acpi device or acpi disabled");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-08 21:20:53 +03:00
|
|
|
if (is_nvdimm && !ms->nvdimms_state->is_enabled) {
|
2018-06-19 16:41:34 +03:00
|
|
|
error_setg(errp, "nvdimm is not enabled: missing 'nvdimm' in '-M'");
|
|
|
|
return;
|
|
|
|
}
|
2018-08-01 16:34:41 +03:00
|
|
|
|
2020-09-15 15:09:02 +03:00
|
|
|
hotplug_handler_pre_plug(x86ms->acpi_dev, dev, &local_err);
|
2019-04-07 12:23:14 +03:00
|
|
|
if (local_err) {
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-28 12:26:33 +03:00
|
|
|
pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), errp);
|
2018-06-19 16:41:34 +03:00
|
|
|
}
|
|
|
|
|
2018-06-19 16:41:31 +03:00
|
|
|
static void pc_memory_plug(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
2014-06-02 17:25:12 +04:00
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
2020-09-15 15:09:02 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
2019-03-08 21:20:53 +03:00
|
|
|
MachineState *ms = MACHINE(hotplug_dev);
|
hw/i386: fix nvdimm check error path
Commit e987c37aee1752177906847630d32477da57e705 ("hw/i386: check if
nvdimm is enabled before plugging") introduced a check to reject nvdimm
hotplug if -machine pc,nvdimm=on was not given.
This check executes after pc_dimm_memory_plug() has already completed
and does not reverse the effect of this function in the case of failure.
Perform the check before calling pc_dimm_memory_plug(). This fixes the
following abort:
$ qemu -M accel=kvm -m 1G,slots=4,maxmem=8G \
-object memory-backend-file,id=mem1,share=on,mem-path=nvdimm.dat,size=1G
(qemu) device_add nvdimm,memdev=mem1
nvdimm is not enabled: missing 'nvdimm' in '-M'
(qemu) device_add nvdimm,memdev=mem1
Core dumped
The backtrace is:
#0 0x00007fffdb5b191f in raise () at /lib64/libc.so.6
#1 0x00007fffdb5b351a in abort () at /lib64/libc.so.6
#2 0x00007fffdb5a9da7 in __assert_fail_base () at /lib64/libc.so.6
#3 0x00007fffdb5a9e52 in () at /lib64/libc.so.6
#4 0x000055555577a5fa in qemu_ram_set_idstr (new_block=0x555556747a00, name=<optimized out>, dev=dev@entry=0x555556705590) at qemu/exec.c:1709
#5 0x0000555555a0fe86 in vmstate_register_ram (mr=mr@entry=0x55555673a0e0, dev=dev@entry=0x555556705590) at migration/savevm.c:2293
#6 0x0000555555965088 in pc_dimm_memory_plug (dev=dev@entry=0x555556705590, hpms=hpms@entry=0x5555566bb0e0, mr=mr@entry=0x555556705630, align=<optimized out>, errp=errp@entry=0x7fffffffc660)
at hw/mem/pc-dimm.c:110
#7 0x000055555581d89b in pc_dimm_plug (errp=0x7fffffffc6c0, dev=0x555556705590, hotplug_dev=<optimized out>) at qemu/hw/i386/pc.c:1713
#8 0x000055555581d89b in pc_machine_device_plug_cb (hotplug_dev=<optimized out>, dev=0x555556705590, errp=0x7fffffffc6c0) at qemu/hw/i386/pc.c:2004
#9 0x0000555555914da6 in device_set_realized (obj=<optimized out>, value=<optimized out>, errp=0x7fffffffc7e8) at hw/core/qdev.c:926
Cc: Haozhong Zhang <haozhong.zhang@intel.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Haozhong Zhang <haozhong.zhang@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2017-06-09 18:16:15 +03:00
|
|
|
bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
|
2014-06-02 17:25:12 +04:00
|
|
|
|
2020-10-19 11:48:04 +03:00
|
|
|
pc_dimm_plug(PC_DIMM(dev), MACHINE(pcms));
|
2014-10-31 19:38:32 +03:00
|
|
|
|
hw/i386: fix nvdimm check error path
Commit e987c37aee1752177906847630d32477da57e705 ("hw/i386: check if
nvdimm is enabled before plugging") introduced a check to reject nvdimm
hotplug if -machine pc,nvdimm=on was not given.
This check executes after pc_dimm_memory_plug() has already completed
and does not reverse the effect of this function in the case of failure.
Perform the check before calling pc_dimm_memory_plug(). This fixes the
following abort:
$ qemu -M accel=kvm -m 1G,slots=4,maxmem=8G \
-object memory-backend-file,id=mem1,share=on,mem-path=nvdimm.dat,size=1G
(qemu) device_add nvdimm,memdev=mem1
nvdimm is not enabled: missing 'nvdimm' in '-M'
(qemu) device_add nvdimm,memdev=mem1
Core dumped
The backtrace is:
#0 0x00007fffdb5b191f in raise () at /lib64/libc.so.6
#1 0x00007fffdb5b351a in abort () at /lib64/libc.so.6
#2 0x00007fffdb5a9da7 in __assert_fail_base () at /lib64/libc.so.6
#3 0x00007fffdb5a9e52 in () at /lib64/libc.so.6
#4 0x000055555577a5fa in qemu_ram_set_idstr (new_block=0x555556747a00, name=<optimized out>, dev=dev@entry=0x555556705590) at qemu/exec.c:1709
#5 0x0000555555a0fe86 in vmstate_register_ram (mr=mr@entry=0x55555673a0e0, dev=dev@entry=0x555556705590) at migration/savevm.c:2293
#6 0x0000555555965088 in pc_dimm_memory_plug (dev=dev@entry=0x555556705590, hpms=hpms@entry=0x5555566bb0e0, mr=mr@entry=0x555556705630, align=<optimized out>, errp=errp@entry=0x7fffffffc660)
at hw/mem/pc-dimm.c:110
#7 0x000055555581d89b in pc_dimm_plug (errp=0x7fffffffc6c0, dev=0x555556705590, hotplug_dev=<optimized out>) at qemu/hw/i386/pc.c:1713
#8 0x000055555581d89b in pc_machine_device_plug_cb (hotplug_dev=<optimized out>, dev=0x555556705590, errp=0x7fffffffc6c0) at qemu/hw/i386/pc.c:2004
#9 0x0000555555914da6 in device_set_realized (obj=<optimized out>, value=<optimized out>, errp=0x7fffffffc7e8) at hw/core/qdev.c:926
Cc: Haozhong Zhang <haozhong.zhang@intel.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Reviewed-by: Haozhong Zhang <haozhong.zhang@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2017-06-09 18:16:15 +03:00
|
|
|
if (is_nvdimm) {
|
2019-03-08 21:20:53 +03:00
|
|
|
nvdimm_plug(ms->nvdimms_state);
|
2016-11-07 14:13:36 +03:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:09:02 +03:00
|
|
|
hotplug_handler_plug(x86ms->acpi_dev, dev, &error_abort);
|
2014-06-02 17:25:12 +04:00
|
|
|
}
|
|
|
|
|
2018-06-19 16:41:31 +03:00
|
|
|
static void pc_memory_unplug_request(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
2015-04-27 11:47:17 +03:00
|
|
|
{
|
2020-09-15 15:09:02 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
2015-04-27 11:47:17 +03:00
|
|
|
|
2017-12-22 04:51:20 +03:00
|
|
|
/*
|
2024-01-18 13:37:57 +03:00
|
|
|
* When "acpi=off" is used with the Q35 machine type, no ACPI is built,
|
2017-12-22 04:51:20 +03:00
|
|
|
* but pcms->acpi_dev is still created. Check !acpi_enabled in
|
|
|
|
* addition to cover this case.
|
|
|
|
*/
|
2020-09-15 15:09:02 +03:00
|
|
|
if (!x86ms->acpi_dev || !x86_machine_is_acpi_enabled(x86ms)) {
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 19:06:01 +03:00
|
|
|
error_setg(errp,
|
2017-12-22 04:51:20 +03:00
|
|
|
"memory hotplug is not enabled: missing acpi device or acpi disabled");
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 19:06:01 +03:00
|
|
|
return;
|
2015-04-27 11:47:17 +03:00
|
|
|
}
|
|
|
|
|
2016-10-28 19:35:40 +03:00
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 19:06:01 +03:00
|
|
|
error_setg(errp, "nvdimm device hot unplug is not supported yet.");
|
|
|
|
return;
|
2016-10-28 19:35:40 +03:00
|
|
|
}
|
|
|
|
|
2020-09-15 15:09:02 +03:00
|
|
|
hotplug_handler_unplug_request(x86ms->acpi_dev, dev,
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 19:06:01 +03:00
|
|
|
errp);
|
2015-04-27 11:47:17 +03:00
|
|
|
}
|
|
|
|
|
2018-06-19 16:41:31 +03:00
|
|
|
static void pc_memory_unplug(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
2015-04-27 11:47:18 +03:00
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
2020-09-15 15:09:02 +03:00
|
|
|
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
|
2015-04-27 11:47:18 +03:00
|
|
|
Error *local_err = NULL;
|
|
|
|
|
2020-09-15 15:09:02 +03:00
|
|
|
hotplug_handler_unplug(x86ms->acpi_dev, dev, &local_err);
|
2015-04-27 11:47:18 +03:00
|
|
|
if (local_err) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-10-05 12:20:12 +03:00
|
|
|
pc_dimm_unplug(PC_DIMM(dev), MACHINE(pcms));
|
2020-06-10 08:31:56 +03:00
|
|
|
qdev_unrealize(dev);
|
2015-04-27 11:47:18 +03:00
|
|
|
out:
|
|
|
|
error_propagate(errp, local_err);
|
|
|
|
}
|
|
|
|
|
2023-08-24 00:36:35 +03:00
|
|
|
static void pc_hv_balloon_pre_plug(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
/* The vmbus handler has no hotplug handler; we should never end up here. */
|
|
|
|
g_assert(!dev->hotplugged);
|
2024-02-28 12:26:53 +03:00
|
|
|
memory_device_pre_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev), errp);
|
2023-08-24 00:36:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_hv_balloon_plug(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
memory_device_plug(MEMORY_DEVICE(dev), MACHINE(hotplug_dev));
|
|
|
|
}
|
|
|
|
|
2016-07-06 09:20:40 +03:00
|
|
|
static void pc_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
2018-06-19 16:41:34 +03:00
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
|
|
|
pc_memory_pre_plug(hotplug_dev, dev, errp);
|
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
2020-09-15 15:09:03 +03:00
|
|
|
x86_cpu_pre_plug(hotplug_dev, dev, errp);
|
2023-07-11 18:34:40 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
|
|
|
virtio_md_pci_pre_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
|
2021-10-26 21:20:23 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
|
|
|
/* Declare the APIC range as the reserved MSI region */
|
|
|
|
char *resv_prop_str = g_strdup_printf("0xfee00000:0xfeefffff:%d",
|
|
|
|
VIRTIO_IOMMU_RESV_MEM_T_MSI);
|
2023-11-09 20:42:30 +03:00
|
|
|
QList *reserved_regions = qlist_new();
|
|
|
|
|
|
|
|
qlist_append_str(reserved_regions, resv_prop_str);
|
|
|
|
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
|
2021-10-26 21:20:23 +03:00
|
|
|
|
|
|
|
g_free(resv_prop_str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_X86_IOMMU_DEVICE) ||
|
|
|
|
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
2021-10-26 21:20:22 +03:00
|
|
|
PCMachineState *pcms = PC_MACHINE(hotplug_dev);
|
|
|
|
|
|
|
|
if (pcms->iommu) {
|
|
|
|
error_setg(errp, "QEMU does not support multiple vIOMMUs "
|
|
|
|
"for x86 yet.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pcms->iommu = dev;
|
2023-08-24 00:36:35 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_HV_BALLOON)) {
|
|
|
|
pc_hv_balloon_pre_plug(hotplug_dev, dev, errp);
|
2016-07-06 09:20:40 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-02 17:25:12 +04:00
|
|
|
static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
2018-06-19 16:41:31 +03:00
|
|
|
pc_memory_plug(hotplug_dev, dev, errp);
|
2014-10-22 07:24:28 +04:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
2020-09-15 15:09:03 +03:00
|
|
|
x86_cpu_plug(hotplug_dev, dev, errp);
|
2023-07-11 18:34:40 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
|
|
|
virtio_md_pci_plug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
|
2023-08-24 00:36:35 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_HV_BALLOON)) {
|
|
|
|
pc_hv_balloon_plug(hotplug_dev, dev, errp);
|
2014-06-02 17:25:12 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-28 10:45:37 +03:00
|
|
|
static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
2015-04-27 11:47:17 +03:00
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
2018-06-19 16:41:31 +03:00
|
|
|
pc_memory_unplug_request(hotplug_dev, dev, errp);
|
2016-06-14 17:14:02 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
2020-09-15 15:09:03 +03:00
|
|
|
x86_cpu_unplug_request_cb(hotplug_dev, dev, errp);
|
2023-07-11 18:34:40 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
|
|
|
virtio_md_pci_unplug_request(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev),
|
|
|
|
errp);
|
2015-04-27 11:47:17 +03:00
|
|
|
} else {
|
|
|
|
error_setg(errp, "acpi: device unplug request for not supported device"
|
|
|
|
" type: %s", object_get_typename(OBJECT(dev)));
|
|
|
|
}
|
2015-01-28 10:45:37 +03:00
|
|
|
}
|
|
|
|
|
2015-01-28 10:45:39 +03:00
|
|
|
static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
|
|
|
|
DeviceState *dev, Error **errp)
|
|
|
|
{
|
2015-04-27 11:47:18 +03:00
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
|
2018-06-19 16:41:31 +03:00
|
|
|
pc_memory_unplug(hotplug_dev, dev, errp);
|
2016-06-14 17:14:02 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
2020-09-15 15:09:03 +03:00
|
|
|
x86_cpu_unplug_cb(hotplug_dev, dev, errp);
|
2023-07-11 18:34:40 +03:00
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
|
|
|
virtio_md_pci_unplug(VIRTIO_MD_PCI(dev), MACHINE(hotplug_dev), errp);
|
2015-04-27 11:47:18 +03:00
|
|
|
} else {
|
|
|
|
error_setg(errp, "acpi: device unplug for not supported device"
|
|
|
|
" type: %s", object_get_typename(OBJECT(dev)));
|
|
|
|
}
|
2015-01-28 10:45:39 +03:00
|
|
|
}
|
|
|
|
|
2019-01-24 10:36:26 +03:00
|
|
|
static HotplugHandler *pc_get_hotplug_handler(MachineState *machine,
|
2014-06-02 17:25:12 +04:00
|
|
|
DeviceState *dev)
|
|
|
|
{
|
2014-10-22 07:24:28 +04:00
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
|
2019-06-19 12:49:07 +03:00
|
|
|
object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
|
2023-07-11 18:34:40 +03:00
|
|
|
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI) ||
|
2021-10-26 21:20:23 +03:00
|
|
|
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
|
2023-08-24 00:36:35 +03:00
|
|
|
object_dynamic_cast(OBJECT(dev), TYPE_HV_BALLOON) ||
|
2021-10-26 21:20:22 +03:00
|
|
|
object_dynamic_cast(OBJECT(dev), TYPE_X86_IOMMU_DEVICE)) {
|
2014-06-02 17:25:12 +04:00
|
|
|
return HOTPLUG_HANDLER(machine);
|
|
|
|
}
|
|
|
|
|
2018-05-10 20:10:56 +03:00
|
|
|
return NULL;
|
2014-06-02 17:25:12 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void pc_machine_get_vmport(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2014-10-04 01:33:37 +04:00
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
2014-11-21 19:18:52 +03:00
|
|
|
OnOffAuto vmport = pcms->vmport;
|
2014-10-04 01:33:37 +04:00
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_OnOffAuto(v, name, &vmport, errp);
|
2014-10-04 01:33:37 +04:00
|
|
|
}
|
|
|
|
|
qom: Swap 'name' next to visitor in ObjectPropertyAccessor
Similar to the previous patch, it's nice to have all functions
in the tree that involve a visitor and a name for conversion to
or from QAPI to consistently stick the 'name' parameter next
to the Visitor parameter.
Done by manually changing include/qom/object.h and qom/object.c,
then running this Coccinelle script and touching up the fallout
(Coccinelle insisted on adding some trailing whitespace).
@ rule1 @
identifier fn;
typedef Object, Visitor, Error;
identifier obj, v, opaque, name, errp;
@@
void fn
- (Object *obj, Visitor *v, void *opaque, const char *name,
+ (Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp) { ... }
@@
identifier rule1.fn;
expression obj, v, opaque, name, errp;
@@
fn(obj, v,
- opaque, name,
+ name, opaque,
errp)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-20-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:55 +03:00
|
|
|
static void pc_machine_set_vmport(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
2014-10-04 01:33:37 +04:00
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
qapi: Swap visit_* arguments for consistent 'name' placement
JSON uses "name":value, but many of our visitor interfaces were
called with visit_type_FOO(v, &value, name, errp). This can be
a bit confusing to have to mentally swap the parameter order to
match JSON order. It's particularly bad for visit_start_struct(),
where the 'name' parameter is smack in the middle of the
otherwise-related group of 'obj, kind, size' parameters! It's
time to do a global swap of the parameter ordering, so that the
'name' parameter is always immediately after the Visitor argument.
Additional reason in favor of the swap: the existing include/qjson.h
prefers listing 'name' first in json_prop_*(), and I have plans to
unify that file with the qapi visitors; listing 'name' first in
qapi will minimize churn to the (admittedly few) qjson.h clients.
Later patches will then fix docs, object.h, visitor-impl.h, and
those clients to match.
Done by first patching scripts/qapi*.py by hand to make generated
files do what I want, then by running the following Coccinelle
script to affect the rest of the code base:
$ spatch --sp-file script `git grep -l '\bvisit_' -- '**/*.[ch]'`
I then had to apply some touchups (Coccinelle insisted on TAB
indentation in visitor.h, and botched the signature of
visit_type_enum() by rewriting 'const char *const strings[]' to
the syntactically invalid 'const char*const[] strings'). The
movement of parameters is sufficient to provoke compiler errors
if any callers were missed.
// Part 1: Swap declaration order
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_start_struct
-(TV v, TObj OBJ, T1 ARG1, const char *name, T2 ARG2, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type bool, TV, T1;
identifier ARG1;
@@
bool visit_optional
-(TV v, T1 ARG1, const char *name)
+(TV v, const char *name, T1 ARG1)
{ ... }
@@
type TV, TErr, TObj, T1;
identifier OBJ, ARG1;
@@
void visit_get_next_type
-(TV v, TObj OBJ, T1 ARG1, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, TErr errp)
{ ... }
@@
type TV, TErr, TObj, T1, T2;
identifier OBJ, ARG1, ARG2;
@@
void visit_type_enum
-(TV v, TObj OBJ, T1 ARG1, T2 ARG2, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, T1 ARG1, T2 ARG2, TErr errp)
{ ... }
@@
type TV, TErr, TObj;
identifier OBJ;
identifier VISIT_TYPE =~ "^visit_type_";
@@
void VISIT_TYPE
-(TV v, TObj OBJ, const char *name, TErr errp)
+(TV v, const char *name, TObj OBJ, TErr errp)
{ ... }
// Part 2: swap caller order
@@
expression V, NAME, OBJ, ARG1, ARG2, ERR;
identifier VISIT_TYPE =~ "^visit_type_";
@@
(
-visit_start_struct(V, OBJ, ARG1, NAME, ARG2, ERR)
+visit_start_struct(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-visit_optional(V, ARG1, NAME)
+visit_optional(V, NAME, ARG1)
|
-visit_get_next_type(V, OBJ, ARG1, NAME, ERR)
+visit_get_next_type(V, NAME, OBJ, ARG1, ERR)
|
-visit_type_enum(V, OBJ, ARG1, ARG2, NAME, ERR)
+visit_type_enum(V, NAME, OBJ, ARG1, ARG2, ERR)
|
-VISIT_TYPE(V, OBJ, NAME, ERR)
+VISIT_TYPE(V, NAME, OBJ, ERR)
)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <1454075341-13658-19-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-01-29 16:48:54 +03:00
|
|
|
visit_type_OnOffAuto(v, name, &pcms->vmport, errp);
|
2014-10-04 01:33:37 +04:00
|
|
|
}
|
|
|
|
|
2024-02-13 12:56:56 +03:00
|
|
|
static bool pc_machine_get_fd_bootchk(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
return pcms->fd_bootchk;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_fd_bootchk(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
pcms->fd_bootchk = value;
|
|
|
|
}
|
|
|
|
|
2016-11-05 10:19:48 +03:00
|
|
|
static bool pc_machine_get_smbus(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
2018-11-07 18:24:34 +03:00
|
|
|
return pcms->smbus_enabled;
|
2016-11-05 10:19:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_smbus(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
2018-11-07 18:24:34 +03:00
|
|
|
pcms->smbus_enabled = value;
|
2016-11-05 10:19:48 +03:00
|
|
|
}
|
|
|
|
|
2016-11-05 10:19:49 +03:00
|
|
|
static bool pc_machine_get_sata(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
2018-11-07 18:24:34 +03:00
|
|
|
return pcms->sata_enabled;
|
2016-11-05 10:19:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_sata(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
2018-11-07 18:24:34 +03:00
|
|
|
pcms->sata_enabled = value;
|
2016-11-05 10:19:49 +03:00
|
|
|
}
|
|
|
|
|
2020-10-21 17:47:16 +03:00
|
|
|
static bool pc_machine_get_hpet(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
return pcms->hpet_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_hpet(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
pcms->hpet_enabled = value;
|
|
|
|
}
|
|
|
|
|
2022-02-28 00:06:55 +03:00
|
|
|
static bool pc_machine_get_i8042(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
return pcms->i8042_enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_i8042(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
pcms->i8042_enabled = value;
|
|
|
|
}
|
|
|
|
|
2021-07-08 15:55:14 +03:00
|
|
|
static bool pc_machine_get_default_bus_bypass_iommu(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
return pcms->default_bus_bypass_iommu;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_default_bus_bypass_iommu(Object *obj, bool value,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
pcms->default_bus_bypass_iommu = value;
|
|
|
|
}
|
|
|
|
|
2021-10-26 18:11:00 +03:00
|
|
|
static void pc_machine_get_smbios_ep(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
SmbiosEntryPointType smbios_entry_point_type = pcms->smbios_entry_point_type;
|
|
|
|
|
|
|
|
visit_type_SmbiosEntryPointType(v, name, &smbios_entry_point_type, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_smbios_ep(Object *obj, Visitor *v, const char *name,
|
|
|
|
void *opaque, Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
|
|
|
|
visit_type_SmbiosEntryPointType(v, name, &pcms->smbios_entry_point_type, errp);
|
|
|
|
}
|
|
|
|
|
2020-05-29 10:39:56 +03:00
|
|
|
static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
uint64_t value = pcms->max_ram_below_4g;
|
|
|
|
|
|
|
|
visit_type_size(v, name, &value, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
uint64_t value;
|
|
|
|
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!visit_type_size(v, name, &value, errp)) {
|
2020-05-29 10:39:56 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (value > 4 * GiB) {
|
error: Avoid unnecessary error_propagate() after error_setg()
Replace
error_setg(&err, ...);
error_propagate(errp, err);
by
error_setg(errp, ...);
Related pattern:
if (...) {
error_setg(&err, ...);
goto out;
}
...
out:
error_propagate(errp, err);
return;
When all paths to label out are that way, replace by
if (...) {
error_setg(errp, ...);
return;
}
and delete the label along with the error_propagate().
When we have at most one other path that actually needs to propagate,
and maybe one at the end that where propagation is unnecessary, e.g.
foo(..., &err);
if (err) {
goto out;
}
...
bar(..., &err);
out:
error_propagate(errp, err);
return;
move the error_propagate() to where it's needed, like
if (...) {
foo(..., &err);
error_propagate(errp, err);
return;
}
...
bar(..., errp);
return;
and transform the error_setg() as above.
In some places, the transformation results in obviously unnecessary
error_propagate(). The next few commits will eliminate them.
Bonus: the elimination of gotos will make later patches in this series
easier to review.
Candidates for conversion tracked down with this Coccinelle script:
@@
identifier err, errp;
expression list args;
@@
- error_setg(&err, args);
+ error_setg(errp, args);
... when != err
error_propagate(errp, err);
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-34-armbru@redhat.com>
2020-07-07 19:06:01 +03:00
|
|
|
error_setg(errp,
|
2020-05-29 10:39:56 +03:00
|
|
|
"Machine option 'max-ram-below-4g=%"PRIu64
|
|
|
|
"' expects size less than or equal to 4G", value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < 1 * MiB) {
|
|
|
|
warn_report("Only %" PRIu64 " bytes of RAM below the 4GiB boundary,"
|
|
|
|
"BIOS may not work with less than 1MiB", value);
|
|
|
|
}
|
|
|
|
|
|
|
|
pcms->max_ram_below_4g = value;
|
|
|
|
}
|
|
|
|
|
2020-12-08 18:53:38 +03:00
|
|
|
static void pc_machine_get_max_fw_size(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
uint64_t value = pcms->max_fw_size;
|
|
|
|
|
|
|
|
visit_type_size(v, name, &value, errp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pc_machine_set_max_fw_size(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
|
|
|
uint64_t value;
|
|
|
|
|
2022-11-21 11:50:53 +03:00
|
|
|
if (!visit_type_size(v, name, &value, errp)) {
|
2020-12-08 18:53:38 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-09-12 18:55:53 +03:00
|
|
|
* We don't have a theoretically justifiable exact lower bound on the base
|
|
|
|
* address of any flash mapping. In practice, the IO-APIC MMIO range is
|
|
|
|
* [0xFEE00000..0xFEE01000] -- see IO_APIC_DEFAULT_ADDRESS --, leaving free
|
|
|
|
* only 18MiB-4KiB below 4GiB. For now, restrict the cumulative mapping to
|
|
|
|
* 16MiB in size.
|
|
|
|
*/
|
2020-12-08 18:53:38 +03:00
|
|
|
if (value > 16 * MiB) {
|
|
|
|
error_setg(errp,
|
|
|
|
"User specified max allowed firmware size %" PRIu64 " is "
|
2023-07-14 14:16:12 +03:00
|
|
|
"greater than 16MiB. If combined firmware size exceeds "
|
2020-12-08 18:53:38 +03:00
|
|
|
"16MiB the system may not boot, or experience intermittent"
|
|
|
|
"stability issues.",
|
|
|
|
value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pcms->max_fw_size = value;
|
|
|
|
}
|
|
|
|
|
2021-01-19 03:32:13 +03:00
|
|
|
|
2014-06-02 17:25:27 +04:00
|
|
|
static void pc_machine_initfn(Object *obj)
|
|
|
|
{
|
2014-06-20 05:40:25 +04:00
|
|
|
PCMachineState *pcms = PC_MACHINE(obj);
|
2023-06-07 23:57:16 +03:00
|
|
|
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(pcms);
|
2014-06-20 05:40:25 +04:00
|
|
|
|
2019-07-12 19:02:57 +03:00
|
|
|
#ifdef CONFIG_VMPORT
|
2014-11-21 19:18:52 +03:00
|
|
|
pcms->vmport = ON_OFF_AUTO_AUTO;
|
2019-07-12 19:02:57 +03:00
|
|
|
#else
|
|
|
|
pcms->vmport = ON_OFF_AUTO_OFF;
|
|
|
|
#endif /* CONFIG_VMPORT */
|
2020-05-29 10:39:56 +03:00
|
|
|
pcms->max_ram_below_4g = 0; /* use default */
|
2023-06-07 23:57:16 +03:00
|
|
|
pcms->smbios_entry_point_type = pcmc->default_smbios_ep_type;
|
2023-10-07 15:38:37 +03:00
|
|
|
pcms->south_bridge = pcmc->default_south_bridge;
|
2021-10-26 18:11:00 +03:00
|
|
|
|
2016-11-01 20:44:16 +03:00
|
|
|
/* acpi build is enabled by default if machine supports it */
|
2023-06-09 19:41:07 +03:00
|
|
|
pcms->acpi_build_enabled = pcmc->has_acpi_build;
|
2018-11-07 18:24:34 +03:00
|
|
|
pcms->smbus_enabled = true;
|
|
|
|
pcms->sata_enabled = true;
|
2022-02-28 00:06:55 +03:00
|
|
|
pcms->i8042_enabled = true;
|
2020-12-08 18:53:38 +03:00
|
|
|
pcms->max_fw_size = 8 * MiB;
|
2020-10-21 17:47:16 +03:00
|
|
|
#ifdef CONFIG_HPET
|
|
|
|
pcms->hpet_enabled = true;
|
|
|
|
#endif
|
2024-02-13 12:56:56 +03:00
|
|
|
pcms->fd_bootchk = true;
|
2021-07-08 15:55:14 +03:00
|
|
|
pcms->default_bus_bypass_iommu = false;
|
pc: Support firmware configuration with -blockdev
The PC machines put firmware in ROM by default. To get it put into
flash memory (required by OVMF), you have to use -drive
if=pflash,unit=0,... and optionally -drive if=pflash,unit=1,...
Why two -drive? This permits setting up one part of the flash memory
read-only, and the other part read/write. It also makes upgrading
firmware on the host easier. Below the hood, it creates two separate
flash devices, because we were too lazy to improve our flash device
models to support sector protection.
The problem at hand is to do the same with -blockdev somehow, as one
more step towards deprecating -drive.
Mapping -drive if=none,... to -blockdev is a solved problem. With
if=T other than if=none, -drive additionally configures a block device
frontend. For non-onboard devices, that part maps to -device. Also a
solved problem. For onboard devices such as PC flash memory, we have
an unsolved problem.
This is actually an instance of a wider problem: our general device
configuration interface doesn't cover onboard devices. Instead, we have
a zoo of ad hoc interfaces that are much more limited. One of them is
-drive, which we'd rather deprecate, but can't until we have suitable
replacements for all its uses.
Sadly, I can't attack the wider problem today. So back to the narrow
problem.
My first idea was to reduce it to its solved buddy by using pluggable
instead of onboard devices for the flash memory. Workable, but it
requires some extra smarts in firmware descriptors and libvirt. Paolo
had an idea that is simpler for libvirt: keep the devices onboard, and
add machine properties for their block backends.
The implementation is less than straightforward, I'm afraid.
First, block backend properties are *qdev* properties. Machines can't
have those, as they're not devices. I could duplicate these qdev
properties as QOM properties, but I hate that.
More seriously, the properties do not belong to the machine, they
belong to the onboard flash devices. Adding them to the machine would
then require bad magic to somehow transfer them to the flash devices.
Fortunately, QOM provides the means to handle exactly this case: add
alias properties to the machine that forward to the onboard devices'
properties.
Properties need to be created in .instance_init() methods. For PC
machines, that's pc_machine_initfn(). To make alias properties work,
we need to create the onboard flash devices there, too. Requires
several bug fixes, in the previous commits. We also have to realize
the devices. More on that below.
If the user sets pflash0, firmware resides in flash memory.
pc_system_firmware_init() maps and realizes the flash devices.
Else, firmware resides in ROM. The onboard flash devices aren't used
then. pc_system_firmware_init() destroys them unrealized, along with
the alias properties.
The existing code to pick up drives defined with -drive if=pflash is
replaced by code to desugar into the machine properties.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <87ftrtux81.fsf@dusky.pond.sub.org>
2019-03-11 20:39:26 +03:00
|
|
|
|
2024-02-27 00:59:09 +03:00
|
|
|
pc_system_flash_create(pcms);
|
2020-07-02 16:25:21 +03:00
|
|
|
pcms->pcspk = isa_new(TYPE_PC_SPEAKER);
|
2020-07-02 16:25:22 +03:00
|
|
|
object_property_add_alias(OBJECT(pcms), "pcspk-audiodev",
|
|
|
|
OBJECT(pcms->pcspk), "audiodev");
|
2024-03-27 19:14:38 +03:00
|
|
|
if (pcmc->pci_enabled) {
|
|
|
|
cxl_machine_init(obj, &pcms->cxl_devices_state);
|
|
|
|
}
|
2024-02-09 01:03:44 +03:00
|
|
|
|
|
|
|
pcms->machine_done.notify = pc_machine_done;
|
|
|
|
qemu_add_machine_init_done_notifier(&pcms->machine_done);
|
2014-06-02 17:25:27 +04:00
|
|
|
}
|
|
|
|
|
2022-10-25 03:43:17 +03:00
|
|
|
static void pc_machine_reset(MachineState *machine, ShutdownCause reason)
|
2015-09-16 12:19:13 +03:00
|
|
|
{
|
|
|
|
CPUState *cs;
|
|
|
|
X86CPU *cpu;
|
|
|
|
|
2022-10-25 03:43:17 +03:00
|
|
|
qemu_devices_reset(reason);
|
2015-09-16 12:19:13 +03:00
|
|
|
|
|
|
|
/* Reset APIC after devices have been reset to cancel
|
|
|
|
* any changes that qemu_devices_reset() might have done.
|
|
|
|
*/
|
|
|
|
CPU_FOREACH(cs) {
|
|
|
|
cpu = X86_CPU(cs);
|
|
|
|
|
2022-09-30 18:52:03 +03:00
|
|
|
x86_cpu_after_reset(cpu);
|
2015-09-16 12:19:13 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-22 09:17:51 +03:00
|
|
|
static void pc_machine_wakeup(MachineState *machine)
|
|
|
|
{
|
|
|
|
cpu_synchronize_all_states();
|
2022-10-25 03:43:17 +03:00
|
|
|
pc_machine_reset(machine, SHUTDOWN_CAUSE_NONE);
|
2019-07-22 09:17:51 +03:00
|
|
|
cpu_synchronize_all_post_reset();
|
|
|
|
}
|
|
|
|
|
2019-09-16 11:07:17 +03:00
|
|
|
static bool pc_hotplug_allowed(MachineState *ms, DeviceState *dev, Error **errp)
|
|
|
|
{
|
|
|
|
X86IOMMUState *iommu = x86_iommu_get_default();
|
|
|
|
IntelIOMMUState *intel_iommu;
|
|
|
|
|
|
|
|
if (iommu &&
|
|
|
|
object_dynamic_cast((Object *)iommu, TYPE_INTEL_IOMMU_DEVICE) &&
|
|
|
|
object_dynamic_cast((Object *)dev, "vfio-pci")) {
|
|
|
|
intel_iommu = INTEL_IOMMU_DEVICE(iommu);
|
|
|
|
if (!intel_iommu->caching_mode) {
|
|
|
|
error_setg(errp, "Device assignment is not allowed without "
|
|
|
|
"enabling caching-mode=on for Intel IOMMU.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-06-02 17:25:12 +04:00
|
|
|
static void pc_machine_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
2024-02-09 01:03:43 +03:00
|
|
|
X86MachineClass *x86mc = X86_MACHINE_CLASS(oc);
|
2014-06-02 17:25:12 +04:00
|
|
|
PCMachineClass *pcmc = PC_MACHINE_CLASS(oc);
|
|
|
|
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
|
|
|
|
|
2015-12-02 01:58:03 +03:00
|
|
|
pcmc->pci_enabled = true;
|
|
|
|
pcmc->has_acpi_build = true;
|
|
|
|
pcmc->smbios_defaults = true;
|
|
|
|
pcmc->gigabyte_align = true;
|
|
|
|
pcmc->has_reserved_memory = true;
|
2022-07-19 20:00:14 +03:00
|
|
|
pcmc->enforce_amd_1tb_hole = true;
|
hw/i386/pc_sysfw: Alias rather than copy isa-bios region
In the -bios case the "isa-bios" memory region is an alias to the BIOS mapped
to the top of the 4G memory boundary. Do the same in the -pflash case, but only
for new machine versions for migration compatibility. This establishes common
behavior and makes pflash commands work in the "isa-bios" region which some
real-world legacy bioses rely on.
Note that in the sev_enabled() case, the "isa-bios" memory region in the -pflash
case will now also point to encrypted memory, just like it already does in the
-bios case.
When running `info mtree` before and after this commit with
`qemu-system-x86_64 -S -drive \
if=pflash,format=raw,readonly=on,file=/usr/share/qemu/bios-256k.bin` and running
`diff -u before.mtree after.mtree` results in the following changes in the
memory tree:
--- before.mtree
+++ after.mtree
@@ -71,7 +71,7 @@
0000000000000000-ffffffffffffffff (prio -1, i/o): pci
00000000000a0000-00000000000bffff (prio 1, i/o): vga-lowmem
00000000000c0000-00000000000dffff (prio 1, rom): pc.rom
- 00000000000e0000-00000000000fffff (prio 1, rom): isa-bios
+ 00000000000e0000-00000000000fffff (prio 1, romd): alias isa-bios @system.flash0 0000000000020000-000000000003ffff
00000000000a0000-00000000000bffff (prio 1, i/o): alias smram-region @pci 00000000000a0000-00000000000bffff
00000000000c0000-00000000000c3fff (prio 1, i/o): alias pam-pci @pci 00000000000c0000-00000000000c3fff
00000000000c4000-00000000000c7fff (prio 1, i/o): alias pam-pci @pci 00000000000c4000-00000000000c7fff
@@ -108,7 +108,7 @@
0000000000000000-ffffffffffffffff (prio -1, i/o): pci
00000000000a0000-00000000000bffff (prio 1, i/o): vga-lowmem
00000000000c0000-00000000000dffff (prio 1, rom): pc.rom
- 00000000000e0000-00000000000fffff (prio 1, rom): isa-bios
+ 00000000000e0000-00000000000fffff (prio 1, romd): alias isa-bios @system.flash0 0000000000020000-000000000003ffff
00000000000a0000-00000000000bffff (prio 1, i/o): alias smram-region @pci 00000000000a0000-00000000000bffff
00000000000c0000-00000000000c3fff (prio 1, i/o): alias pam-pci @pci 00000000000c0000-00000000000c3fff
00000000000c4000-00000000000c7fff (prio 1, i/o): alias pam-pci @pci 00000000000c4000-00000000000c7fff
@@ -131,11 +131,14 @@
memory-region: pc.ram
0000000000000000-0000000007ffffff (prio 0, ram): pc.ram
+memory-region: system.flash0
+ 00000000fffc0000-00000000ffffffff (prio 0, romd): system.flash0
+
memory-region: pci
0000000000000000-ffffffffffffffff (prio -1, i/o): pci
00000000000a0000-00000000000bffff (prio 1, i/o): vga-lowmem
00000000000c0000-00000000000dffff (prio 1, rom): pc.rom
- 00000000000e0000-00000000000fffff (prio 1, rom): isa-bios
+ 00000000000e0000-00000000000fffff (prio 1, romd): alias isa-bios @system.flash0 0000000000020000-000000000003ffff
memory-region: smram
00000000000a0000-00000000000bffff (prio 0, ram): alias smram-low @pc.ram 00000000000a0000-00000000000bffff
Note that in both cases the "system" memory region contains the entry
00000000fffc0000-00000000ffffffff (prio 0, romd): system.flash0
but the "system.flash0" memory region only appears standalone when "isa-bios" is
an alias.
Signed-off-by: Bernhard Beschow <shentey@gmail.com>
Message-ID: <20240508175507.22270-7-shentey@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-05-08 20:55:07 +03:00
|
|
|
pcmc->isa_bios_alias = true;
|
2015-12-02 01:58:05 +03:00
|
|
|
/* BIOS ACPI tables: 128K. Other BIOS datastructures: less than 4K reported
|
|
|
|
* to be used at the moment, 32K should be enough for a while. */
|
|
|
|
pcmc->acpi_data_size = 0x20000 + 0x8000;
|
2019-01-22 15:10:48 +03:00
|
|
|
pcmc->pvh_enabled = true;
|
2020-09-22 18:19:34 +03:00
|
|
|
pcmc->kvmclock_create_always = true;
|
2024-02-09 01:03:43 +03:00
|
|
|
x86mc->apic_xrupt_override = true;
|
2018-05-10 20:10:56 +03:00
|
|
|
assert(!mc->get_hotplug_handler);
|
2019-01-24 10:36:26 +03:00
|
|
|
mc->get_hotplug_handler = pc_get_hotplug_handler;
|
2019-09-16 11:07:17 +03:00
|
|
|
mc->hotplug_allowed = pc_hotplug_allowed;
|
2017-11-14 05:34:01 +03:00
|
|
|
mc->auto_enable_numa_with_memhp = true;
|
2020-06-26 10:22:48 +03:00
|
|
|
mc->auto_enable_numa_with_memdev = true;
|
2017-02-10 13:20:57 +03:00
|
|
|
mc->has_hotpluggable_cpus = true;
|
2015-08-07 22:55:47 +03:00
|
|
|
mc->default_boot_order = "cad";
|
2017-02-15 13:05:40 +03:00
|
|
|
mc->block_default_type = IF_IDE;
|
2015-08-07 22:55:48 +03:00
|
|
|
mc->max_cpus = 255;
|
2015-09-16 12:19:13 +03:00
|
|
|
mc->reset = pc_machine_reset;
|
2019-07-22 09:17:51 +03:00
|
|
|
mc->wakeup = pc_machine_wakeup;
|
2016-07-06 09:20:40 +03:00
|
|
|
hc->pre_plug = pc_machine_device_pre_plug_cb;
|
2014-06-02 17:25:12 +04:00
|
|
|
hc->plug = pc_machine_device_plug_cb;
|
2015-01-28 10:45:37 +03:00
|
|
|
hc->unplug_request = pc_machine_device_unplug_request_cb;
|
2015-01-28 10:45:39 +03:00
|
|
|
hc->unplug = pc_machine_device_unplug_cb;
|
2017-09-13 19:04:56 +03:00
|
|
|
mc->default_cpu_type = TARGET_DEFAULT_CPU_TYPE;
|
2019-03-08 21:20:53 +03:00
|
|
|
mc->nvdimm_supported = true;
|
2021-09-29 05:58:12 +03:00
|
|
|
mc->smp_props.dies_supported = true;
|
hw/i386/pc: Support smp.modules for x86 PC machine
As module-level topology support is added to X86CPU, now we can enable
the support for the modules parameter on PC machines. With this support,
we can define a 5-level x86 CPU topology with "-smp":
-smp cpus=*,maxcpus=*,sockets=*,dies=*,modules=*,cores=*,threads=*.
So, add the 5-level topology example in description of "-smp".
Additionally, add the missed drawers and books options in previous
example.
Tested-by: Yongwei Ma <yongwei.ma@intel.com>
Co-developed-by: Zhuocheng Ding <zhuocheng.ding@intel.com>
Signed-off-by: Zhuocheng Ding <zhuocheng.ding@intel.com>
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
Tested-by: Babu Moger <babu.moger@amd.com>
Reviewed-by: Babu Moger <babu.moger@amd.com>
Message-ID: <20240424154929.1487382-19-zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2024-04-24 18:49:26 +03:00
|
|
|
mc->smp_props.modules_supported = true;
|
2020-02-19 19:09:17 +03:00
|
|
|
mc->default_ram_id = "pc.ram";
|
2024-03-14 18:23:00 +03:00
|
|
|
pcmc->default_smbios_ep_type = SMBIOS_ENTRY_POINT_TYPE_AUTO;
|
2016-10-13 23:48:36 +03:00
|
|
|
|
2020-05-29 10:39:56 +03:00
|
|
|
object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size",
|
|
|
|
pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g,
|
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, PC_MACHINE_MAX_RAM_BELOW_4G,
|
|
|
|
"Maximum ram below the 4G boundary (32bit boundary)");
|
|
|
|
|
2016-10-13 23:48:36 +03:00
|
|
|
object_class_property_add(oc, PC_MACHINE_VMPORT, "OnOffAuto",
|
|
|
|
pc_machine_get_vmport, pc_machine_set_vmport,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
NULL, NULL);
|
2016-10-13 23:48:36 +03:00
|
|
|
object_class_property_set_description(oc, PC_MACHINE_VMPORT,
|
2020-05-05 18:29:15 +03:00
|
|
|
"Enable vmport (pc & q35)");
|
2016-10-13 23:48:36 +03:00
|
|
|
|
2016-11-05 10:19:48 +03:00
|
|
|
object_class_property_add_bool(oc, PC_MACHINE_SMBUS,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
pc_machine_get_smbus, pc_machine_set_smbus);
|
2021-12-06 16:42:55 +03:00
|
|
|
object_class_property_set_description(oc, PC_MACHINE_SMBUS,
|
|
|
|
"Enable/disable system management bus");
|
2016-11-05 10:19:49 +03:00
|
|
|
|
|
|
|
object_class_property_add_bool(oc, PC_MACHINE_SATA,
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
pc_machine_get_sata, pc_machine_set_sata);
|
2021-12-06 16:42:55 +03:00
|
|
|
object_class_property_set_description(oc, PC_MACHINE_SATA,
|
|
|
|
"Enable/disable Serial ATA bus");
|
2016-11-05 10:19:50 +03:00
|
|
|
|
2020-10-21 17:47:16 +03:00
|
|
|
object_class_property_add_bool(oc, "hpet",
|
|
|
|
pc_machine_get_hpet, pc_machine_set_hpet);
|
2021-12-06 16:42:55 +03:00
|
|
|
object_class_property_set_description(oc, "hpet",
|
|
|
|
"Enable/disable high precision event timer emulation");
|
2020-12-08 18:53:38 +03:00
|
|
|
|
2022-02-28 00:06:55 +03:00
|
|
|
object_class_property_add_bool(oc, PC_MACHINE_I8042,
|
|
|
|
pc_machine_get_i8042, pc_machine_set_i8042);
|
|
|
|
|
2021-10-25 13:47:38 +03:00
|
|
|
object_class_property_add_bool(oc, "default-bus-bypass-iommu",
|
2021-07-08 15:55:14 +03:00
|
|
|
pc_machine_get_default_bus_bypass_iommu,
|
|
|
|
pc_machine_set_default_bus_bypass_iommu);
|
|
|
|
|
2020-12-08 18:53:38 +03:00
|
|
|
object_class_property_add(oc, PC_MACHINE_MAX_FW_SIZE, "size",
|
|
|
|
pc_machine_get_max_fw_size, pc_machine_set_max_fw_size,
|
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, PC_MACHINE_MAX_FW_SIZE,
|
|
|
|
"Maximum combined firmware size");
|
2021-10-26 18:11:00 +03:00
|
|
|
|
|
|
|
object_class_property_add(oc, PC_MACHINE_SMBIOS_EP, "str",
|
|
|
|
pc_machine_get_smbios_ep, pc_machine_set_smbios_ep,
|
|
|
|
NULL, NULL);
|
|
|
|
object_class_property_set_description(oc, PC_MACHINE_SMBIOS_EP,
|
|
|
|
"SMBIOS Entry Point type [32, 64]");
|
2024-02-13 12:56:56 +03:00
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "fd-bootchk",
|
|
|
|
pc_machine_get_fd_bootchk,
|
|
|
|
pc_machine_set_fd_bootchk);
|
2014-06-02 17:25:12 +04:00
|
|
|
}
|
|
|
|
|
2014-06-02 17:24:57 +04:00
|
|
|
static const TypeInfo pc_machine_info = {
|
|
|
|
.name = TYPE_PC_MACHINE,
|
2019-10-22 10:39:50 +03:00
|
|
|
.parent = TYPE_X86_MACHINE,
|
2014-06-02 17:24:57 +04:00
|
|
|
.abstract = true,
|
|
|
|
.instance_size = sizeof(PCMachineState),
|
2014-06-02 17:25:27 +04:00
|
|
|
.instance_init = pc_machine_initfn,
|
2014-06-02 17:24:57 +04:00
|
|
|
.class_size = sizeof(PCMachineClass),
|
2014-06-02 17:25:12 +04:00
|
|
|
.class_init = pc_machine_class_init,
|
|
|
|
.interfaces = (InterfaceInfo[]) {
|
|
|
|
{ TYPE_HOTPLUG_HANDLER },
|
|
|
|
{ }
|
|
|
|
},
|
2014-06-02 17:24:57 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static void pc_machine_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&pc_machine_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(pc_machine_register_types)
|