Introduce the microvm machine type
v5 cover Introduce the microvm machine type
Microvm is a machine type inspired by Firecracker and constructed after the its machine model.
It's a minimalist machine type without PCI nor ACPI support, designed for short-lived guests. Microvm also establishes a baseline for benchmarking and optimizing both QEMU and guest operating systems, since it is optimized for both boot time and footprint.
---
Changelog
v5:
- Drop unneeded "[PATCH v4 2/8] hw/i386: Factorize e820 related functions" (Philippe Mathieu-Daudé)
- Drop unneeded "[PATCH v4 1/8] hw/i386: Factorize PVH related functions" (Stefano Garzarella)
- Split X86MachineState introduction into smaller patches (Philippe Mathieu-Daudé)
- Change option-roms to x-option-roms and kernel-cmdline to auto-kernel-cmdline (Paolo Bonzini)
- Make i8259 PIT and i8254 PIC optional (Paolo Bonzini)
- Some fixes to the documentation (Paolo Bonzini)
- Switch documentation format from txt to rst (Peter Maydell)
- Move NMI interface to X86_MACHINE (Philippe Mathieu-Daudé, Paolo Bonzini)
v4:
- This is a complete rewrite of the whole patchset, with a focus on reusing as much existing code as possible to ease the maintenance burden and making the machine type as compatible as possible by default. As a result, the number of lines dedicated specifically to microvm is 383 (code lines measured by "cloc") and, with the default configuration, it's now able to boot both PVH ELF images and bzImages with either SeaBIOS or qboot.
v3:
- Add initrd support (thanks Stefano).
v2:
- Drop "[PATCH 1/4] hw/i386: Factorize CPU routine".
- Simplify machine definition (thanks Eduardo).
- Remove use of unneeded NUMA-related callbacks (thanks Eduardo).
- Add a patch to factorize PVH-related functions.
- Replace use of Linux's Zero Page with PVH (thanks Maran and Paolo).
---
Sergio Lopez (10):
hw/virtio: Factorize virtio-mmio headers
hw/i386/pc: rename functions shared with non-PC machines hw/i386/pc: move shared x86 functions to x86.c and export them hw/i386: split PCMachineState deriving X86MachineState from it hw/i386: make x86.c independent from PCMachineState
fw_cfg: add "modify" functions for all types hw/intc/apic: reject pic ints if isa_pic == NULL
roms: add microvm-bios (qboot) as binary and git submodule docs/microvm.rst: document the new microvm machine type hw/i386: Introduce the microvm machine type
.gitmodules | 3 + default-configs/i386-softmmu.mak | 1 + docs/microvm.rst | 98 ++++ hw/acpi/cpu_hotplug.c | 10 +- hw/i386/Kconfig | 4 + hw/i386/Makefile.objs | 2 + hw/i386/acpi-build.c | 29 +- hw/i386/amd_iommu.c | 3 +- hw/i386/intel_iommu.c | 3 +- hw/i386/microvm.c | 574 ++++++++++++++++++++++ hw/i386/pc.c | 779 +++--------------------------- hw/i386/pc_piix.c | 46 +- hw/i386/pc_q35.c | 38 +- hw/i386/pc_sysfw.c | 58 +-- hw/i386/x86.c | 789 +++++++++++++++++++++++++++++++ hw/intc/apic.c | 2 +- hw/intc/ioapic.c | 2 +- hw/nvram/fw_cfg.c | 29 ++ hw/virtio/virtio-mmio.c | 48 +- include/hw/i386/microvm.h | 83 ++++ include/hw/i386/pc.h | 28 +- include/hw/i386/x86.h | 93 ++++ include/hw/nvram/fw_cfg.h | 42 ++ include/hw/virtio/virtio-mmio.h | 73 +++ pc-bios/bios-microvm.bin | Bin 0 -> 65536 bytes roms/Makefile | 6 + roms/qboot | 1 + 27 files changed, 1948 insertions(+), 896 deletions(-) create mode 100644 docs/microvm.rst create mode 100644 hw/i386/microvm.c create mode 100644 hw/i386/x86.c create mode 100644 include/hw/i386/microvm.h create mode 100644 include/hw/i386/x86.h create mode 100644 include/hw/virtio/virtio-mmio.h create mode 100755 pc-bios/bios-microvm.bin create mode 160000 roms/qboot
Signature · 1 line
2.21.0
PATCH v5 1/10 hw/virtio: Factorize virtio-mmio headers
Put QOM and main struct definition in a separate header file, so it can be accessed from other components.
--- hw/virtio/virtio-mmio.c | 48 +--------------------- include/hw/virtio/virtio-mmio.h | 73 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 47 deletions(-) create mode 100644 include/hw/virtio/virtio-mmio.h
hw/virtio/virtio-mmio.c +1 -47
@@ -29,57 +29,11 @@#include "qemu/host-utils.h" #include "qemu/module.h" #include "sysemu/kvm.h" -#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-mmio.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "trace.h" -/* QOM macros */ -/* virtio-mmio-bus */ -#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus" -#define VIRTIO_MMIO_BUS (obj) \ - OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS) -#define VIRTIO_MMIO_BUS_GET_CLASS (obj) \ - OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS) -#define VIRTIO_MMIO_BUS_CLASS (klass) \ - OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS) - -/* virtio-mmio */ -#define TYPE_VIRTIO_MMIO "virtio-mmio" -#define VIRTIO_MMIO (obj) \ - OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO) - -#define VIRT_MAGIC 0x74726976/* 'virt' */ -#define VIRT_VERSION 2 -#define VIRT_VERSION_LEGACY 1 -#define VIRT_VENDOR 0x554D4551/* 'QEMU' */ - -typedef struct VirtIOMMIOQueue { -uint16_t num; -bool enabled; -uint32_t desc[2 ]; -uint32_t avail[2 ]; -uint32_t used[2 ]; -}VirtIOMMIOQueue ; - -typedef struct { -/* Generic */ -SysBusDevice parent_obj; -MemoryRegion iomem; -qemu_irq irq; -bool legacy; -/* Guest accessible state needing migration and reset */ -uint32_t host_features_sel; -uint32_t guest_features_sel; -uint32_t guest_page_shift; -/* virtio-bus */ -VirtioBusState bus; -bool format_transport_address; -/* Fields only used for non-legacy (v2) devices */ -uint32_t guest_features[2 ]; -VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX ]; -}VirtIOMMIOProxy ; -static bool virtio_mmio_ioeventfd_enabled (DeviceState *d) {return kvm_eventfds_enabled ();
include/hw/virtio/virtio-mmio.h new file +73 -0
73 lines not on this page · raw message
Signature · 1 line
2.21.0
Re: [PATCH v5 01/10] hw/virtio: Factorize virtio-mmio headers
Quoted 92 lines · Sergio Lopez
Put QOM and main struct definition in a separate header file, so it can be accessed from other components.
Signed-off-by Sergio Lopez <[email protected]>--- hw/virtio/virtio-mmio.c | 48 +--------------------- include/hw/virtio/virtio-mmio.h | 73 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 47 deletions(-)create mode 100644
include/hw/virtio/virtio-mmio.hhw/virtio/virtio-mmio.c +1
-47@@ -29,57 +29,11 @@#include "qemu/host-utils.h" #include "qemu/module.h" #include "sysemu/kvm.h" -#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-mmio.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "trace.h" -/* QOM macros */ -/* virtio-mmio-bus */ -#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus" -#define VIRTIO_MMIO_BUS (obj) \ - OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS) -#define VIRTIO_MMIO_BUS_GET_CLASS (obj) \ - OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS) -#define VIRTIO_MMIO_BUS_CLASS (klass) \ - OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS) - -/* virtio-mmio */ -#define TYPE_VIRTIO_MMIO "virtio-mmio" -#define VIRTIO_MMIO (obj) \ - OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO) - -#define VIRT_MAGIC 0x74726976/* 'virt' */ -#define VIRT_VERSION 2 -#define VIRT_VERSION_LEGACY 1 -#define VIRT_VENDOR 0x554D4551/* 'QEMU' */ - -typedef struct VirtIOMMIOQueue { -uint16_t num; -bool enabled; -uint32_t desc[2 ]; -uint32_t avail[2 ]; -uint32_t used[2 ]; -}VirtIOMMIOQueue ; - -typedef struct { -/* Generic */ -SysBusDevice parent_obj; -MemoryRegion iomem; -qemu_irq irq; -bool legacy; -/* Guest accessible state needing migration and reset */ -uint32_t host_features_sel; -uint32_t guest_features_sel; -uint32_t guest_page_shift; -/* virtio-bus */ -VirtioBusState bus; -bool format_transport_address; -/* Fields only used for non-legacy (v2) devices */ -uint32_t guest_features[2 ]; -VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX ]; -}VirtIOMMIOProxy ; -static bool virtio_mmio_ioeventfd_enabled (DeviceState *d) {return kvm_eventfds_enabled ();include/hw/virtio/virtio-mmio.h new file +13
-0@@ -0,0 +1,73 @@ +/* +* Virtio MMIO bindings +* +* Copyright (c) 2011 Linaro Limited +* +* Author: +* Peter Maydell <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful,
include/hw/virtio/virtio-mmio.h line 23
Quoted 10 lines
include/hw/virtio/virtio-mmio.h new file +10
-0+* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef QEMU_VIRTIO_MMIO_H +#define QEMU_VIRTIO_MMIO_H
I'd rather use HW_VIRTIO_MMIO_H
Regardless:
Quoted 51 lines
include/hw/virtio/virtio-mmio.h new file +50
-0+ +#include "hw/virtio/virtio-bus.h" + +/* QOM macros */ +/* virtio-mmio-bus */ +#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus" +#define VIRTIO_MMIO_BUS (obj) \ + OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS) +#define VIRTIO_MMIO_BUS_GET_CLASS (obj) \ + OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS) +#define VIRTIO_MMIO_BUS_CLASS (klass) \ + OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS) + +/* virtio-mmio */ +#define TYPE_VIRTIO_MMIO "virtio-mmio" +#define VIRTIO_MMIO (obj) \ + OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO) + +#define VIRT_MAGIC 0x74726976/* 'virt' */ +#define VIRT_VERSION 2 +#define VIRT_VERSION_LEGACY 1 +#define VIRT_VENDOR 0x554D4551/* 'QEMU' */ + +typedef struct VirtIOMMIOQueue { +uint16_t num; +bool enabled; +uint32_t desc[2 ]; +uint32_t avail[2 ]; +uint32_t used[2 ]; +}VirtIOMMIOQueue ; + +typedef struct { +/* Generic */ +SysBusDevice parent_obj; +MemoryRegion iomem; +qemu_irq irq; +bool legacy; +/* Guest accessible state needing migration and reset */ +uint32_t host_features_sel; +uint32_t guest_features_sel; +uint32_t guest_page_shift; +/* virtio-bus */ +VirtioBusState bus; +bool format_transport_address; +/* Fields only used for non-legacy (v2) devices */ +uint32_t guest_features[2 ]; +VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX ]; +}VirtIOMMIOProxy ; + +#endif
Re: [PATCH v5 01/10] hw/virtio: Factorize virtio-mmio headers
Quoted 96 lines · Philippe Mathieu-Daudé
Quoted 95 lines · Sergio Lopez
Put QOM and main struct definition in a separate header file, so it can be accessed from other components.
Signed-off-by Sergio Lopez <[email protected]>--- hw/virtio/virtio-mmio.c | 48 +--------------------- include/hw/virtio/virtio-mmio.h | 73 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 47 deletions(-)create mode 100644
include/hw/virtio/virtio-mmio.hhw/virtio/virtio-mmio.c +1
-46@@ -29,57 +29,11 @@#include "qemu/host-utils.h" #include "qemu/module.h" #include "sysemu/kvm.h" -#include "hw/virtio/virtio-bus.h" +#include "hw/virtio/virtio-mmio.h" #include "qemu/error-report.h" #include "qemu/log.h" #include "trace.h" -/* QOM macros */ -/* virtio-mmio-bus */ -#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus" -#define VIRTIO_MMIO_BUS (obj) \ - OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS) -#define VIRTIO_MMIO_BUS_GET_CLASS (obj) \ - OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS) -#define VIRTIO_MMIO_BUS_CLASS (klass) \ - OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS) - -/* virtio-mmio */ -#define TYPE_VIRTIO_MMIO "virtio-mmio" -#define VIRTIO_MMIO (obj) \ - OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO) - -#define VIRT_MAGIC 0x74726976/* 'virt' */ -#define VIRT_VERSION 2 -#define VIRT_VERSION_LEGACY 1 -#define VIRT_VENDOR 0x554D4551/* 'QEMU' */ - -typedef struct VirtIOMMIOQueue { -uint16_t num; -bool enabled; -uint32_t desc[2 ]; -uint32_t avail[2 ]; -uint32_t used[2 ]; -}VirtIOMMIOQueue ; - -typedef struct { -/* Generic */ -SysBusDevice parent_obj; -MemoryRegion iomem; -qemu_irq irq; -bool legacy; -/* Guest accessible state needing migration and reset */ -uint32_t host_features_sel; -uint32_t guest_features_sel; -uint32_t guest_page_shift; -/* virtio-bus */ -VirtioBusState bus; -bool format_transport_address; -/* Fields only used for non-legacy (v2) devices */ -uint32_t guest_features[2 ]; -VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX ]; -}VirtIOMMIOProxy ; - static bool virtio_mmio_ioeventfd_enabled(DeviceState *d) {return kvm_eventfds_enabled ();include/hw/virtio/virtio-mmio.h new file +17
-0@@ -0,0 +1,73 @@ +/* +* Virtio MMIO bindings +* +* Copyright (c) 2011 Linaro Limited +* +* Author: +* Peter Maydell <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*
Quoted 8 lines
include/hw/virtio/virtio-mmio.h line 23
Quoted 6 lines
include/hw/virtio/virtio-mmio.h new file +6
-0+* You should have received a copy of the GNU General Public License along +* with this program; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef QEMU_VIRTIO_MMIO_H +#define QEMU_VIRTIO_MMIO_H I'd rather use
HW_VIRTIO_MMIO_H
Looks like there isn't a consensus in this regard:
$ grep "ifndef" * vhost-backend.h:#ifndef VHOST_BACKEND_H vhost.h:#ifndef VHOST_H vhost-scsi-common.h:#ifndef VHOST_SCSI_COMMON_H vhost-scsi.h:#ifndef VHOST_SCSI_H vhost-user-blk.h:#ifndef VHOST_USER_BLK_H vhost-user.h:#ifndef HW_VIRTIO_VHOST_USER_H vhost-user-scsi.h:#ifndef VHOST_USER_SCSI_H vhost-vsock.h:#ifndef QEMU_VHOST_VSOCK_H virtio-access.h:#ifndef QEMU_VIRTIO_ACCESS_H virtio-balloon.h:#ifndef QEMU_VIRTIO_BALLOON_H virtio-balloon.h.orig:#ifndef QEMU_VIRTIO_BALLOON_H virtio-blk.h:#ifndef QEMU_VIRTIO_BLK_H virtio-bus.h:#ifndef VIRTIO_BUS_H virtio-crypto.h:#ifndef QEMU_VIRTIO_CRYPTO_H virtio-gpu-bswap.h:#ifndef HW_VIRTIO_GPU_BSWAP_H virtio-gpu.h:#ifndef HW_VIRTIO_GPU_H virtio-gpu-pci.h:#ifndef HW_VIRTIO_GPU_PCI_H virtio-gpu-pixman.h:#ifndef HW_VIRTIO_GPU_PIXMAN_H virtio.h:#ifndef QEMU_VIRTIO_H virtio-input.h:#ifndef QEMU_VIRTIO_INPUT_H virtio-mmio.h:#ifndef QEMU_VIRTIO_MMIO_H virtio-net.h:#ifndef QEMU_VIRTIO_NET_H virtio-pmem.h:#ifndef HW_VIRTIO_PMEM_H virtio-rng.h:#ifndef QEMU_VIRTIO_RNG_H virtio-scsi.h:#ifndef QEMU_VIRTIO_SCSI_H virtio-serial.h:#ifndef QEMU_VIRTIO_SERIAL_H
Do we have an actual policy written somewhere?
Quoted 55 lines
Regardless:
Reviewed-by Philippe Mathieu-Daudé <[email protected]>Quoted 51 lines
include/hw/virtio/virtio-mmio.h new file +50
-0+ +#include "hw/virtio/virtio-bus.h" + +/* QOM macros */ +/* virtio-mmio-bus */ +#define TYPE_VIRTIO_MMIO_BUS "virtio-mmio-bus" +#define VIRTIO_MMIO_BUS (obj) \ + OBJECT_CHECK(VirtioBusState, (obj), TYPE_VIRTIO_MMIO_BUS) +#define VIRTIO_MMIO_BUS_GET_CLASS (obj) \ + OBJECT_GET_CLASS(VirtioBusClass, (obj), TYPE_VIRTIO_MMIO_BUS) +#define VIRTIO_MMIO_BUS_CLASS (klass) \ + OBJECT_CLASS_CHECK(VirtioBusClass, (klass), TYPE_VIRTIO_MMIO_BUS) + +/* virtio-mmio */ +#define TYPE_VIRTIO_MMIO "virtio-mmio" +#define VIRTIO_MMIO (obj) \ + OBJECT_CHECK(VirtIOMMIOProxy, (obj), TYPE_VIRTIO_MMIO) + +#define VIRT_MAGIC 0x74726976/* 'virt' */ +#define VIRT_VERSION 2 +#define VIRT_VERSION_LEGACY 1 +#define VIRT_VENDOR 0x554D4551/* 'QEMU' */ + +typedef struct VirtIOMMIOQueue { +uint16_t num; +bool enabled; +uint32_t desc[2 ]; +uint32_t avail[2 ]; +uint32_t used[2 ]; +}VirtIOMMIOQueue ; + +typedef struct { +/* Generic */ +SysBusDevice parent_obj; +MemoryRegion iomem; +qemu_irq irq; +bool legacy; +/* Guest accessible state needing migration and reset */ +uint32_t host_features_sel; +uint32_t guest_features_sel; +uint32_t guest_page_shift; +/* virtio-bus */ +VirtioBusState bus; +bool format_transport_address; +/* Fields only used for non-legacy (v2) devices */ +uint32_t guest_features[2 ]; +VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX ]; +}VirtIOMMIOProxy ; + +#endif
Re: [PATCH v5 01/10] hw/virtio: Factorize virtio-mmio headers
Quoted 15 lines · Sergio Lopez
Quoted 11 lines · Philippe Mathieu-Daudé
include/hw/virtio/virtio-mmio.h line 23
Quoted 8 lines · Sergio Lopez
Put QOM and main struct definition in a separate header file, so it can be accessed from other components.
Signed-off-by Sergio Lopez <[email protected]>include/hw/virtio/virtio-mmio.h new file +3
-0+ +#ifndef QEMU_VIRTIO_MMIO_H +#define QEMU_VIRTIO_MMIO_H I'd rather use
HW_VIRTIO_MMIO_H
Quoted 6 lines
Looks like there isn't a consensus in this regard:
$ grep "ifndef" *Do we have an actual policy written somewhere?
Past history shows several cleanups near commit fe2611b016, including commit c0a9956b which mentions scripts/clean-header-guards specifically for this purpose. So yes, we have a policy, although it is not always enforced in a timely manner.
Signature · 3 lines
Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3226 Virtualization: qemu.org | libvirt.org
Re: [PATCH v5 01/10] hw/virtio: Factorize virtio-mmio headers
Quoted 14 lines · Eric Blake
Quoted 13 lines · Sergio Lopez
Quoted 11 lines · Philippe Mathieu-Daudé
include/hw/virtio/virtio-mmio.h line 23
Quoted 8 lines · Sergio Lopez
Put QOM and main struct definition in a separate header file, so it can be accessed from other components.
Signed-off-by Sergio Lopez <[email protected]>include/hw/virtio/virtio-mmio.h new file +3
-0+ +#ifndef QEMU_VIRTIO_MMIO_H +#define QEMU_VIRTIO_MMIO_H I'd rather use
HW_VIRTIO_MMIO_H
Quoted 8 lines
Quoted 6 lines
Looks like there isn't a consensus in this regard:
$ grep "ifndef" *Do we have an actual policy written somewhere?
Past history shows several cleanups near commit
fe2611b016, including commitc0a9956bwhich mentionsscripts/clean-header-guardsspecifically for this purpose. So yes, we have a policy, although it is not always enforced in a timely manner.
Paul Brook started to use the HW_ prefix introducing the hw/ directory in commit 87ecb68bd (12 years ago). Most of the headers added out of hw/ and moved there later do not use this pattern.
Markus Armbruster
Reviewed-by Richard HendersonRe: [PATCH v5 01/10] hw/virtio: Factorize virtio-mmio headers
In reply to Eric BlakeQuoted 21 lines · Eric Blake
Quoted 20 lines · Sergio Lopez
Quoted 11 lines · Philippe Mathieu-Daudé
include/hw/virtio/virtio-mmio.h line 23
Quoted 8 lines · Sergio Lopez
Put QOM and main struct definition in a separate header file, so it can be accessed from other components.
Signed-off-by Sergio Lopez <[email protected]>include/hw/virtio/virtio-mmio.h new file +3
-0+ +#ifndef QEMU_VIRTIO_MMIO_H +#define QEMU_VIRTIO_MMIO_H I'd rather use
HW_VIRTIO_MMIO_HLooks like there isn't a consensus in this regard:
$ grep "ifndef" *
Quoted 6 lines
Quoted 1 line
Do we have an actual policy written somewhere?
Past history shows several cleanups near commit
fe2611b016, including commitc0a9956bwhich mentionsscripts/clean-header-guardsspecifically for this purpose. So yes, we have a policy, although it is not always enforced in a timely manner.
We haven't adopted a strict policy.
I created clean-header-guards.pl to help me tidy up the resulting mess somewhat. The script can clean up "untidy" header guards. This may involve replacing the guard symbol. It derives the replacement symbol from the file name the obvious way: convert a-z to A_Z, replace any character that isn't okay in an identifier by '_'. Guard symbols chosen that way are fairly unlikely to collide.
Existing guard symbols often omit directories, and the script tolerates that. For instance, in sub/dir/base.h, anything ending in BASE_H is considered tidy enough. Might be a bad idea.
I wouldn't go as far as calling this a policy. Perhaps it should be.
commit 2dbc4ebc1712a5cf9e6a36327dce0b465abd5bbe
Author: Markus Armbruster <[email protected]> Date: Tue Jun 28 13:07:36 2016 +0200
scripts: New clean-header-guards.pl
The conventional way to ensure a header can be included multiple times is to bracket it like this:
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
...
#endif
where HEADER_NAME_H is a symbol unique to this header.
The endif may be optionally decorated like this:
#endif /* HEADER_NAME_H */
Unconventional ways present in our code:
* Identifiers reserved for any use:
#define _FILEOP_H
* Lowercase (bad idea for object-like macros):
#define __linux_video_vga_h__
* Roundabout ways to say the same thing (and hide from grep):
#if !defined(__PPC_MAC_H__)
#endif /* !defined(__PPC_MAC_H__) */
* Redundant values:
#define HW_ALPHA_H 1
* Funny redundant values:
# define PXA_H "pxa.h"
* Decorations with bangs:
#endif /* !QEMU_ARM_GIC_INTERNAL_H */
The negation actually makes sense, but almost all our header guard #endif decorations don't negate.
* Useless decorations:
#endif /* audio.h */
Header guards are not the place to show off creativity. This script normalizes them to the conventional way, and cleans up whitespace while there. It warns when it renames guard symbols, and explains how to find occurences of these symbols that may have to be updated manually.
Another issue is use of the same guard symbol in multiple headers. That's okay only for headers that cannot be used together, such as the *-user/*/target_syscall.h. This script can't tell, so it warns when it sees a reuse.
The script also warns when preprocessing a header with its guard symbol defined produces anything but whitespace.
The next commits will put the script to use.
PATCH v5 2/10 hw/i386/pc: rename functions shared with non-PC machines
In reply to Sergio Lopezload_linux -> x86_load_linux pc_new_cpu -> x86_new_cpu pc_cpus_init -> x86_cpus_init pc_cpu_index_to_props -> x86_cpu_index_to_props
pc_get_default_cpu_node_id -> x86_get_default_cpu_node_idpc_possible_cpu_arch_ids -> x86_possible_cpu_arch_idsold_pc_system_rom_init -> x86_system_rom_init
--- hw/i386/pc.c | 28 ++++++++++++++-------------- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- hw/i386/pc_sysfw.c | 6 +++--- include/hw/i386/pc.h | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-)
hw/i386/pc.c +14 -14
@@ -1019,8 +1019,8 @@ static bool load_elfboot(const char *kernel_filename,return true; } -static void load_linux (PCMachineState *pcms, -FWCfgState *fw_cfg) +static void x86_load_linux (PCMachineState *pcms, +FWCfgState *fw_cfg) {uint16_t protocol;int setup_size, kernel_size, cmdline_size;
@@ -1374,7 +1374,7 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static void pc_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp) +static void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp) {Object *cpu =NULL ;Error *local_err =NULL ;
@@ -1490,14 +1490,14 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp)return ; } -pc_new_cpu (PC_MACHINE (ms), apic_id, &local_err); +x86_new_cpu (PC_MACHINE (ms), apic_id, &local_err);if (local_err) {error_propagate (errp, local_err);return ; } } -void pc_cpus_init (PCMachineState *pcms) +void x86_cpus_init (PCMachineState *pcms) {int i;const CPUArchIdList *possible_cpus;
@@ -1518,7 +1518,7 @@ void pc_cpus_init(PCMachineState *pcms) ms->smp.max_cpus - 1) + 1; possible_cpus = mc->possible_cpu_arch_ids (ms);for (i =0 ; i < ms->smp.cpus; i++) { -pc_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); +x86_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); } }
@@ -1621,7 +1621,7 @@ void xen_load_linux(PCMachineState *pcms)fw_cfg_add_i16 (fw_cfg,FW_CFG_NB_CPUS , pcms->boot_cpus);rom_set_fw (fw_cfg); -load_linux (pcms, fw_cfg); +x86_load_linux (pcms, fw_cfg);for (i =0 ; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "linuxboot_dma.bin") ||
@@ -1756,7 +1756,7 @@ void pc_memory_init(PCMachineState *pcms, }if (linux_boot) { -load_linux (pcms, fw_cfg); +x86_load_linux (pcms, fw_cfg); }for (i =0 ; i < nb_option_roms; i++) {
@@ -2678,7 +2678,7 @@ static void pc_machine_wakeup(MachineState *machine) }static CpuInstanceProperties -pc_cpu_index_to_props (MachineState *ms,unsigned cpu_index) +x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index) {MachineClass *mc =MACHINE_GET_CLASS (ms);const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids (ms);
@@ -2687,7 +2687,7 @@ pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index)return possible_cpus->cpus[cpu_index].props; } -static int64_t pc_get_default_cpu_node_id (const MachineState *ms,int idx) +static int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx) {X86CPUTopoInfo topo;PCMachineState *pcms =PC_MACHINE (ms);
@@ -2699,7 +2699,7 @@ static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx)return topo.pkg_id % ms->numa_state->num_nodes; } -static const CPUArchIdList *pc_possible_cpu_arch_ids (MachineState *ms) +static const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms) {PCMachineState *pcms =PC_MACHINE (ms);int i;
@@ -2801,9 +2801,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)assert (!mc->get_hotplug_handler); mc->get_hotplug_handler = pc_get_hotplug_handler; mc->hotplug_allowed = pc_hotplug_allowed; - mc->cpu_index_to_instance_props = pc_cpu_index_to_props; - mc->get_default_cpu_node_id = pc_get_default_cpu_node_id; - mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids; + mc->cpu_index_to_instance_props = x86_cpu_index_to_props; + mc->get_default_cpu_node_id = x86_get_default_cpu_node_id; + mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids; mc->auto_enable_numa_with_memhp = true; mc->has_hotpluggable_cpus = true; mc->default_boot_order ="cad" ;
hw/i386/pc_piix.c +1 -1
@@ -152,7 +152,7 @@ static void pc_init1(MachineState *machine, } } -pc_cpus_init (pcms); +x86_cpus_init (pcms);if (kvm_enabled () && pcmc->kvmclock_enabled) {kvmclock_create ();
hw/i386/pc_q35.c +1 -1
@@ -179,7 +179,7 @@ static void pc_q35_init(MachineState *machine)xen_hvm_init (pcms, &ram_memory); } -pc_cpus_init (pcms); +x86_cpus_init (pcms);kvmclock_create ();
hw/i386/pc_sysfw.c +3 -3
@@ -211,7 +211,7 @@ static void pc_system_flash_map(PCMachineState *pcms, } } -static void old_pc_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw) +static void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw) {char *filename;MemoryRegion *bios, *isa_bios;
@@ -272,7 +272,7 @@ void pc_system_firmware_init(PCMachineState *pcms,BlockBackend *pflash_blk[ARRAY_SIZE (pcms->flash)];if (!pcmc->pci_enabled) { -old_pc_system_rom_init (rom_memory, true); +x86_system_rom_init (rom_memory, true);return ; }
@@ -293,7 +293,7 @@ void pc_system_firmware_init(PCMachineState *pcms,if (!pflash_blk[0 ]) {/* Machine property pflash0 not set, use ROM mode */ -old_pc_system_rom_init (rom_memory, false); +x86_system_rom_init (rom_memory, false); }else {if (kvm_enabled () && !kvm_readonly_mem_enabled ()) {/*
include/hw/i386/pc.h +1 -1
@@ -195,7 +195,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);void pc_register_ferr_irq (qemu_irq irq);void pc_acpi_smi_interrupt (void *opaque,int irq,int level); -void pc_cpus_init (PCMachineState *pcms); +void x86_cpus_init (PCMachineState *pcms);void pc_hot_add_cpu (MachineState *ms,const int64_t id,Error **errp);void pc_smp_parse (MachineState *ms,QemuOpts *opts);
Signature · 1 line
2.21.0
Re: [PATCH v5 02/10] hw/i386/pc: rename functions shared with non-PC machines
Hi Sergio,
Depending of the IDE developers use, the patch subject is not always prepended to the patch description.
You can add: "The following functions are named *pc* but are not PC-machine specific but generic to the X86 architecture, rename them:"
Quoted 2 lines · Sergio Lopez
load_linux->x86_load_linuxpc_new_cpu->x86_new_cpu
Maybe we can rename this one 'x86_cpu_new'?
Quoted 5 lines
pc_cpus_init->x86_cpus_initpc_cpu_index_to_props->x86_cpu_index_to_propspc_get_default_cpu_node_id->x86_get_default_cpu_node_idpc_possible_cpu_arch_ids->x86_possible_cpu_arch_idsold_pc_system_rom_init->x86_system_rom_init
This one as 'x86_bios_rom_init'?
Nit: Adding 2 spaces before each line would ease readability.
Quoted 181 lines
Signed-off-by Sergio Lopez <[email protected]>--- hw/i386/pc.c | 28 ++++++++++++++-------------- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- hw/i386/pc_sysfw.c | 6 +++--- include/hw/i386/pc.h | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-)hw/i386/pc.c +14
-14@@ -1019,8 +1019,8 @@ static bool load_elfboot(const char *kernel_filename,return true; } -static void load_linux (PCMachineState *pcms, -FWCfgState *fw_cfg) +static void x86_load_linux (PCMachineState *pcms, +FWCfgState *fw_cfg) {uint16_t protocol;int setup_size, kernel_size, cmdline_size;@@ -1374,7 +1374,7 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static void pc_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp) +static void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp) {Object *cpu =NULL ;Error *local_err =NULL ;@@ -1490,14 +1490,14 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp)return ; } -pc_new_cpu (PC_MACHINE (ms), apic_id, &local_err); +x86_new_cpu (PC_MACHINE (ms), apic_id, &local_err);if (local_err) {error_propagate (errp, local_err);return ; } } -void pc_cpus_init (PCMachineState *pcms) +void x86_cpus_init (PCMachineState *pcms) {int i;const CPUArchIdList *possible_cpus;@@ -1518,7 +1518,7 @@ void pc_cpus_init(PCMachineState *pcms) ms->smp.max_cpus - 1) + 1; possible_cpus = mc->possible_cpu_arch_ids (ms);for (i =0 ; i < ms->smp.cpus; i++) { -pc_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); +x86_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); } }@@ -1621,7 +1621,7 @@ void xen_load_linux(PCMachineState *pcms)fw_cfg_add_i16 (fw_cfg,FW_CFG_NB_CPUS , pcms->boot_cpus);rom_set_fw (fw_cfg); -load_linux (pcms, fw_cfg); +x86_load_linux (pcms, fw_cfg);for (i =0 ; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "linuxboot_dma.bin") ||@@ -1756,7 +1756,7 @@ void pc_memory_init(PCMachineState *pcms, }if (linux_boot) { -load_linux (pcms, fw_cfg); +x86_load_linux (pcms, fw_cfg); }for (i =0 ; i < nb_option_roms; i++) {@@ -2678,7 +2678,7 @@ static void pc_machine_wakeup(MachineState *machine) }static CpuInstanceProperties -pc_cpu_index_to_props (MachineState *ms,unsigned cpu_index) +x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index) {MachineClass *mc =MACHINE_GET_CLASS (ms);const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids (ms);@@ -2687,7 +2687,7 @@ pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index)return possible_cpus->cpus[cpu_index].props; } -static int64_t pc_get_default_cpu_node_id (const MachineState *ms,int idx) +static int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx) {X86CPUTopoInfo topo;PCMachineState *pcms =PC_MACHINE (ms);@@ -2699,7 +2699,7 @@ static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx)return topo.pkg_id % ms->numa_state->num_nodes; } -static const CPUArchIdList *pc_possible_cpu_arch_ids (MachineState *ms) +static const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms) {PCMachineState *pcms =PC_MACHINE (ms);int i;@@ -2801,9 +2801,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)assert (!mc->get_hotplug_handler); mc->get_hotplug_handler = pc_get_hotplug_handler; mc->hotplug_allowed = pc_hotplug_allowed; - mc->cpu_index_to_instance_props = pc_cpu_index_to_props; - mc->get_default_cpu_node_id = pc_get_default_cpu_node_id; - mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids; + mc->cpu_index_to_instance_props = x86_cpu_index_to_props; + mc->get_default_cpu_node_id = x86_get_default_cpu_node_id; + mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids; mc->auto_enable_numa_with_memhp = true; mc->has_hotpluggable_cpus = true; mc->default_boot_order ="cad" ;hw/i386/pc_piix.c +1
-1@@ -152,7 +152,7 @@ static void pc_init1(MachineState *machine, } } -pc_cpus_init (pcms); +x86_cpus_init (pcms);if (kvm_enabled () && pcmc->kvmclock_enabled) {kvmclock_create ();hw/i386/pc_q35.c +1
-1@@ -179,7 +179,7 @@ static void pc_q35_init(MachineState *machine)xen_hvm_init (pcms, &ram_memory); } -pc_cpus_init (pcms); +x86_cpus_init (pcms);kvmclock_create ();hw/i386/pc_sysfw.c +3
-3@@ -211,7 +211,7 @@ static void pc_system_flash_map(PCMachineState *pcms, } } -static void old_pc_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw) +static void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw) {char *filename;MemoryRegion *bios, *isa_bios;@@ -272,7 +272,7 @@ void pc_system_firmware_init(PCMachineState *pcms,BlockBackend *pflash_blk[ARRAY_SIZE (pcms->flash)];if (!pcmc->pci_enabled) { -old_pc_system_rom_init (rom_memory, true); +x86_system_rom_init (rom_memory, true);return ; }@@ -293,7 +293,7 @@ void pc_system_firmware_init(PCMachineState *pcms,if (!pflash_blk[0 ]) {/* Machine property pflash0 not set, use ROM mode */ -old_pc_system_rom_init (rom_memory, false); +x86_system_rom_init (rom_memory, false); }else {if (kvm_enabled () && !kvm_readonly_mem_enabled ()) {/* include/hw/i386/pc.h +0
-0
include/hw/i386/pc.h bool pc_machine_is_smm_enabled(PCMachineState *pcms); · line 201
Quoted 8 lines
include/hw/i386/pc.h +1
-1@@ -195,7 +195,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);void pc_register_ferr_irq (qemu_irq irq);void pc_acpi_smi_interrupt (void *opaque,int irq,int level); -void pc_cpus_init (PCMachineState *pcms); +void x86_cpus_init (PCMachineState *pcms);void pc_hot_add_cpu (MachineState *ms,const int64_t id,Error **errp);void pc_smp_parse (MachineState *ms,QemuOpts *opts);
Re: [PATCH v5 02/10] hw/i386/pc: rename functions shared with non-PC machines
Quoted 7 lines · Philippe Mathieu-Daudé
Hi Sergio,
Depending of the IDE developers use, the patch subject is not always prepended to the patch description.
You can add: "The following functions are named *pc* but are not PC-machine specific but generic to the X86 architecture, rename them:"
OK, thanks for the tip.
Quoted 5 lines · Sergio Lopez
Quoted 2 lines
load_linux->x86_load_linuxpc_new_cpu->x86_new_cpuMaybe we can rename this one '
x86_cpu_new'?
OK.
Quoted 7 lines
Quoted 5 lines
pc_cpus_init->x86_cpus_initpc_cpu_index_to_props->x86_cpu_index_to_propspc_get_default_cpu_node_id->x86_get_default_cpu_node_idpc_possible_cpu_arch_ids->x86_possible_cpu_arch_idsold_pc_system_rom_init->x86_system_rom_initThis one as '
x86_bios_rom_init'?
Probably that's a better name.
Quoted 1 line
Nit: Adding 2 spaces before each line would ease readability.
Ack.
Quoted 167 lines
Quoted 167 lines
Signed-off-by Sergio Lopez <[email protected]>--- hw/i386/pc.c | 28 ++++++++++++++-------------- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- hw/i386/pc_sysfw.c | 6 +++--- include/hw/i386/pc.h | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-)hw/i386/pc.c +6
-2@@ -1019,8 +1019,8 @@ static bool load_elfboot(const char *kernel_filename,return true; } -static void load_linux(PCMachineState *pcms, -FWCfgState *fw_cfg) +static void x86_load_linux (PCMachineState *pcms, + FWCfgState *fw_cfg) {uint16_t protocol;int setup_size, kernel_size, cmdline_size;@@ -1374,7 +1374,7 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static void pc_new_cpu(PCMachineState *pcms, int64_t apic_id,Error **errp) +static void x86_new_cpu(PCMachineState *pcms, int64_t apic_id, Error **errp) {Object *cpu =NULL ;Error *local_err =NULL ;@@ -1490,14 +1490,14 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp)return ; } -pc_new_cpu (PC_MACHINE (ms), apic_id, &local_err); +x86_new_cpu (PC_MACHINE (ms), apic_id, &local_err);if (local_err) {error_propagate (errp, local_err);return ; } } -void pc_cpus_init(PCMachineState *pcms) +void x86_cpus_init (PCMachineState *pcms) {int i;const CPUArchIdList *possible_cpus;@@ -1518,7 +1518,7 @@ void pc_cpus_init(PCMachineState *pcms) ms->smp.max_cpus - 1) + 1; possible_cpus = mc->possible_cpu_arch_ids (ms);for (i =0 ; i < ms->smp.cpus; i++) { -pc_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); +x86_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); } } @@ -1621,7 +1621,7 @@ void xen_load_linux(PCMachineState *pcms)fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus); rom_set_fw(fw_cfg);-
load_linux(pcms, fw_cfg);hw/i386/pc.c +8
-5+x86_load_linux (pcms, fw_cfg);for (i =0 ; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "linuxboot_dma.bin") ||@@ -1756,7 +1756,7 @@ void pc_memory_init(PCMachineState *pcms, }if (linux_boot) { -load_linux (pcms, fw_cfg); +x86_load_linux (pcms, fw_cfg); }for (i =0 ; i < nb_option_roms; i++) {@@ -2678,7 +2678,7 @@ static void pc_machine_wakeup(MachineState *machine) }static CpuInstanceProperties -pc_cpu_index_to_props (MachineState *ms,unsigned cpu_index) +x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index) {MachineClass *mc =MACHINE_GET_CLASS (ms);const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids (ms);@@ -2687,7 +2687,7 @@ pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index)return possible_cpus->cpus[cpu_index].props; } -static int64_t pc_get_default_cpu_node_id(const MachineState *ms,int idx) +static int64_t x86_get_default_cpu_node_id(const MachineState *ms, int idx) {X86CPUTopoInfo topo;PCMachineState *pcms =PC_MACHINE (ms);@@ -2699,7 +2699,7 @@ static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx)return topo.pkg_id % ms->numa_state->num_nodes; } -static const CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *ms) +static const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms) {PCMachineState *pcms =PC_MACHINE (ms);int i;@@ -2801,9 +2801,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)assert (!mc->get_hotplug_handler); mc->get_hotplug_handler = pc_get_hotplug_handler; mc->hotplug_allowed = pc_hotplug_allowed; - mc->cpu_index_to_instance_props = pc_cpu_index_to_props; - mc->get_default_cpu_node_id = pc_get_default_cpu_node_id; - mc->possible_cpu_arch_ids = pc_possible_cpu_arch_ids; + mc->cpu_index_to_instance_props = x86_cpu_index_to_props; + mc->get_default_cpu_node_id = x86_get_default_cpu_node_id; + mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids; mc->auto_enable_numa_with_memhp = true; mc->has_hotpluggable_cpus = true; mc->default_boot_order ="cad" ;hw/i386/pc_piix.c +1
-0@@ -152,7 +152,7 @@ static void pc_init1(MachineState *machine, } } -pc_cpus_init (pcms); +x86_cpus_init (pcms);if (kvm_enabled () && pcmc->kvmclock_enabled) {kvmclock_create ();hw/i386/pc_q35.c +1
-0@@ -179,7 +179,7 @@ static void pc_q35_init(MachineState *machine)xen_hvm_init (pcms, &ram_memory); } -pc_cpus_init (pcms); +x86_cpus_init (pcms);kvmclock_create (); diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.cindex
a9983f0bfb..1ee254b15e100644hw/i386/pc_sysfw.c +2
-1@@ -211,7 +211,7 @@ static void pc_system_flash_map(PCMachineState *pcms, } } -static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) +static void x86_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) {char *filename;MemoryRegion *bios, *isa_bios;@@ -272,7 +272,7 @@ void pc_system_firmware_init(PCMachineState *pcms,BlockBackend *pflash_blk[ARRAY_SIZE (pcms->flash)];if (!pcmc->pci_enabled) { -old_pc_system_rom_init (rom_memory, true); +x86_system_rom_init (rom_memory, true);return ; } @@ -293,7 +293,7 @@ void pc_system_firmware_init(PCMachineState *pcms,if (!pflash_blk[0]) { /* Machine property pflash0 not set, use ROM mode */hw/i386/pc_sysfw.c +1
-1-old_pc_system_rom_init (rom_memory, false); +x86_system_rom_init (rom_memory, false); }else {if (kvm_enabled () && !kvm_readonly_mem_enabled ()) {/* include/hw/i386/pc.h +0
-0@@ -195,7 +195,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);void pc_register_ferr_irq (qemu_irq irq);void pc_acpi_smi_interrupt (void *opaque,int irq,int level);
Quoted 8 lines
include/hw/i386/pc.h bool pc_machine_is_smm_enabled(PCMachineState *pcms); · line 201
Quoted 6 lines
include/hw/i386/pc.h +1
-0-void pc_cpus_init(PCMachineState *pcms); +void x86_cpus_init (PCMachineState *pcms);void pc_hot_add_cpu (MachineState *ms,const int64_t id,Error **errp);void pc_smp_parse (MachineState *ms,QemuOpts *opts);Reviewed-by Philippe Mathieu-Daudé <[email protected]>
Thanks,
Sergio.
PATCH v5 3/10 hw/i386/pc: move shared x86 functions to x86.c and export them
In reply to Sergio LopezMove x86 functions that will be shared between PC and non-PC machine types to x86.c, along with their helpers.
--- hw/i386/Makefile.objs | 1 + hw/i386/pc.c | 582 +---------------------------------- hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + hw/i386/pc_sysfw.c | 54 +--- hw/i386/x86.c | 684 ++++++++++++++++++++++++++++++++++++++++++ include/hw/i386/pc.h | 1 - include/hw/i386/x86.h | 35 +++ 8 files changed, 724 insertions(+), 635 deletions(-) create mode 100644 hw/i386/x86.c create mode 100644 include/hw/i386/x86.h
hw/i386/Makefile.objs +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += e820_memory_layout.o multiboot.o +obj-y += x86.o obj-y += pc.o obj-$(CONFIG_I440FX) += pc_piix.o obj-$(CONFIG_Q35) += pc_q35.o
hw/i386/pc.c +1 -581
618 lines not on this page · raw message
hw/i386/pc_piix.c +1 -0
@@ -28,6 +28,7 @@#include "qemu/units.h" #include "hw/loader.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/i386/apic.h" #include "hw/display/ramfb.h" #include "hw/firmware/smbios.h"
hw/i386/pc_q35.c +1 -0
@@ -42,6 +42,7 @@#include "hw/qdev-properties.h" #include "exec/address-spaces.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/i386/ich9.h" #include "hw/i386/amd_iommu.h" #include "hw/i386/intel_iommu.h"
hw/i386/pc_sysfw.c +1 -53
66 lines not on this page · raw message
hw/i386/x86.c new file +684 -0
684 lines not on this page · raw message
include/hw/i386/pc.h +0 -1
@@ -195,7 +195,6 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);void pc_register_ferr_irq (qemu_irq irq);void pc_acpi_smi_interrupt (void *opaque,int irq,int level); -void x86_cpus_init (PCMachineState *pcms);void pc_hot_add_cpu (MachineState *ms,const int64_t id,Error **errp);void pc_smp_parse (MachineState *ms,QemuOpts *opts);
include/hw/i386/x86.h new file +35 -0
@@ -0,0 +1,35 @@ +/* +* Copyright (c) 2019 Red Hat, Inc. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2 or later, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef HW_I386_X86_H +#define HW_I386_X86_H + +#include "hw/boards.h" + +uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, +unsigned int cpu_index); +void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp); +void x86_cpus_init (PCMachineState *pcms); +CpuInstanceProperties x86_cpu_index_to_props (MachineState *ms, +unsigned cpu_index); +int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx); +const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms); + +void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw); + +void x86_load_linux (PCMachineState *x86ms,FWCfgState *fw_cfg); + +#endif
Signature · 1 line
2.21.0
Re: [PATCH v5 03/10] hw/i386/pc: move shared x86 functions to x86.c and export them
Quoted 14 lines · Sergio Lopez
Move x86 functions that will be shared between PC and non-PC machine types to
x86.c, along with their helpers.Signed-off-by Sergio Lopez <[email protected]>--- hw/i386/Makefile.objs | 1 + hw/i386/pc.c | 582 +---------------------------------- hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + hw/i386/pc_sysfw.c | 54 +--- hw/i386/x86.c | 684 ++++++++++++++++++++++++++++++++++++++++++ include/hw/i386/pc.h | 1 - include/hw/i386/x86.h | 35 +++ 8 files changed, 724 insertions(+), 635 deletions(-)
Quoted 2 lines
create mode 100644
hw/i386/x86.c
create mode 100644include/hw/i386/x86.h
I recommend you to setup the scripts/git.orderfile file to ease reviewers :)
Quoted 16 lines
hw/i386/Makefile.objs +1
-0@@ -1,5 +1,6 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += e820_memory_layout.o multiboot.o +obj-y += x86.o obj-y += pc.o obj-$(CONFIG_I440FX) += pc_piix.o obj-$(CONFIG_Q35) += pc_q35.ohw/i386/pc.c +0
-0
hw/i386/pc.c line 28
Quoted 4 lines
hw/i386/pc.c +1
-0@@ -25,6 +25,7 @@#include "qemu/osdep.h" #include "qemu/units.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h"
Nit: Include before "pc.h" :)
Quoted 1,459 lines
hw/i386/pc.c +0
-581#include "hw/char/serial.h" #include "hw/char/parallel.h" #include "hw/i386/apic.h" @@ -102,9 +103,6 @@struct hpet_fw_config hpet_cfg = {.count =UINT8_MAX }; -/* Physical Address of PVH entry point read from kernel ELF NOTE */ -static size_t pvh_start_addr; -GlobalProperty pc_compat_4_1[] = {};const size_t pc_compat_4_1_len =G_N_ELEMENTS (pc_compat_4_1);@@ -866,478 +864,6 @@ static void handle_a20_line_change(void *opaque, int irq, int level)x86_cpu_set_a20 (cpu, level); } -/* Calculates initial APIC ID for a specific CPU index -* -* Currently we need to be able to calculate the APIC ID from the CPU index -* alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have -* no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of -* all CPUs up to max_cpus. -*/ -static uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, -unsigned int cpu_index) -{ -MachineState *ms =MACHINE (pcms); -PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); -uint32_t correct_id; -static bool warned; - - correct_id =x86_apicid_from_cpu_idx (pcms->smp_dies, ms->smp.cores, - ms->smp.threads, cpu_index); -if (pcmc->compat_apic_id_mode) { -if (cpu_index != correct_id && !warned && !qtest_enabled ()) { -error_report ("APIC IDs set in compatibility mode, " -"CPU topology won't match the configuration" ); - warned = true; - } -return cpu_index; - }else { -return correct_id; - } -} - -static long get_file_size (FILE *f) -{ -long where, size; - -/* XXX: on Unix systems, using fstat() probably makes more sense */ - - where =ftell (f); -fseek (f,0 ,SEEK_END ); - size =ftell (f); -fseek (f, where,SEEK_SET ); - -return size; -} - -struct setup_data { -uint64_t next; -uint32_t type; -uint32_t len; -uint8_t data[0 ]; -} __attribute__((packed)); - - -/* -* The entry point into the kernel for PVH boot is different from -* the native entry point. The PVH entry is defined by the x86/HVM -* direct boot ABI and is available in an ELFNOTE in the kernel binary. -* -* This function is passed to load_elf() when it is called from -* load_elfboot() which then additionally checks for an ELF Note of -* type XEN_ELFNOTE_PHYS32_ENTRY and passes it to this function to -* parse the PVH entry address from the ELF Note. -* -* Due to trickery in elf_opts.h, load_elf() is actually available as -* load_elf32() or load_elf64() and this routine needs to be able -* to deal with being called as 32 or 64 bit. -* -* The address of the PVH entry point is saved to the 'pvh_start_addr' -* global variable. (although the entry point is 32-bit, the kernel -* binary can be either 32-bit or 64-bit). -*/ -static uint64_t read_pvh_start_addr (void *arg1,void *arg2,bool is64) -{ -size_t *elf_note_data_addr; - -/* Check if ELF Note header passed in is valid */ -if (arg1 ==NULL ) { -return 0 ; - } - -if (is64) { -struct elf64_note *nhdr64 = (struct elf64_note *)arg1; -uint64_t nhdr_size64 =sizeof (struct elf64_note ); -uint64_t phdr_align = *(uint64_t *)arg2; -uint64_t nhdr_namesz = nhdr64->n_namesz; - - elf_note_data_addr = - ((void *)nhdr64) + nhdr_size64 + -QEMU_ALIGN_UP (nhdr_namesz, phdr_align); - }else { -struct elf32_note *nhdr32 = (struct elf32_note *)arg1; -uint32_t nhdr_size32 =sizeof (struct elf32_note ); -uint32_t phdr_align = *(uint32_t *)arg2; -uint32_t nhdr_namesz = nhdr32->n_namesz; - - elf_note_data_addr = - ((void *)nhdr32) + nhdr_size32 + -QEMU_ALIGN_UP (nhdr_namesz, phdr_align); - } - - pvh_start_addr = *elf_note_data_addr; - -return pvh_start_addr; -} - -static bool load_elfboot (const char *kernel_filename, -int kernel_file_size, -uint8_t *header, -size_t pvh_xen_start_addr, -FWCfgState *fw_cfg) -{ -uint32_t flags =0 ; -uint32_t mh_load_addr =0 ; -uint32_t elf_kernel_size =0 ; -uint64_t elf_entry; -uint64_t elf_low, elf_high; -int kernel_size; - -if (ldl_p (header) !=0x464c457f ) { -return false;/* no elfboot */ - } - -bool elf_is64 = header[EI_CLASS ] ==ELFCLASS64 ; - flags = elf_is64 ? - ((Elf64_Ehdr *)header)->e_flags : ((Elf32_Ehdr *)header)->e_flags; - -if (flags &0x00010004 ) {/* LOAD_ELF_HEADER_HAS_ADDR */ -error_report ("elfboot unsupported flags = %x" , flags); -exit (1 ); - } - -uint64_t elf_note_type =XEN_ELFNOTE_PHYS32_ENTRY ; - kernel_size =load_elf (kernel_filename, read_pvh_start_addr, -NULL , &elf_note_type, &elf_entry, - &elf_low, &elf_high,0 ,I386_ELF_MACHINE , -0 ,0 ); - -if (kernel_size <0 ) { -error_report ("Error while loading elf kernel" ); -exit (1 ); - } - mh_load_addr = elf_low; - elf_kernel_size = elf_high - elf_low; - -if (pvh_start_addr ==0 ) { -error_report ("Error loading uncompressed kernel without PVH ELF Note" ); -exit (1 ); - } -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ENTRY , pvh_start_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , mh_load_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , elf_kernel_size); - -return true; -} - -static void x86_load_linux (PCMachineState *pcms, -FWCfgState *fw_cfg) -{ -uint16_t protocol; -int setup_size, kernel_size, cmdline_size; -int dtb_size, setup_data_offset; -uint32_t initrd_max; -uint8_t header[8192 ], *setup, *kernel; -hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr =0 ; -FILE *f; -char *vmode; -MachineState *machine =MACHINE (pcms); -PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); -struct setup_data *setup_data; -const char *kernel_filename = machine->kernel_filename; -const char *initrd_filename = machine->initrd_filename; -const char *dtb_filename = machine->dtb; -const char *kernel_cmdline = machine->kernel_cmdline; - -/* Align to 16 bytes as a paranoia measure */ - cmdline_size = (strlen (kernel_cmdline)+16 ) & ~15 ; - -/* load the kernel header */ - f =fopen (kernel_filename,"rb" ); -if (!f || !(kernel_size =get_file_size (f)) || -fread (header,1 ,MIN (ARRAY_SIZE (header), kernel_size), f) != -MIN (ARRAY_SIZE (header), kernel_size)) { -fprintf (stderr,"qemu: could not load kernel '%s': %s\n" , - kernel_filename,strerror (errno)); -exit (1 ); - } - -/* kernel protocol version */ -#if 0 -fprintf (stderr,"header magic: %#x\n" ,ldl_p (header+0x202 )); -#endif -if (ldl_p (header+0x202 ) ==0x53726448 ) { - protocol =lduw_p (header+0x206 ); - }else { -/* -* This could be a multiboot kernel. If it is, let's stop treating it -* like a Linux kernel. -* Note: some multiboot images could be in the ELF format (the same of -* PVH), so we try multiboot first since we check the multiboot magic -* header before to load it. -*/ -if (load_multiboot (fw_cfg, f, kernel_filename, initrd_filename, - kernel_cmdline, kernel_size, header)) { -return ; - } -/* -* Check if the file is an uncompressed kernel file (ELF) and load it, -* saving the PVH entry point used by the x86/HVM direct boot ABI. -* If load_elfboot() is successful, populate the fw_cfg info. -*/ -if (pcmc->pvh_enabled && -load_elfboot (kernel_filename, kernel_size, - header, pvh_start_addr, fw_cfg)) { -fclose (f); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE , -strlen (kernel_cmdline) +1 ); -fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE ,sizeof (header)); -fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , - header,sizeof (header)); - -/* load initrd */ -if (initrd_filename) { -GMappedFile *mapped_file; -gsize initrd_size; -gchar *initrd_data; -GError *gerr =NULL ; - - mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); -if (!mapped_file) { -fprintf (stderr,"qemu: error reading initrd %s: %s\n" , - initrd_filename, gerr->message); -exit (1 ); - } - pcms->initrd_mapped_file = mapped_file; - - initrd_data =g_mapped_file_get_contents (mapped_file); - initrd_size =g_mapped_file_get_length (mapped_file); - initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; -if (initrd_size >= initrd_max) { -fprintf (stderr,"qemu: initrd is too large, cannot support." -"(max: %" PRIu32", need %" PRId64")\n" , - initrd_max, (uint64_t )initrd_size); -exit (1 ); - } - - initrd_addr = (initrd_max - initrd_size) & ~4095 ; - -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, - initrd_size); - } - - option_rom[nb_option_roms].bootindex =0 ; - option_rom[nb_option_roms].name ="pvh.bin" ; - nb_option_roms++; - -return ; - } - protocol =0 ; - } - -if (protocol <0x200 || !(header[0x211 ] &0x01 )) { -/* Low kernel */ - real_addr =0x90000 ; - cmdline_addr =0x9a000 - cmdline_size; - prot_addr =0x10000 ; - }else if (protocol <0x202 ) { -/* High but ancient kernel */ - real_addr =0x90000 ; - cmdline_addr =0x9a000 - cmdline_size; - prot_addr =0x100000 ; - }else { -/* High and recent kernel */ - real_addr =0x10000 ; - cmdline_addr =0x20000 ; - prot_addr =0x100000 ; - } - -#if 0 -fprintf (stderr, -"qemu: real_addr = 0x" TARGET_FMT_plx"\n" -"qemu: cmdline_addr = 0x" TARGET_FMT_plx"\n" -"qemu: prot_addr = 0x" TARGET_FMT_plx"\n" , - real_addr, - cmdline_addr, - prot_addr); -#endif - -/* highest address for loading the initrd */ -if (protocol >=0x20c && -lduw_p (header+0x236 ) &XLF_CAN_BE_LOADED_ABOVE_4G ) { -/* -* Linux has supported initrd up to 4 GB for a very long time (2007, -* long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013), -* though it only sets initrd_max to 2 GB to "work around bootloader -* bugs". Luckily, QEMU firmware(which does something like bootloader) -* has supported this. -* -* It's believed that if XLF_CAN_BE_LOADED_ABOVE_4G is set, initrd can -* be loaded into any address. -* -* In addition, initrd_max is uint32_t simply because QEMU doesn't -* support the 64-bit boot protocol (specifically the ext_ramdisk_image -* field). -* -* Therefore here just limit initrd_max to UINT32_MAX simply as well. -*/ - initrd_max =UINT32_MAX ; - }else if (protocol >=0x203 ) { - initrd_max =ldl_p (header+0x22c ); - }else { - initrd_max =0x37ffffff ; - } - -if (initrd_max >= pcms->below_4g_mem_size - pcmc->acpi_data_size) { - initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; - } - -fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_ADDR , cmdline_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE ,strlen (kernel_cmdline)+1 ); -fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); - -if (protocol >=0x202 ) { -stl_p (header+0x228 , cmdline_addr); - }else { -stw_p (header+0x20 ,0xA33F ); -stw_p (header+0x22 , cmdline_addr-real_addr); - } - -/* handle vga= parameter */ - vmode =strstr (kernel_cmdline,"vga=" ); -if (vmode) { -unsigned int video_mode; -/* skip "vga=" */ - vmode +=4 ; -if (!strncmp (vmode,"normal" ,6 )) { - video_mode =0xffff ; - }else if (!strncmp (vmode,"ext" ,3 )) { - video_mode =0xfffe ; - }else if (!strncmp (vmode,"ask" ,3 )) { - video_mode =0xfffd ; - }else { - video_mode =strtol (vmode,NULL ,0 ); - } -stw_p (header+0x1fa , video_mode); - } - -/* loader type */ -/* High nybble = B reserved for QEMU; low nybble is revision number. -If this code is substantially changed, you may want to consider -incrementing the revision. */ -if (protocol >=0x200 ) { - header[0x210 ] =0xB0 ; - } -/* heap */ -if (protocol >=0x201 ) { - header[0x211 ] |=0x80 ;/* CAN_USE_HEAP */ -stw_p (header+0x224 , cmdline_addr-real_addr-0x200 ); - } - -/* load initrd */ -if (initrd_filename) { -GMappedFile *mapped_file; -gsize initrd_size; -gchar *initrd_data; -GError *gerr =NULL ; - -if (protocol <0x200 ) { -fprintf (stderr,"qemu: linux kernel too old to load a ram disk\n" ); -exit (1 ); - } - - mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); -if (!mapped_file) { -fprintf (stderr,"qemu: error reading initrd %s: %s\n" , - initrd_filename, gerr->message); -exit (1 ); - } - pcms->initrd_mapped_file = mapped_file; - - initrd_data =g_mapped_file_get_contents (mapped_file); - initrd_size =g_mapped_file_get_length (mapped_file); -if (initrd_size >= initrd_max) { -fprintf (stderr,"qemu: initrd is too large, cannot support." -"(max: %" PRIu32", need %" PRId64")\n" , - initrd_max, (uint64_t )initrd_size); -exit (1 ); - } - - initrd_addr = (initrd_max-initrd_size) & ~4095 ; - -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, initrd_size); - -stl_p (header+0x218 , initrd_addr); -stl_p (header+0x21c , initrd_size); - } - -/* load kernel and setup */ - setup_size = header[0x1f1 ]; -if (setup_size ==0 ) { - setup_size =4 ; - } - setup_size = (setup_size+1 )*512 ; -if (setup_size > kernel_size) { -fprintf (stderr,"qemu: invalid kernel header\n" ); -exit (1 ); - } - kernel_size -= setup_size; - - setup =g_malloc (setup_size); - kernel =g_malloc (kernel_size); -fseek (f,0 ,SEEK_SET ); -if (fread (setup,1 , setup_size, f) != setup_size) { -fprintf (stderr,"fread() failed\n" ); -exit (1 ); - } -if (fread (kernel,1 , kernel_size, f) != kernel_size) { -fprintf (stderr,"fread() failed\n" ); -exit (1 ); - } -fclose (f); - -/* append dtb to kernel */ -if (dtb_filename) { -if (protocol <0x209 ) { -fprintf (stderr,"qemu: Linux kernel too old to load a dtb\n" ); -exit (1 ); - } - - dtb_size =get_image_size (dtb_filename); -if (dtb_size <=0 ) { -fprintf (stderr,"qemu: error reading dtb %s: %s\n" , - dtb_filename,strerror (errno)); -exit (1 ); - } - - setup_data_offset =QEMU_ALIGN_UP (kernel_size,16 ); - kernel_size = setup_data_offset +sizeof (struct setup_data ) + dtb_size; - kernel =g_realloc (kernel, kernel_size); - -stq_p (header+0x250 , prot_addr + setup_data_offset); - - setup_data = (struct setup_data *)(kernel + setup_data_offset); - setup_data->next =0 ; - setup_data->type =cpu_to_le32 (SETUP_DTB ); - setup_data->len =cpu_to_le32 (dtb_size); - -load_image_size (dtb_filename, setup_data->data, dtb_size); - } - -memcpy (setup, header,MIN (sizeof (header), setup_size)); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , prot_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , kernel_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_KERNEL_DATA , kernel, kernel_size); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_ADDR , real_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE , setup_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , setup, setup_size); - - option_rom[nb_option_roms].bootindex =0 ; - option_rom[nb_option_roms].name ="linuxboot.bin" ; -if (pcmc->linuxboot_dma_enabled &&fw_cfg_dma_enabled (fw_cfg)) { - option_rom[nb_option_roms].name ="linuxboot_dma.bin" ; - } - nb_option_roms++; -} -#define NE2000_NB_MAX 6static const int ne2000_io[NE2000_NB_MAX ] = {0x300 ,0x320 ,0x340 ,0x360 ,@@ -1374,24 +900,6 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp) -{ -Object *cpu =NULL ; -Error *local_err =NULL ; -CPUX86State *env =NULL ; - - cpu =object_new (MACHINE (pcms)->cpu_type); - - env = &X86_CPU (cpu)->env; - env->nr_dies = pcms->smp_dies; - -object_property_set_uint (cpu, apic_id,"apic-id" , &local_err); -object_property_set_bool (cpu, true,"realized" , &local_err); - -object_unref (cpu); -error_propagate (errp, local_err); -} -/* * This function is very similar to smp_parse() * in hw/core/machine.c but includes CPU die support. @@ -1497,31 +1005,6 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp) } } -void x86_cpus_init (PCMachineState *pcms) -{ -int i; -const CPUArchIdList *possible_cpus; -MachineState *ms =MACHINE (pcms); -MachineClass *mc =MACHINE_GET_CLASS (pcms); -PCMachineClass *pcmc =PC_MACHINE_CLASS (mc); - -x86_cpu_set_default_version (pcmc->default_cpu_version); - -/* Calculates the limit to CPU APIC ID values -* -* Limit for the APIC ID value, so that all -* CPU APIC IDs are < pcms->apic_id_limit. -* -* This is used for FW_CFG_MAX_CPUS. See comments on fw_cfg_arch_create(). -*/ - pcms->apic_id_limit =x86_cpu_apic_id_from_index (pcms, - ms->smp.max_cpus -1 ) +1 ; - possible_cpus = mc->possible_cpu_arch_ids (ms); -for (i =0 ; i < ms->smp.cpus; i++) { -x86_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); - } -} -static void rtc_set_cpus_count (ISADevice *rtc,uint16_t cpus_count) {if (cpus_count >0xff ) {@@ -2677,69 +2160,6 @@ static void pc_machine_wakeup(MachineState *machine)cpu_synchronize_all_post_reset (); } -static CpuInstanceProperties -x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index) -{ -MachineClass *mc =MACHINE_GET_CLASS (ms); -const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids (ms); - -assert (cpu_index < possible_cpus->len); -return possible_cpus->cpus[cpu_index].props; -} - -static int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx) -{ -X86CPUTopoInfo topo; -PCMachineState *pcms =PC_MACHINE (ms); - -assert (idx < ms->possible_cpus->len); -x86_topo_ids_from_apicid (ms->possible_cpus->cpus[idx].arch_id, - pcms->smp_dies, ms->smp.cores, - ms->smp.threads, &topo); -return topo.pkg_id % ms->numa_state->num_nodes; -} - -static const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms) -{ -PCMachineState *pcms =PC_MACHINE (ms); -int i; -unsigned int max_cpus = ms->smp.max_cpus; - -if (ms->possible_cpus) { -/* -* make sure that max_cpus hasn't changed since the first use, i.e. -* -smp hasn't been parsed after it -*/ -assert (ms->possible_cpus->len == max_cpus); -return ms->possible_cpus; - } - - ms->possible_cpus =g_malloc0 (sizeof (CPUArchIdList) + -sizeof (CPUArchId) * max_cpus); - ms->possible_cpus->len = max_cpus; -for (i =0 ; i < ms->possible_cpus->len; i++) { -X86CPUTopoInfo topo; - - ms->possible_cpus->cpus[i].type = ms->cpu_type; - ms->possible_cpus->cpus[i].vcpus_count =1 ; - ms->possible_cpus->cpus[i].arch_id =x86_cpu_apic_id_from_index (pcms, i); -x86_topo_ids_from_apicid (ms->possible_cpus->cpus[i].arch_id, - pcms->smp_dies, ms->smp.cores, - ms->smp.threads, &topo); - ms->possible_cpus->cpus[i].props.has_socket_id = true; - ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; -if (pcms->smp_dies >1 ) { - ms->possible_cpus->cpus[i].props.has_die_id = true; - ms->possible_cpus->cpus[i].props.die_id = topo.die_id; - } - ms->possible_cpus->cpus[i].props.has_core_id = true; - ms->possible_cpus->cpus[i].props.core_id = topo.core_id; - ms->possible_cpus->cpus[i].props.has_thread_id = true; - ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id; - } -return ms->possible_cpus; -} -static void x86_nmi (NMIState *n,int cpu_index,Error **errp) {/* cpu index isn't used */ hw/i386/pc_piix.c +1
-0@@ -28,6 +28,7 @@#include "qemu/units.h" #include "hw/loader.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/i386/apic.h" #include "hw/display/ramfb.h" #include "hw/firmware/smbios.h" hw/i386/pc_q35.c +1
-0@@ -42,6 +42,7 @@#include "hw/qdev-properties.h" #include "exec/address-spaces.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/i386/ich9.h" #include "hw/i386/amd_iommu.h" #include "hw/i386/intel_iommu.h" hw/i386/pc_sysfw.c +1
-53@@ -32,6 +32,7 @@#include "qemu/units.h" #include "hw/sysbus.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/loader.h" #include "hw/qdev-properties.h" #include "sysemu/sysemu.h" @@ -211,59 +212,6 @@ static void pc_system_flash_map(PCMachineState *pcms, } } -static void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw) -{ -char *filename; -MemoryRegion *bios, *isa_bios; -int bios_size, isa_bios_size; -int ret; - -/* BIOS load */ -if (bios_name ==NULL ) { - bios_name =BIOS_FILENAME ; - } - filename =qemu_find_file (QEMU_FILE_TYPE_BIOS , bios_name); -if (filename) { - bios_size =get_image_size (filename); - }else { - bios_size =-1 ; - } -if (bios_size <=0 || - (bios_size %65536 ) !=0 ) { - goto bios_error; - } - bios =g_malloc (sizeof (*bios)); -memory_region_init_ram (bios,NULL ,"pc.bios" , bios_size, &error_fatal); -if (!isapc_ram_fw) { -memory_region_set_readonly (bios, true); - } - ret =rom_add_file_fixed (bios_name, (uint32_t )(-bios_size),-1 ); -if (ret !=0 ) { - bios_error: -fprintf (stderr,"qemu: could not load PC BIOS '%s'\n" , bios_name); -exit (1 ); - } -g_free (filename); - -/* map the last 128KB of the BIOS in ISA space */ - isa_bios_size =MIN (bios_size,128 * KiB); - isa_bios =g_malloc (sizeof (*isa_bios)); -memory_region_init_alias (isa_bios,NULL ,"isa-bios" , bios, - bios_size - isa_bios_size, isa_bios_size); -memory_region_add_subregion_overlap (rom_memory, -0x100000 - isa_bios_size, - isa_bios, -1 ); -if (!isapc_ram_fw) { -memory_region_set_readonly (isa_bios, true); - } - -/* map all the bios at the top of memory */ -memory_region_add_subregion (rom_memory, - (uint32_t )(-bios_size), - bios); -} -void pc_system_firmware_init (PCMachineState *pcms,MemoryRegion *rom_memory) {hw/i386/x86.c new file +684
-0@@ -0,0 +1,684 @@ +/* +* Copyright (c) 2003-2004 Fabrice Bellard +* Copyright (c) 2019 Red Hat, Inc. +* +* 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. +*/ +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "qemu/cutils.h" +#include "qemu/units.h" +#include "qemu-common.h" +#include "qapi/error.h" +#include "qapi/qmp/qerror.h" +#include "qapi/qapi-visit-common.h" +#include "qapi/visitor.h" +#include "sysemu/qtest.h" +#include "sysemu/numa.h" +#include "sysemu/replay.h" +#include "sysemu/sysemu.h" + +#include "hw/i386/x86.h" +#include "hw/i386/pc.h" +#include "target/i386/cpu.h" +#include "hw/i386/topology.h" +#include "hw/i386/fw_cfg.h" + +#include "hw/acpi/cpu_hotplug.h" +#include "hw/nmi.h" +#include "hw/loader.h" +#include "multiboot.h" +#include "elf.h" +#include "standard-headers/asm-x86/bootparam.h" + +#define BIOS_FILENAME "bios.bin" + +/* Physical Address of PVH entry point read from kernel ELF NOTE */ +static size_t pvh_start_addr; + +/* Calculates initial APIC ID for a specific CPU index +* +* Currently we need to be able to calculate the APIC ID from the CPU index +* alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have +* no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of +* all CPUs up to max_cpus. +*/ +uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, +unsigned int cpu_index) +{ +MachineState *ms =MACHINE (pcms); +PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); +uint32_t correct_id; +static bool warned; + + correct_id =x86_apicid_from_cpu_idx (pcms->smp_dies, ms->smp.cores, + ms->smp.threads, cpu_index); +if (pcmc->compat_apic_id_mode) { +if (cpu_index != correct_id && !warned && !qtest_enabled ()) { +error_report ("APIC IDs set in compatibility mode, " +"CPU topology won't match the configuration" ); + warned = true; + } +return cpu_index; + }else { +return correct_id; + } +} + +void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp) +{ +Object *cpu =NULL ; +Error *local_err =NULL ; +CPUX86State *env =NULL ; + + cpu =object_new (MACHINE (pcms)->cpu_type); + + env = &X86_CPU (cpu)->env; + env->nr_dies = pcms->smp_dies; + +object_property_set_uint (cpu, apic_id,"apic-id" , &local_err); +object_property_set_bool (cpu, true,"realized" , &local_err); + +object_unref (cpu); +error_propagate (errp, local_err); +} + +void x86_cpus_init (PCMachineState *pcms) +{ +int i; +const CPUArchIdList *possible_cpus; +MachineState *ms =MACHINE (pcms); +MachineClass *mc =MACHINE_GET_CLASS (pcms); +PCMachineClass *pcmc =PC_MACHINE_CLASS (mc); + +x86_cpu_set_default_version (pcmc->default_cpu_version); + +/* Calculates the limit to CPU APIC ID values +* +* Limit for the APIC ID value, so that all +* CPU APIC IDs are < pcms->apic_id_limit. +* +* This is used for FW_CFG_MAX_CPUS. See comments on fw_cfg_arch_create(). +*/ + pcms->apic_id_limit =x86_cpu_apic_id_from_index (pcms, + ms->smp.max_cpus -1 ) +1 ; + possible_cpus = mc->possible_cpu_arch_ids (ms); +for (i =0 ; i < ms->smp.cpus; i++) { +x86_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); + } +} + +CpuInstanceProperties +x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index) +{ +MachineClass *mc =MACHINE_GET_CLASS (ms); +const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids (ms); + +assert (cpu_index < possible_cpus->len); +return possible_cpus->cpus[cpu_index].props; +} + +int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx) +{ +X86CPUTopoInfo topo; +PCMachineState *pcms =PC_MACHINE (ms); + +assert (idx < ms->possible_cpus->len); +x86_topo_ids_from_apicid (ms->possible_cpus->cpus[idx].arch_id, + pcms->smp_dies, ms->smp.cores, + ms->smp.threads, &topo); +return topo.pkg_id % ms->numa_state->num_nodes; +} + +const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms) +{ +PCMachineState *pcms =PC_MACHINE (ms); +int i; +unsigned int max_cpus = ms->smp.max_cpus; + +if (ms->possible_cpus) { +/* +* make sure that max_cpus hasn't changed since the first use, i.e. +* -smp hasn't been parsed after it +*/ +assert (ms->possible_cpus->len == max_cpus); +return ms->possible_cpus; + } + + ms->possible_cpus =g_malloc0 (sizeof (CPUArchIdList) + +sizeof (CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; +for (i =0 ; i < ms->possible_cpus->len; i++) { +X86CPUTopoInfo topo; + + ms->possible_cpus->cpus[i].type = ms->cpu_type; + ms->possible_cpus->cpus[i].vcpus_count =1 ; + ms->possible_cpus->cpus[i].arch_id =x86_cpu_apic_id_from_index (pcms, i); +x86_topo_ids_from_apicid (ms->possible_cpus->cpus[i].arch_id, + pcms->smp_dies, ms->smp.cores, + ms->smp.threads, &topo); + ms->possible_cpus->cpus[i].props.has_socket_id = true; + ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; +if (pcms->smp_dies >1 ) { + ms->possible_cpus->cpus[i].props.has_die_id = true; + ms->possible_cpus->cpus[i].props.die_id = topo.die_id; + } + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = topo.core_id; + ms->possible_cpus->cpus[i].props.has_thread_id = true; + ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id; + } +return ms->possible_cpus; +} + +static long get_file_size (FILE *f) +{ +long where, size; + +/* XXX: on Unix systems, using fstat() probably makes more sense */ + + where =ftell (f); +fseek (f,0 ,SEEK_END ); + size =ftell (f); +fseek (f, where,SEEK_SET ); + +return size; +} + +struct setup_data { +uint64_t next; +uint32_t type; +uint32_t len; +uint8_t data[0 ]; +} __attribute__((packed)); + +/* +* The entry point into the kernel for PVH boot is different from +* the native entry point. The PVH entry is defined by the x86/HVM +* direct boot ABI and is available in an ELFNOTE in the kernel binary. +* +* This function is passed to load_elf() when it is called from +* load_elfboot() which then additionally checks for an ELF Note of +* type XEN_ELFNOTE_PHYS32_ENTRY and passes it to this function to +* parse the PVH entry address from the ELF Note. +* +* Due to trickery in elf_opts.h, load_elf() is actually available as +* load_elf32() or load_elf64() and this routine needs to be able +* to deal with being called as 32 or 64 bit. +* +* The address of the PVH entry point is saved to the 'pvh_start_addr' +* global variable. (although the entry point is 32-bit, the kernel +* binary can be either 32-bit or 64-bit). +*/ +static uint64_t read_pvh_start_addr (void *arg1,void *arg2,bool is64) +{ +size_t *elf_note_data_addr; + +/* Check if ELF Note header passed in is valid */ +if (arg1 ==NULL ) { +return 0 ; + } + +if (is64) { +struct elf64_note *nhdr64 = (struct elf64_note *)arg1; +uint64_t nhdr_size64 =sizeof (struct elf64_note ); +uint64_t phdr_align = *(uint64_t *)arg2; +uint64_t nhdr_namesz = nhdr64->n_namesz; + + elf_note_data_addr = + ((void *)nhdr64) + nhdr_size64 + +QEMU_ALIGN_UP (nhdr_namesz, phdr_align); + }else { +struct elf32_note *nhdr32 = (struct elf32_note *)arg1; +uint32_t nhdr_size32 =sizeof (struct elf32_note ); +uint32_t phdr_align = *(uint32_t *)arg2; +uint32_t nhdr_namesz = nhdr32->n_namesz; + + elf_note_data_addr = + ((void *)nhdr32) + nhdr_size32 + +QEMU_ALIGN_UP (nhdr_namesz, phdr_align); + } + + pvh_start_addr = *elf_note_data_addr; + +return pvh_start_addr; +} + +static bool load_elfboot (const char *kernel_filename, +int kernel_file_size, +uint8_t *header, +size_t pvh_xen_start_addr, +FWCfgState *fw_cfg) +{ +uint32_t flags =0 ; +uint32_t mh_load_addr =0 ; +uint32_t elf_kernel_size =0 ; +uint64_t elf_entry; +uint64_t elf_low, elf_high; +int kernel_size; + +if (ldl_p (header) !=0x464c457f ) { +return false;/* no elfboot */ + } + +bool elf_is64 = header[EI_CLASS ] ==ELFCLASS64 ; + flags = elf_is64 ? + ((Elf64_Ehdr *)header)->e_flags : ((Elf32_Ehdr *)header)->e_flags; + +if (flags &0x00010004 ) {/* LOAD_ELF_HEADER_HAS_ADDR */ +error_report ("elfboot unsupported flags = %x" , flags); +exit (1 ); + } + +uint64_t elf_note_type =XEN_ELFNOTE_PHYS32_ENTRY ; + kernel_size =load_elf (kernel_filename, read_pvh_start_addr, +NULL , &elf_note_type, &elf_entry, + &elf_low, &elf_high,0 ,I386_ELF_MACHINE , +0 ,0 ); + +if (kernel_size <0 ) { +error_report ("Error while loading elf kernel" ); +exit (1 ); + } + mh_load_addr = elf_low; + elf_kernel_size = elf_high - elf_low; + +if (pvh_start_addr ==0 ) { +error_report ("Error loading uncompressed kernel without PVH ELF Note" ); +exit (1 ); + } +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ENTRY , pvh_start_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , mh_load_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , elf_kernel_size); + +return true; +} + +void x86_load_linux (PCMachineState *pcms, +FWCfgState *fw_cfg) +{ +uint16_t protocol; +int setup_size, kernel_size, cmdline_size; +int dtb_size, setup_data_offset; +uint32_t initrd_max; +uint8_t header[8192 ], *setup, *kernel; +hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr =0 ; +FILE *f; +char *vmode; +MachineState *machine =MACHINE (pcms); +PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); +struct setup_data *setup_data; +const char *kernel_filename = machine->kernel_filename; +const char *initrd_filename = machine->initrd_filename; +const char *dtb_filename = machine->dtb; +const char *kernel_cmdline = machine->kernel_cmdline; + +/* Align to 16 bytes as a paranoia measure */ + cmdline_size = (strlen (kernel_cmdline)+16 ) & ~15 ; + +/* load the kernel header */ + f =fopen (kernel_filename,"rb" ); +if (!f || !(kernel_size =get_file_size (f)) || +fread (header,1 ,MIN (ARRAY_SIZE (header), kernel_size), f) != +MIN (ARRAY_SIZE (header), kernel_size)) { +fprintf (stderr,"qemu: could not load kernel '%s': %s\n" , + kernel_filename,strerror (errno)); +exit (1 ); + } + +/* kernel protocol version */ +#if 0 +fprintf (stderr,"header magic: %#x\n" ,ldl_p (header+0x202 )); +#endif +if (ldl_p (header+0x202 ) ==0x53726448 ) { + protocol =lduw_p (header+0x206 ); + }else { +/* +* This could be a multiboot kernel. If it is, let's stop treating it +* like a Linux kernel. +* Note: some multiboot images could be in the ELF format (the same of +* PVH), so we try multiboot first since we check the multiboot magic +* header before to load it. +*/ +if (load_multiboot (fw_cfg, f, kernel_filename, initrd_filename, + kernel_cmdline, kernel_size, header)) { +return ; + } +/* +* Check if the file is an uncompressed kernel file (ELF) and load it, +* saving the PVH entry point used by the x86/HVM direct boot ABI. +* If load_elfboot() is successful, populate the fw_cfg info. +*/ +if (pcmc->pvh_enabled && +load_elfboot (kernel_filename, kernel_size, + header, pvh_start_addr, fw_cfg)) { +fclose (f); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE , +strlen (kernel_cmdline) +1 ); +fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE ,sizeof (header)); +fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , + header,sizeof (header)); + +/* load initrd */ +if (initrd_filename) { +GMappedFile *mapped_file; +gsize initrd_size; +gchar *initrd_data; +GError *gerr =NULL ; + + mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); +if (!mapped_file) { +fprintf (stderr,"qemu: error reading initrd %s: %s\n" , + initrd_filename, gerr->message); +exit (1 ); + } + pcms->initrd_mapped_file = mapped_file; + + initrd_data =g_mapped_file_get_contents (mapped_file); + initrd_size =g_mapped_file_get_length (mapped_file); + initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; +if (initrd_size >= initrd_max) { +fprintf (stderr,"qemu: initrd is too large, cannot support." +"(max: %" PRIu32", need %" PRId64")\n" , + initrd_max, (uint64_t )initrd_size); +exit (1 ); + } + + initrd_addr = (initrd_max - initrd_size) & ~4095 ; + +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, + initrd_size); + } + + option_rom[nb_option_roms].bootindex =0 ; + option_rom[nb_option_roms].name ="pvh.bin" ; + nb_option_roms++; + +return ; + } + protocol =0 ; + } + +if (protocol <0x200 || !(header[0x211 ] &0x01 )) { +/* Low kernel */ + real_addr =0x90000 ; + cmdline_addr =0x9a000 - cmdline_size; + prot_addr =0x10000 ; + }else if (protocol <0x202 ) { +/* High but ancient kernel */ + real_addr =0x90000 ; + cmdline_addr =0x9a000 - cmdline_size; + prot_addr =0x100000 ; + }else { +/* High and recent kernel */ + real_addr =0x10000 ; + cmdline_addr =0x20000 ; + prot_addr =0x100000 ; + } + +#if 0 +fprintf (stderr, +"qemu: real_addr = 0x" TARGET_FMT_plx"\n" +"qemu: cmdline_addr = 0x" TARGET_FMT_plx"\n" +"qemu: prot_addr = 0x" TARGET_FMT_plx"\n" , + real_addr, + cmdline_addr, + prot_addr); +#endif + +/* highest address for loading the initrd */ +if (protocol >=0x20c && +lduw_p (header+0x236 ) &XLF_CAN_BE_LOADED_ABOVE_4G ) { +/* +* Linux has supported initrd up to 4 GB for a very long time (2007, +* long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013), +* though it only sets initrd_max to 2 GB to "work around bootloader +* bugs". Luckily, QEMU firmware(which does something like bootloader) +* has supported this. +* +* It's believed that if XLF_CAN_BE_LOADED_ABOVE_4G is set, initrd can +* be loaded into any address. +* +* In addition, initrd_max is uint32_t simply because QEMU doesn't +* support the 64-bit boot protocol (specifically the ext_ramdisk_image +* field). +* +* Therefore here just limit initrd_max to UINT32_MAX simply as well. +*/ + initrd_max =UINT32_MAX ; + }else if (protocol >=0x203 ) { + initrd_max =ldl_p (header+0x22c ); + }else { + initrd_max =0x37ffffff ; + } + +if (initrd_max >= pcms->below_4g_mem_size - pcmc->acpi_data_size) { + initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; + } + +fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_ADDR , cmdline_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE ,strlen (kernel_cmdline)+1 ); +fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); + +if (protocol >=0x202 ) { +stl_p (header+0x228 , cmdline_addr); + }else { +stw_p (header+0x20 ,0xA33F ); +stw_p (header+0x22 , cmdline_addr-real_addr); + } + +/* handle vga= parameter */ + vmode =strstr (kernel_cmdline,"vga=" ); +if (vmode) { +unsigned int video_mode; +/* skip "vga=" */ + vmode +=4 ; +if (!strncmp (vmode,"normal" ,6 )) { + video_mode =0xffff ; + }else if (!strncmp (vmode,"ext" ,3 )) { + video_mode =0xfffe ; + }else if (!strncmp (vmode,"ask" ,3 )) { + video_mode =0xfffd ; + }else { + video_mode =strtol (vmode,NULL ,0 ); + } +stw_p (header+0x1fa , video_mode); + } + +/* loader type */ +/* High nybble = B reserved for QEMU; low nybble is revision number. +If this code is substantially changed, you may want to consider +incrementing the revision. */ +if (protocol >=0x200 ) { + header[0x210 ] =0xB0 ; + } +/* heap */ +if (protocol >=0x201 ) { + header[0x211 ] |=0x80 ;/* CAN_USE_HEAP */ +stw_p (header+0x224 , cmdline_addr-real_addr-0x200 ); + } + +/* load initrd */ +if (initrd_filename) { +GMappedFile *mapped_file; +gsize initrd_size; +gchar *initrd_data; +GError *gerr =NULL ; + +if (protocol <0x200 ) { +fprintf (stderr,"qemu: linux kernel too old to load a ram disk\n" ); +exit (1 ); + } + + mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); +if (!mapped_file) { +fprintf (stderr,"qemu: error reading initrd %s: %s\n" , + initrd_filename, gerr->message); +exit (1 ); + } + pcms->initrd_mapped_file = mapped_file; + + initrd_data =g_mapped_file_get_contents (mapped_file); + initrd_size =g_mapped_file_get_length (mapped_file); +if (initrd_size >= initrd_max) { +fprintf (stderr,"qemu: initrd is too large, cannot support." +"(max: %" PRIu32", need %" PRId64")\n" , + initrd_max, (uint64_t )initrd_size); +exit (1 ); + } + + initrd_addr = (initrd_max-initrd_size) & ~4095 ; + +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, initrd_size); + +stl_p (header+0x218 , initrd_addr); +stl_p (header+0x21c , initrd_size); + } + +/* load kernel and setup */ + setup_size = header[0x1f1 ]; +if (setup_size ==0 ) { + setup_size =4 ; + } + setup_size = (setup_size+1 )*512 ; +if (setup_size > kernel_size) { +fprintf (stderr,"qemu: invalid kernel header\n" ); +exit (1 ); + } + kernel_size -= setup_size; + + setup =g_malloc (setup_size); + kernel =g_malloc (kernel_size); +fseek (f,0 ,SEEK_SET ); +if (fread (setup,1 , setup_size, f) != setup_size) { +fprintf (stderr,"fread() failed\n" ); +exit (1 ); + } +if (fread (kernel,1 , kernel_size, f) != kernel_size) { +fprintf (stderr,"fread() failed\n" ); +exit (1 ); + } +fclose (f); + +/* append dtb to kernel */ +if (dtb_filename) { +if (protocol <0x209 ) { +fprintf (stderr,"qemu: Linux kernel too old to load a dtb\n" ); +exit (1 ); + } + + dtb_size =get_image_size (dtb_filename); +if (dtb_size <=0 ) { +fprintf (stderr,"qemu: error reading dtb %s: %s\n" , + dtb_filename,strerror (errno)); +exit (1 ); + } + + setup_data_offset =QEMU_ALIGN_UP (kernel_size,16 ); + kernel_size = setup_data_offset +sizeof (struct setup_data ) + dtb_size; + kernel =g_realloc (kernel, kernel_size); + +stq_p (header+0x250 , prot_addr + setup_data_offset); + + setup_data = (struct setup_data *)(kernel + setup_data_offset); + setup_data->next =0 ; + setup_data->type =cpu_to_le32 (SETUP_DTB ); + setup_data->len =cpu_to_le32 (dtb_size); + +load_image_size (dtb_filename, setup_data->data, dtb_size); + } + +memcpy (setup, header,MIN (sizeof (header), setup_size)); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , prot_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , kernel_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_KERNEL_DATA , kernel, kernel_size); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_ADDR , real_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE , setup_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , setup, setup_size); + + option_rom[nb_option_roms].bootindex =0 ; + option_rom[nb_option_roms].name ="linuxboot.bin" ; +if (pcmc->linuxboot_dma_enabled &&fw_cfg_dma_enabled (fw_cfg)) { + option_rom[nb_option_roms].name ="linuxboot_dma.bin" ; + } + nb_option_roms++; +} + +void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw) +{ +char *filename; +MemoryRegion *bios, *isa_bios; +int bios_size, isa_bios_size; +int ret; + +/* BIOS load */ +if (bios_name ==NULL ) { + bios_name =BIOS_FILENAME ; + } + filename =qemu_find_file (QEMU_FILE_TYPE_BIOS , bios_name); +if (filename) { + bios_size =get_image_size (filename); + }else { + bios_size =-1 ; + } +if (bios_size <=0 || + (bios_size %65536 ) !=0 ) { + goto bios_error; + } + bios =g_malloc (sizeof (*bios)); +memory_region_init_ram (bios,NULL ,"pc.bios" , bios_size, &error_fatal); +if (!isapc_ram_fw) { +memory_region_set_readonly (bios, true); + } + ret =rom_add_file_fixed (bios_name, (uint32_t )(-bios_size),-1 ); +if (ret !=0 ) { + bios_error: +fprintf (stderr,"qemu: could not load PC BIOS '%s'\n" , bios_name); +exit (1 ); + } +g_free (filename); + +/* map the last 128KB of the BIOS in ISA space */ + isa_bios_size =MIN (bios_size,128 * KiB); + isa_bios =g_malloc (sizeof (*isa_bios)); +memory_region_init_alias (isa_bios,NULL ,"isa-bios" , bios, + bios_size - isa_bios_size, isa_bios_size); +memory_region_add_subregion_overlap (rom_memory, +0x100000 - isa_bios_size, + isa_bios, +1 ); +if (!isapc_ram_fw) { +memory_region_set_readonly (isa_bios, true); + } + +/* map all the bios at the top of memory */ +memory_region_add_subregion (rom_memory, + (uint32_t )(-bios_size), + bios); +}include/hw/i386/pc.h +0
-1@@ -195,7 +195,6 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);void pc_register_ferr_irq (qemu_irq irq);void pc_acpi_smi_interrupt (void *opaque,int irq,int level); -void x86_cpus_init (PCMachineState *pcms);void pc_hot_add_cpu (MachineState *ms,const int64_t id,Error **errp);void pc_smp_parse (MachineState *ms,QemuOpts *opts);include/hw/i386/x86.h new file +35
-0@@ -0,0 +1,35 @@ +/* +* Copyright (c) 2019 Red Hat, Inc. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2 or later, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef HW_I386_X86_H +#define HW_I386_X86_H + +#include "hw/boards.h" + +uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, +unsigned int cpu_index); +void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp); +void x86_cpus_init (PCMachineState *pcms); +CpuInstanceProperties x86_cpu_index_to_props (MachineState *ms, +unsigned cpu_index); +int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx); +const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms); + +void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw); + +void x86_load_linux (PCMachineState *x86ms,FWCfgState *fw_cfg); + +#endif
Re: [PATCH v5 03/10] hw/i386/pc: move shared x86 functions to x86.c and export them
Quoted 18 lines · Philippe Mathieu-Daudé
Quoted 14 lines · Sergio Lopez
Move x86 functions that will be shared between PC and non-PC machine types to
x86.c, along with their helpers.Signed-off-by Sergio Lopez <[email protected]>--- hw/i386/Makefile.objs | 1 + hw/i386/pc.c | 582 +---------------------------------- hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + hw/i386/pc_sysfw.c | 54 +--- hw/i386/x86.c | 684 ++++++++++++++++++++++++++++++++++++++++++ include/hw/i386/pc.h | 1 - include/hw/i386/x86.h | 35 +++ 8 files changed, 724 insertions(+), 635 deletions(-)Quoted 2 lines
create mode 100644
hw/i386/x86.c
create mode 100644include/hw/i386/x86.h
Quoted 1 line
I recommend you to setup the
scripts/git.orderfilefile to ease reviewers :)
Thanks, I wasn't aware of that feature.
Quoted 14 lines
Quoted 14 lines
hw/i386/Makefile.objs +1
-0@@ -1,5 +1,6 @@ obj-$(CONFIG_KVM) += kvm/ obj-y += e820_memory_layout.o multiboot.o +obj-y += x86.o obj-y += pc.o obj-$(CONFIG_I440FX) += pc_piix.o obj-$(CONFIG_Q35) += pc_q35.ohw/i386/pc.c +0
-1--- a/hw/i386/pc.c
Quoted 8 lines
hw/i386/pc.c line 28
Quoted 6 lines
+++
b/hw/i386/pc.chw/i386/pc.c +1
-0@@ -25,6 +25,7 @@#include "qemu/osdep.h" #include "qemu/units.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" Nit: Include before "
pc.h" :)
OK, I'll check other appearances too.
Quoted 2 lines
Reviewed-by Philippe Mathieu-Daudé <[email protected]>
Thanks,
Sergio.
Quoted 1,453 lines
Quoted 1,453 lines
hw/i386/pc.c +0
-2#include "hw/char/serial.h" #include "hw/char/parallel.h" #include "hw/i386/apic.h" @@ -102,9 +103,6 @@struct hpet_fw_config hpet_cfg = {.count =UINT8_MAX }; -/* Physical Address of PVH entry point read from kernel ELF NOTE */ -static size_t pvh_start_addr; - GlobalProperty pc_compat_4_1[] = {};const size_t pc_compat_4_1_len =G_N_ELEMENTS (pc_compat_4_1); @@ -866,478 +864,6 @@ static void handle_a20_line_change(void*opaque, int irq, int level)
x86_cpu_set_a20(cpu, level);}
-/* Calculates initial APIC ID for a specific CPU index
- *
- * Currently we need to be able to calculate the APIC ID from the CPU index
- * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
- * no concept of "CPU index", and the NUMA tables onfw_cfgneed the APIC ID of
- * all CPUs up tomax_cpus.
- */hw/i386/pc.c +0
-465-static uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, -unsigned int cpu_index) -{ -MachineState *ms =MACHINE (pcms); -PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); -uint32_t correct_id; -static bool warned; - - correct_id =x86_apicid_from_cpu_idx (pcms->smp_dies, ms->smp.cores, - ms->smp.threads, cpu_index); -if (pcmc->compat_apic_id_mode) { -if (cpu_index != correct_id && !warned && !qtest_enabled ()) { -error_report ("APIC IDs set in compatibility mode, " -"CPU topology won't match the configuration" ); - warned = true; - } -return cpu_index; - }else { -return correct_id; - } -} - -static long get_file_size (FILE *f) -{ -long where, size; - -/* XXX: on Unix systems, using fstat() probably makes more sense */ - - where =ftell (f); -fseek (f,0 ,SEEK_END ); - size =ftell (f); -fseek (f, where,SEEK_SET ); - -return size; -} - -struct setup_data { -uint64_t next; -uint32_t type; -uint32_t len; -uint8_t data[0 ]; -} __attribute__((packed)); - - -/* -* The entry point into the kernel for PVH boot is different from -* the native entry point. The PVH entry is defined by the x86/HVM -* direct boot ABI and is available in an ELFNOTE in the kernel binary. -* -* This function is passed to load_elf() when it is called from -* load_elfboot() which then additionally checks for an ELF Note of -* type XEN_ELFNOTE_PHYS32_ENTRY and passes it to this function to -* parse the PVH entry address from the ELF Note. -* -* Due to trickery in elf_opts.h, load_elf() is actually available as -* load_elf32() or load_elf64() and this routine needs to be able -* to deal with being called as 32 or 64 bit. -* -* The address of the PVH entry point is saved to the 'pvh_start_addr' -* global variable. (although the entry point is 32-bit, the kernel -* binary can be either 32-bit or 64-bit). -*/ -static uint64_t read_pvh_start_addr (void *arg1,void *arg2,bool is64) -{ -size_t *elf_note_data_addr; - -/* Check if ELF Note header passed in is valid */ -if (arg1 ==NULL ) { -return 0 ; - } - -if (is64) { -struct elf64_note *nhdr64 = (struct elf64_note *)arg1; -uint64_t nhdr_size64 =sizeof (struct elf64_note ); -uint64_t phdr_align = *(uint64_t *)arg2; -uint64_t nhdr_namesz = nhdr64->n_namesz; - - elf_note_data_addr = - ((void *)nhdr64) + nhdr_size64 + -QEMU_ALIGN_UP (nhdr_namesz, phdr_align); - }else { -struct elf32_note *nhdr32 = (struct elf32_note *)arg1; -uint32_t nhdr_size32 =sizeof (struct elf32_note ); -uint32_t phdr_align = *(uint32_t *)arg2; -uint32_t nhdr_namesz = nhdr32->n_namesz; - - elf_note_data_addr = - ((void *)nhdr32) + nhdr_size32 + -QEMU_ALIGN_UP (nhdr_namesz, phdr_align); - } - - pvh_start_addr = *elf_note_data_addr; - -return pvh_start_addr; -} - -static bool load_elfboot (const char *kernel_filename, -int kernel_file_size, -uint8_t *header, -size_t pvh_xen_start_addr, -FWCfgState *fw_cfg) -{ -uint32_t flags =0 ; -uint32_t mh_load_addr =0 ; -uint32_t elf_kernel_size =0 ; -uint64_t elf_entry; -uint64_t elf_low, elf_high; -int kernel_size; - -if (ldl_p (header) !=0x464c457f ) { -return false;/* no elfboot */ - } - -bool elf_is64 = header[EI_CLASS ] ==ELFCLASS64 ; - flags = elf_is64 ? - ((Elf64_Ehdr *)header)->e_flags : ((Elf32_Ehdr *)header)->e_flags; - -if (flags &0x00010004 ) {/* LOAD_ELF_HEADER_HAS_ADDR */ -error_report ("elfboot unsupported flags = %x" , flags); -exit (1 ); - } - -uint64_t elf_note_type =XEN_ELFNOTE_PHYS32_ENTRY ; - kernel_size =load_elf (kernel_filename, read_pvh_start_addr, -NULL , &elf_note_type, &elf_entry, - &elf_low, &elf_high,0 ,I386_ELF_MACHINE , -0 ,0 ); - -if (kernel_size <0 ) { -error_report ("Error while loading elf kernel" ); -exit (1 ); - } - mh_load_addr = elf_low; - elf_kernel_size = elf_high - elf_low; - -if (pvh_start_addr ==0 ) { -error_report ("Error loading uncompressed kernel without PVH ELF Note" ); -exit (1 ); - } -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ENTRY , pvh_start_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , mh_load_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , elf_kernel_size); - -return true; -} - -static void x86_load_linux (PCMachineState *pcms, -FWCfgState *fw_cfg) -{ -uint16_t protocol; -int setup_size, kernel_size, cmdline_size; -int dtb_size, setup_data_offset; -uint32_t initrd_max; -uint8_t header[8192 ], *setup, *kernel; -hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr =0 ; -FILE *f; -char *vmode; -MachineState *machine =MACHINE (pcms); -PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); -struct setup_data *setup_data; -const char *kernel_filename = machine->kernel_filename; -const char *initrd_filename = machine->initrd_filename; -const char *dtb_filename = machine->dtb; -const char *kernel_cmdline = machine->kernel_cmdline; - -/* Align to 16 bytes as a paranoia measure */ - cmdline_size = (strlen (kernel_cmdline)+16 ) & ~15 ; - -/* load the kernel header */ - f =fopen (kernel_filename,"rb" ); -if (!f || !(kernel_size =get_file_size (f)) || -fread (header,1 ,MIN (ARRAY_SIZE (header), kernel_size), f) != -MIN (ARRAY_SIZE (header), kernel_size)) { -fprintf (stderr,"qemu: could not load kernel '%s': %s\n" , - kernel_filename,strerror (errno)); -exit (1 ); - } - -/* kernel protocol version */ -#if 0 -fprintf (stderr,"header magic: %#x\n" ,ldl_p (header+0x202 )); -#endif -if (ldl_p (header+0x202 ) ==0x53726448 ) { - protocol =lduw_p (header+0x206 ); - }else { -/* -* This could be a multiboot kernel. If it is, let's stop treating it -* like a Linux kernel. -* Note: some multiboot images could be in the ELF format (the same of -* PVH), so we try multiboot first since we check the multiboot magic -* header before to load it. -*/ -if (load_multiboot (fw_cfg, f, kernel_filename, initrd_filename, - kernel_cmdline, kernel_size, header)) { -return ; - } -/* -* Check if the file is an uncompressed kernel file (ELF) and load it, -* saving the PVH entry point used by the x86/HVM direct boot ABI. -* If load_elfboot() is successful, populate the fw_cfg info. -*/ -if (pcmc->pvh_enabled && -load_elfboot (kernel_filename, kernel_size, - header, pvh_start_addr, fw_cfg)) { -fclose (f); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE , -strlen (kernel_cmdline) +1 ); -fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE ,sizeof (header)); -fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , - header,sizeof (header)); - -/* load initrd */ -if (initrd_filename) { -GMappedFile *mapped_file; -gsize initrd_size; -gchar *initrd_data; -GError *gerr =NULL ; - - mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); -if (!mapped_file) { -fprintf (stderr,"qemu: error reading initrd %s: %s\n" , - initrd_filename, gerr->message); -exit (1 ); - } - pcms->initrd_mapped_file = mapped_file; - - initrd_data =g_mapped_file_get_contents (mapped_file); - initrd_size =g_mapped_file_get_length (mapped_file); - initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; -if (initrd_size >= initrd_max) { -fprintf (stderr,"qemu: initrd is too large, cannot support." -"(max: %" PRIu32", need %" PRId64")\n" , - initrd_max, (uint64_t )initrd_size); -exit (1 ); - } - - initrd_addr = (initrd_max - initrd_size) & ~4095 ; - -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, - initrd_size); - } - - option_rom[nb_option_roms].bootindex =0 ; - option_rom[nb_option_roms].name ="pvh.bin" ; - nb_option_roms++; - -return ; - } - protocol =0 ; - } - -if (protocol <0x200 || !(header[0x211 ] &0x01 )) { -/* Low kernel */ - real_addr =0x90000 ; - cmdline_addr =0x9a000 - cmdline_size; - prot_addr =0x10000 ; - }else if (protocol <0x202 ) { -/* High but ancient kernel */ - real_addr =0x90000 ; - cmdline_addr =0x9a000 - cmdline_size; - prot_addr =0x100000 ; - }else { -/* High and recent kernel */ - real_addr =0x10000 ; - cmdline_addr =0x20000 ; - prot_addr =0x100000 ; - } - -#if 0 -fprintf (stderr, -"qemu: real_addr = 0x" TARGET_FMT_plx"\n" -"qemu: cmdline_addr = 0x" TARGET_FMT_plx"\n" -"qemu: prot_addr = 0x" TARGET_FMT_plx"\n" , - real_addr, - cmdline_addr, - prot_addr); -#endif - -/* highest address for loading the initrd */ -if (protocol >=0x20c && -lduw_p (header+0x236 ) &XLF_CAN_BE_LOADED_ABOVE_4G ) { -/* -* Linux has supported initrd up to 4 GB for a very long time (2007, -* long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013), -* though it only sets initrd_max to 2 GB to "work around bootloader -* bugs". Luckily, QEMU firmware(which does something like bootloader) -* has supported this. -* -* It's believed that if XLF_CAN_BE_LOADED_ABOVE_4G is set, initrd can -* be loaded into any address. -* -* In addition, initrd_max is uint32_t simply because QEMU doesn't -* support the 64-bit boot protocol (specifically the ext_ramdisk_image -* field). -* -* Therefore here just limit initrd_max to UINT32_MAX simply as well. -*/ - initrd_max =UINT32_MAX ; - }else if (protocol >=0x203 ) { - initrd_max =ldl_p (header+0x22c ); - }else { - initrd_max =0x37ffffff ; - } - -if (initrd_max >= pcms->below_4g_mem_size - pcmc->acpi_data_size) { - initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; - } - -fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_ADDR , cmdline_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE ,strlen (kernel_cmdline)+1 ); -fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); - -if (protocol >=0x202 ) { -stl_p (header+0x228 , cmdline_addr); - }else { -stw_p (header+0x20 ,0xA33F ); -stw_p (header+0x22 , cmdline_addr-real_addr); - } - -/* handle vga= parameter */ - vmode =strstr (kernel_cmdline,"vga=" ); -if (vmode) { -unsigned int video_mode; -/* skip "vga=" */ - vmode +=4 ; -if (!strncmp (vmode,"normal" ,6 )) { - video_mode =0xffff ; - }else if (!strncmp (vmode,"ext" ,3 )) { - video_mode =0xfffe ; - }else if (!strncmp (vmode,"ask" ,3 )) { - video_mode =0xfffd ; - }else { - video_mode =strtol (vmode,NULL ,0 ); - } -stw_p (header+0x1fa , video_mode); - } - -/* loader type */ -/* High nybble = B reserved for QEMU; low nybble is revision number. -If this code is substantially changed, you may want to consider -incrementing the revision. */ -if (protocol >=0x200 ) { - header[0x210 ] =0xB0 ; - } -/* heap */ -if (protocol >=0x201 ) { - header[0x211 ] |=0x80 ;/* CAN_USE_HEAP */ -stw_p (header+0x224 , cmdline_addr-real_addr-0x200 ); - } - -/* load initrd */ -if (initrd_filename) { -GMappedFile *mapped_file; -gsize initrd_size; -gchar *initrd_data; -GError *gerr =NULL ; - -if (protocol <0x200 ) { -fprintf (stderr,"qemu: linux kernel too old to load a ram disk\n" ); -exit (1 ); - } - - mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); -if (!mapped_file) { -fprintf (stderr,"qemu: error reading initrd %s: %s\n" , - initrd_filename, gerr->message); -exit (1 ); - } - pcms->initrd_mapped_file = mapped_file; - - initrd_data =g_mapped_file_get_contents (mapped_file); - initrd_size =g_mapped_file_get_length (mapped_file); -if (initrd_size >= initrd_max) { -fprintf (stderr,"qemu: initrd is too large, cannot support." -"(max: %" PRIu32", need %" PRId64")\n" , - initrd_max, (uint64_t )initrd_size); -exit (1 ); - } - - initrd_addr = (initrd_max-initrd_size) & ~4095 ; - -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, initrd_size); - -stl_p (header+0x218 , initrd_addr); -stl_p (header+0x21c , initrd_size); - } - -/* load kernel and setup */ - setup_size = header[0x1f1 ]; -if (setup_size ==0 ) { - setup_size =4 ; - } - setup_size = (setup_size+1 )*512 ; -if (setup_size > kernel_size) { -fprintf (stderr,"qemu: invalid kernel header\n" ); -exit (1 ); - } - kernel_size -= setup_size; - - setup =g_malloc (setup_size); - kernel =g_malloc (kernel_size); -fseek (f,0 ,SEEK_SET ); -if (fread (setup,1 , setup_size, f) != setup_size) { -fprintf (stderr,"fread() failed\n" ); -exit (1 ); - } -if (fread (kernel,1 , kernel_size, f) != kernel_size) { -fprintf (stderr,"fread() failed\n" ); -exit (1 ); - } -fclose (f); - -/* append dtb to kernel */ -if (dtb_filename) { -if (protocol <0x209 ) { -fprintf (stderr,"qemu: Linux kernel too old to load a dtb\n" ); -exit (1 ); - } - - dtb_size =get_image_size (dtb_filename); -if (dtb_size <=0 ) { -fprintf (stderr,"qemu: error reading dtb %s: %s\n" , - dtb_filename,strerror (errno)); -exit (1 ); - } - - setup_data_offset =QEMU_ALIGN_UP (kernel_size,16 ); - kernel_size = setup_data_offset +sizeof (struct setup_data ) + dtb_size; - kernel =g_realloc (kernel, kernel_size); - -stq_p (header+0x250 , prot_addr + setup_data_offset); - - setup_data = (struct setup_data *)(kernel + setup_data_offset); - setup_data->next =0 ; - setup_data->type =cpu_to_le32 (SETUP_DTB ); - setup_data->len =cpu_to_le32 (dtb_size); - -load_image_size (dtb_filename, setup_data->data, dtb_size); - } - -memcpy (setup, header,MIN (sizeof (header), setup_size)); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , prot_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , kernel_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_KERNEL_DATA , kernel, kernel_size); - -fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_ADDR , real_addr); -fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE , setup_size); -fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , setup, setup_size); - - option_rom[nb_option_roms].bootindex =0 ; - option_rom[nb_option_roms].name ="linuxboot.bin" ; -if (pcmc->linuxboot_dma_enabled &&fw_cfg_dma_enabled (fw_cfg)) { - option_rom[nb_option_roms].name ="linuxboot_dma.bin" ; - } - nb_option_roms++; -} -#define NE2000_NB_MAX 6static const int ne2000_io[NE2000_NB_MAX ] = {0x300 ,0x320 ,
0x340,0x360,hw/i386/pc.c +0
-103@@ -1374,24 +900,6 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level) } } -static void x86_new_cpu(PCMachineState *pcms, int64_t apic_id,Error **errp) -{ -Object *cpu =NULL ; -Error *local_err =NULL ; -CPUX86State *env =NULL ; - - cpu =object_new (MACHINE (pcms)->cpu_type); - - env = &X86_CPU (cpu)->env; - env->nr_dies = pcms->smp_dies; - -object_property_set_uint (cpu, apic_id,"apic-id" , &local_err); -object_property_set_bool (cpu, true,"realized" , &local_err); - -object_unref (cpu); -error_propagate (errp, local_err); -} -/* * This function is very similar to smp_parse() * in hw/core/machine.c but includes CPU die support. @@ -1497,31 +1005,6 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp) } } -void x86_cpus_init(PCMachineState *pcms) -{ -int i; -const CPUArchIdList *possible_cpus; -MachineState *ms =MACHINE (pcms); -MachineClass *mc =MACHINE_GET_CLASS (pcms); -PCMachineClass *pcmc =PC_MACHINE_CLASS (mc); - -x86_cpu_set_default_version (pcmc->default_cpu_version); - -/* Calculates the limit to CPU APIC ID values -* -* Limit for the APIC ID value, so that all -* CPU APIC IDs are < pcms->apic_id_limit. -* -* This is used for FW_CFG_MAX_CPUS. See comments on fw_cfg_arch_create(). -*/ - pcms->apic_id_limit =x86_cpu_apic_id_from_index (pcms, - ms->smp.max_cpus -1 ) +1 ; - possible_cpus = mc->possible_cpu_arch_ids (ms); -for (i =0 ; i < ms->smp.cpus; i++) { -x86_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); - } -} -static void rtc_set_cpus_count (ISADevice *rtc,uint16_t cpus_count) {if (cpus_count >0xff ) {@@ -2677,69 +2160,6 @@ static void pc_machine_wakeup(MachineState *machine)cpu_synchronize_all_post_reset (); } -static CpuInstanceProperties -x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index) -{ -MachineClass *mc =MACHINE_GET_CLASS (ms); -const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids (ms); - -assert (cpu_index < possible_cpus->len); -return possible_cpus->cpus[cpu_index].props; -} - -static int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx) -{ -X86CPUTopoInfo topo; -PCMachineState *pcms =PC_MACHINE (ms); - -assert (idx < ms->possible_cpus->len); -x86_topo_ids_from_apicid (ms->possible_cpus->cpus[idx].arch_id, - pcms->smp_dies, ms->smp.cores, - ms->smp.threads, &topo); -return topo.pkg_id % ms->numa_state->num_nodes; -} - -static const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms) -{ -PCMachineState *pcms =PC_MACHINE (ms); -int i; -unsigned int max_cpus = ms->smp.max_cpus; - -if (ms->possible_cpus) { -/* -* make sure that max_cpus hasn't changed since the first use, i.e. -* -smp hasn't been parsed after it -*/ -assert (ms->possible_cpus->len == max_cpus); -return ms->possible_cpus; - } - - ms->possible_cpus =g_malloc0 (sizeof (CPUArchIdList) + -sizeof (CPUArchId) * max_cpus); - ms->possible_cpus->len = max_cpus; -for (i =0 ; i < ms->possible_cpus->len; i++) { -X86CPUTopoInfo topo; - - ms->possible_cpus->cpus[i].type = ms->cpu_type; - ms->possible_cpus->cpus[i].vcpus_count =1 ; - ms->possible_cpus->cpus[i].arch_id =x86_cpu_apic_id_from_index (pcms, i); -x86_topo_ids_from_apicid (ms->possible_cpus->cpus[i].arch_id, - pcms->smp_dies, ms->smp.cores, - ms->smp.threads, &topo); - ms->possible_cpus->cpus[i].props.has_socket_id = true; - ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; -if (pcms->smp_dies >1 ) { - ms->possible_cpus->cpus[i].props.has_die_id = true; - ms->possible_cpus->cpus[i].props.die_id = topo.die_id; - } - ms->possible_cpus->cpus[i].props.has_core_id = true; - ms->possible_cpus->cpus[i].props.core_id = topo.core_id; - ms->possible_cpus->cpus[i].props.has_thread_id = true; - ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id; - } -return ms->possible_cpus; -} -static void x86_nmi (NMIState *n,int cpu_index,Error **errp) {/* cpu index isn't used */ hw/i386/pc_piix.c +1
-0@@ -28,6 +28,7 @@#include "qemu/units.h" #include "hw/loader.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/i386/apic.h" #include "hw/display/ramfb.h" #include "hw/firmware/smbios.h" hw/i386/pc_q35.c +1
-0@@ -42,6 +42,7 @@#include "hw/qdev-properties.h" #include "exec/address-spaces.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/i386/ich9.h" #include "hw/i386/amd_iommu.h" #include "hw/i386/intel_iommu.h" hw/i386/pc_sysfw.c +1
-52@@ -32,6 +32,7 @@#include "qemu/units.h" #include "hw/sysbus.h" #include "hw/i386/pc.h" +#include "hw/i386/x86.h" #include "hw/loader.h" #include "hw/qdev-properties.h" #include "sysemu/sysemu.h" @@ -211,59 +212,6 @@ static void pc_system_flash_map(PCMachineState *pcms, } } -static void x86_system_rom_init(MemoryRegion *rom_memory, bool isapc_ram_fw) -{ -char *filename; -MemoryRegion *bios, *isa_bios; -int bios_size, isa_bios_size; -int ret; - -/* BIOS load */ -if (bios_name ==NULL ) { - bios_name =BIOS_FILENAME ; - } - filename =qemu_find_file (QEMU_FILE_TYPE_BIOS , bios_name); -if (filename) { - bios_size =get_image_size (filename); - }else { - bios_size =-1 ; - } -if (bios_size <=0 || - (bios_size %65536 ) !=0 ) { - goto bios_error; - } - bios =g_malloc (sizeof (*bios)); -memory_region_init_ram (bios,NULL ,"pc.bios" , bios_size, &error_fatal); -if (!isapc_ram_fw) { -memory_region_set_readonly (bios, true); - } - ret =rom_add_file_fixed (bios_name, (uint32_t )(-bios_size),-1 ); -if (ret !=0 ) { - bios_error: -fprintf (stderr,"qemu: could not load PC BIOS '%s'\n" , bios_name); -exit (1 ); - } -g_free (filename); - -/* map the last 128KB of the BIOS in ISA space */ - isa_bios_size =MIN (bios_size,128 * KiB); - isa_bios =g_malloc (sizeof (*isa_bios)); -memory_region_init_alias (isa_bios,NULL ,"isa-bios" , bios, - bios_size - isa_bios_size, isa_bios_size); -memory_region_add_subregion_overlap (rom_memory, -0x100000 - isa_bios_size, - isa_bios, -1 ); -if (!isapc_ram_fw) { -memory_region_set_readonly (isa_bios, true); - } - -/* map all the bios at the top of memory */ -memory_region_add_subregion (rom_memory, - (uint32_t )(-bios_size), - bios); -} - voidpc_system_firmware_init (PCMachineState *pcms, MemoryRegion *rom_memory) {hw/i386/x86.c new file +684
-0@@ -0,0 +1,684 @@ +/* +* Copyright (c) 2003-2004 Fabrice Bellard +* Copyright (c) 2019 Red Hat, Inc. +* +* 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. +*/ +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/option.h" +#include "qemu/cutils.h" +#include "qemu/units.h" +#include "qemu-common.h" +#include "qapi/error.h" +#include "qapi/qmp/qerror.h" +#include "qapi/qapi-visit-common.h" +#include "qapi/visitor.h" +#include "sysemu/qtest.h" +#include "sysemu/numa.h" +#include "sysemu/replay.h" +#include "sysemu/sysemu.h" + +#include "hw/i386/x86.h" +#include "hw/i386/pc.h" +#include "target/i386/cpu.h" +#include "hw/i386/topology.h" +#include "hw/i386/fw_cfg.h" + +#include "hw/acpi/cpu_hotplug.h" +#include "hw/nmi.h" +#include "hw/loader.h" +#include "multiboot.h" +#include "elf.h" +#include "standard-headers/asm-x86/bootparam.h" + +#define BIOS_FILENAME "bios.bin" + +/* Physical Address of PVH entry point read from kernel ELF NOTE */ +static size_t pvh_start_addr; + +/* Calculates initial APIC ID for a specific CPU index +* +* Currently we need to be able to calculate the APIC ID from the CPU index +* alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have +* no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of +* all CPUs up to max_cpus. +*/ +uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, +unsigned int cpu_index) +{ +MachineState *ms =MACHINE (pcms); +PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); +uint32_t correct_id; +static bool warned; + + correct_id =x86_apicid_from_cpu_idx (pcms->smp_dies, ms->smp.cores, + ms->smp.threads, cpu_index); +if (pcmc->compat_apic_id_mode) { +if (cpu_index != correct_id && !warned && !qtest_enabled ()) { +error_report ("APIC IDs set in compatibility mode, " +"CPU topology won't match the configuration" ); + warned = true; + } +return cpu_index; + }else { +return correct_id; + } +} + +void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp) +{ +Object *cpu =NULL ; +Error *local_err =NULL ; +CPUX86State *env =NULL ; + + cpu =object_new (MACHINE (pcms)->cpu_type); + + env = &X86_CPU (cpu)->env; + env->nr_dies = pcms->smp_dies; + +object_property_set_uint (cpu, apic_id,"apic-id" , &local_err); +object_property_set_bool (cpu, true,"realized" , &local_err); + +object_unref (cpu); +error_propagate (errp, local_err); +} + +void x86_cpus_init (PCMachineState *pcms) +{ +int i; +const CPUArchIdList *possible_cpus; +MachineState *ms =MACHINE (pcms); +MachineClass *mc =MACHINE_GET_CLASS (pcms); +PCMachineClass *pcmc =PC_MACHINE_CLASS (mc); + +x86_cpu_set_default_version (pcmc->default_cpu_version); + +/* Calculates the limit to CPU APIC ID values +* +* Limit for the APIC ID value, so that all +* CPU APIC IDs are < pcms->apic_id_limit. +* +* This is used for FW_CFG_MAX_CPUS. See comments on fw_cfg_arch_create(). +*/ + pcms->apic_id_limit =x86_cpu_apic_id_from_index (pcms, + ms->smp.max_cpus -1 ) +1 ; + possible_cpus = mc->possible_cpu_arch_ids (ms); +for (i =0 ; i < ms->smp.cpus; i++) { +x86_new_cpu (pcms, possible_cpus->cpus[i].arch_id, &error_fatal); + } +} + +CpuInstanceProperties +x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index) +{ +MachineClass *mc =MACHINE_GET_CLASS (ms); +const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids (ms); + +assert (cpu_index < possible_cpus->len); +return possible_cpus->cpus[cpu_index].props; +} + +int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx) +{ +X86CPUTopoInfo topo; +PCMachineState *pcms =PC_MACHINE (ms); + +assert (idx < ms->possible_cpus->len); +x86_topo_ids_from_apicid (ms->possible_cpus->cpus[idx].arch_id, + pcms->smp_dies, ms->smp.cores, + ms->smp.threads, &topo); +return topo.pkg_id % ms->numa_state->num_nodes; +} + +const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms) +{ +PCMachineState *pcms =PC_MACHINE (ms); +int i; +unsigned int max_cpus = ms->smp.max_cpus; + +if (ms->possible_cpus) { +/* +* make sure that max_cpus hasn't changed since the first use, i.e. +* -smp hasn't been parsed after it +*/ +assert (ms->possible_cpus->len == max_cpus); +return ms->possible_cpus; + } + + ms->possible_cpus =g_malloc0 (sizeof (CPUArchIdList) + +sizeof (CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; +for (i =0 ; i < ms->possible_cpus->len; i++) { +X86CPUTopoInfo topo; + + ms->possible_cpus->cpus[i].type = ms->cpu_type; + ms->possible_cpus->cpus[i].vcpus_count =1 ; + ms->possible_cpus->cpus[i].arch_id =x86_cpu_apic_id_from_index (pcms, i); +x86_topo_ids_from_apicid (ms->possible_cpus->cpus[i].arch_id, + pcms->smp_dies, ms->smp.cores, + ms->smp.threads, &topo); + ms->possible_cpus->cpus[i].props.has_socket_id = true; + ms->possible_cpus->cpus[i].props.socket_id = topo.pkg_id; +if (pcms->smp_dies >1 ) { + ms->possible_cpus->cpus[i].props.has_die_id = true; + ms->possible_cpus->cpus[i].props.die_id = topo.die_id; + } + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = topo.core_id; + ms->possible_cpus->cpus[i].props.has_thread_id = true; + ms->possible_cpus->cpus[i].props.thread_id = topo.smt_id; + } +return ms->possible_cpus; +} + +static long get_file_size (FILE *f) +{ +long where, size; + +/* XXX: on Unix systems, using fstat() probably makes more sense */ + + where =ftell (f); +fseek (f,0 ,SEEK_END ); + size =ftell (f); +fseek (f, where,SEEK_SET ); + +return size; +} + +struct setup_data { +uint64_t next; +uint32_t type; +uint32_t len; +uint8_t data[0 ]; +} __attribute__((packed)); + +/* +* The entry point into the kernel for PVH boot is different from +* the native entry point. The PVH entry is defined by the x86/HVM +* direct boot ABI and is available in an ELFNOTE in the kernel binary. +* +* This function is passed to load_elf() when it is called from +* load_elfboot() which then additionally checks for an ELF Note of +* type XEN_ELFNOTE_PHYS32_ENTRY and passes it to this function to +* parse the PVH entry address from the ELF Note. +* +* Due to trickery in elf_opts.h, load_elf() is actually available as +* load_elf32() or load_elf64() and this routine needs to be able +* to deal with being called as 32 or 64 bit. +* +* The address of the PVH entry point is saved to the 'pvh_start_addr' +* global variable. (although the entry point is 32-bit, the kernel +* binary can be either 32-bit or 64-bit). +*/ +static uint64_t read_pvh_start_addr (void *arg1,void *arg2,bool is64) +{ +size_t *elf_note_data_addr; + +/* Check if ELF Note header passed in is valid */ +if (arg1 ==NULL ) { +return 0 ; + } + +if (is64) { +struct elf64_note *nhdr64 = (struct elf64_note *)arg1; +uint64_t nhdr_size64 =sizeof (struct elf64_note ); +uint64_t phdr_align = *(uint64_t *)arg2; +uint64_t nhdr_namesz = nhdr64->n_namesz; + + elf_note_data_addr = + ((void *)nhdr64) + nhdr_size64 + +QEMU_ALIGN_UP (nhdr_namesz, phdr_align); + }else { +struct elf32_note *nhdr32 = (struct elf32_note *)arg1; +uint32_t nhdr_size32 =sizeof (struct elf32_note ); +uint32_t phdr_align = *(uint32_t *)arg2; +uint32_t nhdr_namesz = nhdr32->n_namesz; + + elf_note_data_addr = + ((void *)nhdr32) + nhdr_size32 + +QEMU_ALIGN_UP (nhdr_namesz, phdr_align); + } + + pvh_start_addr = *elf_note_data_addr; + +return pvh_start_addr; +} + +static bool load_elfboot (const char *kernel_filename, +int kernel_file_size, +uint8_t *header, +size_t pvh_xen_start_addr, +FWCfgState *fw_cfg) +{ +uint32_t flags =0 ; +uint32_t mh_load_addr =0 ; +uint32_t elf_kernel_size =0 ; +uint64_t elf_entry; +uint64_t elf_low, elf_high; +int kernel_size; + +if (ldl_p (header) !=0x464c457f ) { +return false;/* no elfboot */ + } + +bool elf_is64 = header[EI_CLASS ] ==ELFCLASS64 ; + flags = elf_is64 ? + ((Elf64_Ehdr *)header)->e_flags : ((Elf32_Ehdr *)header)->e_flags; + +if (flags &0x00010004 ) {/* LOAD_ELF_HEADER_HAS_ADDR */ +error_report ("elfboot unsupported flags = %x" , flags); +exit (1 ); + } + +uint64_t elf_note_type =XEN_ELFNOTE_PHYS32_ENTRY ; + kernel_size =load_elf (kernel_filename, read_pvh_start_addr, +NULL , &elf_note_type, &elf_entry, + &elf_low, &elf_high,0 ,I386_ELF_MACHINE , +0 ,0 ); + +if (kernel_size <0 ) { +error_report ("Error while loading elf kernel" ); +exit (1 ); + } + mh_load_addr = elf_low; + elf_kernel_size = elf_high - elf_low; + +if (pvh_start_addr ==0 ) { +error_report ("Error loading uncompressed kernel without PVH ELF Note" ); +exit (1 ); + } +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ENTRY , pvh_start_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , mh_load_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , elf_kernel_size); + +return true; +} + +void x86_load_linux (PCMachineState *pcms, +FWCfgState *fw_cfg) +{ +uint16_t protocol; +int setup_size, kernel_size, cmdline_size; +int dtb_size, setup_data_offset; +uint32_t initrd_max; +uint8_t header[8192 ], *setup, *kernel; +hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr =0 ; +FILE *f; +char *vmode; +MachineState *machine =MACHINE (pcms); +PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); +struct setup_data *setup_data; +const char *kernel_filename = machine->kernel_filename; +const char *initrd_filename = machine->initrd_filename; +const char *dtb_filename = machine->dtb; +const char *kernel_cmdline = machine->kernel_cmdline; + +/* Align to 16 bytes as a paranoia measure */ + cmdline_size = (strlen (kernel_cmdline)+16 ) & ~15 ; + +/* load the kernel header */ + f =fopen (kernel_filename,"rb" ); +if (!f || !(kernel_size =get_file_size (f)) || +fread (header,1 ,MIN (ARRAY_SIZE (header), kernel_size), f) != +MIN (ARRAY_SIZE (header), kernel_size)) { +fprintf (stderr,"qemu: could not load kernel '%s': %s\n" , + kernel_filename,strerror (errno)); +exit (1 ); + } + +/* kernel protocol version */ +#if 0 +fprintf (stderr,"header magic: %#x\n" ,ldl_p (header+0x202 )); +#endif +if (ldl_p (header+0x202 ) ==0x53726448 ) { + protocol =lduw_p (header+0x206 ); + }else { +/* +* This could be a multiboot kernel. If it is, let's stop treating it +* like a Linux kernel. +* Note: some multiboot images could be in the ELF format (the same of +* PVH), so we try multiboot first since we check the multiboot magic +* header before to load it. +*/ +if (load_multiboot (fw_cfg, f, kernel_filename, initrd_filename, + kernel_cmdline, kernel_size, header)) { +return ; + } +/* +* Check if the file is an uncompressed kernel file (ELF) and load it, +* saving the PVH entry point used by the x86/HVM direct boot ABI. +* If load_elfboot() is successful, populate the fw_cfg info. +*/ +if (pcmc->pvh_enabled && +load_elfboot (kernel_filename, kernel_size, + header, pvh_start_addr, fw_cfg)) { +fclose (f); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE , +strlen (kernel_cmdline) +1 ); +fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE ,sizeof (header)); +fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , + header,sizeof (header)); + +/* load initrd */ +if (initrd_filename) { +GMappedFile *mapped_file; +gsize initrd_size; +gchar *initrd_data; +GError *gerr =NULL ; + + mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); +if (!mapped_file) { +fprintf (stderr,"qemu: error reading initrd %s: %s\n" , + initrd_filename, gerr->message); +exit (1 ); + } + pcms->initrd_mapped_file = mapped_file; + + initrd_data =g_mapped_file_get_contents (mapped_file); + initrd_size =g_mapped_file_get_length (mapped_file); + initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; +if (initrd_size >= initrd_max) { +fprintf (stderr,"qemu: initrd is too large, cannot support." +"(max: %" PRIu32", need %" PRId64")\n" , + initrd_max, (uint64_t )initrd_size); +exit (1 ); + } + + initrd_addr = (initrd_max - initrd_size) & ~4095 ; + +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, + initrd_size); + } + + option_rom[nb_option_roms].bootindex =0 ; + option_rom[nb_option_roms].name ="pvh.bin" ; + nb_option_roms++; + +return ; + } + protocol =0 ; + } + +if (protocol <0x200 || !(header[0x211 ] &0x01 )) { +/* Low kernel */ + real_addr =0x90000 ; + cmdline_addr =0x9a000 - cmdline_size; + prot_addr =0x10000 ; + }else if (protocol <0x202 ) { +/* High but ancient kernel */ + real_addr =0x90000 ; + cmdline_addr =0x9a000 - cmdline_size; + prot_addr =0x100000 ; + }else { +/* High and recent kernel */ + real_addr =0x10000 ; + cmdline_addr =0x20000 ; + prot_addr =0x100000 ; + } + +#if 0 +fprintf (stderr, +"qemu: real_addr = 0x" TARGET_FMT_plx"\n" +"qemu: cmdline_addr = 0x" TARGET_FMT_plx"\n" +"qemu: prot_addr = 0x" TARGET_FMT_plx"\n" , + real_addr, + cmdline_addr, + prot_addr); +#endif + +/* highest address for loading the initrd */ +if (protocol >=0x20c && +lduw_p (header+0x236 ) &XLF_CAN_BE_LOADED_ABOVE_4G ) { +/* +* Linux has supported initrd up to 4 GB for a very long time (2007, +* long before XLF_CAN_BE_LOADED_ABOVE_4G which was added in 2013), +* though it only sets initrd_max to 2 GB to "work around bootloader +* bugs". Luckily, QEMU firmware(which does something like bootloader) +* has supported this. +* +* It's believed that if XLF_CAN_BE_LOADED_ABOVE_4G is set, initrd can +* be loaded into any address. +* +* In addition, initrd_max is uint32_t simply because QEMU doesn't +* support the 64-bit boot protocol (specifically the ext_ramdisk_image +* field). +* +* Therefore here just limit initrd_max to UINT32_MAX simply as well. +*/ + initrd_max =UINT32_MAX ; + }else if (protocol >=0x203 ) { + initrd_max =ldl_p (header+0x22c ); + }else { + initrd_max =0x37ffffff ; + } + +if (initrd_max >= pcms->below_4g_mem_size - pcmc->acpi_data_size) { + initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size -1 ; + } + +fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_ADDR , cmdline_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_CMDLINE_SIZE ,strlen (kernel_cmdline)+1 ); +fw_cfg_add_string (fw_cfg,FW_CFG_CMDLINE_DATA , kernel_cmdline); + +if (protocol >=0x202 ) { +stl_p (header+0x228 , cmdline_addr); + }else { +stw_p (header+0x20 ,0xA33F ); +stw_p (header+0x22 , cmdline_addr-real_addr); + } + +/* handle vga= parameter */ + vmode =strstr (kernel_cmdline,"vga=" ); +if (vmode) { +unsigned int video_mode; +/* skip "vga=" */ + vmode +=4 ; +if (!strncmp (vmode,"normal" ,6 )) { + video_mode =0xffff ; + }else if (!strncmp (vmode,"ext" ,3 )) { + video_mode =0xfffe ; + }else if (!strncmp (vmode,"ask" ,3 )) { + video_mode =0xfffd ; + }else { + video_mode =strtol (vmode,NULL ,0 ); + } +stw_p (header+0x1fa , video_mode); + } + +/* loader type */ +/* High nybble = B reserved for QEMU; low nybble is revision number. +If this code is substantially changed, you may want to consider +incrementing the revision. */ +if (protocol >=0x200 ) { + header[0x210 ] =0xB0 ; + } +/* heap */ +if (protocol >=0x201 ) { + header[0x211 ] |=0x80 ;/* CAN_USE_HEAP */ +stw_p (header+0x224 , cmdline_addr-real_addr-0x200 ); + } + +/* load initrd */ +if (initrd_filename) { +GMappedFile *mapped_file; +gsize initrd_size; +gchar *initrd_data; +GError *gerr =NULL ; + +if (protocol <0x200 ) { +fprintf (stderr,"qemu: linux kernel too old to load a ram disk\n" ); +exit (1 ); + } + + mapped_file =g_mapped_file_new (initrd_filename, false, &gerr); +if (!mapped_file) { +fprintf (stderr,"qemu: error reading initrd %s: %s\n" , + initrd_filename, gerr->message); +exit (1 ); + } + pcms->initrd_mapped_file = mapped_file; + + initrd_data =g_mapped_file_get_contents (mapped_file); + initrd_size =g_mapped_file_get_length (mapped_file); +if (initrd_size >= initrd_max) { +fprintf (stderr,"qemu: initrd is too large, cannot support." +"(max: %" PRIu32", need %" PRId64")\n" , + initrd_max, (uint64_t )initrd_size); +exit (1 ); + } + + initrd_addr = (initrd_max-initrd_size) & ~4095 ; + +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_ADDR , initrd_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_INITRD_SIZE , initrd_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_INITRD_DATA , initrd_data, initrd_size); + +stl_p (header+0x218 , initrd_addr); +stl_p (header+0x21c , initrd_size); + } + +/* load kernel and setup */ + setup_size = header[0x1f1 ]; +if (setup_size ==0 ) { + setup_size =4 ; + } + setup_size = (setup_size+1 )*512 ; +if (setup_size > kernel_size) { +fprintf (stderr,"qemu: invalid kernel header\n" ); +exit (1 ); + } + kernel_size -= setup_size; + + setup =g_malloc (setup_size); + kernel =g_malloc (kernel_size); +fseek (f,0 ,SEEK_SET ); +if (fread (setup,1 , setup_size, f) != setup_size) { +fprintf (stderr,"fread() failed\n" ); +exit (1 ); + } +if (fread (kernel,1 , kernel_size, f) != kernel_size) { +fprintf (stderr,"fread() failed\n" ); +exit (1 ); + } +fclose (f); + +/* append dtb to kernel */ +if (dtb_filename) { +if (protocol <0x209 ) { +fprintf (stderr,"qemu: Linux kernel too old to load a dtb\n" ); +exit (1 ); + } + + dtb_size =get_image_size (dtb_filename); +if (dtb_size <=0 ) { +fprintf (stderr,"qemu: error reading dtb %s: %s\n" , + dtb_filename,strerror (errno)); +exit (1 ); + } + + setup_data_offset =QEMU_ALIGN_UP (kernel_size,16 ); + kernel_size = setup_data_offset +sizeof (struct setup_data ) + dtb_size; + kernel =g_realloc (kernel, kernel_size); + +stq_p (header+0x250 , prot_addr + setup_data_offset); + + setup_data = (struct setup_data *)(kernel + setup_data_offset); + setup_data->next =0 ; + setup_data->type =cpu_to_le32 (SETUP_DTB ); + setup_data->len =cpu_to_le32 (dtb_size); + +load_image_size (dtb_filename, setup_data->data, dtb_size); + } + +memcpy (setup, header,MIN (sizeof (header), setup_size)); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_ADDR , prot_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_KERNEL_SIZE , kernel_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_KERNEL_DATA , kernel, kernel_size); + +fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_ADDR , real_addr); +fw_cfg_add_i32 (fw_cfg,FW_CFG_SETUP_SIZE , setup_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_SETUP_DATA , setup, setup_size); + + option_rom[nb_option_roms].bootindex =0 ; + option_rom[nb_option_roms].name ="linuxboot.bin" ; +if (pcmc->linuxboot_dma_enabled &&fw_cfg_dma_enabled (fw_cfg)) { + option_rom[nb_option_roms].name ="linuxboot_dma.bin" ; + } + nb_option_roms++; +} + +void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw) +{ +char *filename; +MemoryRegion *bios, *isa_bios; +int bios_size, isa_bios_size; +int ret; + +/* BIOS load */ +if (bios_name ==NULL ) { + bios_name =BIOS_FILENAME ; + } + filename =qemu_find_file (QEMU_FILE_TYPE_BIOS , bios_name); +if (filename) { + bios_size =get_image_size (filename); + }else { + bios_size =-1 ; + } +if (bios_size <=0 || + (bios_size %65536 ) !=0 ) { + goto bios_error; + } + bios =g_malloc (sizeof (*bios)); +memory_region_init_ram (bios,NULL ,"pc.bios" , bios_size, &error_fatal); +if (!isapc_ram_fw) { +memory_region_set_readonly (bios, true); + } + ret =rom_add_file_fixed (bios_name, (uint32_t )(-bios_size),-1 ); +if (ret !=0 ) { + bios_error: +fprintf (stderr,"qemu: could not load PC BIOS '%s'\n" , bios_name); +exit (1 ); + } +g_free (filename); + +/* map the last 128KB of the BIOS in ISA space */ + isa_bios_size =MIN (bios_size,128 * KiB); + isa_bios =g_malloc (sizeof (*isa_bios)); +memory_region_init_alias (isa_bios,NULL ,"isa-bios" , bios, + bios_size - isa_bios_size, isa_bios_size); +memory_region_add_subregion_overlap (rom_memory, +0x100000 - isa_bios_size, + isa_bios, +1 ); +if (!isapc_ram_fw) { +memory_region_set_readonly (isa_bios, true); + } + +/* map all the bios at the top of memory */ +memory_region_add_subregion (rom_memory, + (uint32_t )(-bios_size), + bios); +}include/hw/i386/pc.h +0
-0@@ -195,7 +195,6 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);void pc_register_ferr_irq (qemu_irq irq);void pc_acpi_smi_interrupt (void *opaque,int irq,int level); -void x86_cpus_init(PCMachineState *pcms);void pc_hot_add_cpu (MachineState *ms,const int64_t id,Error **errp);void pc_smp_parse (MachineState *ms,QemuOpts *opts); diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.hnew file mode 100644
index 0000000000..bc1b594a93include/hw/i386/x86.h new file +35
-0@@ -0,0 +1,35 @@ +/* +* Copyright (c) 2019 Red Hat, Inc. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2 or later, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along with +* this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef HW_I386_X86_H +#define HW_I386_X86_H + +#include "hw/boards.h" + +uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, +unsigned int cpu_index); +void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp); +void x86_cpus_init (PCMachineState *pcms); +CpuInstanceProperties x86_cpu_index_to_props (MachineState *ms, +unsigned cpu_index); +int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx); +const CPUArchIdList *x86_possible_cpu_arch_ids (MachineState *ms); + +void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw); + +void x86_load_linux (PCMachineState *x86ms,FWCfgState *fw_cfg); + +#endif
PATCH v5 4/10 hw/i386: split PCMachineState deriving X86MachineState from it
In reply to Sergio LopezSplit up PCMachineState and PCMachineClass and derive X86MachineState and X86MachineClass from them. This allows sharing code with non-PC x86 machine types.
--- hw/acpi/cpu_hotplug.c | 10 +-- hw/i386/acpi-build.c | 29 ++++--- hw/i386/amd_iommu.c | 3 +- hw/i386/intel_iommu.c | 3 +- hw/i386/pc.c | 178 ++++++++++++++---------------------------- hw/i386/pc_piix.c | 43 +++++----- hw/i386/pc_q35.c | 35 +++++---- hw/i386/x86.c | 139 +++++++++++++++++++++++++++++---- hw/intc/ioapic.c | 2 +- include/hw/i386/pc.h | 27 +------ include/hw/i386/x86.h | 56 ++++++++++++- 11 files changed, 308 insertions(+), 217 deletions(-)
hw/acpi/cpu_hotplug.c +5 -5
@@ -128,7 +128,7 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,Aml *one =aml_int (1 );MachineClass *mc =MACHINE_GET_CLASS (machine);const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids (machine); -PCMachineState *pcms =PC_MACHINE (machine); +X86MachineState *x86ms =X86_MACHINE (machine);/* * _MAT method - creates an madt apic buffer
@@ -236,9 +236,9 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,/* The current AML generator can cover the APIC ID range [0..255], * inclusive, for VCPU hotplug. */ QEMU_BUILD_BUG_ON (ACPI_CPU_HOTPLUG_ID_LIMIT >256 ); -if (pcms->apic_id_limit >ACPI_CPU_HOTPLUG_ID_LIMIT ) { +if (x86ms->apic_id_limit >ACPI_CPU_HOTPLUG_ID_LIMIT ) {error_report ("max_cpus is too large. APIC ID of last CPU is %u" , - pcms->apic_id_limit -1 ); + x86ms->apic_id_limit -1 );exit (1 ); }
@@ -315,8 +315,8 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineState *machine,* ith up to 255 elements. Windows guests up to win2k8 fail when * VarPackageOp is used. */ - pkg = pcms->apic_id_limit <=255 ?aml_package (pcms->apic_id_limit) : -aml_varpackage (pcms->apic_id_limit); + pkg = x86ms->apic_id_limit <=255 ?aml_package (x86ms->apic_id_limit) : +aml_varpackage (x86ms->apic_id_limit);for (i =0 , apic_idx =0 ; i < apic_ids->len; i++) {int apic_id = apic_ids->cpus[i].arch_id;
hw/i386/acpi-build.c +17 -12
@@ -361,6 +361,7 @@ static void build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) {MachineClass *mc =MACHINE_GET_CLASS (pcms); +X86MachineState *x86ms =X86_MACHINE (pcms);const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids (MACHINE (pcms));int madt_start = table_data->len;AcpiDeviceIfClass *adevc =ACPI_DEVICE_IF_GET_CLASS (pcms->acpi_dev);
@@ -390,7 +391,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) io_apic->address =cpu_to_le32 (IO_APIC_DEFAULT_ADDRESS ); io_apic->interrupt =cpu_to_le32 (0 ); -if (pcms->apic_xrupt_override) { +if (x86ms->apic_xrupt_override) { intsrcovr =acpi_data_push (table_data,sizeof *intsrcovr); intsrcovr->type =ACPI_APIC_XRUPT_OVERRIDE ; intsrcovr->length =sizeof (*intsrcovr);
@@ -1831,6 +1832,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,CrsRangeSet crs_range_set;PCMachineState *pcms =PC_MACHINE (machine);PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (machine); +X86MachineState *x86ms =X86_MACHINE (machine);AcpiMcfgInfo mcfg;uint32_t nr_mem = machine->ram_slots;int root_bus_limit =0xFF ;
@@ -2098,7 +2100,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,* with half of the 16-bit control register. Hence, the total size * of the i/o region used is FW_CFG_CTL_SIZE; when using DMA, the * DMA control register is located at FW_CFG_DMA_IO_BASE + 4 */ -uint8_t io_size =object_property_get_bool (OBJECT (pcms->fw_cfg), +uint8_t io_size =object_property_get_bool (OBJECT (x86ms->fw_cfg),"dma_enabled" ,NULL ) ?ROUND_UP (FW_CFG_CTL_SIZE ,4 ) +sizeof (dma_addr_t) :FW_CFG_CTL_SIZE ;
@@ -2331,6 +2333,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)int srat_start, numa_start, slots;uint64_t mem_len, mem_base, next_base;MachineClass *mc =MACHINE_GET_CLASS (machine); +X86MachineState *x86ms =X86_MACHINE (machine);const CPUArchIdList *apic_ids = mc->possible_cpu_arch_ids (machine);PCMachineState *pcms =PC_MACHINE (machine); ram_addr_t hotplugabble_address_space_size =
@@ -2401,16 +2404,16 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine) }/* Cut out the ACPI_PCI hole */ -if (mem_base <= pcms->below_4g_mem_size && - next_base > pcms->below_4g_mem_size) { - mem_len -= next_base - pcms->below_4g_mem_size; +if (mem_base <= x86ms->below_4g_mem_size && + next_base > x86ms->below_4g_mem_size) { + mem_len -= next_base - x86ms->below_4g_mem_size;if (mem_len >0 ) { numamem =acpi_data_push (table_data,sizeof *numamem);build_srat_memory (numamem, mem_base, mem_len, i -1 ,MEM_AFFINITY_ENABLED ); } mem_base =1ULL <<32 ; - mem_len = next_base - pcms->below_4g_mem_size; + mem_len = next_base - x86ms->below_4g_mem_size; next_base = mem_base + mem_len; }
@@ -2629,6 +2632,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine) {PCMachineState *pcms =PC_MACHINE (machine);PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); +X86MachineState *x86ms =X86_MACHINE (machine);GArray *table_offsets;unsigned facs, dsdt, rsdt, fadt;AcpiPmInfo pm;
@@ -2790,7 +2794,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)*/ int legacy_aml_len = pcmc->legacy_acpi_table_size + -ACPI_BUILD_LEGACY_CPU_AML_SIZE * pcms->apic_id_limit; +ACPI_BUILD_LEGACY_CPU_AML_SIZE * x86ms->apic_id_limit;int legacy_table_size =ROUND_UP (tables_blob->len - aml_len + legacy_aml_len,ACPI_BUILD_ALIGN_SIZE );
@@ -2880,13 +2884,14 @@ void acpi_setup(void) {PCMachineState *pcms =PC_MACHINE (qdev_get_machine ());PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); +X86MachineState *x86ms =X86_MACHINE (pcms);AcpiBuildTables tables;AcpiBuildState *build_state;Object *vmgenid_dev;TPMIf *tpm;static FwCfgTPMConfig tpm_config; -if (!pcms->fw_cfg) { +if (!x86ms->fw_cfg) {ACPI_BUILD_DPRINTF ("No fw cfg. Bailing out.\n" );return ; }
@@ -2917,7 +2922,7 @@ void acpi_setup(void)acpi_add_rom_blob (acpi_build_update, build_state, tables.linker->cmd_blob,"etc/table-loader" ,0 ); -fw_cfg_add_file (pcms->fw_cfg,ACPI_BUILD_TPMLOG_FILE , +fw_cfg_add_file (x86ms->fw_cfg,ACPI_BUILD_TPMLOG_FILE , tables.tcpalog->data,acpi_data_len (tables.tcpalog)); tpm =tpm_find ();
@@ -2927,13 +2932,13 @@ void acpi_setup(void) .tpm_version = tpm_get_version(tpm), .tpmppi_version = TPM_PPI_VERSION_1_30 }; -fw_cfg_add_file (pcms->fw_cfg,"etc/tpm/config" , +fw_cfg_add_file (x86ms->fw_cfg,"etc/tpm/config" , &tpm_config,sizeof tpm_config); } vmgenid_dev =find_vmgenid_dev ();if (vmgenid_dev) { -vmgenid_add_fw_cfg (VMGENID (vmgenid_dev), pcms->fw_cfg, +vmgenid_add_fw_cfg (VMGENID (vmgenid_dev), x86ms->fw_cfg, tables.vmgenid); }
@@ -2946,7 +2951,7 @@ void acpi_setup(void)uint32_t rsdp_size =acpi_data_len (tables.rsdp); build_state->rsdp =g_memdup (tables.rsdp->data, rsdp_size); -fw_cfg_add_file_callback (pcms->fw_cfg,ACPI_BUILD_RSDP_FILE , +fw_cfg_add_file_callback (x86ms->fw_cfg,ACPI_BUILD_RSDP_FILE , acpi_build_update,NULL , build_state, build_state->rsdp, rsdp_size, true); build_state->rsdp_mr =NULL ;
hw/i386/amd_iommu.c +2 -1
@@ -1537,6 +1537,7 @@ static void amdvi_realize(DeviceState *dev, Error **err)X86IOMMUState *x86_iommu =X86_IOMMU_DEVICE (dev);MachineState *ms =MACHINE (qdev_get_machine ());PCMachineState *pcms =PC_MACHINE (ms); +X86MachineState *x86ms =X86_MACHINE (ms);PCIBus *bus = pcms->bus; s->iotlb = g_hash_table_new_full(amdvi_uint64_hash,
@@ -1565,7 +1566,7 @@ static void amdvi_realize(DeviceState *dev, Error **err) }/* Pseudo address space under root PCI bus. */ - pcms->ioapic_as =amdvi_host_dma_iommu (bus, s,AMDVI_IOAPIC_SB_DEVID ); + x86ms->ioapic_as =amdvi_host_dma_iommu (bus, s,AMDVI_IOAPIC_SB_DEVID );/* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
hw/i386/intel_iommu.c +2 -1
@@ -3731,6 +3731,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) {MachineState *ms =MACHINE (qdev_get_machine ());PCMachineState *pcms =PC_MACHINE (ms); +X86MachineState *x86ms =X86_MACHINE (ms);PCIBus *bus = pcms->bus;IntelIOMMUState *s =INTEL_IOMMU_DEVICE (dev);X86IOMMUState *x86_iommu =X86_IOMMU_DEVICE (dev);
@@ -3771,7 +3772,7 @@ static void vtd_realize(DeviceState *dev, Error **errp)sysbus_mmio_map (SYS_BUS_DEVICE (s),0 ,Q35_HOST_BRIDGE_IOMMU_ADDR );pci_setup_iommu (bus, vtd_host_dma_iommu, dev);/* Pseudo address space under root PCI bus. */ - pcms->ioapic_as =vtd_host_dma_iommu (bus, s,Q35_PSEUDO_DEVFN_IOAPIC ); + x86ms->ioapic_as =vtd_host_dma_iommu (bus, s,Q35_PSEUDO_DEVFN_IOAPIC );qemu_add_machine_init_done_notifier (&vtd_machine_done_notify); }
hw/i386/pc.c +59 -119
454 lines not on this page · raw message
hw/i386/pc_piix.c +22 -21
124 lines not on this page · raw message
hw/i386/pc_q35.c +18 -17
@@ -116,6 +116,7 @@ static void pc_q35_init(MachineState *machine) {PCMachineState *pcms =PC_MACHINE (machine);PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms); +X86MachineState *x86ms =X86_MACHINE (machine);Q35PCIHost *q35_host;PCIHostState *phb;PCIBus *host_bus;
@@ -153,27 +154,27 @@ static void pc_q35_init(MachineState *machine)/* Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). */ -if (!pcms->max_ram_below_4g) { - pcms->max_ram_below_4g =1ULL <<32 ;/* default: 4G */ ; +if (!x86ms->max_ram_below_4g) { + x86ms->max_ram_below_4g =1ULL <<32 ;/* default: 4G */ ; } -if (lowmem > pcms->max_ram_below_4g) { - lowmem = pcms->max_ram_below_4g; +if (lowmem > x86ms->max_ram_below_4g) { + lowmem = x86ms->max_ram_below_4g;if (machine->ram_size - lowmem > lowmem && lowmem & (1 * GiB -1 )) {warn_report ("There is possibly poor performance as the ram size " " (0x%" PRIx64") is more then twice the size of" " max-ram-below-4g (%" PRIu64") and" " max-ram-below-4g is not a multiple of 1G." , - (uint64_t )machine->ram_size, pcms->max_ram_below_4g); + (uint64_t )machine->ram_size, x86ms->max_ram_below_4g); } }if (machine->ram_size >= lowmem) { - pcms->above_4g_mem_size = machine->ram_size - lowmem; - pcms->below_4g_mem_size = lowmem; + x86ms->above_4g_mem_size = machine->ram_size - lowmem; + x86ms->below_4g_mem_size = lowmem; }else { - pcms->above_4g_mem_size =0 ; - pcms->below_4g_mem_size = machine->ram_size; + x86ms->above_4g_mem_size =0 ; + x86ms->below_4g_mem_size = machine->ram_size; }if (xen_enabled ()) {
@@ -214,10 +215,10 @@ static void pc_q35_init(MachineState *machine) gsi_state =g_malloc0 (sizeof (*gsi_state));if (kvm_ioapic_in_kernel ()) {kvm_pc_setup_irq_routing (pcmc->pci_enabled); - pcms->gsi =qemu_allocate_irqs (kvm_pc_gsi_handler, gsi_state, + x86ms->gsi =qemu_allocate_irqs (kvm_pc_gsi_handler, gsi_state,GSI_NUM_PINS ); }else { - pcms->gsi =qemu_allocate_irqs (gsi_handler, gsi_state,GSI_NUM_PINS ); + x86ms->gsi =qemu_allocate_irqs (gsi_handler, gsi_state,GSI_NUM_PINS ); }/* create pci host bus */
@@ -232,9 +233,9 @@ static void pc_q35_init(MachineState *machine) MCH_HOST_PROP_SYSTEM_MEM, NULL);object_property_set_link (OBJECT (q35_host),OBJECT (system_io),MCH_HOST_PROP_IO_MEM ,NULL ); -object_property_set_int (OBJECT (q35_host), pcms->below_4g_mem_size, +object_property_set_int (OBJECT (q35_host), x86ms->below_4g_mem_size,PCI_HOST_BELOW_4G_MEM_SIZE ,NULL ); -object_property_set_int (OBJECT (q35_host), pcms->above_4g_mem_size, +object_property_set_int (OBJECT (q35_host), x86ms->above_4g_mem_size,PCI_HOST_ABOVE_4G_MEM_SIZE ,NULL );/* pci */ qdev_init_nofail (DEVICE (q35_host));
@@ -256,7 +257,7 @@ static void pc_q35_init(MachineState *machine) ich9_lpc =ICH9_LPC_DEVICE (lpc); lpc_dev =DEVICE (lpc);for (i =0 ; i <GSI_NUM_PINS ; i++) { -qdev_connect_gpio_out_named (lpc_dev,ICH9_GPIO_GSI , i, pcms->gsi[i]); +qdev_connect_gpio_out_named (lpc_dev,ICH9_GPIO_GSI , i, x86ms->gsi[i]); }pci_bus_irqs (host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,ICH9_LPC_NB_PIRQS );
@@ -280,7 +281,7 @@ static void pc_q35_init(MachineState *machine)ioapic_init_gsi (gsi_state,"q35" ); } -pc_register_ferr_irq (pcms->gsi[13 ]); +pc_register_ferr_irq (x86ms->gsi[13 ]);assert (pcms->vmport !=ON_OFF_AUTO__MAX );if (pcms->vmport ==ON_OFF_AUTO_AUTO ) {
@@ -288,7 +289,7 @@ static void pc_q35_init(MachineState *machine) }/* init basic PC hardware */ -pc_basic_device_init (isa_bus, pcms->gsi, &rtc_state, !mc->no_floppy, +pc_basic_device_init (isa_bus, x86ms->gsi, &rtc_state, !mc->no_floppy, (pcms->vmport !=ON_OFF_AUTO_ON ), pcms->pit_enabled,0xff0104 );
@@ -331,7 +332,7 @@ static void pc_q35_init(MachineState *machine)if (machine->nvdimms_state->is_enabled) {nvdimm_init_acpi_state (machine->nvdimms_state, system_io, - pcms->fw_cfg,OBJECT (pcms)); + x86ms->fw_cfg,OBJECT (pcms)); } }
hw/i386/x86.c +124 -15
231 lines not on this page · raw message
hw/intc/ioapic.c +1 -1
@@ -89,7 +89,7 @@ static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)static void ioapic_service (IOAPICCommonState *s) { -AddressSpace *ioapic_as =PC_MACHINE (qdev_get_machine ())->ioapic_as; +AddressSpace *ioapic_as =X86_MACHINE (qdev_get_machine ())->ioapic_as;struct ioapic_entry_info info;uint8_t i;uint32_t mask;
include/hw/i386/pc.h +3 -24
@@ -8,6 +8,7 @@#include "hw/block/flash.h" #include "net/net.h" #include "hw/i386/ioapic.h" +#include "hw/i386/x86.h" #include "qemu/range.h" #include "qemu/bitmap.h"
@@ -27,7 +28,7 @@*/ struct PCMachineState {/*< private >*/ -MachineState parent_obj; +X86MachineState parent_obj;/* <public> */
@@ -36,16 +37,11 @@ struct PCMachineState {/* Pointers to devices and objects: */ HotplugHandler *acpi_dev; -ISADevice *rtc;PCIBus *bus;I2CBus *smbus; -FWCfgState *fw_cfg; -qemu_irq *gsi;PFlashCFI01 *flash[2 ]; -GMappedFile *initrd_mapped_file;/* Configuration options: */ -uint64_t max_ram_below_4g;OnOffAuto vmport;OnOffAuto smm;
@@ -54,27 +50,13 @@ struct PCMachineState {bool sata_enabled;bool pit_enabled; -/* RAM information (sizes, addresses, configuration): */ -ram_addr_t below_4g_mem_size, above_4g_mem_size; - -/* CPU and apic information: */ -bool apic_xrupt_override; -unsigned apic_id_limit; -uint16_t boot_cpus; -unsigned smp_dies; -/* NUMA information: */ uint64_t numa_nodes;uint64_t *node_mem; - -/* Address space used by IOAPIC device. All IOAPIC interrupts -* will be translated to MSI messages in the address space. */ -AddressSpace *ioapic_as; };#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"#define PC_MACHINE_DEVMEM_REGION_SIZE "device-memory-region-size" -#define PC_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g"#define PC_MACHINE_VMPORT "vmport"#define PC_MACHINE_SMM "smm"#define PC_MACHINE_SMBUS "smbus"
@@ -99,7 +81,7 @@ struct PCMachineState {*/ typedef struct PCMachineClass { /*< private >*/ - MachineClass parent_class; + X86MachineClass parent_class; /*< public >*/
@@ -141,9 +123,6 @@ typedef struct PCMachineClass {/* use PVH to load kernels that support this feature */ bool pvh_enabled; - -/* Enables contiguous-apic-ID mode */ -bool compat_apic_id_mode; } PCMachineClass;#define TYPE_PC_MACHINE "generic-pc-machine"
include/hw/i386/x86.h +55 -1
68 lines not on this page · raw message
Signature · 1 line
2.21.0
Re: [PATCH v5 04/10] hw/i386: split PCMachineState deriving X86MachineState from it
Hi Sergio,
Quoted 19 lines · Sergio Lopez
Split up PCMachineState and PCMachineClass and derive X86MachineState and X86MachineClass from them. This allows sharing code with non-PC x86 machine types.
Signed-off-by Sergio Lopez <[email protected]>--- hw/acpi/cpu_hotplug.c | 10 +-- hw/i386/acpi-build.c | 29 ++++--- hw/i386/amd_iommu.c | 3 +- hw/i386/intel_iommu.c | 3 +- hw/i386/pc.c | 178 ++++++++++++++---------------------------- hw/i386/pc_piix.c | 43 +++++----- hw/i386/pc_q35.c | 35 +++++---- hw/i386/x86.c | 139 +++++++++++++++++++++++++++++---- hw/intc/ioapic.c | 2 +- include/hw/i386/pc.h | 27 +------ include/hw/i386/x86.h | 56 ++++++++++++- 11 files changed, 308 insertions(+), 217 deletions(-)
[...]
Quoted 68 lines
include/hw/i386/x86.h +54
-0@@ -17,7 +17,61 @@#ifndef HW_I386_X86_H #define HW_I386_X86_H +#include "qemu-common.h" +#include "exec/hwaddr.h" +#include "qemu/notify.h" +#include "hw/boards.h" +#include "hw/nmi.h" + +typedef struct { +/*< private >*/ +MachineClass parent; + +/*< public >*/ + +/* Enables contiguous-apic-ID mode */ +bool compat_apic_id_mode; +}X86MachineClass ; + +typedef struct { +/*< private >*/ +MachineState parent; + +/*< public >*/ + +/* Pointers to devices and objects: */ +ISADevice *rtc; +FWCfgState *fw_cfg; +qemu_irq *gsi; +GMappedFile *initrd_mapped_file; + +/* Configuration options: */ +uint64_t max_ram_below_4g; + +/* RAM information (sizes, addresses, configuration): */ +ram_addr_t below_4g_mem_size, above_4g_mem_size; + +/* CPU and apic information: */ +bool apic_xrupt_override; +unsigned apic_id_limit; +uint16_t boot_cpus; +unsigned smp_dies; + +/* Address space used by IOAPIC device. All IOAPIC interrupts +* will be translated to MSI messages in the address space. */ +AddressSpace *ioapic_as; +}X86MachineState ; + +#define X86_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g" + +#define TYPE_X86_MACHINE MACHINE_TYPE_NAME("x86") +#define X86_MACHINE (obj) \ + OBJECT_CHECK(X86MachineState, (obj), TYPE_X86_MACHINE) +#define X86_MACHINE_GET_CLASS (obj) \ + OBJECT_GET_CLASS(X86MachineClass, obj, TYPE_X86_MACHINE) +#define X86_MACHINE_CLASS (class) \ + OBJECT_CLASS_CHECK(X86MachineClass, class, TYPE_X86_MACHINE)uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms,unsigned int cpu_index);
include/hw/i386/x86.h const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms); · line 89
Quoted 7 lines
include/hw/i386/x86.h +1
-1@@ -30,6 +84,6 @@ const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms);void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw); -void x86_load_linux (PCMachineState *x86ms,FWCfgState *fw_cfg); +void x86_load_linux (PCMachineState *pcms,FWCfgState *fw_cfg);#endif
You forgot to update Xen:
hw/i386/xen/xen-hvm.c: In function ‘xen_ram_init’:hw/i386/xen/xen-hvm.c:203:53: error: ‘PC_MACHINE_MAX_RAM_BELOW_4G’ undeclared (first use in this function); did you mean ‘X86_MACHINE_MAX_RAM_BELOW_4G’?
PC_MACHINE_MAX_RAM_BELOW_4G,
^~~~~~~~~~~~~~~~~~~~~~~~~~~
X86_MACHINE_MAX_RAM_BELOW_4Ghw/i386/xen/xen-hvm.c:203:53: note: each undeclared identifier is reported only once for each function it appears in hw/i386/xen/xen-hvm.c:217:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’
pcms->above_4g_mem_size = ram_size - user_lowmem;
^~
hw/i386/xen/xen-hvm.c:218:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘below_4g_mem_size’
pcms->below_4g_mem_size = user_lowmem;
^~
hw/i386/xen/xen-hvm.c:220:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’
pcms->above_4g_mem_size = 0;
^~
hw/i386/xen/xen-hvm.c:221:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘below_4g_mem_size’
pcms->below_4g_mem_size = ram_size;
^~
hw/i386/xen/xen-hvm.c:223:14: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’
if (!pcms->above_4g_mem_size) {
^~
hw/i386/xen/xen-hvm.c:230:40: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’
block_len = (1ULL << 32) + pcms->above_4g_mem_size;
^~
hw/i386/xen/xen-hvm.c:247:34: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘below_4g_mem_size’
pcms->below_4g_mem_size - 0xc0000);
^~
hw/i386/xen/xen-hvm.c:249:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’
if (pcms->above_4g_mem_size > 0) {
^~
hw/i386/xen/xen-hvm.c:252:38: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’
pcms->above_4g_mem_size);
^~make[1]: *** [rules.mak:69: hw/i386/xen/xen-hvm.o] Error 1
Re: [PATCH v5 04/10] hw/i386: split PCMachineState deriving X86MachineState from it
Quoted 145 lines · Philippe Mathieu-Daudé
Hi Sergio,
Quoted 19 lines · Sergio Lopez
Split up PCMachineState and PCMachineClass and derive X86MachineState and X86MachineClass from them. This allows sharing code with non-PC x86 machine types.
Signed-off-by Sergio Lopez <[email protected]>--- hw/acpi/cpu_hotplug.c | 10 +-- hw/i386/acpi-build.c | 29 ++++--- hw/i386/amd_iommu.c | 3 +- hw/i386/intel_iommu.c | 3 +- hw/i386/pc.c | 178 ++++++++++++++---------------------------- hw/i386/pc_piix.c | 43 +++++----- hw/i386/pc_q35.c | 35 +++++---- hw/i386/x86.c | 139 +++++++++++++++++++++++++++++---- hw/intc/ioapic.c | 2 +- include/hw/i386/pc.h | 27 +------ include/hw/i386/x86.h | 56 ++++++++++++- 11 files changed, 308 insertions(+), 217 deletions(-)[...]
Quoted 65 lines
include/hw/i386/x86.h +53
-0@@ -17,7 +17,61 @@#ifndef HW_I386_X86_H #define HW_I386_X86_H +#include "qemu-common.h" +#include "exec/hwaddr.h" +#include "qemu/notify.h" +#include "hw/boards.h" +#include "hw/nmi.h" + +typedef struct { +/*< private >*/ +MachineClass parent; + +/*< public >*/ + +/* Enables contiguous-apic-ID mode */ +bool compat_apic_id_mode; +}X86MachineClass ; + +typedef struct { +/*< private >*/ +MachineState parent; + +/*< public >*/ + +/* Pointers to devices and objects: */ +ISADevice *rtc; +FWCfgState *fw_cfg; +qemu_irq *gsi; +GMappedFile *initrd_mapped_file; + +/* Configuration options: */ +uint64_t max_ram_below_4g; + +/* RAM information (sizes, addresses, configuration): */ +ram_addr_t below_4g_mem_size, above_4g_mem_size; + +/* CPU and apic information: */ +bool apic_xrupt_override; +unsigned apic_id_limit; +uint16_t boot_cpus; +unsigned smp_dies; + +/* Address space used by IOAPIC device. All IOAPIC interrupts +* will be translated to MSI messages in the address space. */ +AddressSpace *ioapic_as; +}X86MachineState ; + +#define X86_MACHINE_MAX_RAM_BELOW_4G "max-ram-below-4g" + +#define TYPE_X86_MACHINE MACHINE_TYPE_NAME("x86") +#define X86_MACHINE (obj) \ + OBJECT_CHECK(X86MachineState, (obj), TYPE_X86_MACHINE) +#define X86_MACHINE_GET_CLASS (obj) \ + OBJECT_GET_CLASS(X86MachineClass, obj, TYPE_X86_MACHINE) +#define X86_MACHINE_CLASS (class) \ + OBJECT_CLASS_CHECK(X86MachineClass, class, TYPE_X86_MACHINE)uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms,unsigned int cpu_index);include/hw/i386/x86.h const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms); · line 89
Quoted 6 lines
include/hw/i386/x86.h +1
-0@@ -30,6 +84,6 @@ const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms);void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw); -void x86_load_linux(PCMachineState *x86ms, FWCfgState *fw_cfg); +void x86_load_linux (PCMachineState *pcms,FWCfgState *fw_cfg);#endif You forgot to update Xen:
hw/i386/xen/xen-hvm.c: In function ‘xen_ram_init’:hw/i386/xen/xen-hvm.c:203:53: error: ‘PC_MACHINE_MAX_RAM_BELOW_4G’ undeclared (first use in this function); did you mean ‘X86_MACHINE_MAX_RAM_BELOW_4G’?
PC_MACHINE_MAX_RAM_BELOW_4G,^~~~~~~~~~~~~~~~~~~~~~~~~~~
X86_MACHINE_MAX_RAM_BELOW_4Ghw/i386/xen/xen-hvm.c:203:53: note: each undeclared identifier is reported only once for each function it appears inhw/i386/xen/xen-hvm.c:217:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’pcms->above_4g_mem_size = ram_size - user_lowmem; ^~ hw/i386/xen/xen-hvm.c:218:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘below_4g_mem_size’ pcms->below_4g_mem_size = user_lowmem; ^~ hw/i386/xen/xen-hvm.c:220:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’ pcms->above_4g_mem_size = 0; ^~ hw/i386/xen/xen-hvm.c:221:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘below_4g_mem_size’ pcms->below_4g_mem_size = ram_size; ^~ hw/i386/xen/xen-hvm.c:223:14: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’ if (!pcms->above_4g_mem_size) { ^~ hw/i386/xen/xen-hvm.c:230:40: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’ block_len = (1ULL << 32) + pcms->above_4g_mem_size; ^~ hw/i386/xen/xen-hvm.c:247:34: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘below_4g_mem_size’ pcms->below_4g_mem_size - 0xc0000); ^~ hw/i386/xen/xen-hvm.c:249:13: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’ if (pcms->above_4g_mem_size > 0) { ^~ hw/i386/xen/xen-hvm.c:252:38: error: ‘PCMachineState’ {aka ‘struct PCMachineState’} has no member named ‘above_4g_mem_size’ pcms->above_4g_mem_size); ^~
Quoted 1 line
make[1]: *** [rules.mak:69:
hw/i386/xen/xen-hvm.o] Error 1
Ouch, turns out I forgot to install xen-devel when I renewed the VM that I'm using for this project.
I'll fix it right now.
Thanks,
Sergio.
PATCH v5 5/10 hw/i386: make x86.c independent from PCMachineState
In reply to Sergio LopezAs a last step into splitting PCMachineState and deriving X86MachineState from it, make the functions previously extracted from pc.c to x86.c independent from PCMachineState, using X86MachineState instead.
--- hw/i386/pc.c | 13 +++++++----- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- hw/i386/x86.c | 48 ++++++++++++++++++++----------------------- include/hw/i386/x86.h | 12 +++++++---- 5 files changed, 40 insertions(+), 37 deletions(-)
hw/i386/pc.c +8 -5
@@ -982,8 +982,8 @@ void pc_smp_parse(MachineState *ms, QemuOpts *opts)void pc_hot_add_cpu (MachineState *ms,const int64_t id,Error **errp) { -PCMachineState *pcms =PC_MACHINE (ms); -int64_t apic_id =x86_cpu_apic_id_from_index (pcms, id); +X86MachineState *x86ms =X86_MACHINE (ms); +int64_t apic_id =x86_cpu_apic_id_from_index (x86ms, id);Error *local_err =NULL ;if (id <0 ) {
@@ -998,7 +998,7 @@ void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp)return ; } -x86_new_cpu (PC_MACHINE (ms), apic_id, &local_err); +x86_new_cpu (X86_MACHINE (ms), apic_id, &local_err);if (local_err) {error_propagate (errp, local_err);return ;
@@ -1099,6 +1099,7 @@ void xen_load_linux(PCMachineState *pcms) {int i;FWCfgState *fw_cfg; +PCMachineClass *pcmc =PC_MACHINE_GET_CLASS (pcms);X86MachineState *x86ms =X86_MACHINE (pcms);assert (MACHINE (pcms)->kernel_filename !=NULL );
@@ -1107,7 +1108,8 @@ void xen_load_linux(PCMachineState *pcms)fw_cfg_add_i16 (fw_cfg,FW_CFG_NB_CPUS , x86ms->boot_cpus);rom_set_fw (fw_cfg); -x86_load_linux (pcms, fw_cfg); +x86_load_linux (x86ms, fw_cfg, pcmc->acpi_data_size, + pcmc->pvh_enabled, pcmc->linuxboot_dma_enabled);for (i =0 ; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "linuxboot_dma.bin") ||
@@ -1243,7 +1245,8 @@ void pc_memory_init(PCMachineState *pcms, }if (linux_boot) { -x86_load_linux (pcms, fw_cfg); +x86_load_linux (x86ms, fw_cfg, pcmc->acpi_data_size, + pcmc->pvh_enabled, pcmc->linuxboot_dma_enabled); }for (i =0 ; i < nb_option_roms; i++) {
hw/i386/pc_piix.c +1 -1
@@ -154,7 +154,7 @@ static void pc_init1(MachineState *machine, } } -x86_cpus_init (pcms); +x86_cpus_init (x86ms, pcmc->default_cpu_version);if (kvm_enabled () && pcmc->kvmclock_enabled) {kvmclock_create ();
hw/i386/pc_q35.c +1 -1
@@ -181,7 +181,7 @@ static void pc_q35_init(MachineState *machine)xen_hvm_init (pcms, &ram_memory); } -x86_cpus_init (pcms); +x86_cpus_init (x86ms, pcmc->default_cpu_version);kvmclock_create ();
hw/i386/x86.c +22 -26
134 lines not on this page · raw message
include/hw/i386/x86.h +8 -4
@@ -73,10 +73,10 @@ typedef struct {#define X86_MACHINE_CLASS (class) \ OBJECT_CLASS_CHECK(X86MachineClass, class, TYPE_X86_MACHINE) -uint32_t x86_cpu_apic_id_from_index (PCMachineState *pcms, +uint32_t x86_cpu_apic_id_from_index (X86MachineState *pcms,unsigned int cpu_index); -void x86_new_cpu (PCMachineState *pcms,int64_t apic_id,Error **errp); -void x86_cpus_init (PCMachineState *pcms); +void x86_new_cpu (X86MachineState *x86ms,int64_t apic_id,Error **errp); +void x86_cpus_init (X86MachineState *x86ms,int default_cpu_version);CpuInstanceProperties x86_cpu_index_to_props (MachineState *ms,unsigned cpu_index);int64_t x86_get_default_cpu_node_id (const MachineState *ms,int idx);
@@ -84,6 +84,10 @@ const CPUArchIdList *x86_possible_cpu_arch_ids(MachineState *ms);void x86_system_rom_init (MemoryRegion *rom_memory,bool isapc_ram_fw); -void x86_load_linux (PCMachineState *pcms,FWCfgState *fw_cfg); +void x86_load_linux (X86MachineState *x86ms, +FWCfgState *fw_cfg, +int acpi_data_size, +bool pvh_enabled, +bool linuxboot_dma_enabled);#endif
Signature · 1 line
2.21.0
PATCH v5 6/10 fw_cfg: add "modify" functions for all types
In reply to Sergio LopezThis allows to alter the contents of an already added item.
--- hw/nvram/fw_cfg.c | 29 +++++++++++++++++++++++++++ include/hw/nvram/fw_cfg.h | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+)
hw/nvram/fw_cfg.c +29 -0
@@ -690,6 +690,15 @@ void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value)fw_cfg_add_bytes (s, key,g_memdup (value, sz), sz); } +void fw_cfg_modify_string (FWCfgState *s,uint16_t key,const char *value) +{ +size_t sz =strlen (value) +1 ; +char *old; + + old =fw_cfg_modify_bytes_read (s, key,g_memdup (value, sz), sz); +g_free (old); +} +void fw_cfg_add_i16 (FWCfgState *s,uint16_t key,uint16_t value) {uint16_t *copy;
@@ -720,6 +729,16 @@ void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value)fw_cfg_add_bytes (s, key, copy,sizeof (value)); } +void fw_cfg_modify_i32 (FWCfgState *s,uint16_t key,uint32_t value) +{ +uint32_t *copy, *old; + + copy =g_malloc (sizeof (value)); + *copy =cpu_to_le32 (value); + old =fw_cfg_modify_bytes_read (s, key, copy,sizeof (value)); +g_free (old); +} +void fw_cfg_add_i64 (FWCfgState *s,uint16_t key,uint64_t value) {uint64_t *copy;
@@ -730,6 +749,16 @@ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value)fw_cfg_add_bytes (s, key, copy,sizeof (value)); } +void fw_cfg_modify_i64 (FWCfgState *s,uint16_t key,uint64_t value) +{ +uint64_t *copy, *old; + + copy =g_malloc (sizeof (value)); + *copy =cpu_to_le64 (value); + old =fw_cfg_modify_bytes_read (s, key, copy,sizeof (value)); +g_free (old); +} +void fw_cfg_set_order_override (FWCfgState *s,int order) {assert (s->fw_cfg_order_override ==0 );
include/hw/nvram/fw_cfg.h +42 -0
60 lines not on this page · raw message
Signature · 1 line
2.21.0
PATCH v5 7/10 hw/intc/apic: reject pic ints if isa_pic == NULL
In reply to Sergio LopezIn apic_accept_pic_intr(), reject PIC interruptions if a i8259 PIC has not been instantiated (isa_pic == NULL).
--- hw/intc/apic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
hw/intc/apic.c +1 -1
@@ -610,7 +610,7 @@ int apic_accept_pic_intr(DeviceState *dev)if ((s->apicbase &MSR_IA32_APICBASE_ENABLE ) ==0 || (lvt0 &APIC_LVT_MASKED ) ==0 ) -return 1 ; +return isa_pic !=NULL ;return 0 ; }
Signature · 1 line
2.21.0
PATCH v5 8/10 roms: add microvm-bios (qboot) as binary and git submodule
In reply to Sergio Lopezqboot is a minimalist x86 firmware for booting Linux kernels. It does the mininum amount of work required for the task, and it's able to boot both PVH images and bzImages without relying on option roms.
This characteristics make it an ideal companion for the microvm machine type.
--- .gitmodules | 3 +++ pc-bios/bios-microvm.bin | Bin 0 -> 65536 bytes roms/Makefile | 6 ++++++ roms/qboot | 1 + 4 files changed, 10 insertions(+) create mode 100755 pc-bios/bios-microvm.bin create mode 160000 roms/qboot
.gitmodules +3 -0
@@ -58,3 +58,6 @@ [submodule "roms/opensbi"] path = roms/opensbi url = https://git.qemu.org/git/opensbi.git +[submodule "roms/qboot"] + path = roms/qboot + url = https://github.com/bonzini/qboot
pc-bios/bios-microvm.bin new file binary +0 -0
roms/Makefile +6 -0
@@ -67,6 +67,7 @@ default: @echo " opensbi32-virt -- update OpenSBI for 32-bit virt machine" @echo " opensbi64-virt -- update OpenSBI for 64-bit virt machine" @echo " opensbi64-sifive_u -- update OpenSBI for 64-bit sifive_u machine" + @echo " bios-microvm -- update bios-microvm.bin (qboot)" @echo " clean -- delete the files generated by the previous" \ "build targets"
@@ -185,6 +186,10 @@ opensbi64-sifive_u: PLATFORM="sifive/fu540" cp opensbi/build/platform/sifive/fu540/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin +bios-microvm: + $(MAKE) -C qboot + cp qboot/bios.bin ../pc-bios/bios-microvm.bin + clean: rm -rf seabios/.config seabios/out seabios/builds $(MAKE) -C sgabios clean
@@ -197,3 +202,4 @@ clean: $(MAKE) -C skiboot clean $(MAKE) -f Makefile.edk2 clean $(MAKE) -C opensbi clean + $(MAKE) -C qboot clean
roms/qboot new file +1 -0
@@ -0,0 +1 @@ +Subproject commit cb1c49e0cfac99b9961d136ac0194da62c28cf64
Signature · 1 line
2.21.0
Re: [PATCH v5 08/10] roms: add microvm-bios (qboot) as binary and git submodule
Quoted 3 lines · Sergio Lopez
qboot is a minimalist x86 firmware for booting Linux kernels. It does the mininum amount of work required for the task, and it's able to boot both PVH images and bzImages without relying on option roms.
I've just noticed all other submodules refer to mirrors hosted in git.qemu.org. What's our policy regarding this submodules? Can we add a reference to an external repo or should I somehow request a mirror in the aforementioned repo?
Thanks,
Sergio.
Quoted 216 lines
This characteristics make it an ideal companion for the microvm machine type.
Signed-off-by Sergio Lopez <[email protected]>--- .gitmodules | 3 +++ pc-bios/bios-microvm.bin | Bin 0 -> 65536 bytes roms/Makefile | 6 ++++++ roms/qboot | 1 + 4 files changed, 10 insertions(+) create mode 100755 pc-bios/bios-microvm.bin create mode 160000 roms/qboot.gitmodules +3
-0@@ -58,3 +58,6 @@ [submodule "roms/opensbi"] path = roms/opensbi url = https://git.qemu.org/git/opensbi.git +[submodule "roms/qboot"] + path = roms/qboot + url = https://github.com/bonzini/qbootpc-bios/bios-microvm.bin new file binary +0
-0roms/Makefile +6
-0@@ -67,6 +67,7 @@ default: @echo " opensbi32-virt -- update OpenSBI for 32-bit virt machine" @echo " opensbi64-virt -- update OpenSBI for 64-bit virt machine" @echo " opensbi64-sifive_u -- update OpenSBI for 64-bit sifive_u machine" + @echo " bios-microvm -- update bios-microvm.bin (qboot)" @echo " clean -- delete the files generated by the previous" \ "build targets"@@ -185,6 +186,10 @@ opensbi64-sifive_u: PLATFORM="sifive/fu540" cp opensbi/build/platform/sifive/fu540/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin +bios-microvm: + $(MAKE) -C qboot + cp qboot/bios.bin ../pc-bios/bios-microvm.bin + clean: rm -rf seabios/.config seabios/out seabios/builds $(MAKE) -C sgabios clean@@ -197,3 +202,4 @@ clean: $(MAKE) -C skiboot clean $(MAKE) -f Makefile.edk2 clean $(MAKE) -C opensbi clean + $(MAKE) -C qboot cleanroms/qboot new file +1
-0@@ -0,0 +1 @@ +Subproject commit cb1c49e0cfac99b9961d136ac0194da62c28cf64
Re: [PATCH v5 08/10] roms: add microvm-bios (qboot) as binary and git submodule
Quoted 8 lines · Sergio Lopez
Quoted 4 lines
qboot is a minimalist x86 firmware for booting Linux kernels. It does the mininum amount of work required for the task, and it's able to boot both PVH images and bzImages without relying on option roms.
I've just noticed all other submodules refer to mirrors hosted in git.qemu.org. What's our policy regarding this submodules? Can we add a reference to an external repo or should I somehow request a mirror in the aforementioned repo?
We usually start with an external repo and then sooner or later change it to a mirror on qemu.org.
Paolo
Re: [PATCH v5 08/10] roms: add microvm-bios (qboot) as binary and git submodule
Quoted 5 lines · Paolo Bonzini
Quoted 4 lines · Sergio Lopez
Quoted 4 lines
qboot is a minimalist x86 firmware for booting Linux kernels. It does the mininum amount of work required for the task, and it's able to boot both PVH images and bzImages without relying on option roms.
Quoted 7 lines
Quoted 4 lines
I've just noticed all other submodules refer to mirrors hosted in git.qemu.org. What's our policy regarding this submodules? Can we add a reference to an external repo or should I somehow request a mirror in the aforementioned repo?
We usually start with an external repo and then sooner or later change it to a mirror on qemu.org.
OK, good to know.
Thanks,
Sergio.
PATCH v5 9/10 docs/microvm.rst: document the new microvm machine type
In reply to Sergio LopezDocument the new microvm machine type.
--- docs/microvm.rst | 98 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 docs/microvm.rst
docs/microvm.rst new file +98 -0
@@ -0,0 +1,98 @@ +==================== +Microvm Machine Type +==================== + +Microvm is a machine type inspired by ``Firecracker`` and constructed +after the its machine model. + +It's a minimalist machine type without ``PCI`` nor ``ACPI`` support, +designed for short-lived guests. Microvm also establishes a baseline +for benchmarking and optimizing both QEMU and guest operating systems, +since it is optimized for both boot time and footprint. + + +Supported devices +----------------- + +The microvm machine type supports the following devices: + +- ISA bus +- i8259 PIC (optional) +- i8254 PIT (optional) +- MC146818 RTC (optional) +- One ISA serial port (optional) +- LAPIC (in userspace by default) +- IOAPIC (in userspace by default) +- kvmclock (if using KVM) +- fw_cfg +- Up to eight virtio-mmio devices (configured by the user) + + +Using the microvm machine type +------------------------------ + +Machine-specific options +~~~~~~~~~~~~~~~~~~~~~~~~ + +It supports the following machine-specific options: + +- microvm.x-option-roms=bool (Set off to disable loading option ROMs) +- microvm.pit=OnOffAuto (Enable i8254 PIT) +- microvm.isa-serial=bool (Set off to disable the instantiation an ISA serial port) +- microvm.pic=OnOffAuto (Enable i8259 PIC) +- microvm.rtc=OnOffAuto (Enable MC146818 RTC) +- microvm.auto-kernel-cmdline=bool (Set off to disable adding virtio-mmio devices to the kernel cmdline) + + +Boot options +~~~~~~~~~~~~ + +By default, microvm uses ``qboot`` as its BIOS, to obtain better boot +times, but it's also compatible with ``SeaBIOS``. + +As no current FW is able to boot from a block device using +``virtio-mmio`` as its transport, a microvm-based VM needs to be run +using a host-side kernel and, optionally, an initrd image. + + +Running a microvm-based VM +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, microvm aims for maximum compatibility, enabling both +legacy and non-legacy devices. In this example, a VM is created +without passing any additional machine-specific option, using the +legacy ``ISA serial`` device as console:: + + $ qemu-system-x86_64 -M microvm \ + -enable-kvm -cpu host -m 512m -smp 2 \ + -kernel vmlinux -append "earlyprintk=ttyS0 console=ttyS0 root=/dev/vda" \ + -nodefaults -no-user-config -nographic \ + -serial stdio \ + -drive id=test,file=test.img,format=raw,if=none \ + -device virtio-blk-device,drive=test \ + -netdev tap,id=tap0,script=no,downscript=no \ + -device virtio-net-device,netdev=tap0 + +While the example above works, you might be interested in reducing the +footprint further by disabling some legacy devices. If you're using +``KVM``, you can disable the ``RTC``, making the Guest rely on +``kvmclock`` exclusively. Additionally, if your host's CPUs have the +``TSC_DEADLINE`` feature, you can also disable both the i8259 PIC and +the i8254 PIT (make sure you're also emulating a CPU with such feature +in the guest). + +This is an example of a VM with all optional legacy features +disabled:: + + $ qemu-system-x86_64 \ + -M microvm,x-option-roms=off,pit=off,pic=off,isa-serial=off,rtc=off \ + -enable-kvm -cpu host -m 512m -smp 2 \ + -kernel vmlinux -append "console=hvc0 root=/dev/vda" \ + -nodefaults -no-user-config -nographic \ + -chardev stdio,id=virtiocon0,server \ + -device virtio-serial-device \ + -device virtconsole,chardev=virtiocon0 \ + -drive id=test,file=test.img,format=raw,if=none \ + -device virtio-blk-device,drive=test \ + -netdev tap,id=tap0,script=no,downscript=no \ + -device virtio-net-device,netdev=tap0
Signature · 1 line
2.21.0
Re: [PATCH v5 09/10] docs/microvm.rst: document the new microvm machine type
Quoted 1 line · Sergio Lopez
+- LAPIC (in userspace by default)
Note that LAPIC should be in kernel by default. The userspace LAPIC is slow (cannot use APIC virtualization in recent Intel and AMD processors) and probably somewhat buggy.
Paolo
Quoted 1 line
+- IOAPIC (in userspace by default)
Re: [PATCH v5 09/10] docs/microvm.rst: document the new microvm machine type
Quoted 6 lines · Paolo Bonzini
Quoted 1 line · Sergio Lopez
+- LAPIC (in userspace by default)
Note that LAPIC should be in kernel by default. The userspace LAPIC is slow (cannot use APIC virtualization in recent Intel and AMD processors) and probably somewhat buggy.
Thanks for catching this. It's a copy/paste bug in the doc. The default mode is irqchip_split = true, so the LAPIC is in the kernel and the IOAPIC in userspace. I'll fix it.
Cheers,
Sergio.
Quoted 1 line
Quoted 1 line
+- IOAPIC (in userspace by default)
PATCH v5 10/10 hw/i386: Introduce the microvm machine type
In reply to Sergio LopezMicrovm is a machine type inspired by Firecracker and constructed after the its machine model.
It's a minimalist machine type without PCI nor ACPI support, designed for short-lived guests. Microvm also establishes a baseline for benchmarking and optimizing both QEMU and guest operating systems, since it is optimized for both boot time and footprint.
--- default-configs/i386-softmmu.mak | 1 + hw/i386/Kconfig | 4 + hw/i386/Makefile.objs | 1 + hw/i386/microvm.c | 574 +++++++++++++++++++++++++++++++ include/hw/i386/microvm.h | 83 +++++ 5 files changed, 663 insertions(+) create mode 100644 hw/i386/microvm.c create mode 100644 include/hw/i386/microvm.h
default-configs/i386-softmmu.mak +1 -0
@@ -28,3 +28,4 @@ CONFIG_ISAPC=y CONFIG_I440FX=y CONFIG_Q35=y +CONFIG_MICROVM=y
hw/i386/Kconfig +4 -0
@@ -92,6 +92,10 @@ config Q35 select SMBIOS select FW_CFG_DMA +config MICROVM + bool + select VIRTIO_MMIO + config VTD bool
hw/i386/Makefile.objs +1 -0
@@ -4,6 +4,7 @@ obj-y += x86.o obj-y += pc.o obj-$(CONFIG_I440FX) += pc_piix.o obj-$(CONFIG_Q35) += pc_q35.o +obj-$(CONFIG_MICROVM) += microvm.o obj-y += fw_cfg.o pc_sysfw.o obj-y += x86-iommu.o obj-$(CONFIG_VTD) += intel_iommu.o
hw/i386/microvm.c new file +574 -0
574 lines not on this page · raw message
include/hw/i386/microvm.h new file +83 -0
83 lines not on this page · raw message
Signature · 1 line
2.21.0
Re: [PATCH v5 10/10] hw/i386: Introduce the microvm machine type
Quoted 33 lines · Sergio Lopez
Microvm is a machine type inspired by Firecracker and constructed after the its machine model.
It's a minimalist machine type without PCI nor ACPI support, designed for short-lived guests. Microvm also establishes a baseline for benchmarking and optimizing both QEMU and guest operating systems, since it is optimized for both boot time and footprint.
Signed-off-by Sergio Lopez <[email protected]>--- default-configs/i386-softmmu.mak | 1 + hw/i386/Kconfig | 4 + hw/i386/Makefile.objs | 1 + hw/i386/microvm.c | 574 +++++++++++++++++++++++++++++++ include/hw/i386/microvm.h | 83 +++++ 5 files changed, 663 insertions(+) create mode 100644 hw/i386/microvm.c create mode 100644 include/hw/i386/microvm.hdefault-configs/i386-softmmu.mak +1
-0@@ -28,3 +28,4 @@ CONFIG_ISAPC=y CONFIG_I440FX=y CONFIG_Q35=y +CONFIG_MICROVM=yhw/i386/Kconfig +0
-0
hw/i386/Kconfig config Q35 · line 97
Quoted 6 lines
hw/i386/Kconfig +3
-0@@ -92,6 +92,10 @@ config Q35 select SMBIOS select FW_CFG_DMA +config MICROVM + bool + select VIRTIO_MMIO
You also need these switches, I think:
select I8259
select ISA_BUS
select SERIAL_ISA
select MC146818RTC(ideally, it should be possible to disable all the other machines in default-configs/i386-softmmu.mak and only compile with CONFIG_MICROVM=y ... but seems like there are also some other indirect dependencies left)
Thomas
Re: [PATCH v5 10/10] hw/i386: Introduce the microvm machine type
Quoted 43 lines · Thomas Huth
Quoted 33 lines · Sergio Lopez
Microvm is a machine type inspired by Firecracker and constructed after the its machine model.
It's a minimalist machine type without PCI nor ACPI support, designed for short-lived guests. Microvm also establishes a baseline for benchmarking and optimizing both QEMU and guest operating systems, since it is optimized for both boot time and footprint.
Signed-off-by Sergio Lopez <[email protected]>--- default-configs/i386-softmmu.mak | 1 + hw/i386/Kconfig | 4 + hw/i386/Makefile.objs | 1 + hw/i386/microvm.c | 574 +++++++++++++++++++++++++++++++ include/hw/i386/microvm.h | 83 +++++ 5 files changed, 663 insertions(+) create mode 100644 hw/i386/microvm.c create mode 100644 include/hw/i386/microvm.hdefault-configs/i386-softmmu.mak +1
-0@@ -28,3 +28,4 @@ CONFIG_ISAPC=y CONFIG_I440FX=y CONFIG_Q35=y +CONFIG_MICROVM=yhw/i386/Kconfig +0
-0hw/i386/Kconfig config Q35 · line 97
Quoted 6 lines
hw/i386/Kconfig +3
-0@@ -92,6 +92,10 @@ config Q35 select SMBIOS select FW_CFG_DMA +config MICROVM + bool + select VIRTIO_MMIOYou also need these switches, I think:
Quoted 8 lines
select I8259 select ISA_BUS select SERIAL_ISA select MC146818RTC(ideally, it should be possible to disable all the other machines in default-configs/i386-softmmu.mak and only compile with
CONFIG_MICROVM=y... but seems like there are also some other indirect dependencies left)
Yes, probably others too. I didn't bother building an accurate list of components, because when I tried disabling PC, the build broke (I don't remember the details, I think it crashed somewhere around the floppy disk and something else).
My intention was, if microvm gets merged, to work on the build system to ensure to make possible a microvm-only build, and fill the actual list of components then.
Thanks,
Sergio.
Patchew URL: https://patchew.org/QEMU/[email protected]/
Patchew URL: https://patchew.org/QEMU/[email protected]/
Hi,
This series failed the docker-quick@centos7 build test. Please find the testing commands and their output below. If you have Docker installed, you can probably reproduce it locally.
=== TEST SCRIPT BEGIN ===
#!/bin/bash
make docker-image-centos7 V=1 NETWORK=1
time make docker-test-quick@centos7 SHOW_ENV=1 J=14 NETWORK=1 === TEST SCRIPT END ===
CC aarch64-softmmu/hw/arm/virt.o
CC aarch64-softmmu/hw/arm/virt-acpi-build.o/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c: In function 'xen_ram_init':/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:203:53: error: 'PC_MACHINE_MAX_RAM_BELOW_4G' undeclared (first use in this function)
PC_MACHINE_MAX_RAM_BELOW_4G,
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:203:53: note: each undeclared identifier is reported only once for each function it appears in
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:217:13: error: 'PCMachineState' has no member named 'above_4g_mem_size'
pcms->above_4g_mem_size = ram_size - user_lowmem;
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:218:13: error: 'PCMachineState' has no member named 'below_4g_mem_size'
pcms->below_4g_mem_size = user_lowmem;
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:220:13: error: 'PCMachineState' has no member named 'above_4g_mem_size'
pcms->above_4g_mem_size = 0;
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:221:13: error: 'PCMachineState' has no member named 'below_4g_mem_size'
pcms->below_4g_mem_size = ram_size;
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:223:14: error: 'PCMachineState' has no member named 'above_4g_mem_size'
if (!pcms->above_4g_mem_size) {
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:230:40: error: 'PCMachineState' has no member named 'above_4g_mem_size'
block_len = (1ULL << 32) + pcms->above_4g_mem_size;
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:247:34: error: 'PCMachineState' has no member named 'below_4g_mem_size'
pcms->below_4g_mem_size - 0xc0000);
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:249:13: error: 'PCMachineState' has no member named 'above_4g_mem_size'
if (pcms->above_4g_mem_size > 0) {
^
/tmp/qemu-test/src/hw/i386/xen/xen-hvm.c:252:38: error: 'PCMachineState' has no member named 'above_4g_mem_size'
pcms->above_4g_mem_size);
^make[1]: *** [hw/i386/xen/xen-hvm.o] Error 1
make[1]: *** Waiting for unfinished jobs....
CC x86_64-softmmu/target/i386/translate.o
CC aarch64-softmmu/hw/arm/digic_boards.o
---
CC aarch64-softmmu/hw/arm/realview.o CC aarch64-softmmu/hw/arm/sbsa-ref.o CC aarch64-softmmu/hw/arm/stellaris.o
make: *** [x86_64-softmmu/all] Error 2
make: *** Waiting for unfinished jobs....
CC aarch64-softmmu/hw/arm/collie.o
CC aarch64-softmmu/hw/arm/versatilepb.o
---
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['sudo', '-n', 'docker', 'run', '--label', 'com.qemu.instance.uuid=f1c2f7c4cc1b4d368566f09386dc38ef', '-u', '1003', '--security-opt', 'seccomp=unconfined', '--rm', '-e', 'TARGET_LIST=', '-e', 'EXTRA_CONFIGURE_OPTS=', '-e', 'V=', '-e', 'J=14', '-e', 'DEBUG=', '-e', 'SHOW_ENV=1', '-e', 'CCACHE_DIR=/var/tmp/ccache', '-v', '/home/patchew2/.cache/qemu-docker-ccache:/var/tmp/ccache:z', '-v', '/var/tmp/patchew-tester-tmp-yoe776nw/src/docker-src.2019-10-02-08.00.47.19037:/var/tmp/qemu:z,ro', 'qemu:centos7', '/var/tmp/qemu/run', 'test-quick']' returned non-zero exit status 2. filter=--filter=label=com.qemu.instance.uuid=f1c2f7c4cc1b4d368566f09386dc38ef
make[1]: *** [docker-run] Error 1
make[1]: Leaving directory `/var/tmp/patchew-tester-tmp-yoe776nw/src'
make: *** [docker-run-test-quick@centos7] Error 2
real 2m25.365s
user 0m7.863s
The full log is available at
http://patchew.org/logs/[email protected]/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to [email protected]
Patchew URL: https://patchew.org/QEMU/[email protected]/
Patchew URL: https://patchew.org/QEMU/[email protected]/
Hi,
This series seems to have some coding style problems. See output below for more information:
Type: series
Message-id: [email protected]
Subject: [PATCH v5 00/10] Introduce the microvm machine type
=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===
Switched to a new branch 'test'
7b4ed4b hw/i386: Introduce the microvm machine type
e5bff45 docs/microvm.rst: document the new microvm machine type 5d497ed roms: add microvm-bios (qboot) as binary and git submodule de77277 hw/intc/apic: reject pic ints if isa_pic == NULL 5e6a3a1 fw_cfg: add "modify" functions for all types adb0c9b hw/i386: make x86.c independent from PCMachineState 4d909dc hw/i386: split PCMachineState deriving X86MachineState from it cdb8355 hw/i386/pc: move shared x86 functions to x86.c and export them f591a05 hw/i386/pc: rename functions shared with non-PC machines 1051f6f hw/virtio: Factorize virtio-mmio headers
=== OUTPUT BEGIN ===
1/10 Checking commit 1051f6fcc0c0 (hw/virtio: Factorize virtio-mmio headers)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #77:
new file mode 100644
total: 0 errors, 1 warnings, 131 lines checked
Patch 1/10 has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
2/10 Checking commit f591a05ac797 (hw/i386/pc: rename functions shared with non-PC machines) 3/10 Checking commit cdb83552a361 (hw/i386/pc: move shared x86 functions to x86.c and export them)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#749:
new file mode 100644
WARNING: Block comments use a leading /* on a separate line #809: FILE: hw/i386/x86.c:56:
+/* Calculates initial APIC ID for a specific CPU index
WARNING: Block comments use a leading /* on a separate line #866: FILE: hw/i386/x86.c:113:
+ /* Calculates the limit to CPU APIC ID values
WARNING: Block comments should align the * on each line #913: FILE: hw/i386/x86.c:160:
+ * -smp hasn't been parsed after it
+ */
WARNING: line over 80 characters
#926: FILE: hw/i386/x86.c:173:
+ ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(pcms, i);
ERROR: spaces required around that '+' (ctx:VxV)
#1087: FILE: hw/i386/x86.c:334:
+ cmdline_size = (strlen(kernel_cmdline)+16) & ~15;
^ERROR: do not use assignment in if condition
#1091: FILE: hw/i386/x86.c:338:
+ if (!f || !(kernel_size = get_file_size(f)) ||
ERROR: if this code is redundant consider removing it #1100: FILE: hw/i386/x86.c:347:
+#if 0
ERROR: spaces required around that '+' (ctx:VxV)
#1101: FILE: hw/i386/x86.c:348:
+ fprintf(stderr, "header magic: %#x\n", ldl_p(header+0x202));
^ERROR: spaces required around that '+' (ctx:VxV)
#1103: FILE: hw/i386/x86.c:350:
+ if (ldl_p(header+0x202) == 0x53726448) {
^ERROR: spaces required around that '+' (ctx:VxV)
#1104: FILE: hw/i386/x86.c:351:
+ protocol = lduw_p(header+0x206);
^ERROR: if this code is redundant consider removing it #1194: FILE: hw/i386/x86.c:441:
+#if 0
ERROR: spaces required around that '+' (ctx:VxV)
#1206: FILE: hw/i386/x86.c:453:
+ lduw_p(header+0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) {
^ERROR: spaces required around that '+' (ctx:VxV)
#1225: FILE: hw/i386/x86.c:472:
+ initrd_max = ldl_p(header+0x22c);
^ERROR: spaces required around that '+' (ctx:VxV)
#1235: FILE: hw/i386/x86.c:482:
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1);
^ERROR: spaces required around that '+' (ctx:VxV)
#1239: FILE: hw/i386/x86.c:486:
+ stl_p(header+0x228, cmdline_addr);
^ERROR: spaces required around that '+' (ctx:VxV)
#1241: FILE: hw/i386/x86.c:488:
+ stw_p(header+0x20, 0xA33F);
^ERROR: spaces required around that '+' (ctx:VxV)
#1242: FILE: hw/i386/x86.c:489:
+ stw_p(header+0x22, cmdline_addr-real_addr);
^ERROR: spaces required around that '-' (ctx:VxV)
#1242: FILE: hw/i386/x86.c:489:
+ stw_p(header+0x22, cmdline_addr-real_addr);
^ERROR: consider using qemu_strtol in preference to strtol #1258: FILE: hw/i386/x86.c:505:
+ video_mode = strtol(vmode, NULL, 0);
ERROR: spaces required around that '+' (ctx:VxV)
#1260: FILE: hw/i386/x86.c:507:
+ stw_p(header+0x1fa, video_mode);
^WARNING: Block comments use a leading /* on a separate line #1264: FILE: hw/i386/x86.c:511:
+ /* High nybble = B reserved for QEMU; low nybble is revision number.
WARNING: Block comments use * on subsequent lines
#1265: FILE: hw/i386/x86.c:512:
+ /* High nybble = B reserved for QEMU; low nybble is revision number.
+ If this code is substantially changed, you may want to consider
WARNING: Block comments use a trailing */ on a separate line #1266: FILE: hw/i386/x86.c:513:
+ incrementing the revision. */
ERROR: code indent should never use tabs
#1272: FILE: hw/i386/x86.c:519:
+ header[0x211] |= 0x80;^I/* CAN_USE_HEAP */$
ERROR: spaces required around that '+' (ctx:VxV)
#1273: FILE: hw/i386/x86.c:520:
+ stw_p(header+0x224, cmdline_addr-real_addr-0x200);
^ERROR: spaces required around that '-' (ctx:VxV)
#1273: FILE: hw/i386/x86.c:520:
+ stw_p(header+0x224, cmdline_addr-real_addr-0x200);
^ERROR: spaces required around that '-' (ctx:VxV)
#1273: FILE: hw/i386/x86.c:520:
+ stw_p(header+0x224, cmdline_addr-real_addr-0x200);
^ERROR: spaces required around that '-' (ctx:VxV)
#1305: FILE: hw/i386/x86.c:552:
+ initrd_addr = (initrd_max-initrd_size) & ~4095;
^ERROR: spaces required around that '+' (ctx:VxV)
#1311: FILE: hw/i386/x86.c:558:
+ stl_p(header+0x218, initrd_addr);
^ERROR: spaces required around that '+' (ctx:VxV)
#1312: FILE: hw/i386/x86.c:559:
+ stl_p(header+0x21c, initrd_size);
^ERROR: spaces required around that '+' (ctx:VxV)
#1320: FILE: hw/i386/x86.c:567:
+ setup_size = (setup_size+1)*512;
^ERROR: spaces required around that '*' (ctx:VxV)
#1320: FILE: hw/i386/x86.c:567:
+ setup_size = (setup_size+1)*512;
^ERROR: spaces required around that '+' (ctx:VxV)
#1358: FILE: hw/i386/x86.c:605:
+ stq_p(header+0x250, prot_addr + setup_data_offset);
^total: 26 errors, 8 warnings, 1430 lines checked
Patch 3/10 has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS.
4/10 Checking commit 4d909dcf38f6 (hw/i386: split PCMachineState deriving X86MachineState from it)
WARNING: Block comments use a leading /* on a separate line
#880: FILE: hw/i386/pc_q35.c:158:
+ x86ms->max_ram_below_4g = 1ULL << 32; /* default: 4G */;
WARNING: line over 80 characters
#1103: FILE: hw/i386/x86.c:420:
+ initrd_max = x86ms->below_4g_mem_size - pcmc->acpi_data_size - 1;
WARNING: Block comments use a leading /* on a separate line #1366: FILE: include/hw/i386/x86.h:61:
+ /* Address space used by IOAPIC device. All IOAPIC interrupts
WARNING: Block comments use a trailing */ on a separate line #1367: FILE: include/hw/i386/x86.h:62:
+ * will be translated to MSI messages in the address space. */
total: 0 errors, 4 warnings, 1235 lines checked
Patch 4/10 has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
5/10 Checking commit adb0c9bd5e70 (hw/i386: make x86.c independent from PCMachineState)
WARNING: line over 80 characters
#176: FILE: hw/i386/x86.c:172:
+ ms->possible_cpus->cpus[i].arch_id = x86_cpu_apic_id_from_index(x86ms, i);
total: 0 errors, 1 warnings, 217 lines checked
Patch 5/10 has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
6/10 Checking commit 5e6a3a1d589a (fw_cfg: add "modify" functions for all types) 7/10 Checking commit de7727755ee9 (hw/intc/apic: reject pic ints if isa_pic == NULL) 8/10 Checking commit 5d497ed4b132 (roms: add microvm-bios (qboot) as binary and git submodule)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#29:
new file mode 100755
total: 0 errors, 1 warnings, 28 lines checked
Patch 8/10 has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
9/10 Checking commit e5bff45525b6 (docs/microvm.rst: document the new microvm machine type)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #13:
new file mode 100644
total: 0 errors, 1 warnings, 98 lines checked
Patch 9/10 has style problems, please review. If any of these errors are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
10/10 Checking commit 7b4ed4bfb853 (hw/i386: Introduce the microvm machine type)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #55:
new file mode 100644
total: 0 errors, 1 warnings, 678 lines checked
Patch 10/10 has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===
Test command exited with code: 1
The full log is available at
http://patchew.org/logs/[email protected]/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to [email protected]