From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569332732; cv=none; d=zoho.com; s=zohoarc; b=YK8h7kmF2dVpNKLk1d8zeq8avBHV5b6nEY7CQtMu3jZMpgcEInIAfnP4IcmP33IG9obos5vpF2xvqZfDWW8OlBVeyefn8lg7/dJizZGDYwUoqto2Xtq+jMxXPH3pAcaLx0SuY17MUJCqss41tFaIylxmLUTRhxirx/bTXYbZ/X8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569332732; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=XexmbqPYnky/rcE2AZt0fZENH6ujUrixt1z59Fgxytw=; b=kKLsIH3DanIeGlKQK5M7/wjpL28YM/WzU7LBc08P2kn65L3bHC4oaIOw5oHB2WzzxSNuh+pX7MtIaqlP2ROsqggeknnDAujTKZzJdxtKbELjWkwJvKYI5OyRRI3KOi5Ig79T5x8d+If4SMUTguNoN7Il45nld3S9nLOI5NQWKU8= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 15693327329620.14282195084240357; Tue, 24 Sep 2019 06:45:32 -0700 (PDT) Received: from localhost ([::1]:45852 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCl8D-0006ZH-5U for importer@patchew.org; Tue, 24 Sep 2019 09:45:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52303) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkBu-0002iM-E9 for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkBs-0004ZU-GT for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:14 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49392) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkBr-0004Xu-H1 for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:12 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CE74030860CB; Tue, 24 Sep 2019 12:45:10 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8135160852; Tue, 24 Sep 2019 12:45:04 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 1/8] hw/i386: Factorize PVH related functions Date: Tue, 24 Sep 2019 14:44:26 +0200 Message-Id: <20190924124433.96810-2-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.44]); Tue, 24 Sep 2019 12:45:10 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Extract PVH related functions from pc.c, and put them in pvh.c, so they can be shared with other components. Signed-off-by: Sergio Lopez --- hw/i386/Makefile.objs | 1 + hw/i386/pc.c | 120 +++++------------------------------------- hw/i386/pvh.c | 113 +++++++++++++++++++++++++++++++++++++++ hw/i386/pvh.h | 10 ++++ 4 files changed, 136 insertions(+), 108 deletions(-) create mode 100644 hw/i386/pvh.c create mode 100644 hw/i386/pvh.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 5d9c9efd5f..c5f20bbd72 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,5 +1,6 @@ obj-$(CONFIG_KVM) +=3D kvm/ obj-y +=3D multiboot.o +obj-y +=3D pvh.o obj-y +=3D pc.o obj-$(CONFIG_I440FX) +=3D pc_piix.o obj-$(CONFIG_Q35) +=3D pc_q35.o diff --git a/hw/i386/pc.c b/hw/i386/pc.c index bad866fe44..10e4ced0c6 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -42,6 +42,7 @@ #include "elf.h" #include "migration/vmstate.h" #include "multiboot.h" +#include "pvh.h" #include "hw/timer/mc146818rtc.h" #include "hw/dma/i8257.h" #include "hw/timer/i8254.h" @@ -116,9 +117,6 @@ static struct e820_entry *e820_table; static unsigned e820_entries; struct hpet_fw_config hpet_cfg =3D {.count =3D UINT8_MAX}; =20 -/* Physical Address of PVH entry point read from kernel ELF NOTE */ -static size_t pvh_start_addr; - GlobalProperty pc_compat_4_1[] =3D {}; const size_t pc_compat_4_1_len =3D G_N_ELEMENTS(pc_compat_4_1); =20 @@ -1076,109 +1074,6 @@ struct setup_data { uint8_t data[0]; } __attribute__((packed)); =20 - -/* - * 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 =3D=3D NULL) { - return 0; - } - - if (is64) { - struct elf64_note *nhdr64 =3D (struct elf64_note *)arg1; - uint64_t nhdr_size64 =3D sizeof(struct elf64_note); - uint64_t phdr_align =3D *(uint64_t *)arg2; - uint64_t nhdr_namesz =3D nhdr64->n_namesz; - - elf_note_data_addr =3D - ((void *)nhdr64) + nhdr_size64 + - QEMU_ALIGN_UP(nhdr_namesz, phdr_align); - } else { - struct elf32_note *nhdr32 =3D (struct elf32_note *)arg1; - uint32_t nhdr_size32 =3D sizeof(struct elf32_note); - uint32_t phdr_align =3D *(uint32_t *)arg2; - uint32_t nhdr_namesz =3D nhdr32->n_namesz; - - elf_note_data_addr =3D - ((void *)nhdr32) + nhdr_size32 + - QEMU_ALIGN_UP(nhdr_namesz, phdr_align); - } - - pvh_start_addr =3D *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 =3D 0; - uint32_t mh_load_addr =3D 0; - uint32_t elf_kernel_size =3D 0; - uint64_t elf_entry; - uint64_t elf_low, elf_high; - int kernel_size; - - if (ldl_p(header) !=3D 0x464c457f) { - return false; /* no elfboot */ - } - - bool elf_is64 =3D header[EI_CLASS] =3D=3D ELFCLASS64; - flags =3D 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 =3D %x", flags); - exit(1); - } - - uint64_t elf_note_type =3D XEN_ELFNOTE_PHYS32_ENTRY; - kernel_size =3D 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 =3D elf_low; - elf_kernel_size =3D elf_high - elf_low; - - if (pvh_start_addr =3D=3D 0) { - error_report("Error loading uncompressed kernel without PVH ELF No= te"); - 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 load_linux(PCMachineState *pcms, FWCfgState *fw_cfg) { @@ -1218,6 +1113,9 @@ static void load_linux(PCMachineState *pcms, if (ldl_p(header+0x202) =3D=3D 0x53726448) { protocol =3D lduw_p(header+0x206); } else { + size_t pvh_start_addr; + uint32_t mh_load_addr =3D 0; + uint32_t elf_kernel_size =3D 0; /* * This could be a multiboot kernel. If it is, let's stop treating= it * like a Linux kernel. @@ -1235,10 +1133,16 @@ static void load_linux(PCMachineState *pcms, * 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)) { + pvh_load_elfboot(kernel_filename, + &mh_load_addr, &elf_kernel_size)) { fclose(f); =20 + pvh_start_addr =3D pvh_get_start_addr(); + + 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); + 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); diff --git a/hw/i386/pvh.c b/hw/i386/pvh.c new file mode 100644 index 0000000000..1c81727811 --- /dev/null +++ b/hw/i386/pvh.c @@ -0,0 +1,113 @@ +/* + * PVH Boot Helper + * + * Copyright (C) 2019 Oracle + * Copyright (C) 2019 Red Hat, Inc + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qemu/error-report.h" +#include "hw/loader.h" +#include "cpu.h" +#include "elf.h" +#include "pvh.h" + +static size_t pvh_start_addr; + +size_t pvh_get_start_addr(void) +{ + return pvh_start_addr; +} + +/* + * 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 =3D=3D NULL) { + return 0; + } + + if (is64) { + struct elf64_note *nhdr64 =3D (struct elf64_note *)arg1; + uint64_t nhdr_size64 =3D sizeof(struct elf64_note); + uint64_t phdr_align =3D *(uint64_t *)arg2; + uint64_t nhdr_namesz =3D nhdr64->n_namesz; + + elf_note_data_addr =3D + ((void *)nhdr64) + nhdr_size64 + + QEMU_ALIGN_UP(nhdr_namesz, phdr_align); + } else { + struct elf32_note *nhdr32 =3D (struct elf32_note *)arg1; + uint32_t nhdr_size32 =3D sizeof(struct elf32_note); + uint32_t phdr_align =3D *(uint32_t *)arg2; + uint32_t nhdr_namesz =3D nhdr32->n_namesz; + + elf_note_data_addr =3D + ((void *)nhdr32) + nhdr_size32 + + QEMU_ALIGN_UP(nhdr_namesz, phdr_align); + } + + pvh_start_addr =3D *elf_note_data_addr; + + return pvh_start_addr; +} + +bool pvh_load_elfboot(const char *kernel_filename, + uint32_t *mh_load_addr, + uint32_t *elf_kernel_size) +{ + uint64_t elf_entry; + uint64_t elf_low, elf_high; + int kernel_size; + uint64_t elf_note_type =3D XEN_ELFNOTE_PHYS32_ENTRY; + + kernel_size =3D 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"); + return false; + } + + if (pvh_start_addr =3D=3D 0) { + error_report("Error loading uncompressed kernel without PVH ELF No= te"); + return false; + } + + if (mh_load_addr) { + *mh_load_addr =3D elf_low; + } + + if (elf_kernel_size) { + *elf_kernel_size =3D elf_high - elf_low; + } + + return true; +} diff --git a/hw/i386/pvh.h b/hw/i386/pvh.h new file mode 100644 index 0000000000..ada67ff6e8 --- /dev/null +++ b/hw/i386/pvh.h @@ -0,0 +1,10 @@ +#ifndef HW_I386_PVH_H +#define HW_I386_PVH_H + +size_t pvh_get_start_addr(void); + +bool pvh_load_elfboot(const char *kernel_filename, + uint32_t *mh_load_addr, + uint32_t *elf_kernel_size); + +#endif --=20 2.21.0 From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569333052; cv=none; d=zoho.com; s=zohoarc; b=m+Pdd0mC4XZCB1exJXblU1GQx5h6fzGAk7tl8J1z35jioSHsyG2HYmGPsvbcjvTZyLSsGWlTVafOHL9MngYZhG/zOiRZE/o4WZGzWN5jpzILlJ/CXuor2CziofHBsOSIoKAnIerPrZbu0ZOzcrOrFa6pfBpzPXqAC5Q5XeQSWlE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569333052; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=lc+UyW7o8X7FmjKrBuzXYiakz4usY27XVWb+Xqc6tec=; b=VLodhUMDnKXLEa4q2qCTJwtpwEIySUn05s749J9nykghRwqyxy8xaj7/tZgibASVcl5rA15co5TJqIE8FQSkveaESrRoEZl89mnGsxjCqhg8rEH3yaSGc1XPy5HRhALO9qneITwlKMypxUA/nAFhians6FcxmXBkf65E6M8Apdg= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569333052705783.3870773723734; Tue, 24 Sep 2019 06:50:52 -0700 (PDT) Received: from localhost ([::1]:45900 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iClDK-0003Yb-8Q for importer@patchew.org; Tue, 24 Sep 2019 09:50:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52363) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkCF-0002qd-8l for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkCC-0004nk-K1 for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:34 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58059) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkCB-0004iw-Rw for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:32 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1051A10CC1F7; Tue, 24 Sep 2019 12:45:27 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3062E60852; Tue, 24 Sep 2019 12:45:11 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 2/8] hw/i386: Factorize e820 related functions Date: Tue, 24 Sep 2019 14:44:27 +0200 Message-Id: <20190924124433.96810-3-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.6.2 (mx1.redhat.com [10.5.110.65]); Tue, 24 Sep 2019 12:45:27 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Extract e820 related functions from pc.c, and put them in e820.c, so they can be shared with other components. Signed-off-by: Sergio Lopez --- hw/i386/Makefile.objs | 1 + hw/i386/e820.c | 99 +++++++++++++++++++++++++++++++++++++++++++ hw/i386/e820.h | 11 +++++ hw/i386/pc.c | 66 +---------------------------- include/hw/i386/pc.h | 11 ----- target/i386/kvm.c | 1 + 6 files changed, 114 insertions(+), 75 deletions(-) create mode 100644 hw/i386/e820.c create mode 100644 hw/i386/e820.h diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index c5f20bbd72..149712db07 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -2,6 +2,7 @@ obj-$(CONFIG_KVM) +=3D kvm/ obj-y +=3D multiboot.o obj-y +=3D pvh.o obj-y +=3D pc.o +obj-y +=3D e820.o obj-$(CONFIG_I440FX) +=3D pc_piix.o obj-$(CONFIG_Q35) +=3D pc_q35.o obj-y +=3D fw_cfg.o pc_sysfw.o diff --git a/hw/i386/e820.c b/hw/i386/e820.c new file mode 100644 index 0000000000..d5c5c0d528 --- /dev/null +++ b/hw/i386/e820.c @@ -0,0 +1,99 @@ +/* + * 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"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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/cutils.h" +#include "qemu/units.h" + +#include "hw/i386/e820.h" +#include "hw/i386/fw_cfg.h" + +#define E820_NR_ENTRIES 16 + +struct e820_entry { + uint64_t address; + uint64_t length; + uint32_t type; +} QEMU_PACKED __attribute((__aligned__(4))); + +struct e820_table { + uint32_t count; + struct e820_entry entry[E820_NR_ENTRIES]; +} QEMU_PACKED __attribute((__aligned__(4))); + +static struct e820_table e820_reserve; +static struct e820_entry *e820_table; +static unsigned e820_entries; + +int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) +{ + int index =3D le32_to_cpu(e820_reserve.count); + struct e820_entry *entry; + + if (type !=3D E820_RAM) { + /* old FW_CFG_E820_TABLE entry -- reservations only */ + if (index >=3D E820_NR_ENTRIES) { + return -EBUSY; + } + entry =3D &e820_reserve.entry[index++]; + + entry->address =3D cpu_to_le64(address); + entry->length =3D cpu_to_le64(length); + entry->type =3D cpu_to_le32(type); + + e820_reserve.count =3D cpu_to_le32(index); + } + + /* new "etc/e820" file -- include ram too */ + e820_table =3D g_renew(struct e820_entry, e820_table, e820_entries + 1= ); + e820_table[e820_entries].address =3D cpu_to_le64(address); + e820_table[e820_entries].length =3D cpu_to_le64(length); + e820_table[e820_entries].type =3D cpu_to_le32(type); + e820_entries++; + + return e820_entries; +} + +int e820_get_num_entries(void) +{ + return e820_entries; +} + +bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *l= ength) +{ + if (idx < e820_entries && e820_table[idx].type =3D=3D cpu_to_le32(type= )) { + *address =3D le64_to_cpu(e820_table[idx].address); + *length =3D le64_to_cpu(e820_table[idx].length); + return true; + } + return false; +} + +void e820_create_fw_entry(FWCfgState *fw_cfg) +{ + fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, + &e820_reserve, sizeof(e820_reserve)); + fw_cfg_add_file(fw_cfg, "etc/e820", e820_table, + sizeof(struct e820_entry) * e820_entries); +} diff --git a/hw/i386/e820.h b/hw/i386/e820.h new file mode 100644 index 0000000000..569d1f0ab5 --- /dev/null +++ b/hw/i386/e820.h @@ -0,0 +1,11 @@ +/* e820 types */ +#define E820_RAM 1 +#define E820_RESERVED 2 +#define E820_ACPI 3 +#define E820_NVS 4 +#define E820_UNUSABLE 5 + +int e820_add_entry(uint64_t address, uint64_t length, uint32_t type); +int e820_get_num_entries(void); +bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *l= ength); +void e820_create_fw_entry(FWCfgState *fw_cfg); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 10e4ced0c6..3920aa7e85 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -30,6 +30,7 @@ #include "hw/i386/apic.h" #include "hw/i386/topology.h" #include "hw/i386/fw_cfg.h" +#include "hw/i386/e820.h" #include "sysemu/cpus.h" #include "hw/block/fdc.h" #include "hw/ide.h" @@ -99,22 +100,6 @@ #define DPRINTF(fmt, ...) #endif =20 -#define E820_NR_ENTRIES 16 - -struct e820_entry { - uint64_t address; - uint64_t length; - uint32_t type; -} QEMU_PACKED __attribute((__aligned__(4))); - -struct e820_table { - uint32_t count; - struct e820_entry entry[E820_NR_ENTRIES]; -} QEMU_PACKED __attribute((__aligned__(4))); - -static struct e820_table e820_reserve; -static struct e820_entry *e820_table; -static unsigned e820_entries; struct hpet_fw_config hpet_cfg =3D {.count =3D UINT8_MAX}; =20 GlobalProperty pc_compat_4_1[] =3D {}; @@ -878,50 +863,6 @@ static void handle_a20_line_change(void *opaque, int i= rq, int level) x86_cpu_set_a20(cpu, level); } =20 -int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) -{ - int index =3D le32_to_cpu(e820_reserve.count); - struct e820_entry *entry; - - if (type !=3D E820_RAM) { - /* old FW_CFG_E820_TABLE entry -- reservations only */ - if (index >=3D E820_NR_ENTRIES) { - return -EBUSY; - } - entry =3D &e820_reserve.entry[index++]; - - entry->address =3D cpu_to_le64(address); - entry->length =3D cpu_to_le64(length); - entry->type =3D cpu_to_le32(type); - - e820_reserve.count =3D cpu_to_le32(index); - } - - /* new "etc/e820" file -- include ram too */ - e820_table =3D g_renew(struct e820_entry, e820_table, e820_entries + 1= ); - e820_table[e820_entries].address =3D cpu_to_le64(address); - e820_table[e820_entries].length =3D cpu_to_le64(length); - e820_table[e820_entries].type =3D cpu_to_le32(type); - e820_entries++; - - return e820_entries; -} - -int e820_get_num_entries(void) -{ - return e820_entries; -} - -bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *l= ength) -{ - if (idx < e820_entries && e820_table[idx].type =3D=3D cpu_to_le32(type= )) { - *address =3D le64_to_cpu(e820_table[idx].address); - *length =3D le64_to_cpu(e820_table[idx].length); - return true; - } - return false; -} - /* Calculates initial APIC ID for a specific CPU index * * Currently we need to be able to calculate the APIC ID from the CPU index @@ -1024,10 +965,7 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, = PCMachineState *pcms) acpi_tables, acpi_tables_len); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override(= )); =20 - fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, - &e820_reserve, sizeof(e820_reserve)); - fw_cfg_add_file(fw_cfg, "etc/e820", e820_table, - sizeof(struct e820_entry) * e820_entries); + e820_create_fw_entry(fw_cfg); =20 fw_cfg_add_bytes(fw_cfg, FW_CFG_HPET, &hpet_cfg, sizeof(hpet_cfg)); /* allocate memory for the NUMA channel: one (64bit) word for the numb= er diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 19a837889d..062feeb69e 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -291,17 +291,6 @@ void pc_system_firmware_init(PCMachineState *pcms, Mem= oryRegion *rom_memory); void pc_madt_cpu_entry(AcpiDeviceIf *adev, int uid, const CPUArchIdList *apic_ids, GArray *entry); =20 -/* e820 types */ -#define E820_RAM 1 -#define E820_RESERVED 2 -#define E820_ACPI 3 -#define E820_NVS 4 -#define E820_UNUSABLE 5 - -int e820_add_entry(uint64_t, uint64_t, uint32_t); -int e820_get_num_entries(void); -bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); - extern GlobalProperty pc_compat_4_1[]; extern const size_t pc_compat_4_1_len; =20 diff --git a/target/i386/kvm.c b/target/i386/kvm.c index 8023c679ea..8ce56db7d4 100644 --- a/target/i386/kvm.c +++ b/target/i386/kvm.c @@ -41,6 +41,7 @@ #include "hw/i386/apic-msidef.h" #include "hw/i386/intel_iommu.h" #include "hw/i386/x86-iommu.h" +#include "hw/i386/e820.h" =20 #include "hw/pci/pci.h" #include "hw/pci/msi.h" --=20 2.21.0 From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569331791; cv=none; d=zoho.com; s=zohoarc; b=UDZ2KvlheExa12ebrqjiRvuDLtbTC6I9Tq96HIz4b77EAAefSvUI4KQelli+CcM38ZwWiQx+OMN0uofij5USMVLJtjIG0BD6M2dVobn+6Y/SSSxZyY5ZjAUz9MU6Ty+SaIOpbKGbhWqkNjF6fdVUOL9NDmpk6NQ7s/DbFWnSt9A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569331791; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=v0jQywYF5jN9h2pg/6eQfOQJgMX1lOil/p/bOidSaHk=; b=CLnDmLa0Y78CUothMAdaiaWn0gR9edYIT5Z+T7yzj/RCvpwbjcC1VKZgV+66hnFR6sn3Ep2hFTRcjdtsXSL6oqEg4lrjHNjeP9h90uZ9vOUu2EYAv2AG3PxuQu/PFy25Xr8st9ZhWPUS8fVqSaiaXLtyDmb2DLy5I9K50ZuSoIQ= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569331791494369.3134113317018; Tue, 24 Sep 2019 06:29:51 -0700 (PDT) Received: from localhost ([::1]:45656 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkt3-0000Fc-JC for importer@patchew.org; Tue, 24 Sep 2019 09:29:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52362) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkCF-0002qc-8M for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:37 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkCC-0004nx-Jg for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:34 -0400 Received: from mx1.redhat.com ([209.132.183.28]:38702) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkCB-0004n8-Rn for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:32 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 68DA585362; Tue, 24 Sep 2019 12:45:30 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6B99360852; Tue, 24 Sep 2019 12:45:27 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 3/8] hw/virtio: Factorize virtio-mmio headers Date: Tue, 24 Sep 2019 14:44:28 +0200 Message-Id: <20190924124433.96810-4-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 24 Sep 2019 12:45:30 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Put QOM and main struct definition in a separate header file, so it can be accessed from other components. Signed-off-by: Sergio Lopez --- hw/virtio/virtio-mmio.c | 35 +------------------ include/hw/virtio/virtio-mmio.h | 60 +++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 include/hw/virtio/virtio-mmio.h diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index eccc795f28..6be6b298d5 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -29,44 +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" =20 -/* 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 1 -#define VIRT_VENDOR 0x554D4551 /* 'QEMU' */ - -typedef struct { - /* Generic */ - SysBusDevice parent_obj; - MemoryRegion iomem; - qemu_irq irq; - /* 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; -} VirtIOMMIOProxy; - static bool virtio_mmio_ioeventfd_enabled(DeviceState *d) { return kvm_eventfds_enabled(); diff --git a/include/hw/virtio/virtio-mmio.h b/include/hw/virtio/virtio-mmi= o.h new file mode 100644 index 0000000000..2f3973f8c7 --- /dev/null +++ b/include/hw/virtio/virtio-mmio.h @@ -0,0 +1,60 @@ +/* + * Virtio MMIO bindings + * + * Copyright (c) 2011 Linaro Limited + * + * Author: + * Peter Maydell + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + */ + +#ifndef QEMU_VIRTIO_MMIO_H +#define QEMU_VIRTIO_MMIO_H + +#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 1 +#define VIRT_VENDOR 0x554D4551 /* 'QEMU' */ + +typedef struct { + /* Generic */ + SysBusDevice parent_obj; + MemoryRegion iomem; + qemu_irq irq; + /* 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; +} VirtIOMMIOProxy; + +#endif --=20 2.21.0 From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569332081; cv=none; d=zoho.com; s=zohoarc; b=K3CnceVVLlesqxCMvbRMOzvLi9qIooDyPqzsosWrhitD8B8MXm7u/ZwPfKUO3nBF0aw5xCWYWYnrNgMr03/C+n6p6JV/XeaL9YdoKy/PONBbyAbLmv1/0OJcP4GCO43t9TOKTubt9ZIZYaftQ+bxADHR+ZLNngoAKymoBRX9SKA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569332081; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=J7H3EM+Syu3hfpjwhV1/O2AVZFAR37T5PWV3AockLfg=; b=PKG0y2yHJQOZWSNbLX2TbCEdMCNpsAP/POQ1CosuVZp3pPTurg4iQRacQdA66DCTjPwcEAn+KH3ZMzWNuIQ/hwie4SSoTvnJqEkfQrVxaYri6BJdidBAkn8+DvltQR6lc2cEP4CICAzZxhCYbWqy9Ulgui0YnRxizbISbz6BGds= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569332081568986.7045092947914; Tue, 24 Sep 2019 06:34:41 -0700 (PDT) Received: from localhost ([::1]:45732 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkxj-0003xj-KU for importer@patchew.org; Tue, 24 Sep 2019 09:34:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52393) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkCX-0002zH-4K for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:03 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkCM-0004qA-P5 for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:52 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58490) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkCJ-0004pC-0s for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:40 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 044518A1C99; Tue, 24 Sep 2019 12:45:37 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id C6A6760852; Tue, 24 Sep 2019 12:45:30 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 4/8] hw/i386: split PCMachineState deriving X86MachineState from it Date: Tue, 24 Sep 2019 14:44:29 +0200 Message-Id: <20190924124433.96810-5-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.6.2 (mx1.redhat.com [10.5.110.69]); Tue, 24 Sep 2019 12:45:37 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Split up PCMachineState and PCMachineClass and derive X86MachineState and X86MachineClass from them. This allows sharing code with non-PC machine types. Also, move shared functions from pc.c to x86.c. Signed-off-by: Sergio Lopez Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/acpi/cpu_hotplug.c | 10 +- hw/i386/Makefile.objs | 1 + hw/i386/acpi-build.c | 31 +- hw/i386/amd_iommu.c | 4 +- hw/i386/intel_iommu.c | 4 +- hw/i386/pc.c | 796 +++++------------------------------------- hw/i386/pc_piix.c | 48 +-- hw/i386/pc_q35.c | 38 +- hw/i386/pc_sysfw.c | 60 +--- hw/i386/x86.c | 788 +++++++++++++++++++++++++++++++++++++++++ hw/intc/ioapic.c | 3 +- include/hw/i386/pc.h | 29 +- include/hw/i386/x86.h | 97 +++++ 13 files changed, 1045 insertions(+), 864 deletions(-) create mode 100644 hw/i386/x86.c create mode 100644 include/hw/i386/x86.h diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index 6e8293aac9..3ac2045a95 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -128,7 +128,7 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineStat= e *machine, Aml *one =3D aml_int(1); MachineClass *mc =3D MACHINE_GET_CLASS(machine); const CPUArchIdList *apic_ids =3D mc->possible_cpu_arch_ids(machine); - PCMachineState *pcms =3D PC_MACHINE(machine); + X86MachineState *x86ms =3D X86_MACHINE(machine); =20 /* * _MAT method - creates an madt apic buffer @@ -236,9 +236,9 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineStat= e *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); } =20 @@ -315,8 +315,8 @@ void build_legacy_cpu_hotplug_aml(Aml *ctx, MachineStat= e *machine, * ith up to 255 elements. Windows guests up to win2k8 fail when * VarPackageOp is used. */ - pkg =3D pcms->apic_id_limit <=3D 255 ? aml_package(pcms->apic_id_limit= ) : - aml_varpackage(pcms->apic_id_limit); + pkg =3D x86ms->apic_id_limit <=3D 255 ? aml_package(x86ms->apic_id_lim= it) : + aml_varpackage(x86ms->apic_id_limi= t); =20 for (i =3D 0, apic_idx =3D 0; i < apic_ids->len; i++) { int apic_id =3D apic_ids->cpus[i].arch_id; diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 149712db07..5b4b3a672e 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,6 +1,7 @@ obj-$(CONFIG_KVM) +=3D kvm/ obj-y +=3D multiboot.o obj-y +=3D pvh.o +obj-y +=3D x86.o obj-y +=3D pc.o obj-y +=3D e820.o obj-$(CONFIG_I440FX) +=3D pc_piix.o diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index e54e571a75..76e18d3285 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -29,6 +29,7 @@ #include "hw/pci/pci.h" #include "hw/core/cpu.h" #include "target/i386/cpu.h" +#include "hw/i386/x86.h" #include "hw/misc/pvpanic.h" #include "hw/timer/hpet.h" #include "hw/acpi/acpi-defs.h" @@ -361,6 +362,7 @@ static void build_madt(GArray *table_data, BIOSLinker *linker, PCMachineState *pcms) { MachineClass *mc =3D MACHINE_GET_CLASS(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); const CPUArchIdList *apic_ids =3D mc->possible_cpu_arch_ids(MACHINE(pc= ms)); int madt_start =3D table_data->len; AcpiDeviceIfClass *adevc =3D ACPI_DEVICE_IF_GET_CLASS(pcms->acpi_dev); @@ -390,7 +392,7 @@ build_madt(GArray *table_data, BIOSLinker *linker, PCMa= chineState *pcms) io_apic->address =3D cpu_to_le32(IO_APIC_DEFAULT_ADDRESS); io_apic->interrupt =3D cpu_to_le32(0); =20 - if (pcms->apic_xrupt_override) { + if (x86ms->apic_xrupt_override) { intsrcovr =3D acpi_data_push(table_data, sizeof *intsrcovr); intsrcovr->type =3D ACPI_APIC_XRUPT_OVERRIDE; intsrcovr->length =3D sizeof(*intsrcovr); @@ -1817,8 +1819,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, CrsRangeEntry *entry; Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs; CrsRangeSet crs_range_set; - PCMachineState *pcms =3D PC_MACHINE(machine); PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(machine); + X86MachineState *x86ms =3D X86_MACHINE(machine); AcpiMcfgInfo mcfg; uint32_t nr_mem =3D machine->ram_slots; int root_bus_limit =3D 0xFF; @@ -2083,7 +2085,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 =3D object_property_get_bool(OBJECT(pcms->fw_cfg), + uint8_t io_size =3D 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; @@ -2318,6 +2320,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, Ma= chineState *machine) MachineClass *mc =3D MACHINE_GET_CLASS(machine); const CPUArchIdList *apic_ids =3D mc->possible_cpu_arch_ids(machine); PCMachineState *pcms =3D PC_MACHINE(machine); + X86MachineState *x86ms =3D X86_MACHINE(machine); ram_addr_t hotplugabble_address_space_size =3D object_property_get_int(OBJECT(pcms), PC_MACHINE_DEVMEM_REGION_SIZ= E, NULL); @@ -2386,16 +2389,16 @@ build_srat(GArray *table_data, BIOSLinker *linker, = MachineState *machine) } =20 /* Cut out the ACPI_PCI hole */ - if (mem_base <=3D pcms->below_4g_mem_size && - next_base > pcms->below_4g_mem_size) { - mem_len -=3D next_base - pcms->below_4g_mem_size; + if (mem_base <=3D x86ms->below_4g_mem_size && + next_base > x86ms->below_4g_mem_size) { + mem_len -=3D next_base - x86ms->below_4g_mem_size; if (mem_len > 0) { numamem =3D acpi_data_push(table_data, sizeof *numamem); build_srat_memory(numamem, mem_base, mem_len, i - 1, MEM_AFFINITY_ENABLED); } mem_base =3D 1ULL << 32; - mem_len =3D next_base - pcms->below_4g_mem_size; + mem_len =3D next_base - x86ms->below_4g_mem_size; next_base =3D mem_base + mem_len; } =20 @@ -2614,6 +2617,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState= *machine) { PCMachineState *pcms =3D PC_MACHINE(machine); PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); + X86MachineState *x86ms =3D X86_MACHINE(machine); GArray *table_offsets; unsigned facs, dsdt, rsdt, fadt; AcpiPmInfo pm; @@ -2775,7 +2779,7 @@ void acpi_build(AcpiBuildTables *tables, MachineState= *machine) */ int legacy_aml_len =3D 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 =3D ROUND_UP(tables_blob->len - aml_len + legacy_aml_len, ACPI_BUILD_ALIGN_SIZE); @@ -2865,13 +2869,14 @@ void acpi_setup(void) { PCMachineState *pcms =3D PC_MACHINE(qdev_get_machine()); PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); AcpiBuildTables tables; AcpiBuildState *build_state; Object *vmgenid_dev; TPMIf *tpm; static FwCfgTPMConfig tpm_config; =20 - if (!pcms->fw_cfg) { + if (!x86ms->fw_cfg) { ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n"); return; } @@ -2902,7 +2907,7 @@ void acpi_setup(void) acpi_add_rom_blob(acpi_build_update, build_state, tables.linker->cmd_blob, "etc/table-loader", 0); =20 - 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)); =20 tpm =3D tpm_find(); @@ -2912,13 +2917,13 @@ void acpi_setup(void) .tpm_version =3D tpm_get_version(tpm), .tpmppi_version =3D 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); } =20 vmgenid_dev =3D 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); } =20 @@ -2931,7 +2936,7 @@ void acpi_setup(void) uint32_t rsdp_size =3D acpi_data_len(tables.rsdp); =20 build_state->rsdp =3D 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 =3D NULL; diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 08884523e2..bb3b5b4563 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -21,6 +21,7 @@ */ =20 #include "qemu/osdep.h" +#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/pci/msi.h" #include "hw/pci/pci_bus.h" @@ -1537,6 +1538,7 @@ static void amdvi_realize(DeviceState *dev, Error **e= rr) X86IOMMUState *x86_iommu =3D X86_IOMMU_DEVICE(dev); MachineState *ms =3D MACHINE(qdev_get_machine()); PCMachineState *pcms =3D PC_MACHINE(ms); + X86MachineState *x86ms =3D X86_MACHINE(ms); PCIBus *bus =3D pcms->bus; =20 s->iotlb =3D g_hash_table_new_full(amdvi_uint64_hash, @@ -1565,7 +1567,7 @@ static void amdvi_realize(DeviceState *dev, Error **e= rr) } =20 /* Pseudo address space under root PCI bus. */ - pcms->ioapic_as =3D amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID= ); + x86ms->ioapic_as =3D amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVI= D); =20 /* set up MMIO */ memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mm= io", diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 75ca6f9c70..21f091c654 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -29,6 +29,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" +#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/i386/apic-msidef.h" #include "hw/boards.h" @@ -3703,6 +3704,7 @@ static void vtd_realize(DeviceState *dev, Error **err= p) { MachineState *ms =3D MACHINE(qdev_get_machine()); PCMachineState *pcms =3D PC_MACHINE(ms); + X86MachineState *x86ms =3D X86_MACHINE(ms); PCIBus *bus =3D pcms->bus; IntelIOMMUState *s =3D INTEL_IOMMU_DEVICE(dev); X86IOMMUState *x86_iommu =3D X86_IOMMU_DEVICE(dev); @@ -3743,7 +3745,7 @@ static void vtd_realize(DeviceState *dev, Error **err= p) 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 =3D vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC= ); + x86ms->ioapic_as =3D vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPI= C); } =20 static void vtd_class_init(ObjectClass *klass, void *data) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 3920aa7e85..d18b461f01 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -24,6 +24,7 @@ =20 #include "qemu/osdep.h" #include "qemu/units.h" +#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/char/serial.h" #include "hw/char/parallel.h" @@ -676,6 +677,7 @@ void pc_cmos_init(PCMachineState *pcms, BusState *idebus0, BusState *idebus1, ISADevice *s) { + X86MachineState *x86ms =3D X86_MACHINE(pcms); int val; static pc_cmos_init_late_arg arg; =20 @@ -683,12 +685,12 @@ void pc_cmos_init(PCMachineState *pcms, =20 /* memory size */ /* base memory (first MiB) */ - val =3D MIN(pcms->below_4g_mem_size / KiB, 640); + val =3D MIN(x86ms->below_4g_mem_size / KiB, 640); rtc_set_memory(s, 0x15, val); rtc_set_memory(s, 0x16, val >> 8); /* extended memory (next 64MiB) */ - if (pcms->below_4g_mem_size > 1 * MiB) { - val =3D (pcms->below_4g_mem_size - 1 * MiB) / KiB; + if (x86ms->below_4g_mem_size > 1 * MiB) { + val =3D (x86ms->below_4g_mem_size - 1 * MiB) / KiB; } else { val =3D 0; } @@ -699,8 +701,8 @@ void pc_cmos_init(PCMachineState *pcms, rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); /* memory between 16MiB and 4GiB */ - if (pcms->below_4g_mem_size > 16 * MiB) { - val =3D (pcms->below_4g_mem_size - 16 * MiB) / (64 * KiB); + if (x86ms->below_4g_mem_size > 16 * MiB) { + val =3D (x86ms->below_4g_mem_size - 16 * MiB) / (64 * KiB); } else { val =3D 0; } @@ -709,20 +711,20 @@ void pc_cmos_init(PCMachineState *pcms, rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); /* memory above 4GiB */ - val =3D pcms->above_4g_mem_size / 65536; + val =3D x86ms->above_4g_mem_size / 65536; rtc_set_memory(s, 0x5b, val); rtc_set_memory(s, 0x5c, val >> 8); rtc_set_memory(s, 0x5d, val >> 16); =20 - object_property_add_link(OBJECT(pcms), "rtc_state", + object_property_add_link(OBJECT(x86ms), "rtc_state", TYPE_ISA_DEVICE, - (Object **)&pcms->rtc, + (Object **)&x86ms->rtc, object_property_allow_set_link, OBJ_PROP_LINK_STRONG, &error_abort); - object_property_set_link(OBJECT(pcms), OBJECT(s), + object_property_set_link(OBJECT(x86ms), OBJECT(s), "rtc_state", &error_abort); =20 - set_boot_dev(s, MACHINE(pcms)->boot_order, &error_fatal); + set_boot_dev(s, MACHINE(x86ms)->boot_order, &error_fatal); =20 val =3D 0; val |=3D 0x02; /* FPU is there */ @@ -863,35 +865,6 @@ static void handle_a20_line_change(void *opaque, int i= rq, int level) x86_cpu_set_a20(cpu, level); } =20 -/* 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 interface= s 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 =3D MACHINE(pcms); - PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); - uint32_t correct_id; - static bool warned; - - correct_id =3D 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 !=3D correct_id && !warned && !qtest_enabled()) { - error_report("APIC IDs set in compatibility mode, " - "CPU topology won't match the configuration"); - warned =3D true; - } - return cpu_index; - } else { - return correct_id; - } -} - static void pc_build_smbios(PCMachineState *pcms) { uint8_t *smbios_tables, *smbios_anchor; @@ -899,6 +872,7 @@ static void pc_build_smbios(PCMachineState *pcms) struct smbios_phys_mem_area *mem_array; unsigned i, array_count; MachineState *ms =3D MACHINE(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); X86CPU *cpu =3D X86_CPU(ms->possible_cpus->cpus[0].cpu); =20 /* tell smbios about cpuid version and features */ @@ -906,7 +880,7 @@ static void pc_build_smbios(PCMachineState *pcms) =20 smbios_tables =3D smbios_get_table_legacy(ms, &smbios_tables_len); if (smbios_tables) { - fw_cfg_add_bytes(pcms->fw_cfg, FW_CFG_SMBIOS_ENTRIES, + fw_cfg_add_bytes(x86ms->fw_cfg, FW_CFG_SMBIOS_ENTRIES, smbios_tables, smbios_tables_len); } =20 @@ -927,9 +901,9 @@ static void pc_build_smbios(PCMachineState *pcms) g_free(mem_array); =20 if (smbios_anchor) { - fw_cfg_add_file(pcms->fw_cfg, "etc/smbios/smbios-tables", + fw_cfg_add_file(x86ms->fw_cfg, "etc/smbios/smbios-tables", smbios_tables, smbios_tables_len); - fw_cfg_add_file(pcms->fw_cfg, "etc/smbios/smbios-anchor", + fw_cfg_add_file(x86ms->fw_cfg, "etc/smbios/smbios-anchor", smbios_anchor, smbios_anchor_len); } } @@ -942,10 +916,11 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, = PCMachineState *pcms) const CPUArchIdList *cpus; MachineClass *mc =3D MACHINE_GET_CLASS(pcms); MachineState *ms =3D MACHINE(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); int nb_numa_nodes =3D ms->numa_state->num_nodes; =20 fw_cfg =3D fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, as); - fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); =20 /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: * @@ -959,7 +934,7 @@ static FWCfgState *bochs_bios_init(AddressSpace *as, PC= MachineState *pcms) * So for compatibility reasons with old BIOSes we are stuck with * "etc/max-cpus" actually being apic_id_limit */ - fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)pcms->apic_id_limit); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)x86ms->apic_id_limit= ); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, acpi_tables, acpi_tables_len); @@ -972,374 +947,25 @@ static FWCfgState *bochs_bios_init(AddressSpace *as,= PCMachineState *pcms) * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. */ - numa_fw_cfg =3D g_new0(uint64_t, 1 + pcms->apic_id_limit + nb_numa_nod= es); + numa_fw_cfg =3D g_new0(uint64_t, 1 + x86ms->apic_id_limit + nb_numa_no= des); numa_fw_cfg[0] =3D cpu_to_le64(nb_numa_nodes); cpus =3D mc->possible_cpu_arch_ids(MACHINE(pcms)); for (i =3D 0; i < cpus->len; i++) { unsigned int apic_id =3D cpus->cpus[i].arch_id; - assert(apic_id < pcms->apic_id_limit); + assert(apic_id < x86ms->apic_id_limit); numa_fw_cfg[apic_id + 1] =3D cpu_to_le64(cpus->cpus[i].props.node_= id); } for (i =3D 0; i < nb_numa_nodes; i++) { - numa_fw_cfg[pcms->apic_id_limit + 1 + i] =3D + numa_fw_cfg[x86ms->apic_id_limit + 1 + i] =3D cpu_to_le64(ms->numa_state->nodes[i].node_mem); } fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, - (1 + pcms->apic_id_limit + nb_numa_nodes) * + (1 + x86ms->apic_id_limit + nb_numa_nodes) * sizeof(*numa_fw_cfg)); =20 return fw_cfg; } =20 -static long get_file_size(FILE *f) -{ - long where, size; - - /* XXX: on Unix systems, using fstat() probably makes more sense */ - - where =3D ftell(f); - fseek(f, 0, SEEK_END); - size =3D 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)); - -static void 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 =3D 0; - FILE *f; - char *vmode; - MachineState *machine =3D MACHINE(pcms); - PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); - struct setup_data *setup_data; - const char *kernel_filename =3D machine->kernel_filename; - const char *initrd_filename =3D machine->initrd_filename; - const char *dtb_filename =3D machine->dtb; - const char *kernel_cmdline =3D machine->kernel_cmdline; - - /* Align to 16 bytes as a paranoia measure */ - cmdline_size =3D (strlen(kernel_cmdline)+16) & ~15; - - /* load the kernel header */ - f =3D fopen(kernel_filename, "rb"); - if (!f || !(kernel_size =3D get_file_size(f)) || - fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=3D - 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) =3D=3D 0x53726448) { - protocol =3D lduw_p(header+0x206); - } else { - size_t pvh_start_addr; - uint32_t mh_load_addr =3D 0; - uint32_t elf_kernel_size =3D 0; - /* - * 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 sam= e of - * PVH), so we try multiboot first since we check the multiboot ma= gic - * 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 && - pvh_load_elfboot(kernel_filename, - &mh_load_addr, &elf_kernel_size)) { - fclose(f); - - pvh_start_addr =3D pvh_get_start_addr(); - - 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); - - 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 =3D NULL; - - mapped_file =3D 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 =3D mapped_file; - - initrd_data =3D g_mapped_file_get_contents(mapped_file); - initrd_size =3D g_mapped_file_get_length(mapped_file); - initrd_max =3D pcms->below_4g_mem_size - pcmc->acpi_data_s= ize - 1; - if (initrd_size >=3D initrd_max) { - fprintf(stderr, "qemu: initrd is too large, cannot sup= port." - "(max: %"PRIu32", need %"PRId64")\n", - initrd_max, (uint64_t)initrd_size); - exit(1); - } - - initrd_addr =3D (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 =3D 0; - option_rom[nb_option_roms].name =3D "pvh.bin"; - nb_option_roms++; - - return; - } - protocol =3D 0; - } - - if (protocol < 0x200 || !(header[0x211] & 0x01)) { - /* Low kernel */ - real_addr =3D 0x90000; - cmdline_addr =3D 0x9a000 - cmdline_size; - prot_addr =3D 0x10000; - } else if (protocol < 0x202) { - /* High but ancient kernel */ - real_addr =3D 0x90000; - cmdline_addr =3D 0x9a000 - cmdline_size; - prot_addr =3D 0x100000; - } else { - /* High and recent kernel */ - real_addr =3D 0x10000; - cmdline_addr =3D 0x20000; - prot_addr =3D 0x100000; - } - -#if 0 - fprintf(stderr, - "qemu: real_addr =3D 0x" TARGET_FMT_plx "\n" - "qemu: cmdline_addr =3D 0x" TARGET_FMT_plx "\n" - "qemu: prot_addr =3D 0x" TARGET_FMT_plx "\n", - real_addr, - cmdline_addr, - prot_addr); -#endif - - /* highest address for loading the initrd */ - if (protocol >=3D 0x20c && - lduw_p(header+0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) { - /* - * Linux has supported initrd up to 4 GB for a very long time (200= 7, - * 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 bootload= er - * bugs". Luckily, QEMU firmware(which does something like bootloa= der) - * 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 we= ll. - */ - initrd_max =3D UINT32_MAX; - } else if (protocol >=3D 0x203) { - initrd_max =3D ldl_p(header+0x22c); - } else { - initrd_max =3D 0x37ffffff; - } - - if (initrd_max >=3D pcms->below_4g_mem_size - pcmc->acpi_data_size) { - initrd_max =3D 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 >=3D 0x202) { - stl_p(header+0x228, cmdline_addr); - } else { - stw_p(header+0x20, 0xA33F); - stw_p(header+0x22, cmdline_addr-real_addr); - } - - /* handle vga=3D parameter */ - vmode =3D strstr(kernel_cmdline, "vga=3D"); - if (vmode) { - unsigned int video_mode; - /* skip "vga=3D" */ - vmode +=3D 4; - if (!strncmp(vmode, "normal", 6)) { - video_mode =3D 0xffff; - } else if (!strncmp(vmode, "ext", 3)) { - video_mode =3D 0xfffe; - } else if (!strncmp(vmode, "ask", 3)) { - video_mode =3D 0xfffd; - } else { - video_mode =3D strtol(vmode, NULL, 0); - } - stw_p(header+0x1fa, video_mode); - } - - /* loader type */ - /* High nybble =3D 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 >=3D 0x200) { - header[0x210] =3D 0xB0; - } - /* heap */ - if (protocol >=3D 0x201) { - header[0x211] |=3D 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 =3D NULL; - - if (protocol < 0x200) { - fprintf(stderr, "qemu: linux kernel too old to load a ram disk= \n"); - exit(1); - } - - mapped_file =3D 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 =3D mapped_file; - - initrd_data =3D g_mapped_file_get_contents(mapped_file); - initrd_size =3D g_mapped_file_get_length(mapped_file); - if (initrd_size >=3D 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 =3D (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_s= ize); - - stl_p(header+0x218, initrd_addr); - stl_p(header+0x21c, initrd_size); - } - - /* load kernel and setup */ - setup_size =3D header[0x1f1]; - if (setup_size =3D=3D 0) { - setup_size =3D 4; - } - setup_size =3D (setup_size+1)*512; - if (setup_size > kernel_size) { - fprintf(stderr, "qemu: invalid kernel header\n"); - exit(1); - } - kernel_size -=3D setup_size; - - setup =3D g_malloc(setup_size); - kernel =3D g_malloc(kernel_size); - fseek(f, 0, SEEK_SET); - if (fread(setup, 1, setup_size, f) !=3D setup_size) { - fprintf(stderr, "fread() failed\n"); - exit(1); - } - if (fread(kernel, 1, kernel_size, f) !=3D 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 =3D get_image_size(dtb_filename); - if (dtb_size <=3D 0) { - fprintf(stderr, "qemu: error reading dtb %s: %s\n", - dtb_filename, strerror(errno)); - exit(1); - } - - setup_data_offset =3D QEMU_ALIGN_UP(kernel_size, 16); - kernel_size =3D setup_data_offset + sizeof(struct setup_data) + dt= b_size; - kernel =3D g_realloc(kernel, kernel_size); - - stq_p(header+0x250, prot_addr + setup_data_offset); - - setup_data =3D (struct setup_data *)(kernel + setup_data_offset); - setup_data->next =3D 0; - setup_data->type =3D cpu_to_le32(SETUP_DTB); - setup_data->len =3D 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 =3D 0; - option_rom[nb_option_roms].name =3D "linuxboot.bin"; - if (pcmc->linuxboot_dma_enabled && fw_cfg_dma_enabled(fw_cfg)) { - option_rom[nb_option_roms].name =3D "linuxboot_dma.bin"; - } - nb_option_roms++; -} - #define NE2000_NB_MAX 6 =20 static const int ne2000_io[NE2000_NB_MAX] =3D { 0x300, 0x320, 0x340, 0x360, @@ -1376,157 +1002,10 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, = int level) } } =20 -static void pc_new_cpu(PCMachineState *pcms, int64_t apic_id, Error **errp) -{ - Object *cpu =3D NULL; - Error *local_err =3D NULL; - CPUX86State *env =3D NULL; - - cpu =3D object_new(MACHINE(pcms)->cpu_type); - - env =3D &X86_CPU(cpu)->env; - env->nr_dies =3D 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. - */ -void pc_smp_parse(MachineState *ms, QemuOpts *opts) -{ - PCMachineState *pcms =3D PC_MACHINE(ms); - - if (opts) { - unsigned cpus =3D qemu_opt_get_number(opts, "cpus", 0); - unsigned sockets =3D qemu_opt_get_number(opts, "sockets", 0); - unsigned dies =3D qemu_opt_get_number(opts, "dies", 1); - unsigned cores =3D qemu_opt_get_number(opts, "cores", 0); - unsigned threads =3D qemu_opt_get_number(opts, "threads", 0); - - /* compute missing values, prefer sockets over cores over threads = */ - if (cpus =3D=3D 0 || sockets =3D=3D 0) { - cores =3D cores > 0 ? cores : 1; - threads =3D threads > 0 ? threads : 1; - if (cpus =3D=3D 0) { - sockets =3D sockets > 0 ? sockets : 1; - cpus =3D cores * threads * dies * sockets; - } else { - ms->smp.max_cpus =3D - qemu_opt_get_number(opts, "maxcpus", cpus); - sockets =3D ms->smp.max_cpus / (cores * threads * dies); - } - } else if (cores =3D=3D 0) { - threads =3D threads > 0 ? threads : 1; - cores =3D cpus / (sockets * dies * threads); - cores =3D cores > 0 ? cores : 1; - } else if (threads =3D=3D 0) { - threads =3D cpus / (cores * dies * sockets); - threads =3D threads > 0 ? threads : 1; - } else if (sockets * dies * cores * threads < cpus) { - error_report("cpu topology: " - "sockets (%u) * dies (%u) * cores (%u) * threads = (%u) < " - "smp_cpus (%u)", - sockets, dies, cores, threads, cpus); - exit(1); - } - - ms->smp.max_cpus =3D - qemu_opt_get_number(opts, "maxcpus", cpus); - - if (ms->smp.max_cpus < cpus) { - error_report("maxcpus must be equal to or greater than smp"); - exit(1); - } - - if (sockets * dies * cores * threads > ms->smp.max_cpus) { - error_report("cpu topology: " - "sockets (%u) * dies (%u) * cores (%u) * threads = (%u) > " - "maxcpus (%u)", - sockets, dies, cores, threads, - ms->smp.max_cpus); - exit(1); - } - - if (sockets * dies * cores * threads !=3D ms->smp.max_cpus) { - warn_report("Invalid CPU topology deprecated: " - "sockets (%u) * dies (%u) * cores (%u) * threads (= %u) " - "!=3D maxcpus (%u)", - sockets, dies, cores, threads, - ms->smp.max_cpus); - } - - ms->smp.cpus =3D cpus; - ms->smp.cores =3D cores; - ms->smp.threads =3D threads; - pcms->smp_dies =3D dies; - } - - if (ms->smp.cpus > 1) { - Error *blocker =3D NULL; - error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp"); - replay_add_blocker(blocker); - } -} - -void pc_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp) -{ - PCMachineState *pcms =3D PC_MACHINE(ms); - int64_t apic_id =3D x86_cpu_apic_id_from_index(pcms, id); - Error *local_err =3D NULL; - - if (id < 0) { - error_setg(errp, "Invalid CPU id: %" PRIi64, id); - return; - } - - if (apic_id >=3D ACPI_CPU_HOTPLUG_ID_LIMIT) { - error_setg(errp, "Unable to add CPU: %" PRIi64 - ", resulting APIC ID (%" PRIi64 ") is too large", - id, apic_id); - return; - } - - pc_new_cpu(PC_MACHINE(ms), apic_id, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; - } -} - -void pc_cpus_init(PCMachineState *pcms) -{ - int i; - const CPUArchIdList *possible_cpus; - MachineState *ms =3D MACHINE(pcms); - MachineClass *mc =3D MACHINE_GET_CLASS(pcms); - PCMachineClass *pcmc =3D 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 bochs_bios_init(). - */ - pcms->apic_id_limit =3D x86_cpu_apic_id_from_index(pcms, - ms->smp.max_cpus - 1)= + 1; - possible_cpus =3D mc->possible_cpu_arch_ids(ms); - for (i =3D 0; i < ms->smp.cpus; i++) { - pc_new_cpu(pcms, possible_cpus->cpus[i].arch_id, &error_fatal); - } -} - static void pc_build_feature_control_file(PCMachineState *pcms) { MachineState *ms =3D MACHINE(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); X86CPU *cpu =3D X86_CPU(ms->possible_cpus->cpus[0].cpu); CPUX86State *env =3D &cpu->env; uint32_t unused, ecx, edx; @@ -1550,7 +1029,7 @@ static void pc_build_feature_control_file(PCMachineSt= ate *pcms) =20 val =3D g_malloc(sizeof(*val)); *val =3D cpu_to_le64(feature_control_bits | FEATURE_CONTROL_LOCKED); - fw_cfg_add_file(pcms->fw_cfg, "etc/msr_feature_control", val, sizeof(*= val)); + fw_cfg_add_file(x86ms->fw_cfg, "etc/msr_feature_control", val, sizeof(= *val)); } =20 static void rtc_set_cpus_count(ISADevice *rtc, uint16_t cpus_count) @@ -1571,10 +1050,11 @@ void pc_machine_done(Notifier *notifier, void *data) { PCMachineState *pcms =3D container_of(notifier, PCMachineState, machine_done); + X86MachineState *x86ms =3D X86_MACHINE(pcms); PCIBus *bus =3D pcms->bus; =20 /* set the number of CPUs */ - rtc_set_cpus_count(pcms->rtc, pcms->boot_cpus); + rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); =20 if (bus) { int extra_hosts =3D 0; @@ -1585,23 +1065,23 @@ void pc_machine_done(Notifier *notifier, void *data) extra_hosts++; } } - if (extra_hosts && pcms->fw_cfg) { + if (extra_hosts && x86ms->fw_cfg) { uint64_t *val =3D g_malloc(sizeof(*val)); *val =3D cpu_to_le64(extra_hosts); - fw_cfg_add_file(pcms->fw_cfg, + fw_cfg_add_file(x86ms->fw_cfg, "etc/extra-pci-roots", val, sizeof(*val)); } } =20 acpi_setup(); - if (pcms->fw_cfg) { + if (x86ms->fw_cfg) { pc_build_smbios(pcms); pc_build_feature_control_file(pcms); /* update FW_CFG_NB_CPUS to account for -device added CPUs */ - fw_cfg_modify_i16(pcms->fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus); + fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); } =20 - if (pcms->apic_id_limit > 255 && !xen_enabled()) { + if (x86ms->apic_id_limit > 255 && !xen_enabled()) { IntelIOMMUState *iommu =3D INTEL_IOMMU_DEVICE(x86_iommu_get_defaul= t()); =20 if (!iommu || !x86_iommu_ir_supported(X86_IOMMU_DEVICE(iommu)) || @@ -1619,8 +1099,9 @@ void pc_guest_info_init(PCMachineState *pcms) { int i; MachineState *ms =3D MACHINE(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); =20 - pcms->apic_xrupt_override =3D kvm_allows_irq0_override(); + x86ms->apic_xrupt_override =3D kvm_allows_irq0_override(); pcms->numa_nodes =3D ms->numa_state->num_nodes; pcms->node_mem =3D g_malloc0(pcms->numa_nodes * sizeof *pcms->node_mem); @@ -1645,14 +1126,17 @@ void xen_load_linux(PCMachineState *pcms) { int i; FWCfgState *fw_cfg; + PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); =20 assert(MACHINE(pcms)->kernel_filename !=3D NULL); =20 fw_cfg =3D fw_cfg_init_io(FW_CFG_IO_BASE); - fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus); + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); rom_set_fw(fw_cfg); =20 - load_linux(pcms, fw_cfg); + load_linux(x86ms, fw_cfg, pcmc->acpi_data_size, + pcmc->linuxboot_dma_enabled, pcmc->pvh_enabled); for (i =3D 0; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "linuxboot_dma.bin") || @@ -1660,7 +1144,7 @@ void xen_load_linux(PCMachineState *pcms) !strcmp(option_rom[i].name, "multiboot.bin")); rom_add_option(option_rom[i].name, option_rom[i].bootindex); } - pcms->fw_cfg =3D fw_cfg; + x86ms->fw_cfg =3D fw_cfg; } =20 void pc_memory_init(PCMachineState *pcms, @@ -1673,10 +1157,11 @@ void pc_memory_init(PCMachineState *pcms, MemoryRegion *ram_below_4g, *ram_above_4g; FWCfgState *fw_cfg; MachineState *machine =3D MACHINE(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); =20 - assert(machine->ram_size =3D=3D pcms->below_4g_mem_size + - pcms->above_4g_mem_size); + assert(machine->ram_size =3D=3D x86ms->below_4g_mem_size + + x86ms->above_4g_mem_size); =20 linux_boot =3D (machine->kernel_filename !=3D NULL); =20 @@ -1690,17 +1175,17 @@ void pc_memory_init(PCMachineState *pcms, *ram_memory =3D ram; ram_below_4g =3D g_malloc(sizeof(*ram_below_4g)); memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ram, - 0, pcms->below_4g_mem_size); + 0, x86ms->below_4g_mem_size); memory_region_add_subregion(system_memory, 0, ram_below_4g); - e820_add_entry(0, pcms->below_4g_mem_size, E820_RAM); - if (pcms->above_4g_mem_size > 0) { + e820_add_entry(0, x86ms->below_4g_mem_size, E820_RAM); + if (x86ms->above_4g_mem_size > 0) { ram_above_4g =3D g_malloc(sizeof(*ram_above_4g)); memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g", ram, - pcms->below_4g_mem_size, - pcms->above_4g_mem_size); + x86ms->below_4g_mem_size, + x86ms->above_4g_mem_size); memory_region_add_subregion(system_memory, 0x100000000ULL, ram_above_4g); - e820_add_entry(0x100000000ULL, pcms->above_4g_mem_size, E820_RAM); + e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM); } =20 if (!pcmc->has_reserved_memory && @@ -1735,7 +1220,7 @@ void pc_memory_init(PCMachineState *pcms, } =20 machine->device_memory->base =3D - ROUND_UP(0x100000000ULL + pcms->above_4g_mem_size, 1 * GiB); + ROUND_UP(0x100000000ULL + x86ms->above_4g_mem_size, 1 * GiB); =20 if (pcmc->enforce_aligned_dimm) { /* size device region assuming 1G page max alignment per slot = */ @@ -1786,16 +1271,17 @@ void pc_memory_init(PCMachineState *pcms, } =20 if (linux_boot) { - load_linux(pcms, fw_cfg); + load_linux(x86ms, fw_cfg, pcmc->acpi_data_size, + pcmc->linuxboot_dma_enabled, pcmc->pvh_enabled); } =20 for (i =3D 0; i < nb_option_roms; i++) { rom_add_option(option_rom[i].name, option_rom[i].bootindex); } - pcms->fw_cfg =3D fw_cfg; + x86ms->fw_cfg =3D fw_cfg; =20 /* Init default IOAPIC address space */ - pcms->ioapic_as =3D &address_space_memory; + x86ms->ioapic_as =3D &address_space_memory; } =20 /* @@ -1807,6 +1293,7 @@ uint64_t pc_pci_hole64_start(void) PCMachineState *pcms =3D PC_MACHINE(qdev_get_machine()); PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); MachineState *ms =3D MACHINE(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); uint64_t hole64_start =3D 0; =20 if (pcmc->has_reserved_memory && ms->device_memory->base) { @@ -1815,7 +1302,7 @@ uint64_t pc_pci_hole64_start(void) hole64_start +=3D memory_region_size(&ms->device_memory->mr); } } else { - hole64_start =3D 0x100000000ULL + pcms->above_4g_mem_size; + hole64_start =3D 0x100000000ULL + x86ms->above_4g_mem_size; } =20 return ROUND_UP(hole64_start, 1 * GiB); @@ -2154,6 +1641,7 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev, Error *local_err =3D NULL; X86CPU *cpu =3D X86_CPU(dev); PCMachineState *pcms =3D PC_MACHINE(hotplug_dev); + X86MachineState *x86ms =3D X86_MACHINE(pcms); =20 if (pcms->acpi_dev) { hotplug_handler_plug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_= err); @@ -2163,12 +1651,12 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev, } =20 /* increment the number of CPUs */ - pcms->boot_cpus++; - if (pcms->rtc) { - rtc_set_cpus_count(pcms->rtc, pcms->boot_cpus); + x86ms->boot_cpus++; + if (x86ms->rtc) { + rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); } - if (pcms->fw_cfg) { - fw_cfg_modify_i16(pcms->fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus); + if (x86ms->fw_cfg) { + fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); } =20 found_cpu =3D pc_find_cpu_slot(MACHINE(pcms), cpu->apic_id, NULL); @@ -2214,6 +1702,7 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplug_= dev, Error *local_err =3D NULL; X86CPU *cpu =3D X86_CPU(dev); PCMachineState *pcms =3D PC_MACHINE(hotplug_dev); + X86MachineState *x86ms =3D X86_MACHINE(pcms); =20 hotplug_handler_unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_er= r); if (local_err) { @@ -2225,10 +1714,10 @@ static void pc_cpu_unplug_cb(HotplugHandler *hotplu= g_dev, object_property_set_bool(OBJECT(dev), false, "realized", NULL); =20 /* decrement the number of CPUs */ - pcms->boot_cpus--; + x86ms->boot_cpus--; /* Update the number of CPUs in CMOS */ - rtc_set_cpus_count(pcms->rtc, pcms->boot_cpus); - fw_cfg_modify_i16(pcms->fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus); + rtc_set_cpus_count(x86ms->rtc, x86ms->boot_cpus); + fw_cfg_modify_i16(x86ms->fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); out: error_propagate(errp, local_err); } @@ -2244,6 +1733,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_d= ev, CPUX86State *env =3D &cpu->env; MachineState *ms =3D MACHINE(hotplug_dev); PCMachineState *pcms =3D PC_MACHINE(hotplug_dev); + X86MachineState *x86ms =3D X86_MACHINE(hotplug_dev); unsigned int smp_cores =3D ms->smp.cores; unsigned int smp_threads =3D ms->smp.threads; =20 @@ -2253,7 +1743,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_d= ev, return; } =20 - env->nr_dies =3D pcms->smp_dies; + env->nr_dies =3D x86ms->smp_dies; =20 /* * If APIC ID is not set, @@ -2261,13 +1751,13 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug= _dev, */ if (cpu->apic_id =3D=3D UNASSIGNED_APIC_ID) { int max_socket =3D (ms->smp.max_cpus - 1) / - smp_threads / smp_cores / pcms->smp_dies; + smp_threads / smp_cores / x86ms->smp_dies; =20 /* * die-id was optional in QEMU 4.0 and older, so keep it optional * if there's only one die per socket. */ - if (cpu->die_id < 0 && pcms->smp_dies =3D=3D 1) { + if (cpu->die_id < 0 && x86ms->smp_dies =3D=3D 1) { cpu->die_id =3D 0; } =20 @@ -2282,9 +1772,9 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_d= ev, if (cpu->die_id < 0) { error_setg(errp, "CPU die-id is not set"); return; - } else if (cpu->die_id > pcms->smp_dies - 1) { + } else if (cpu->die_id > x86ms->smp_dies - 1) { error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u= ", - cpu->die_id, pcms->smp_dies - 1); + cpu->die_id, x86ms->smp_dies - 1); return; } if (cpu->core_id < 0) { @@ -2308,7 +1798,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_d= ev, topo.die_id =3D cpu->die_id; topo.core_id =3D cpu->core_id; topo.smt_id =3D cpu->thread_id; - cpu->apic_id =3D apicid_from_topo_ids(pcms->smp_dies, smp_cores, + cpu->apic_id =3D apicid_from_topo_ids(x86ms->smp_dies, smp_cores, smp_threads, &topo); } =20 @@ -2316,7 +1806,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_d= ev, if (!cpu_slot) { MachineState *ms =3D MACHINE(pcms); =20 - x86_topo_ids_from_apicid(cpu->apic_id, pcms->smp_dies, + x86_topo_ids_from_apicid(cpu->apic_id, x86ms->smp_dies, smp_cores, smp_threads, &topo); error_setg(errp, "Invalid CPU [socket: %u, die: %u, core: %u, thread: %u] with" @@ -2338,7 +1828,7 @@ static void pc_cpu_pre_plug(HotplugHandler *hotplug_d= ev, /* TODO: move socket_id/core_id/thread_id checks into x86_cpu_realizef= n() * once -smp refactoring is complete and there will be CPU private * CPUState::nr_cores and CPUState::nr_threads fields instead of globa= ls */ - x86_topo_ids_from_apicid(cpu->apic_id, pcms->smp_dies, + x86_topo_ids_from_apicid(cpu->apic_id, x86ms->smp_dies, smp_cores, smp_threads, &topo); if (cpu->socket_id !=3D -1 && cpu->socket_id !=3D topo.pkg_id) { error_setg(errp, "property socket-id: %u doesn't match set apic-id= :" @@ -2520,45 +2010,6 @@ pc_machine_get_device_memory_region_size(Object *obj= , Visitor *v, visit_type_int(v, name, &value, errp); } =20 -static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - PCMachineState *pcms =3D PC_MACHINE(obj); - uint64_t value =3D pcms->max_ram_below_4g; - - visit_type_size(v, name, &value, errp); -} - -static void pc_machine_set_max_ram_below_4g(Object *obj, Visitor *v, - const char *name, void *opaque, - Error **errp) -{ - PCMachineState *pcms =3D PC_MACHINE(obj); - Error *error =3D NULL; - uint64_t value; - - visit_type_size(v, name, &value, &error); - if (error) { - error_propagate(errp, error); - return; - } - if (value > 4 * GiB) { - error_setg(&error, - "Machine option 'max-ram-below-4g=3D%"PRIu64 - "' expects size less than or equal to 4G", value); - error_propagate(errp, error); - return; - } - - if (value < 1 * MiB) { - warn_report("Only %" PRIu64 " bytes of RAM below the 4GiB boundary= ," - "BIOS may not work with less than 1MiB", value); - } - - pcms->max_ram_below_4g =3D value; -} - static void pc_machine_get_vmport(Object *obj, Visitor *v, const char *nam= e, void *opaque, Error **errp) { @@ -2664,7 +2115,6 @@ static void pc_machine_initfn(Object *obj) { PCMachineState *pcms =3D PC_MACHINE(obj); =20 - pcms->max_ram_below_4g =3D 0; /* use default */ pcms->smm =3D ON_OFF_AUTO_AUTO; #ifdef CONFIG_VMPORT pcms->vmport =3D ON_OFF_AUTO_AUTO; @@ -2676,7 +2126,6 @@ static void pc_machine_initfn(Object *obj) pcms->smbus_enabled =3D true; pcms->sata_enabled =3D true; pcms->pit_enabled =3D true; - pcms->smp_dies =3D 1; =20 pc_system_flash_create(pcms); } @@ -2707,85 +2156,6 @@ static void pc_machine_wakeup(MachineState *machine) cpu_synchronize_all_post_reset(); } =20 -static CpuInstanceProperties -pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index) -{ - MachineClass *mc =3D MACHINE_GET_CLASS(ms); - const CPUArchIdList *possible_cpus =3D mc->possible_cpu_arch_ids(ms); - - assert(cpu_index < possible_cpus->len); - return possible_cpus->cpus[cpu_index].props; -} - -static int64_t pc_get_default_cpu_node_id(const MachineState *ms, int idx) -{ - X86CPUTopoInfo topo; - PCMachineState *pcms =3D 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 *pc_possible_cpu_arch_ids(MachineState *ms) -{ - PCMachineState *pcms =3D PC_MACHINE(ms); - int i; - unsigned int max_cpus =3D 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 =3D=3D max_cpus); - return ms->possible_cpus; - } - - ms->possible_cpus =3D g_malloc0(sizeof(CPUArchIdList) + - sizeof(CPUArchId) * max_cpus); - ms->possible_cpus->len =3D max_cpus; - for (i =3D 0; i < ms->possible_cpus->len; i++) { - X86CPUTopoInfo topo; - - ms->possible_cpus->cpus[i].type =3D ms->cpu_type; - ms->possible_cpus->cpus[i].vcpus_count =3D 1; - ms->possible_cpus->cpus[i].arch_id =3D 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 =3D true; - ms->possible_cpus->cpus[i].props.socket_id =3D topo.pkg_id; - if (pcms->smp_dies > 1) { - ms->possible_cpus->cpus[i].props.has_die_id =3D true; - ms->possible_cpus->cpus[i].props.die_id =3D topo.die_id; - } - ms->possible_cpus->cpus[i].props.has_core_id =3D true; - ms->possible_cpus->cpus[i].props.core_id =3D topo.core_id; - ms->possible_cpus->cpus[i].props.has_thread_id =3D true; - ms->possible_cpus->cpus[i].props.thread_id =3D topo.smt_id; - } - return ms->possible_cpus; -} - -static void x86_nmi(NMIState *n, int cpu_index, Error **errp) -{ - /* cpu index isn't used */ - CPUState *cs; - - CPU_FOREACH(cs) { - X86CPU *cpu =3D X86_CPU(cs); - - if (!cpu->apic_state) { - cpu_interrupt(cs, CPU_INTERRUPT_NMI); - } else { - apic_deliver_nmi(cpu->apic_state); - } - } -} - static void pc_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc =3D MACHINE_CLASS(oc); @@ -2810,14 +2180,11 @@ static void pc_machine_class_init(ObjectClass *oc, = void *data) pcmc->pvh_enabled =3D true; assert(!mc->get_hotplug_handler); mc->get_hotplug_handler =3D pc_get_hotplug_handler; - mc->cpu_index_to_instance_props =3D pc_cpu_index_to_props; - mc->get_default_cpu_node_id =3D pc_get_default_cpu_node_id; - mc->possible_cpu_arch_ids =3D pc_possible_cpu_arch_ids; mc->auto_enable_numa_with_memhp =3D true; mc->has_hotpluggable_cpus =3D true; mc->default_boot_order =3D "cad"; - mc->hot_add_cpu =3D pc_hot_add_cpu; - mc->smp_parse =3D pc_smp_parse; + mc->hot_add_cpu =3D x86_hot_add_cpu; + mc->smp_parse =3D x86_smp_parse; mc->block_default_type =3D IF_IDE; mc->max_cpus =3D 255; mc->reset =3D pc_machine_reset; @@ -2835,13 +2202,6 @@ static void pc_machine_class_init(ObjectClass *oc, v= oid *data) pc_machine_get_device_memory_region_size, NULL, NULL, NULL, &error_abort); =20 - object_class_property_add(oc, PC_MACHINE_MAX_RAM_BELOW_4G, "size", - pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g, - NULL, NULL, &error_abort); - - object_class_property_set_description(oc, PC_MACHINE_MAX_RAM_BELOW_4G, - "Maximum ram below the 4G boundary (32bit boundary)", &error_abort= ); - object_class_property_add(oc, PC_MACHINE_SMM, "OnOffAuto", pc_machine_get_smm, pc_machine_set_smm, NULL, NULL, &error_abort); @@ -2866,7 +2226,7 @@ static void pc_machine_class_init(ObjectClass *oc, vo= id *data) =20 static const TypeInfo pc_machine_info =3D { .name =3D TYPE_PC_MACHINE, - .parent =3D TYPE_MACHINE, + .parent =3D TYPE_X86_MACHINE, .abstract =3D true, .instance_size =3D sizeof(PCMachineState), .instance_init =3D pc_machine_initfn, diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2362675149..f63c27bc74 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -27,6 +27,7 @@ =20 #include "qemu/units.h" #include "hw/loader.h" +#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" #include "hw/display/ramfb.h" @@ -73,6 +74,7 @@ static void pc_init1(MachineState *machine, { PCMachineState *pcms =3D PC_MACHINE(machine); PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); MemoryRegion *system_memory =3D get_system_memory(); MemoryRegion *system_io =3D get_system_io(); int i; @@ -125,11 +127,11 @@ static void pc_init1(MachineState *machine, if (xen_enabled()) { xen_hvm_init(pcms, &ram_memory); } else { - if (!pcms->max_ram_below_4g) { - pcms->max_ram_below_4g =3D 0xe0000000; /* default: 3.5G */ + if (!x86ms->max_ram_below_4g) { + x86ms->max_ram_below_4g =3D 0xe0000000; /* default: 3.5G */ } - lowmem =3D pcms->max_ram_below_4g; - if (machine->ram_size >=3D pcms->max_ram_below_4g) { + lowmem =3D x86ms->max_ram_below_4g; + if (machine->ram_size >=3D x86ms->max_ram_below_4g) { if (pcmc->gigabyte_align) { if (lowmem > 0xc0000000) { lowmem =3D 0xc0000000; @@ -138,21 +140,21 @@ static void pc_init1(MachineState *machine, warn_report("Large machine and max_ram_below_4g " "(%" PRIu64 ") not a multiple of 1G; " "possible bad performance.", - pcms->max_ram_below_4g); + x86ms->max_ram_below_4g); } } } =20 if (machine->ram_size >=3D lowmem) { - pcms->above_4g_mem_size =3D machine->ram_size - lowmem; - pcms->below_4g_mem_size =3D lowmem; + x86ms->above_4g_mem_size =3D machine->ram_size - lowmem; + x86ms->below_4g_mem_size =3D lowmem; } else { - pcms->above_4g_mem_size =3D 0; - pcms->below_4g_mem_size =3D machine->ram_size; + x86ms->above_4g_mem_size =3D 0; + x86ms->below_4g_mem_size =3D machine->ram_size; } } =20 - pc_cpus_init(pcms); + x86_cpus_init(x86ms, pcmc->default_cpu_version); =20 if (kvm_enabled() && pcmc->kvmclock_enabled) { kvmclock_create(); @@ -190,19 +192,19 @@ static void pc_init1(MachineState *machine, gsi_state =3D g_malloc0(sizeof(*gsi_state)); if (kvm_ioapic_in_kernel()) { kvm_pc_setup_irq_routing(pcmc->pci_enabled); - pcms->gsi =3D qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, - GSI_NUM_PINS); + x86ms->gsi =3D qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, + GSI_NUM_PINS); } else { - pcms->gsi =3D qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_P= INS); + x86ms->gsi =3D qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_= PINS); } =20 if (pcmc->pci_enabled) { pci_bus =3D i440fx_init(host_type, pci_type, - &i440fx_state, &piix3_devfn, &isa_bus, pcms-= >gsi, + &i440fx_state, &piix3_devfn, &isa_bus, x86ms= ->gsi, system_memory, system_io, machine->ram_size, - pcms->below_4g_mem_size, - pcms->above_4g_mem_size, + x86ms->below_4g_mem_size, + x86ms->above_4g_mem_size, pci_memory, ram_memory); pcms->bus =3D pci_bus; } else { @@ -212,7 +214,7 @@ static void pc_init1(MachineState *machine, &error_abort); no_hpet =3D 1; } - isa_bus_irqs(isa_bus, pcms->gsi); + isa_bus_irqs(isa_bus, x86ms->gsi); =20 if (kvm_pic_in_kernel()) { i8259 =3D kvm_i8259_init(isa_bus); @@ -230,7 +232,7 @@ static void pc_init1(MachineState *machine, ioapic_init_gsi(gsi_state, "i440fx"); } =20 - pc_register_ferr_irq(pcms->gsi[13]); + pc_register_ferr_irq(x86ms->gsi[13]); =20 pc_vga_init(isa_bus, pcmc->pci_enabled ? pci_bus : NULL); =20 @@ -240,7 +242,7 @@ static void pc_init1(MachineState *machine, } =20 /* init basic PC hardware */ - pc_basic_device_init(isa_bus, pcms->gsi, &rtc_state, true, + pc_basic_device_init(isa_bus, x86ms->gsi, &rtc_state, true, (pcms->vmport !=3D ON_OFF_AUTO_ON), pcms->pit_ena= bled, 0x4); =20 @@ -288,7 +290,7 @@ else { smi_irq =3D qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0); /* TODO: Populate SPD eeprom data. */ smbus =3D piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, - pcms->gsi[9], smi_irq, + x86ms->gsi[9], smi_irq, pc_machine_is_smm_enabled(pcms), &piix4_pm); smbus_eeprom_init(smbus, 8, NULL, 0); @@ -304,7 +306,7 @@ else { =20 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)); } } =20 @@ -728,7 +730,7 @@ DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_= 1_4_fn, =20 static void pc_i440fx_1_3_machine_options(MachineClass *m) { - PCMachineClass *pcmc =3D PC_MACHINE_CLASS(m); + X86MachineClass *x86mc =3D X86_MACHINE_CLASS(m); static GlobalProperty compat[] =3D { PC_CPU_MODEL_IDS("1.3.0") { "usb-tablet", "usb_version", "1" }, @@ -739,7 +741,7 @@ static void pc_i440fx_1_3_machine_options(MachineClass = *m) =20 pc_i440fx_1_4_machine_options(m); m->hw_version =3D "1.3.0"; - pcmc->compat_apic_id_mode =3D true; + x86mc->compat_apic_id_mode =3D true; compat_props_add(m->compat_props, compat, G_N_ELEMENTS(compat)); } =20 diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index d4e8a1cb9f..71f71bc61d 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -41,6 +41,7 @@ #include "hw/pci-host/q35.h" #include "hw/qdev-properties.h" #include "exec/address-spaces.h" +#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/i386/ich9.h" #include "hw/i386/amd_iommu.h" @@ -115,6 +116,7 @@ static void pc_q35_init(MachineState *machine) { PCMachineState *pcms =3D PC_MACHINE(machine); PCMachineClass *pcmc =3D PC_MACHINE_GET_CLASS(pcms); + X86MachineState *x86ms =3D X86_MACHINE(pcms); Q35PCIHost *q35_host; PCIHostState *phb; PCIBus *host_bus; @@ -152,34 +154,34 @@ 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 =3D 1ULL << 32; /* default: 4G */; + if (!x86ms->max_ram_below_4g) { + x86ms->max_ram_below_4g =3D 1ULL << 32; /* default: 4G */; } - if (lowmem > pcms->max_ram_below_4g) { - lowmem =3D pcms->max_ram_below_4g; + if (lowmem > x86ms->max_ram_below_4g) { + lowmem =3D 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 siz= e " " (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_4= g); + (uint64_t)machine->ram_size, x86ms->max_ram_below_= 4g); } } =20 if (machine->ram_size >=3D lowmem) { - pcms->above_4g_mem_size =3D machine->ram_size - lowmem; - pcms->below_4g_mem_size =3D lowmem; + x86ms->above_4g_mem_size =3D machine->ram_size - lowmem; + x86ms->below_4g_mem_size =3D lowmem; } else { - pcms->above_4g_mem_size =3D 0; - pcms->below_4g_mem_size =3D machine->ram_size; + x86ms->above_4g_mem_size =3D 0; + x86ms->below_4g_mem_size =3D machine->ram_size; } =20 if (xen_enabled()) { xen_hvm_init(pcms, &ram_memory); } =20 - pc_cpus_init(pcms); + x86_cpus_init(x86ms, pcmc->default_cpu_version); =20 kvmclock_create(); =20 @@ -213,10 +215,10 @@ static void pc_q35_init(MachineState *machine) gsi_state =3D g_malloc0(sizeof(*gsi_state)); if (kvm_ioapic_in_kernel()) { kvm_pc_setup_irq_routing(pcmc->pci_enabled); - pcms->gsi =3D qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, + x86ms->gsi =3D qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, GSI_NUM_PINS); } else { - pcms->gsi =3D qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_P= INS); + x86ms->gsi =3D qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_= PINS); } =20 /* create pci host bus */ @@ -231,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)); @@ -255,7 +257,7 @@ static void pc_q35_init(MachineState *machine) ich9_lpc =3D ICH9_LPC_DEVICE(lpc); lpc_dev =3D DEVICE(lpc); for (i =3D 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); @@ -279,7 +281,7 @@ static void pc_q35_init(MachineState *machine) ioapic_init_gsi(gsi_state, "q35"); } =20 - pc_register_ferr_irq(pcms->gsi[13]); + pc_register_ferr_irq(x86ms->gsi[13]); =20 assert(pcms->vmport !=3D ON_OFF_AUTO__MAX); if (pcms->vmport =3D=3D ON_OFF_AUTO_AUTO) { @@ -287,7 +289,7 @@ static void pc_q35_init(MachineState *machine) } =20 /* 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 !=3D ON_OFF_AUTO_ON), pcms->pit_ena= bled, 0xff0104); =20 @@ -330,7 +332,7 @@ static void pc_q35_init(MachineState *machine) =20 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)); } } =20 diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index a9983f0bfb..97f38e0423 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -31,6 +31,7 @@ #include "qemu/option.h" #include "qemu/units.h" #include "hw/sysbus.h" +#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/loader.h" #include "hw/qdev-properties.h" @@ -38,8 +39,6 @@ #include "hw/block/flash.h" #include "sysemu/kvm.h" =20 -#define BIOS_FILENAME "bios.bin" - /* * We don't have a theoretically justifiable exact lower bound on the base * address of any flash mapping. In practice, the IO-APIC MMIO range is @@ -211,59 +210,6 @@ static void pc_system_flash_map(PCMachineState *pcms, } } =20 -static void old_pc_system_rom_init(MemoryRegion *rom_memory, bool isapc_ra= m_fw) -{ - char *filename; - MemoryRegion *bios, *isa_bios; - int bios_size, isa_bios_size; - int ret; - - /* BIOS load */ - if (bios_name =3D=3D NULL) { - bios_name =3D BIOS_FILENAME; - } - filename =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (filename) { - bios_size =3D get_image_size(filename); - } else { - bios_size =3D -1; - } - if (bios_size <=3D 0 || - (bios_size % 65536) !=3D 0) { - goto bios_error; - } - bios =3D 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 =3D rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); - if (ret !=3D 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 =3D MIN(bios_size, 128 * KiB); - isa_bios =3D 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) { @@ -272,7 +218,7 @@ void pc_system_firmware_init(PCMachineState *pcms, BlockBackend *pflash_blk[ARRAY_SIZE(pcms->flash)]; =20 if (!pcmc->pci_enabled) { - old_pc_system_rom_init(rom_memory, true); + x86_system_rom_init(rom_memory, true); return; } =20 @@ -293,7 +239,7 @@ void pc_system_firmware_init(PCMachineState *pcms, =20 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()) { /* diff --git a/hw/i386/x86.c b/hw/i386/x86.c new file mode 100644 index 0000000000..4de9dd100f --- /dev/null +++ b/hw/i386/x86.c @@ -0,0 +1,788 @@ +/* + * 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"), t= o deal + * in the Software without restriction, including without limitation the r= ights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or se= ll + * 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 OT= HER + * 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 "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 "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 "pvh.h" +#include "standard-headers/asm-x86/bootparam.h" + +#define BIOS_FILENAME "bios.bin" + +/* 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 interface= s 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(X86MachineState *x86ms, + unsigned int cpu_index) +{ + MachineState *ms =3D MACHINE(x86ms); + X86MachineClass *x86mc =3D X86_MACHINE_GET_CLASS(x86ms); + uint32_t correct_id; + static bool warned; + + correct_id =3D x86_apicid_from_cpu_idx(x86ms->smp_dies, ms->smp.cores, + ms->smp.threads, cpu_index); + if (x86mc->compat_apic_id_mode) { + if (cpu_index !=3D correct_id && !warned && !qtest_enabled()) { + error_report("APIC IDs set in compatibility mode, " + "CPU topology won't match the configuration"); + warned =3D true; + } + return cpu_index; + } else { + return correct_id; + } +} + + +static void x86_new_cpu(X86MachineState *x86ms, int64_t apic_id, Error **e= rrp) +{ + Object *cpu =3D NULL; + Error *local_err =3D NULL; + CPUX86State *env =3D NULL; + + cpu =3D object_new(MACHINE(x86ms)->cpu_type); + + env =3D &X86_CPU(cpu)->env; + env->nr_dies =3D x86ms->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. + */ +void x86_smp_parse(MachineState *ms, QemuOpts *opts) +{ + X86MachineState *x86ms =3D X86_MACHINE(ms); + + if (opts) { + unsigned cpus =3D qemu_opt_get_number(opts, "cpus", 0); + unsigned sockets =3D qemu_opt_get_number(opts, "sockets", 0); + unsigned dies =3D qemu_opt_get_number(opts, "dies", 1); + unsigned cores =3D qemu_opt_get_number(opts, "cores", 0); + unsigned threads =3D qemu_opt_get_number(opts, "threads", 0); + + /* compute missing values, prefer sockets over cores over threads = */ + if (cpus =3D=3D 0 || sockets =3D=3D 0) { + cores =3D cores > 0 ? cores : 1; + threads =3D threads > 0 ? threads : 1; + if (cpus =3D=3D 0) { + sockets =3D sockets > 0 ? sockets : 1; + cpus =3D cores * threads * dies * sockets; + } else { + ms->smp.max_cpus =3D + qemu_opt_get_number(opts, "maxcpus", cpus); + sockets =3D ms->smp.max_cpus / (cores * threads * dies); + } + } else if (cores =3D=3D 0) { + threads =3D threads > 0 ? threads : 1; + cores =3D cpus / (sockets * dies * threads); + cores =3D cores > 0 ? cores : 1; + } else if (threads =3D=3D 0) { + threads =3D cpus / (cores * dies * sockets); + threads =3D threads > 0 ? threads : 1; + } else if (sockets * dies * cores * threads < cpus) { + error_report("cpu topology: " + "sockets (%u) * dies (%u) * cores (%u) * threads = (%u) < " + "smp_cpus (%u)", + sockets, dies, cores, threads, cpus); + exit(1); + } + + ms->smp.max_cpus =3D + qemu_opt_get_number(opts, "maxcpus", cpus); + + if (ms->smp.max_cpus < cpus) { + error_report("maxcpus must be equal to or greater than smp"); + exit(1); + } + + if (sockets * dies * cores * threads > ms->smp.max_cpus) { + error_report("cpu topology: " + "sockets (%u) * dies (%u) * cores (%u) * threads = (%u) > " + "maxcpus (%u)", + sockets, dies, cores, threads, + ms->smp.max_cpus); + exit(1); + } + + if (sockets * dies * cores * threads !=3D ms->smp.max_cpus) { + warn_report("Invalid CPU topology deprecated: " + "sockets (%u) * dies (%u) * cores (%u) * threads (= %u) " + "!=3D maxcpus (%u)", + sockets, dies, cores, threads, + ms->smp.max_cpus); + } + + ms->smp.cpus =3D cpus; + ms->smp.cores =3D cores; + ms->smp.threads =3D threads; + x86ms->smp_dies =3D dies; + } + + if (ms->smp.cpus > 1) { + Error *blocker =3D NULL; + error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp"); + replay_add_blocker(blocker); + } +} + +void x86_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp) +{ + X86MachineState *x86ms =3D X86_MACHINE(ms); + int64_t apic_id =3D x86_cpu_apic_id_from_index(x86ms, id); + Error *local_err =3D NULL; + + if (id < 0) { + error_setg(errp, "Invalid CPU id: %" PRIi64, id); + return; + } + + if (apic_id >=3D ACPI_CPU_HOTPLUG_ID_LIMIT) { + error_setg(errp, "Unable to add CPU: %" PRIi64 + ", resulting APIC ID (%" PRIi64 ") is too large", + id, apic_id); + return; + } + + x86_new_cpu(X86_MACHINE(ms), apic_id, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } +} + +void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version) +{ + int i; + const CPUArchIdList *possible_cpus; + MachineState *ms =3D MACHINE(x86ms); + MachineClass *mc =3D MACHINE_GET_CLASS(x86ms); + + x86_cpu_set_default_version(default_cpu_version); + + /* Calculates the limit to CPU APIC ID values + * + * Limit for the APIC ID value, so that all + * CPU APIC IDs are < x86ms->apic_id_limit. + * + * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). + */ + x86ms->apic_id_limit =3D x86_cpu_apic_id_from_index(x86ms, + ms->smp.max_cpus - 1= ) + 1; + possible_cpus =3D mc->possible_cpu_arch_ids(ms); + for (i =3D 0; i < ms->smp.cpus; i++) { + x86_new_cpu(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal); + } +} + +void x86_nmi(NMIState *n, int cpu_index, Error **errp) +{ + /* cpu index isn't used */ + CPUState *cs; + + CPU_FOREACH(cs) { + X86CPU *cpu =3D X86_CPU(cs); + + if (!cpu->apic_state) { + cpu_interrupt(cs, CPU_INTERRUPT_NMI); + } else { + apic_deliver_nmi(cpu->apic_state); + } + } +} + +CpuInstanceProperties +x86_cpu_index_to_props(MachineState *ms, unsigned cpu_index) +{ + MachineClass *mc =3D MACHINE_GET_CLASS(ms); + const CPUArchIdList *possible_cpus =3D 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; + X86MachineState *x86ms =3D X86_MACHINE(ms); + + assert(idx < ms->possible_cpus->len); + x86_topo_ids_from_apicid(ms->possible_cpus->cpus[idx].arch_id, + x86ms->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) +{ + X86MachineState *x86ms =3D X86_MACHINE(ms); + int i; + unsigned int max_cpus =3D 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 =3D=3D max_cpus); + return ms->possible_cpus; + } + + ms->possible_cpus =3D g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len =3D max_cpus; + for (i =3D 0; i < ms->possible_cpus->len; i++) { + X86CPUTopoInfo topo; + + ms->possible_cpus->cpus[i].type =3D ms->cpu_type; + ms->possible_cpus->cpus[i].vcpus_count =3D 1; + ms->possible_cpus->cpus[i].arch_id =3D x86_cpu_apic_id_from_index(= x86ms, i); + x86_topo_ids_from_apicid(ms->possible_cpus->cpus[i].arch_id, + x86ms->smp_dies, ms->smp.cores, + ms->smp.threads, &topo); + ms->possible_cpus->cpus[i].props.has_socket_id =3D true; + ms->possible_cpus->cpus[i].props.socket_id =3D topo.pkg_id; + if (x86ms->smp_dies > 1) { + ms->possible_cpus->cpus[i].props.has_die_id =3D true; + ms->possible_cpus->cpus[i].props.die_id =3D topo.die_id; + } + ms->possible_cpus->cpus[i].props.has_core_id =3D true; + ms->possible_cpus->cpus[i].props.core_id =3D topo.core_id; + ms->possible_cpus->cpus[i].props.has_thread_id =3D true; + ms->possible_cpus->cpus[i].props.thread_id =3D topo.smt_id; + } + return ms->possible_cpus; +} + +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 =3D=3D NULL) { + bios_name =3D BIOS_FILENAME; + } + filename =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size =3D get_image_size(filename); + } else { + bios_size =3D -1; + } + if (bios_size <=3D 0 || + (bios_size % 65536) !=3D 0) { + goto bios_error; + } + bios =3D 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 =3D rom_add_file_fixed(bios_name, (uint32_t)(-bios_size), -1); + if (ret !=3D 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 =3D MIN(bios_size, 128 * KiB); + isa_bios =3D 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); +} + +static long get_file_size(FILE *f) +{ + long where, size; + + /* XXX: on Unix systems, using fstat() probably makes more sense */ + + where =3D ftell(f); + fseek(f, 0, SEEK_END); + size =3D 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)); + +void load_linux(X86MachineState *x86ms, + FWCfgState *fw_cfg, + unsigned acpi_data_size, + bool linuxboot_dma_enabled, + bool pvh_enabled) +{ + 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 =3D 0; + FILE *f; + char *vmode; + MachineState *machine =3D MACHINE(x86ms); + struct setup_data *setup_data; + const char *kernel_filename =3D machine->kernel_filename; + const char *initrd_filename =3D machine->initrd_filename; + const char *dtb_filename =3D machine->dtb; + const char *kernel_cmdline =3D machine->kernel_cmdline; + + /* Align to 16 bytes as a paranoia measure */ + cmdline_size =3D (strlen(kernel_cmdline)+16) & ~15; + + /* load the kernel header */ + f =3D fopen(kernel_filename, "rb"); + if (!f || !(kernel_size =3D get_file_size(f)) || + fread(header, 1, MIN(ARRAY_SIZE(header), kernel_size), f) !=3D + 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) =3D=3D 0x53726448) { + protocol =3D lduw_p(header+0x206); + } else { + size_t pvh_start_addr; + uint32_t mh_load_addr =3D 0; + uint32_t elf_kernel_size =3D 0; + /* + * 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 sam= e of + * PVH), so we try multiboot first since we check the multiboot ma= gic + * 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 (pvh_enabled && + pvh_load_elfboot(kernel_filename, + &mh_load_addr, &elf_kernel_size)) { + fclose(f); + + pvh_start_addr =3D pvh_get_start_addr(); + + 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); + + 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 =3D NULL; + + mapped_file =3D 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); + } + x86ms->initrd_mapped_file =3D mapped_file; + + initrd_data =3D g_mapped_file_get_contents(mapped_file); + initrd_size =3D g_mapped_file_get_length(mapped_file); + initrd_max =3D x86ms->below_4g_mem_size - acpi_data_size -= 1; + if (initrd_size >=3D initrd_max) { + fprintf(stderr, "qemu: initrd is too large, cannot sup= port." + "(max: %"PRIu32", need %"PRId64")\n", + initrd_max, (uint64_t)initrd_size); + exit(1); + } + + initrd_addr =3D (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 =3D 0; + option_rom[nb_option_roms].name =3D "pvh.bin"; + nb_option_roms++; + + return; + } + protocol =3D 0; + } + + if (protocol < 0x200 || !(header[0x211] & 0x01)) { + /* Low kernel */ + real_addr =3D 0x90000; + cmdline_addr =3D 0x9a000 - cmdline_size; + prot_addr =3D 0x10000; + } else if (protocol < 0x202) { + /* High but ancient kernel */ + real_addr =3D 0x90000; + cmdline_addr =3D 0x9a000 - cmdline_size; + prot_addr =3D 0x100000; + } else { + /* High and recent kernel */ + real_addr =3D 0x10000; + cmdline_addr =3D 0x20000; + prot_addr =3D 0x100000; + } + +#if 0 + fprintf(stderr, + "qemu: real_addr =3D 0x" TARGET_FMT_plx "\n" + "qemu: cmdline_addr =3D 0x" TARGET_FMT_plx "\n" + "qemu: prot_addr =3D 0x" TARGET_FMT_plx "\n", + real_addr, + cmdline_addr, + prot_addr); +#endif + + /* highest address for loading the initrd */ + if (protocol >=3D 0x20c && + lduw_p(header+0x236) & XLF_CAN_BE_LOADED_ABOVE_4G) { + /* + * Linux has supported initrd up to 4 GB for a very long time (200= 7, + * 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 bootload= er + * bugs". Luckily, QEMU firmware(which does something like bootloa= der) + * 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 we= ll. + */ + initrd_max =3D UINT32_MAX; + } else if (protocol >=3D 0x203) { + initrd_max =3D ldl_p(header+0x22c); + } else { + initrd_max =3D 0x37ffffff; + } + + if (initrd_max >=3D x86ms->below_4g_mem_size - acpi_data_size) { + initrd_max =3D x86ms->below_4g_mem_size - acpi_data_size - 1; + } + + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline)+1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + + if (protocol >=3D 0x202) { + stl_p(header+0x228, cmdline_addr); + } else { + stw_p(header+0x20, 0xA33F); + stw_p(header+0x22, cmdline_addr-real_addr); + } + + /* handle vga=3D parameter */ + vmode =3D strstr(kernel_cmdline, "vga=3D"); + if (vmode) { + unsigned int video_mode; + /* skip "vga=3D" */ + vmode +=3D 4; + if (!strncmp(vmode, "normal", 6)) { + video_mode =3D 0xffff; + } else if (!strncmp(vmode, "ext", 3)) { + video_mode =3D 0xfffe; + } else if (!strncmp(vmode, "ask", 3)) { + video_mode =3D 0xfffd; + } else { + video_mode =3D strtol(vmode, NULL, 0); + } + stw_p(header+0x1fa, video_mode); + } + + /* loader type */ + /* High nybble =3D 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 >=3D 0x200) { + header[0x210] =3D 0xB0; + } + /* heap */ + if (protocol >=3D 0x201) { + header[0x211] |=3D 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 =3D NULL; + + if (protocol < 0x200) { + fprintf(stderr, "qemu: linux kernel too old to load a ram disk= \n"); + exit(1); + } + + mapped_file =3D 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); + } + x86ms->initrd_mapped_file =3D mapped_file; + + initrd_data =3D g_mapped_file_get_contents(mapped_file); + initrd_size =3D g_mapped_file_get_length(mapped_file); + if (initrd_size >=3D 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 =3D (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_s= ize); + + stl_p(header+0x218, initrd_addr); + stl_p(header+0x21c, initrd_size); + } + + /* load kernel and setup */ + setup_size =3D header[0x1f1]; + if (setup_size =3D=3D 0) { + setup_size =3D 4; + } + setup_size =3D (setup_size+1)*512; + if (setup_size > kernel_size) { + fprintf(stderr, "qemu: invalid kernel header\n"); + exit(1); + } + kernel_size -=3D setup_size; + + setup =3D g_malloc(setup_size); + kernel =3D g_malloc(kernel_size); + fseek(f, 0, SEEK_SET); + if (fread(setup, 1, setup_size, f) !=3D setup_size) { + fprintf(stderr, "fread() failed\n"); + exit(1); + } + if (fread(kernel, 1, kernel_size, f) !=3D 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 =3D get_image_size(dtb_filename); + if (dtb_size <=3D 0) { + fprintf(stderr, "qemu: error reading dtb %s: %s\n", + dtb_filename, strerror(errno)); + exit(1); + } + + setup_data_offset =3D QEMU_ALIGN_UP(kernel_size, 16); + kernel_size =3D setup_data_offset + sizeof(struct setup_data) + dt= b_size; + kernel =3D g_realloc(kernel, kernel_size); + + stq_p(header+0x250, prot_addr + setup_data_offset); + + setup_data =3D (struct setup_data *)(kernel + setup_data_offset); + setup_data->next =3D 0; + setup_data->type =3D cpu_to_le32(SETUP_DTB); + setup_data->len =3D 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 =3D 0; + option_rom[nb_option_roms].name =3D "linuxboot.bin"; + if (linuxboot_dma_enabled && fw_cfg_dma_enabled(fw_cfg)) { + option_rom[nb_option_roms].name =3D "linuxboot_dma.bin"; + } + nb_option_roms++; +} + +static void x86_machine_get_max_ram_below_4g(Object *obj, Visitor *v, + const char *name, void *opaqu= e, + Error **errp) +{ + X86MachineState *x86ms =3D X86_MACHINE(obj); + uint64_t value =3D x86ms->max_ram_below_4g; + + visit_type_size(v, name, &value, errp); +} + +static void x86_machine_set_max_ram_below_4g(Object *obj, Visitor *v, + const char *name, void *opaqu= e, + Error **errp) +{ + X86MachineState *x86ms =3D X86_MACHINE(obj); + Error *error =3D NULL; + uint64_t value; + + visit_type_size(v, name, &value, &error); + if (error) { + error_propagate(errp, error); + return; + } + if (value > 4 * GiB) { + error_setg(&error, + "Machine option 'max-ram-below-4g=3D%"PRIu64 + "' expects size less than or equal to 4G", value); + error_propagate(errp, error); + return; + } + + if (value < 1 * MiB) { + warn_report("Only %" PRIu64 " bytes of RAM below the 4GiB boundary= ," + "BIOS may not work with less than 1MiB", value); + } + + x86ms->max_ram_below_4g =3D value; +} + +static void x86_machine_initfn(Object *obj) +{ + X86MachineState *x86ms =3D X86_MACHINE(obj); + + x86ms->max_ram_below_4g =3D 0; /* use default */ + x86ms->smp_dies =3D 1; +} + +static void x86_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + + mc->cpu_index_to_instance_props =3D x86_cpu_index_to_props; + mc->get_default_cpu_node_id =3D x86_get_default_cpu_node_id; + mc->possible_cpu_arch_ids =3D x86_possible_cpu_arch_ids; + + object_class_property_add(oc, X86_MACHINE_MAX_RAM_BELOW_4G, "size", + x86_machine_get_max_ram_below_4g, x86_machine_set_max_ram_below_4g, + NULL, NULL, &error_abort); + + object_class_property_set_description(oc, X86_MACHINE_MAX_RAM_BELOW_4G, + "Maximum ram below the 4G boundary (32bit boundary)", &error_abort= ); +} + +static const TypeInfo x86_machine_info =3D { + .name =3D TYPE_X86_MACHINE, + .parent =3D TYPE_MACHINE, + .abstract =3D true, + .instance_size =3D sizeof(X86MachineState), + .instance_init =3D x86_machine_initfn, + .class_size =3D sizeof(X86MachineClass), + .class_init =3D x86_machine_class_init, +}; + +static void x86_machine_register_types(void) +{ + type_register_static(&x86_machine_info); +} + +type_init(x86_machine_register_types) diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 1ede055387..e621dde6c3 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -23,6 +23,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "monitor/monitor.h" +#include "hw/i386/x86.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" #include "hw/i386/ioapic.h" @@ -89,7 +90,7 @@ static void ioapic_entry_parse(uint64_t entry, struct ioa= pic_entry_info *info) =20 static void ioapic_service(IOAPICCommonState *s) { - AddressSpace *ioapic_as =3D PC_MACHINE(qdev_get_machine())->ioapic_as; + AddressSpace *ioapic_as =3D X86_MACHINE(qdev_get_machine())->ioapic_as; struct ioapic_entry_info info; uint8_t i; uint32_t mask; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 062feeb69e..de28d55e5c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -3,6 +3,7 @@ =20 #include "exec/memory.h" #include "hw/boards.h" +#include "hw/i386/x86.h" #include "hw/isa/isa.h" #include "hw/block/fdc.h" #include "hw/block/flash.h" @@ -27,7 +28,7 @@ */ struct PCMachineState { /*< private >*/ - MachineState parent_obj; + X86MachineState parent_obj; =20 /* */ =20 @@ -36,15 +37,10 @@ struct PCMachineState { =20 /* Pointers to devices and objects: */ HotplugHandler *acpi_dev; - ISADevice *rtc; PCIBus *bus; - FWCfgState *fw_cfg; - qemu_irq *gsi; PFlashCFI01 *flash[2]; - GMappedFile *initrd_mapped_file; =20 /* Configuration options: */ - uint64_t max_ram_below_4g; OnOffAuto vmport; OnOffAuto smm; =20 @@ -53,27 +49,13 @@ struct PCMachineState { bool sata_enabled; bool pit_enabled; =20 - /* 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; }; =20 #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" @@ -139,9 +121,6 @@ typedef struct PCMachineClass { =20 /* use PVH to load kernels that support this feature */ bool pvh_enabled; - - /* Enables contiguous-apic-ID mode */ - bool compat_apic_id_mode; } PCMachineClass; =20 #define TYPE_PC_MACHINE "generic-pc-machine" @@ -193,10 +172,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); =20 -void pc_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); - void pc_guest_info_init(PCMachineState *pcms); =20 #define PCI_HOST_PROP_PCI_HOLE_START "pci-hole-start" diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h new file mode 100644 index 0000000000..5980090b29 --- /dev/null +++ b/include/hw/i386/x86.h @@ -0,0 +1,97 @@ +/* + * 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 f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + +#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(X86MachineState *x86ms, + unsigned int cpu_index); + +void x86_cpus_init(X86MachineState *pcms, int default_cpu_version); +void x86_hot_add_cpu(MachineState *ms, const int64_t id, Error **errp); +void x86_smp_parse(MachineState *ms, QemuOpts *opts); +void x86_nmi(NMIState *n, int cpu_index, Error **errp); + +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 load_linux(X86MachineState *x86ms, + FWCfgState *fw_cfg, + unsigned acpi_data_size, + bool linuxboot_dma_enabled, + bool pvh_enabled); + +#endif --=20 2.21.0 From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569333023; cv=none; d=zoho.com; s=zohoarc; b=LPE4kr1EQWoJL4ulEByEbXTuC7d7EDKhicEvyc/h/0n+dw39L+y6wThHeZ+k906K+YAO+LTX4lg1VmpkN2gfrDx/0JsVe38hSJkvCJWb3RhuRLgFMTPXPUM7CMAPGK6HrP4aUivgCK7m0T9ekk/zpSxxIB/bDhLPU+u9KFuM25U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569333023; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=HCIbMFCINYCiSq3ndM3McDnaxsHodhIvR1n5mzwX1x8=; b=eD1j41QQquNhiA9Wawof06D1NY34RaGbn7sjaKjQIBc6Ap0lzvnUJMAn3CZgOUbH+tYiLzMlb3aSQ5pd6FriCOtlHdYlUtCiTBk2z4RV0RYKhudd5YxjiCPvjcpac3wYTY5vNefSzYjFjvqTgQ36y+AynCbItSyMN6qbgbUYuXo= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569333023829842.2015685736667; Tue, 24 Sep 2019 06:50:23 -0700 (PDT) Received: from localhost ([::1]:45890 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iClCr-00030T-7t for importer@patchew.org; Tue, 24 Sep 2019 09:50:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52414) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkCY-000320-Rp for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:57 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkCX-0004sI-AI for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:54 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43174) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkCX-0004rr-2J for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:53 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 51C45300D20B; Tue, 24 Sep 2019 12:45:52 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5DEAA608C2; Tue, 24 Sep 2019 12:45:37 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 5/8] fw_cfg: add "modify" functions for all types Date: Tue, 24 Sep 2019 14:44:30 +0200 Message-Id: <20190924124433.96810-6-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.40]); Tue, 24 Sep 2019 12:45:52 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" This allows to alter the contents of an already added item. Signed-off-by: Sergio Lopez --- hw/nvram/fw_cfg.c | 29 +++++++++++++++++++++++++++ include/hw/nvram/fw_cfg.h | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 7dc3ac378e..aef1727250 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -690,6 +690,15 @@ void fw_cfg_add_string(FWCfgState *s, uint16_t key, co= nst char *value) fw_cfg_add_bytes(s, key, g_memdup(value, sz), sz); } =20 +void fw_cfg_modify_string(FWCfgState *s, uint16_t key, const char *value) +{ + size_t sz =3D strlen(value) + 1; + char *old; + + old =3D 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, uint3= 2_t value) fw_cfg_add_bytes(s, key, copy, sizeof(value)); } =20 +void fw_cfg_modify_i32(FWCfgState *s, uint16_t key, uint32_t value) +{ + uint32_t *copy, *old; + + copy =3D g_malloc(sizeof(value)); + *copy =3D cpu_to_le32(value); + old =3D 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, uint6= 4_t value) fw_cfg_add_bytes(s, key, copy, sizeof(value)); } =20 +void fw_cfg_modify_i64(FWCfgState *s, uint16_t key, uint64_t value) +{ + uint64_t *copy, *old; + + copy =3D g_malloc(sizeof(value)); + *copy =3D cpu_to_le64(value); + old =3D 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 =3D=3D 0); diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 80e435d303..b5291eefad 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -98,6 +98,20 @@ void fw_cfg_add_bytes(FWCfgState *s, uint16_t key, void = *data, size_t len); */ void fw_cfg_add_string(FWCfgState *s, uint16_t key, const char *value); =20 +/** + * fw_cfg_modify_string: + * @s: fw_cfg device being modified + * @key: selector key value for new fw_cfg item + * @value: NUL-terminated ascii string + * + * Replace the fw_cfg item available by selecting the given key. The new + * data will consist of a dynamically allocated copy of the provided strin= g, + * including its NUL terminator. The data being replaced, assumed to have + * been dynamically allocated during an earlier call to either + * fw_cfg_add_string() or fw_cfg_modify_string(), is freed before returnin= g. + */ +void fw_cfg_modify_string(FWCfgState *s, uint16_t key, const char *value); + /** * fw_cfg_add_i16: * @s: fw_cfg device being modified @@ -136,6 +150,20 @@ void fw_cfg_modify_i16(FWCfgState *s, uint16_t key, ui= nt16_t value); */ void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint32_t value); =20 +/** + * fw_cfg_modify_i32: + * @s: fw_cfg device being modified + * @key: selector key value for new fw_cfg item + * @value: 32-bit integer + * + * Replace the fw_cfg item available by selecting the given key. The new + * data will consist of a dynamically allocated copy of the given 32-bit + * value, converted to little-endian representation. The data being replac= ed, + * assumed to have been dynamically allocated during an earlier call to + * either fw_cfg_add_i32() or fw_cfg_modify_i32(), is freed before returni= ng. + */ +void fw_cfg_modify_i32(FWCfgState *s, uint16_t key, uint32_t value); + /** * fw_cfg_add_i64: * @s: fw_cfg device being modified @@ -148,6 +176,20 @@ void fw_cfg_add_i32(FWCfgState *s, uint16_t key, uint3= 2_t value); */ void fw_cfg_add_i64(FWCfgState *s, uint16_t key, uint64_t value); =20 +/** + * fw_cfg_modify_i64: + * @s: fw_cfg device being modified + * @key: selector key value for new fw_cfg item + * @value: 64-bit integer + * + * Replace the fw_cfg item available by selecting the given key. The new + * data will consist of a dynamically allocated copy of the given 64-bit + * value, converted to little-endian representation. The data being replac= ed, + * assumed to have been dynamically allocated during an earlier call to + * either fw_cfg_add_i64() or fw_cfg_modify_i64(), is freed before returni= ng. + */ +void fw_cfg_modify_i64(FWCfgState *s, uint16_t key, uint64_t value); + /** * fw_cfg_add_file: * @s: fw_cfg device being modified --=20 2.21.0 From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569332334; cv=none; d=zoho.com; s=zohoarc; b=Bj2adHkrejV+O/svEny1IiytSolF5H+mcmtCpmgBpQY8c0y372tzApoRIHe+Am4Oeb8IkjoFNVHQKkwh5n/ZPXKDHSwciRVlPdVHh1svd7D65l7pBWARHMq13KOpnsb3zPEsvE1uUvFlzX6IhGN1QyBd1rIBsIzKZdMydoHHdDI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569332334; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=kuTRpntOi69yANKSfNb1ikN3ACxqfWIVldztjNIkPdw=; b=eNiI1o+QkHPTbYpBQEWtH9MWc06Zya7wEcUeVGtidBRFxQvmZGV0XNhvrfCz6TOtUhqntzMMEFqhAncpmNI1WQx6Zk19VTNo/DsaBPiOOOp6qKmm0oDXigLAvVKb+tT4avnIHUScBUxvRCSBio/6y+XZT0T0SdwyvlMWlJq+qvU= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569332334729754.9732352839876; Tue, 24 Sep 2019 06:38:54 -0700 (PDT) Received: from localhost ([::1]:45768 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCl1m-0007i6-RQ for importer@patchew.org; Tue, 24 Sep 2019 09:38:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52496) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkCg-0003F1-NA for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:05 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkCd-0004wh-CF for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:02 -0400 Received: from mx1.redhat.com ([209.132.183.28]:60342) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkCd-0004w9-1Z for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:45:59 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3F68C190C01D; Tue, 24 Sep 2019 12:45:58 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id ABB92608C2; Tue, 24 Sep 2019 12:45:52 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 6/8] roms: add microvm-bios (qboot) as binary and git submodule Date: Tue, 24 Sep 2019 14:44:31 +0200 Message-Id: <20190924124433.96810-7-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.6.2 (mx1.redhat.com [10.5.110.70]); Tue, 24 Sep 2019 12:45:58 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" 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. This characteristics make it an ideal companion for the microvm machine type. Signed-off-by: Sergio Lopez --- .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 diff --git a/.gitmodules b/.gitmodules index c5c474169d..19792c9a11 100644 --- a/.gitmodules +++ b/.gitmodules @@ -58,3 +58,6 @@ [submodule "roms/opensbi"] path =3D roms/opensbi url =3D https://git.qemu.org/git/opensbi.git +[submodule "roms/qboot"] + path =3D roms/qboot + url =3D https://github.com/bonzini/qboot diff --git a/pc-bios/bios-microvm.bin b/pc-bios/bios-microvm.bin new file mode 100755 index 0000000000000000000000000000000000000000..45eabc516692e2d134bbb630d13= 3c7c2dcc9a9b6 GIT binary patch literal 65536 zcmeI2eS8zwneS)hF_vth5y2#;brv;O^x_6mtAUMO%tn5}IEf)jY``G|XbMBqa_^-@ zBBUXSyplo3+VMx9Ci}VFwz~@rx!t?By&v!0UdNb=3DVGyaU`%sJ0_&U3!!Ij`fT?33lo8bTirhX$S6(dmK^Nu2qLAPZJO zd+n=3D&@XLYwWFdS~Zh2c2gidFUEU-}gkOUzx)FqJ6 z;W433mmmmAY+Noh;tibd?18@VxCH}v4GeX#`0DNc_4sRW0TC1A zmJsrGlX|tHBmSvHZ7h?b^=3D>;mu1$tb(P>mvG{5}(=3D7p;C?X{{UgF+=3Dc4I zP{`<|^mTPhV|UNEdEHc{)HAxSYaiW>P|0;&C$X5aR9UVpQyP@Vl`hhv$gdx{Z+-NR zwvW~;(eFuX@wtUs8?fTZ0 z-^y7ZnXZ(N2F|Wml7g>taRZ)SYa#R~3)d_2XS+8|g~IPiN|W-WvPxO4Jf$R*7zq(M zVPZ7&u2-7NT$&*G^Vf&!N<}4sxYR-&zO@e~z~qj%l+aa&|1SJK8kh_(z79nsokwAD^1AC7pf@Oj~FIF9# zF9b$C2U-gqk-~z?@R7iuo?L~z4ZVWkIiSQ^i}NGJ*2?fn#8cjeR;%3om9j(r$>}0* zmHG01U~>3C;Jl}&R|!j%@?|5s#Espmjtu)+#k%inqSKe2u4Y^$dyZBy&S@?QTm*4Jv!DYIMrLsd*G z=3D`T-i{>XEL^*_04^-~G9FB2d;TMqbVppb+**NV)Wh3cyEi~fAMBS-GYFX{6SqmnR3 zi7j8o-YehtBPZl-;$fEDRenBjZPn_8`k0QW%duAboe{h9;n1k=3DPmPBITKXgysm0cG zff9plWlq19^_3qFT=3Deu943;%0F}d3r9Ci6~gQK=3DUjyF9V9G&A|6db+Rf1l@a_=3Dw-< zIgp;B+L?Gjt)J5Gg)}0q>Wcp0HQVM-TQ2)8SKeoRFckXbZl8$MyIG&-ayp6njK|qn zUpF;;x*hu7L6uw4aN!=3Dm!{{NE=3DUSzLa8KY0G!Yj<9~vxX3HENZ(Onw#yXUrCeraCo zVgU^`gK6GqgVb`wZ;#Gbmy2v_MAjdX^lEFX6)k+K<#J$AXn(Om8@eKmZkcJ?-+r#^ zCA}?|Tk-m02jZiTNML7=3D=3DD)CNvx3sYjI-Lq-*XZa2UU;-+c$WsKoy6%2oD<>eine z!#Ejf&|7)}XW?0sdUNKePg&pstJ#T?3+&za*%{)yhd+P##k*mz+)*)!?YnZKwSKA| zu}@-GBM5lQwXLUnbA-^KRrkB=3D>1G$AHSS_ujsr9%IKnN3NV_f2z%xyG&<)WQp>tn@_V;6awYf z{q=3D0PWP~N+=3D^0|;@HO^_x)<+6Z;;S0r?eL5MGEsG)4dPD(&64oU$Ar(mKJI91WQp* z*fzBkMi!_#i^;Q2JgahPiGQ8gvStZuJR~ zt#rF1Q*=3Db?$N+zvO5*<=3D;%c=3DB9T?OE0Z$h_QD(6#I65=3DXr9N+IZ4eRkS9#6`N53nF zgGh%{`-7vUa`;ocs8#P&SmkZ6Ac(#qhoeSdgWU2t0t?xQx ztJi2*MGFO0nhpzHsS48`Vp6I$SzypCIQ|r)66h+xi_VhantBb5r^GsquKknX=3D-R+M zR5)+3-109(YL#R<<}5hotld~R3DG;%8uwi7=3Dx5}ePWAz;ei|y+wczL$|D53HM*s5Q z=3D%zrc`r^c_nOvX1R?2lfbszGepq#~lx-UxZrlnOz{2p{&Q(UKz(M1ePy8b6tOokmV zLn9Qdcp}|RixRp+gLWhp+axvgJlad?eTee+@?{jXu zfYy+<4a9q#+Xg%bFc#Lkt?+6)8^}a<6=3D7{Pl(xY4C3hw+G;lp|9;H5+Abs%xXQ(ef zlf)pDipQPXQqUx2%7Egdw^JoenzQOp1R=3DJ}G z#oOYxtAp`@B3qnI9t8DHEcgY=3DVF>p@4)U7qZI&7f#y_FB9^0F2j)oj89X~b6STSQI zJGB67=3D8qA3IhV9q{PWleZJ*%`FMcgLjZ#$m)L7J#t+PdmS4q~;K5zNqKq{1(6=3DGPR zzt1jQ+&}|ddcP9G9Na5+7s=3DgK*0Mxk2BxTKvC!2A{4?b4l@75|?ykwFgh^OnXr7ZL z33i+&JdDZR31b~%GO@GXorc9VZcG&~Hp$(SA~o)u=3DmIh;l(c%zVi2>ct4HK+8P1VY z))%OjyZbRz-UVHukq7*D$=3D!{UL`<^vIo7g+DDMc$J5q8GgR;CZl=3DRNu;Fbd2d(lC4 zriJ#~jnN$*YE7SvVGH7y;{%g&a;dneK=3D#pEW<1I(by1@!Ly6_^4fgx76!~?plm%+n z5{9EYS7Y6gk?*3`y|@8xwK@?azsl16k9t%NY`T@Nl08`i3bYI6;DEBwPKPHJZrYud zoU9dPO@-cD*-GuwJh;JyN!V~#+6S;vWoVD#t|#DT!#BC>`HZ{PyBj;gRfXAAGOT^wY+@zX`N53g(TAO^u5eMPrzo_quzVwk?s9XOZ#u`Wf%1iwZW^pj&5Bay_-h4&?!svD7EzF;^s5-#C%kdOM#Y? za@Yk<+8fAV&^B6`nhQ&_8YH*uMTN7?oyxijCbmWhc*lVK22!2VV6WNICN4;=3D#ENPf zBHT7SIiG;A!)*l2Phb~}x8987b92)D_ZSoaU%3bdVOzo&{{{O9OoL)L>`+Wn!p z#QN3ZzZ5U3#V4ZW(Pt!9hI5eUbJplHcDBXJzGsg<=3DVV))p?D$OxjYd#!KTeJY?z&~ zfz2yL=3Ds!A+^!Xn!dcxQkGNBI)$4@(L=3Dh^RU*E49yoIC59*PBRXEDujoIhOBniwe>5W9{HXg z<;*qm=3DHa%JZHcy1ZRxh7>{uw_YVawZlM2o+JVz9du6WKKYVQ0xe6?=3Dvj~e8b9^|0; z>oFzzQ}W>GJQ}vt7j=3Df?u;y#JC~w~hkuG6}O}N)r6#8fwn`OJZ868i5U~}$ndO*%% zk;7}@H#p&{dGJ+*`D(ib^ude<8&a@8wFyz53;WeD?Nv(-XAWBru?UW11Qzq+SMG>S z!-IrAfROsI82`}5>YUNK;*!G{16h+D4z&?}B(;kxjNw3u(fZ?Za31oBflXhq)U<5d zBe2r2$2211gXny_dvgwI!eaG!>kZDuZ#(1#i@a?qz=3D4cjF9Ph?ZS^EoxCBfo5*W#(xICY8?vDl{f1nn!9n&<6< zv)Q`-&R=3D6X(U$xP-rTDlqDLY$5G>h`BRqR_UB9~Sk~xlJb^H+<*4~9gJe}wNn3fjt zQ+evv;tKY{TPzW+-X9vV_&3Sh$rrFY+}BzyMHU{zc}#VmcJ7j){|BT$9=3DeW`@gUrc zjfQmRrrgYU6@1~Cg)KfNho>M(n*|6s7?b|57cL%Md<Hx1Orywv z+FD&f1wCJ;ZtBB^;IC0uw6KNpv88?ForP4^u=3DdP&0>xg3o#JS6;Q*dOa^c7HkUJJ0 zQ(qXsF=3DPDVu4tgoqlPrUhKrUNj>c(e|dX3&vva7^I^n zyjNWyk<4}Dm#!2Y1EC)tN$=3D8zFo?l_XiTBCzjdad>-cnmo~(X9uX_Z?_c7Kt^E2eK z9iNQfAiFRmcN}g$_!*Mg?>|>r{&wI4Hgbam8<9KuGcu*;GX0*)*i9Nc4Lt{k_K*&C z;_QNL!3XY;!)~+@f;}aE8%`qWSX7CCc@AEV8=3Dc6--h<0+c`uzQUa^%_Ra-Y{0eBLs$Cy9f*$ zF<;E}3$dX^Nk)L!Fb%aVFvyJ6GHAZHi%``W%O+xxPYC)mi8iR&{RFC+8ZrEb9rW}V z`@)ojTG4rQ!=3DCZxJu$S~Xx@X=3Dykl)j`_Jw*Iy!5}-1betc|rhY(S zEcgzZA){m@O+SYpJ1m=3Dy!_Q)>y%^exYRcjNftpg#Du;iCAd)5A_Ee71uBZn#EmVHz zFd@7!gcwXdM$9EzT^ccl6_D9DCIiZbjNg<&y$azA&W-*&Jf{3G(A<2;n>Bs6fUbel zN7_t~`36STrwo}Uwmbz>;5)&sZhRJwtiW3=3DgtoF$gO#IE<(5ivO04wmgUnZPw7v&5 zp<4fvTn2~5#cUpVP3ztNgx{9S=3DEy8})VrtW;6#u0!Br+3b$GLj+#%CogsVDY_W^%Gq$AZJ!d^I0O%5r!e zeD2vz%~!3)+jhJ)U$r3|crd!LIO>(gCbkRB9~pC5zcH7Y2C?DLfMv2VSnX5J%CGmZ zYHR6PR?vh~yymN-p>hZ8SDUXdp_yOY{7~uH;M>itAib#hs@+KcHPV}}PNpK~Pbe?i zP<)F5qt(_fDsCwKQ&O~z6@(s{Et*ccpM3QW&>K|NMI}^Ahde1Z#9k%5OU&HOhHlFOKF}Se7{^O zi2VzjKd02d`B}O7cy<-y$N1ntyWxxfE165FzUsxk-rPG8l9IVacsy41=3D%Y9XK&a8> za&@{8=3D>8ZB=3DiL~_@LwDkUrXlBMVufET<^qD$Bm~s6Hc$jcCsG~GMxVu87JfNFKt(_ zTa()!L^E~!pvj}tbOTK^xL9$fKf>N+e~hWi29vcT6rHRkrxki@2ZczL*jr^O!~!qe z2siJo$`RR*CH8%*y5y|qi05QF7j>UfDIP8VUEs2~(k*#Iy@lnHJMb^~?qrQhZnZcV zKV?z(RG?t>Uu*CiO4KXKJW)t4vOLsK=3D~9x5Cb?Yrgo?vy!(beIOLDiRN{pBPK5!W$ zEdDW}cao)5a(g3^J5nnu$y!UHX#96b&vkW~80xilqHg$>o6f^HlF9pC;Ib;om<^>) z3z&cMtgSN4u^euyssPTN%+kJ2}SK9=3D+xQA5M^<~khAvsVdWq>ur#;6Bu5%IZ0t+rzO;df!Z8#MHfrhlo# zz%(cID>xx+@Ac+c(!V8i$q;FhpvkBxhJ%-FMginQoz!|0I6=3DS3DH)<uM-rRoLC+t2igf`Y|;Ad({_=3Dsc^6xzT-L>nK(g_#I(CG(V;*TE}#I08Gt9D6>K&20HSUL!oPU`wj5~y-m zTP#%$`}UkFhjW`$2!a=3DKVaU-3KeIl|jf#+tm6^0H z2;Yt~=3D^)O>pyO^lO&u@=3DynJ{q!+jiS#y=3Ds!j+^RT?I?W#Zc}+fRci_?>u!!k+d<#o z;I8;U*Z&nyD(@CLy_SHZuEtSc>(G-gGq8I9Ap;)-*VLYqH@b4qsz7jQEH1voDW3 zR#rNis?e6y2D?zMHlXV+goSE{bCILC(&1{PrVwW1-k(Wtpmf+3veY_m*RI+AWB*Xs zDL-8<+|++QLmAYzrjBZK{Dkmx-I7DQCL{eAeWfovymzF*9JY+zQzy2HS5DRs+s~MszfA78 zkjwfj`3d>!F2qe9>x)&iRW`00>oga!RHyKuu0Kr@x8h=3D1al=3DSuj!BIWZ%4ilh{dh) zegDScy}BSr7H^ECu565%yYTd$({(!DG27i3zcF8gB${z2%O{UNQgZe>fg z!3qy_x650R$s4<<>(#fn-?h&F-EXcd`&Ow?x<#O{|2t1_ST|?GfBVkbbw3gwZ>Vwk z8XtE-7r!_GPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(8 z6W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;Z zH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULas zfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O z1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1U zPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu z-~>1UPJk2O1ULasfD_;ZH~~(86W|0m0ZxDu-~>1UPJk2O1ULasfD_;ZH~~(86W|0m z0Z!od1Ux-$$J=3D_^2HLc?{{JUzm0dl`OkLOi(JspO^xUV&;+-j7IrD2oSp}ujDU3^> o5d@0NUb>FZ&)-2Do-dnE`R8)xT^9bc5QmajO4XIv_+RY*0|l%Fi~s-t literal 0 HcmV?d00001 diff --git a/roms/Makefile b/roms/Makefile index 775c963f9d..47eabc8633 100644 --- a/roms/Makefile +++ b/roms/Makefile @@ -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" =20 @@ -185,6 +186,10 @@ opensbi64-sifive_u: PLATFORM=3D"qemu/sifive_u" cp opensbi/build/platform/qemu/sifive_u/firmware/fw_jump.bin ../pc-bios/o= pensbi-riscv64-sifive_u-fw_jump.bin =20 +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 diff --git a/roms/qboot b/roms/qboot new file mode 160000 index 0000000000..cb1c49e0cf --- /dev/null +++ b/roms/qboot @@ -0,0 +1 @@ +Subproject commit cb1c49e0cfac99b9961d136ac0194da62c28cf64 --=20 2.21.0 From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569333269; cv=none; d=zoho.com; s=zohoarc; b=RtBm9L7bjNesEXI7TtBeuLCz0GVOq2CkgQAECAsTHzFP5hVXDzMX6pqmiHmj1foEt5Ype7VVyQtfFriulIso9/s2yvdaXMiKsiGNDVOKE8mN/GNnYFxFGfTXuaUo38VlCHLlPbcNHrwG007L4W9w1A2sMI4JEw2zmWsyHEB1XEM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569333269; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=ZAMN58OLzAOPNT1nCjoozv+ZfmuyHOaWeT/mGktdM68=; b=H1c8FkEoxB8g3eR+4Q2EFrRwrL5GcR+I2fZ53yDNqNN4H0I2/oti0SV1ppK3a2V/e+S8aQ5vVXN8T5A7bWKFJXzvjqJlWGk1Upw4qrdkY2jMXvTpluM5U2yn9bAPBnzKer1UBQVBO14QxMuLppfT//x4+ysZ05jmL8POLrfjMkw= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569333269098359.8676880776817; Tue, 24 Sep 2019 06:54:29 -0700 (PDT) Received: from localhost ([::1]:45942 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iClGt-00084H-JK for importer@patchew.org; Tue, 24 Sep 2019 09:54:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52565) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkCl-0003NT-GY for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:08 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkCj-0004yd-RY for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:07 -0400 Received: from mx1.redhat.com ([209.132.183.28]:46692) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkCj-0004yI-IE for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:05 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C26E1307D970; Tue, 24 Sep 2019 12:46:04 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id 94A0160933; Tue, 24 Sep 2019 12:45:58 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 7/8] docs/microvm.txt: document the new microvm machine type Date: Tue, 24 Sep 2019 14:44:32 +0200 Message-Id: <20190924124433.96810-8-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.48]); Tue, 24 Sep 2019 12:46:04 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Document the new microvm machine type. Signed-off-by: Sergio Lopez --- docs/microvm.txt | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 docs/microvm.txt diff --git a/docs/microvm.txt b/docs/microvm.txt new file mode 100644 index 0000000000..0241226b2a --- /dev/null +++ b/docs/microvm.txt @@ -0,0 +1,78 @@ +Microvm is a machine type inspired by both NEMU and Firecracker, and +constructed after the machine model implemented by the latter. + +It's main purpose is providing users a minimalist machine type free +from the burden of legacy compatibility, serving as a stepping stone +for future projects aiming at improving boot times, reducing the +attack surface and slimming down QEMU's footprint. + +The microvm machine type supports the following devices: + + - ISA bus + - i8259 PIC + - LAPIC (implicit if using KVM) + - IOAPIC (defaults to kernel_irqchip_split =3D true) + - i8254 PIT + - MC146818 RTC (optional) + - kvmclock (if using KVM) + - fw_cfg + - One ISA serial port (optional) + - Up to eight virtio-mmio devices (configured by the user) + +It supports the following machine-specific options: + +microvm.option-roms=3Dbool (Set off to disable loading option ROMs) +microvm.isa-serial=3Dbool (Set off to disable the instantiation an ISA ser= ial port) +microvm.rtc=3Dbool (Set off to disable the instantiation of an MC146818 RT= C) +microvm.kernel-cmdline=3Dbool (Set off to disable adding virtio-mmio devic= es to the kernel cmdline) + +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. + +This is an example of instantiating a microvm VM with a virtio-mmio +based console: + +qemu-system-x86_64 -M microvm + -enable-kvm -cpu host -m 512m -smp 2 \ + -kernel vmlinux -append "console=3Dhvc0 root=3D/dev/vda" \ + -nodefaults -no-user-config -nographic \ + -chardev stdio,id=3Dvirtiocon0,server \ + -device virtio-serial-device \ + -device virtconsole,chardev=3Dvirtiocon0 \ + -drive id=3Dtest,file=3Dtest.img,format=3Draw,if=3Dnone \ + -device virtio-blk-device,drive=3Dtest \ + -netdev tap,id=3Dtap0,script=3Dno,downscript=3Dno \ + -device virtio-net-device,netdev=3Dtap0 + +This is another example, this time using an ISA serial port, useful +for debugging purposes: + +qemu-system-x86_64 -M microvm \ + -enable-kvm -cpu host -m 512m -smp 2 \ + -kernel vmlinux -append "earlyprintk=3DttyS0 console=3DttyS0 root=3D/dev/= vda" \ + -nodefaults -no-user-config -nographic \ + -serial stdio \ + -drive id=3Dtest,file=3Dtest.img,format=3Draw,if=3Dnone \ + -device virtio-blk-device,drive=3Dtest \ + -netdev tap,id=3Dtap0,script=3Dno,downscript=3Dno \ + -device virtio-net-device,netdev=3Dtap0 + +Finally, in this example a microvm VM is instantiated without RTC, +without an ISA serial port and without loading the option ROMs, +obtaining the smallest configuration: + +qemu-system-x86_64 -M microvm,rtc=3Doff,isa-serial=3Doff,option-roms=3Doff= \ + -enable-kvm -cpu host -m 512m -smp 2 \ + -kernel vmlinux -append "console=3Dhvc0 root=3D/dev/vda" \ + -nodefaults -no-user-config -nographic \ + -chardev stdio,id=3Dvirtiocon0,server \ + -device virtio-serial-device \ + -device virtconsole,chardev=3Dvirtiocon0 \ + -drive id=3Dtest,file=3Dtest.img,format=3Draw,if=3Dnone \ + -device virtio-blk-device,drive=3Dtest \ + -netdev tap,id=3Dtap0,script=3Dno,downscript=3Dno \ + -device virtio-net-device,netdev=3Dtap0 --=20 2.21.0 From nobody Tue Apr 30 11:23:15 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1569332546; cv=none; d=zoho.com; s=zohoarc; b=msditYYwOGguFP+5kO1nFNPRUG97Xc72nfYw397r6eQrXZDsHKeWNioPEtCIreba3Tft0WpjGlm0sXa4A9npRbH9CXryF9cSWxh7YrJ6G1oVkox2wNYaVe/xPOJN/F6Ul15X73tjZCmZyn+xraptrLb1Z3ibB+QOBGFUegQqKHc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1569332546; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=qb8WKMD23vMbmTFLx4dFxAfKmo526uA6fCatFS+BV3E=; b=WFStxqEAX21vEmPFtcaTGVEkG2tNckQsVrR9CUu6uQFfAjvzCTOe9Cn5Ny/pu7S1jWAWZXgabes0RaDFXAgvBphe5mIcIwkQvcEm0AxIO0vEACC+IwI0E9d23+eFnSmgL1v3I/y6Zy1LMrbSr3EcyvsaUTfxqHydKyaM2Ymq6So= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1569332546387445.1596119955922; Tue, 24 Sep 2019 06:42:26 -0700 (PDT) Received: from localhost ([::1]:45798 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCl5B-00039B-F7 for importer@patchew.org; Tue, 24 Sep 2019 09:42:21 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52633) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iCkCv-0003eT-Mz for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iCkCs-00053K-M4 for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:17 -0400 Received: from mx1.redhat.com ([209.132.183.28]:49672) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iCkCs-000533-D1 for qemu-devel@nongnu.org; Tue, 24 Sep 2019 08:46:14 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AED2C30860B9; Tue, 24 Sep 2019 12:46:13 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.128]) by smtp.corp.redhat.com (Postfix) with ESMTP id 286DA60603; Tue, 24 Sep 2019 12:46:04 +0000 (UTC) From: Sergio Lopez To: qemu-devel@nongnu.org Subject: [PATCH v4 8/8] hw/i386: Introduce the microvm machine type Date: Tue, 24 Sep 2019 14:44:33 +0200 Message-Id: <20190924124433.96810-9-slp@redhat.com> In-Reply-To: <20190924124433.96810-1-slp@redhat.com> References: <20190924124433.96810-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.44]); Tue, 24 Sep 2019 12:46:13 +0000 (UTC) Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Sergio Lopez , ehabkost@redhat.com, kvm@vger.kernel.org, mst@redhat.com, lersek@redhat.com, mtosatti@redhat.com, kraxel@redhat.com, pbonzini@redhat.com, imammedo@redhat.com, philmd@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Microvm is a machine type inspired by both NEMU and Firecracker, and constructed after the machine model implemented by the latter. It's main purpose is providing users a minimalist machine type free from the burden of legacy compatibility, serving as a stepping stone for future projects aiming at improving boot times, reducing the attack surface and slimming down QEMU's footprint. The microvm machine type supports the following devices: - ISA bus - i8259 PIC - LAPIC (implicit if using KVM) - IOAPIC (defaults to kernel_irqchip_split =3D true) - i8254 PIT - MC146818 RTC (optional) - kvmclock (if using KVM) - fw_cfg - One ISA serial port (optional) - Up to eight virtio-mmio devices (configured by the user) It supports the following machine-specific options: microvm.option-roms=3Dbool (Set off to disable loading option ROMs) microvm.isa-serial=3Dbool (Set off to disable the instantiation an ISA seri= al port) microvm.rtc=3Dbool (Set off to disable the instantiation of an MC146818 RTC) microvm.kernel-cmdline=3Dbool (Set off to disable adding virtio-mmio device= s to the kernel cmdline) 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. This is an example of instantiating a microvm VM with a virtio-mmio based console: qemu-system-x86_64 -M microvm -enable-kvm -cpu host -m 512m -smp 2 \ -kernel vmlinux -append "console=3Dhvc0 root=3D/dev/vda" \ -nodefaults -no-user-config -nographic \ -chardev stdio,id=3Dvirtiocon0,server \ -device virtio-serial-device \ -device virtconsole,chardev=3Dvirtiocon0 \ -drive id=3Dtest,file=3Dtest.img,format=3Draw,if=3Dnone \ -device virtio-blk-device,drive=3Dtest \ -netdev tap,id=3Dtap0,script=3Dno,downscript=3Dno \ -device virtio-net-device,netdev=3Dtap0 This is another example, this time using an ISA serial port, useful for debugging purposes: qemu-system-x86_64 -M microvm \ -enable-kvm -cpu host -m 512m -smp 2 \ -kernel vmlinux -append "earlyprintk=3DttyS0 console=3DttyS0 root=3D/dev/v= da" \ -nodefaults -no-user-config -nographic \ -serial stdio \ -drive id=3Dtest,file=3Dtest.img,format=3Draw,if=3Dnone \ -device virtio-blk-device,drive=3Dtest \ -netdev tap,id=3Dtap0,script=3Dno,downscript=3Dno \ -device virtio-net-device,netdev=3Dtap0 Finally, in this example a microvm VM is instantiated without RTC, without an ISA serial port and without loading the option ROMs, obtaining the smallest configuration: qemu-system-x86_64 -M microvm,rtc=3Doff,isa-serial=3Doff,option-roms=3Doff \ -enable-kvm -cpu host -m 512m -smp 2 \ -kernel vmlinux -append "console=3Dhvc0 root=3D/dev/vda" \ -nodefaults -no-user-config -nographic \ -chardev stdio,id=3Dvirtiocon0,server \ -device virtio-serial-device \ -device virtconsole,chardev=3Dvirtiocon0 \ -drive id=3Dtest,file=3Dtest.img,format=3Draw,if=3Dnone \ -device virtio-blk-device,drive=3Dtest \ -netdev tap,id=3Dtap0,script=3Dno,downscript=3Dno \ -device virtio-net-device,netdev=3Dtap0 Signed-off-by: Sergio Lopez --- default-configs/i386-softmmu.mak | 1 + hw/i386/Kconfig | 4 + hw/i386/Makefile.objs | 1 + hw/i386/microvm.c | 512 +++++++++++++++++++++++++++++++ include/hw/i386/microvm.h | 80 +++++ 5 files changed, 598 insertions(+) create mode 100644 hw/i386/microvm.c create mode 100644 include/hw/i386/microvm.h diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmm= u.mak index cd5ea391e8..c27cdd98e9 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -26,3 +26,4 @@ CONFIG_ISAPC=3Dy CONFIG_I440FX=3Dy CONFIG_Q35=3Dy CONFIG_ACPI_PCI=3Dy +CONFIG_MICROVM=3Dy \ No newline at end of file diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index 6350438036..324e193dd8 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -88,6 +88,10 @@ config Q35 select SMBIOS select FW_CFG_DMA =20 +config MICROVM + bool + select VIRTIO_MMIO + config VTD bool =20 diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 5b4b3a672e..bb17d54567 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -6,6 +6,7 @@ obj-y +=3D pc.o obj-y +=3D e820.o obj-$(CONFIG_I440FX) +=3D pc_piix.o obj-$(CONFIG_Q35) +=3D pc_q35.o +obj-$(CONFIG_MICROVM) +=3D microvm.o obj-y +=3D fw_cfg.o pc_sysfw.o obj-y +=3D x86-iommu.o obj-$(CONFIG_VTD) +=3D intel_iommu.o diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c new file mode 100644 index 0000000000..4b494a1b27 --- /dev/null +++ b/hw/i386/microvm.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2018 Intel Corporation + * 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 f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qemu/cutils.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "qapi/visitor.h" +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "sysemu/numa.h" +#include "sysemu/reset.h" + +#include "hw/loader.h" +#include "hw/irq.h" +#include "hw/nmi.h" +#include "hw/kvm/clock.h" +#include "hw/i386/microvm.h" +#include "hw/i386/x86.h" +#include "hw/i386/pc.h" +#include "target/i386/cpu.h" +#include "hw/timer/i8254.h" +#include "hw/timer/mc146818rtc.h" +#include "hw/char/serial.h" +#include "hw/i386/topology.h" +#include "hw/i386/e820.h" +#include "hw/i386/fw_cfg.h" +#include "hw/virtio/virtio-mmio.h" + +#include "cpu.h" +#include "elf.h" +#include "pvh.h" +#include "kvm_i386.h" +#include "hw/xen/start_info.h" + +#define MICROVM_BIOS_FILENAME "bios-microvm.bin" + +static void microvm_set_rtc(MicrovmMachineState *mms, ISADevice *s) +{ + X86MachineState *x86ms =3D X86_MACHINE(mms); + int val; + + val =3D MIN(x86ms->below_4g_mem_size / KiB, 640); + rtc_set_memory(s, 0x15, val); + rtc_set_memory(s, 0x16, val >> 8); + /* extended memory (next 64MiB) */ + if (x86ms->below_4g_mem_size > 1 * MiB) { + val =3D (x86ms->below_4g_mem_size - 1 * MiB) / KiB; + } else { + val =3D 0; + } + if (val > 65535) { + val =3D 65535; + } + rtc_set_memory(s, 0x17, val); + rtc_set_memory(s, 0x18, val >> 8); + rtc_set_memory(s, 0x30, val); + rtc_set_memory(s, 0x31, val >> 8); + /* memory between 16MiB and 4GiB */ + if (x86ms->below_4g_mem_size > 16 * MiB) { + val =3D (x86ms->below_4g_mem_size - 16 * MiB) / (64 * KiB); + } else { + val =3D 0; + } + if (val > 65535) { + val =3D 65535; + } + rtc_set_memory(s, 0x34, val); + rtc_set_memory(s, 0x35, val >> 8); + /* memory above 4GiB */ + val =3D x86ms->above_4g_mem_size / 65536; + rtc_set_memory(s, 0x5b, val); + rtc_set_memory(s, 0x5c, val >> 8); + rtc_set_memory(s, 0x5d, val >> 16); +} + +static void microvm_devices_init(MicrovmMachineState *mms) +{ + X86MachineState *x86ms =3D X86_MACHINE(mms); + ISABus *isa_bus; + ISADevice *rtc_state; + GSIState *gsi_state; + qemu_irq *i8259; + int i; + + gsi_state =3D g_malloc0(sizeof(*gsi_state)); + x86ms->gsi =3D qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS= ); + + isa_bus =3D isa_bus_new(NULL, get_system_memory(), get_system_io(), + &error_abort); + isa_bus_irqs(isa_bus, x86ms->gsi); + + i8259 =3D i8259_init(isa_bus, pc_allocate_cpu_irq()); + + for (i =3D 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] =3D i8259[i]; + } + + ioapic_init_gsi(gsi_state, "machine"); + + if (mms->rtc_enabled) { + rtc_state =3D mc146818_rtc_init(isa_bus, 2000, NULL); + microvm_set_rtc(mms, rtc_state); + } + + if (kvm_pit_in_kernel()) { + kvm_pit_init(isa_bus, 0x40); + } else { + i8254_pit_init(isa_bus, 0x40, 0, NULL); + } + + kvmclock_create(); + + for (i =3D 0; i < VIRTIO_NUM_TRANSPORTS; i++) { + int nirq =3D VIRTIO_IRQ_BASE + i; + ISADevice *isadev =3D isa_create(isa_bus, TYPE_ISA_SERIAL); + qemu_irq mmio_irq; + + isa_init_irq(isadev, &mmio_irq, nirq); + sysbus_create_simple("virtio-mmio", + VIRTIO_MMIO_BASE + i * 512, + x86ms->gsi[VIRTIO_IRQ_BASE + i]); + } + + g_free(i8259); + + if (mms->isa_serial_enabled) { + serial_hds_isa_init(isa_bus, 0, 1); + } + + if (bios_name =3D=3D NULL) { + bios_name =3D MICROVM_BIOS_FILENAME; + } + x86_system_rom_init(get_system_memory(), true); +} + +static void microvm_memory_init(MicrovmMachineState *mms) +{ + MachineState *machine =3D MACHINE(mms); + X86MachineState *x86ms =3D X86_MACHINE(mms); + MemoryRegion *ram, *ram_below_4g, *ram_above_4g; + MemoryRegion *system_memory =3D get_system_memory(); + FWCfgState *fw_cfg; + ram_addr_t lowmem; + int i; + + /* + * Check whether RAM fits below 4G (leaving 1/2 GByte for IO memory + * and 256 Mbytes for PCI Express Enhanced Configuration Access Mapping + * also known as MMCFG). + * If it doesn't, we need to split it in chunks below and above 4G. + * In any case, try to make sure that guest addresses aligned at + * 1G boundaries get mapped to host addresses aligned at 1G boundaries. + */ + if (machine->ram_size >=3D 0xb0000000) { + lowmem =3D 0x80000000; + } else { + lowmem =3D 0xb0000000; + } + + /* + * Handle the machine opt max-ram-below-4g. It is basically doing + * min(qemu limit, user limit). + */ + if (!x86ms->max_ram_below_4g) { + x86ms->max_ram_below_4g =3D 1ULL << 32; /* default: 4G */ + } + if (lowmem > x86ms->max_ram_below_4g) { + lowmem =3D 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 siz= e " + " (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, x86ms->max_ram_below_= 4g); + } + } + + if (machine->ram_size > lowmem) { + x86ms->above_4g_mem_size =3D machine->ram_size - lowmem; + x86ms->below_4g_mem_size =3D lowmem; + } else { + x86ms->above_4g_mem_size =3D 0; + x86ms->below_4g_mem_size =3D machine->ram_size; + } + + ram =3D g_malloc(sizeof(*ram)); + memory_region_allocate_system_memory(ram, NULL, "microvm.ram", + machine->ram_size); + + ram_below_4g =3D g_malloc(sizeof(*ram_below_4g)); + memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ram, + 0, x86ms->below_4g_mem_size); + memory_region_add_subregion(system_memory, 0, ram_below_4g); + + e820_add_entry(0, x86ms->below_4g_mem_size, E820_RAM); + + if (x86ms->above_4g_mem_size > 0) { + ram_above_4g =3D g_malloc(sizeof(*ram_above_4g)); + memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g", ram, + x86ms->below_4g_mem_size, + x86ms->above_4g_mem_size); + memory_region_add_subregion(system_memory, 0x100000000ULL, + ram_above_4g); + e820_add_entry(0x100000000ULL, x86ms->above_4g_mem_size, E820_RAM); + } + + fw_cfg =3D fw_cfg_init_io_dma(FW_CFG_IO_BASE, FW_CFG_IO_BASE + 4, + &address_space_memory); + + fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, x86ms->boot_cpus); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)x86ms->apic_id_limit= ); + fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)machine->ram_size); + fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override(= )); + + rom_set_fw(fw_cfg); + + e820_create_fw_entry(fw_cfg); + + load_linux(x86ms, fw_cfg, 0, true, true); + + if (mms->option_roms_enabled) { + for (i =3D 0; i < nb_option_roms; i++) { + rom_add_option(option_rom[i].name, option_rom[i].bootindex); + } + } + + x86ms->fw_cfg =3D fw_cfg; + x86ms->ioapic_as =3D &address_space_memory; +} + +static gchar *microvm_get_mmio_cmdline(gchar *name) +{ + gchar *cmdline; + gchar *separator; + long int index; + int ret; + + separator =3D g_strrstr(name, "."); + if (!separator) { + return NULL; + } + + if (qemu_strtol(separator + 1, NULL, 10, &index) !=3D 0) { + return NULL; + } + + cmdline =3D g_malloc0(VIRTIO_CMDLINE_MAXLEN); + ret =3D g_snprintf(cmdline, VIRTIO_CMDLINE_MAXLEN, + " virtio_mmio.device=3D512@0x%lx:%ld", + VIRTIO_MMIO_BASE + index * 512, + VIRTIO_IRQ_BASE + index); + if (ret < 0 || ret >=3D VIRTIO_CMDLINE_MAXLEN) { + g_free(cmdline); + return NULL; + } + + return cmdline; +} + +static void microvm_fix_kernel_cmdline(MachineState *machine) +{ + X86MachineState *x86ms =3D X86_MACHINE(machine); + BusState *bus; + BusChild *kid; + char *cmdline; + + /* + * Find MMIO transports with attached devices, and add them to the ker= nel + * command line. + * + * Yes, this is a hack, but one that heavily improves the UX without + * introducing any significant issues. + */ + cmdline =3D g_strdup(machine->kernel_cmdline); + bus =3D sysbus_get_default(); + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev =3D kid->child; + ObjectClass *class =3D object_get_class(OBJECT(dev)); + + if (class =3D=3D object_class_by_name(TYPE_VIRTIO_MMIO)) { + VirtIOMMIOProxy *mmio =3D VIRTIO_MMIO(OBJECT(dev)); + VirtioBusState *mmio_virtio_bus =3D &mmio->bus; + BusState *mmio_bus =3D &mmio_virtio_bus->parent_obj; + + if (!QTAILQ_EMPTY(&mmio_bus->children)) { + gchar *mmio_cmdline =3D microvm_get_mmio_cmdline(mmio_bus-= >name); + if (mmio_cmdline) { + char *newcmd =3D g_strjoin(NULL, cmdline, mmio_cmdline= , NULL); + g_free(mmio_cmdline); + g_free(cmdline); + cmdline =3D newcmd; + } + } + } + } + + fw_cfg_modify_i32(x86ms->fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(cmdline) = + 1); + fw_cfg_modify_string(x86ms->fw_cfg, FW_CFG_CMDLINE_DATA, cmdline); +} + +static void microvm_machine_state_init(MachineState *machine) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(machine); + X86MachineState *x86ms =3D X86_MACHINE(machine); + Error *local_err =3D NULL; + + if (machine->kernel_filename =3D=3D NULL) { + error_report("missing kernel image file name, required by microvm"= ); + exit(1); + } + + microvm_memory_init(mms); + + x86_cpus_init(x86ms, CPU_VERSION_LATEST); + if (local_err) { + error_report_err(local_err); + exit(1); + } + + microvm_devices_init(mms); +} + +static void microvm_machine_reset(MachineState *machine) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(machine); + CPUState *cs; + X86CPU *cpu; + + if (mms->kernel_cmdline_enabled && !mms->kernel_cmdline_fixed) { + microvm_fix_kernel_cmdline(machine); + mms->kernel_cmdline_fixed =3D true; + } + + qemu_devices_reset(); + + CPU_FOREACH(cs) { + cpu =3D X86_CPU(cs); + + if (cpu->apic_state) { + device_reset(cpu->apic_state); + } + } +} + +static bool microvm_machine_get_rtc(Object *obj, Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + return mms->rtc_enabled; +} + +static void microvm_machine_set_rtc(Object *obj, bool value, Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + mms->rtc_enabled =3D value; +} + +static bool microvm_machine_get_isa_serial(Object *obj, Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + return mms->isa_serial_enabled; +} + +static void microvm_machine_set_isa_serial(Object *obj, bool value, + Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + mms->isa_serial_enabled =3D value; +} + +static bool microvm_machine_get_option_roms(Object *obj, Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + return mms->option_roms_enabled; +} + +static void microvm_machine_set_option_roms(Object *obj, bool value, + Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + mms->option_roms_enabled =3D value; +} + +static bool microvm_machine_get_kernel_cmdline(Object *obj, Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + return mms->kernel_cmdline_enabled; +} + +static void microvm_machine_set_kernel_cmdline(Object *obj, bool value, + Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + mms->kernel_cmdline_enabled =3D value; +} + +static void microvm_machine_initfn(Object *obj) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + /* Configuration */ + mms->rtc_enabled =3D true; + mms->isa_serial_enabled =3D true; + mms->option_roms_enabled =3D true; + mms->kernel_cmdline_enabled =3D true; + + /* State */ + mms->kernel_cmdline_fixed =3D false; +} + +static void microvm_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc =3D MACHINE_CLASS(oc); + NMIClass *nc =3D NMI_CLASS(oc); + + mc->init =3D microvm_machine_state_init; + + mc->family =3D "microvm_i386"; + mc->desc =3D "Microvm (i386)"; + mc->units_per_default_bus =3D 1; + mc->no_floppy =3D 1; + machine_class_allow_dynamic_sysbus_dev(mc, "sysbus-debugcon"); + machine_class_allow_dynamic_sysbus_dev(mc, "sysbus-debugexit"); + mc->max_cpus =3D 288; + mc->has_hotpluggable_cpus =3D false; + mc->auto_enable_numa_with_memhp =3D false; + mc->default_cpu_type =3D TARGET_DEFAULT_CPU_TYPE; + mc->nvdimm_supported =3D false; + + /* Avoid relying too much on kernel components */ + mc->default_kernel_irqchip_split =3D true; + + /* Machine class handlers */ + mc->reset =3D microvm_machine_reset; + + /* NMI handler */ + nc->nmi_monitor_handler =3D x86_nmi; + + object_class_property_add_bool(oc, MICROVM_MACHINE_RTC, + microvm_machine_get_rtc, + microvm_machine_set_rtc, + &error_abort); + object_class_property_set_description(oc, MICROVM_MACHINE_RTC, + "Set off to disable the instantiation of an MC146818 RTC", + &error_abort); + + object_class_property_add_bool(oc, MICROVM_MACHINE_ISA_SERIAL, + microvm_machine_get_isa_serial, + microvm_machine_set_isa_serial, + &error_abort); + object_class_property_set_description(oc, MICROVM_MACHINE_ISA_SERIAL, + "Set off to disable the instantiation an ISA serial port", + &error_abort); + + object_class_property_add_bool(oc, MICROVM_MACHINE_OPTION_ROMS, + microvm_machine_get_option_roms, + microvm_machine_set_option_roms, + &error_abort); + object_class_property_set_description(oc, MICROVM_MACHINE_OPTION_ROMS, + "Set off to disable loading option ROMs", &error_abort); + + object_class_property_add_bool(oc, MICROVM_MACHINE_KERNEL_CMDLINE, + microvm_machine_get_kernel_cmdline, + microvm_machine_set_kernel_cmdline, + &error_abort); + object_class_property_set_description(oc, MICROVM_MACHINE_KERNEL_CMDLI= NE, + "Set off to disable adding virtio-mmio devices to the kernel cmdli= ne", + &error_abort); +} + +static const TypeInfo microvm_machine_info =3D { + .name =3D TYPE_MICROVM_MACHINE, + .parent =3D TYPE_X86_MACHINE, + .instance_size =3D sizeof(MicrovmMachineState), + .instance_init =3D microvm_machine_initfn, + .class_size =3D sizeof(MicrovmMachineClass), + .class_init =3D microvm_class_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_NMI }, + { } + }, +}; + +static void microvm_machine_init(void) +{ + type_register_static(µvm_machine_info); +} +type_init(microvm_machine_init); diff --git a/include/hw/i386/microvm.h b/include/hw/i386/microvm.h new file mode 100644 index 0000000000..04c8caf886 --- /dev/null +++ b/include/hw/i386/microvm.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 Intel Corporation + * 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 f= or + * more details. + * + * You should have received a copy of the GNU General Public License along= with + * this program. If not, see . + */ + +#ifndef HW_I386_MICROVM_H +#define HW_I386_MICROVM_H + +#include "qemu-common.h" +#include "exec/hwaddr.h" +#include "qemu/notify.h" + +#include "hw/boards.h" +#include "hw/i386/x86.h" + +/* Microvm memory layout */ +#define PVH_START_INFO 0x6000 +#define MEMMAP_START 0x7000 +#define MODLIST_START 0x7800 +#define BOOT_STACK_POINTER 0x8ff0 +#define PML4_START 0x9000 +#define PDPTE_START 0xa000 +#define PDE_START 0xb000 +#define KERNEL_CMDLINE_START 0x20000 +#define EBDA_START 0x9fc00 +#define HIMEM_START 0x100000 + +/* Platform virtio definitions */ +#define VIRTIO_MMIO_BASE 0xc0000000 +#define VIRTIO_IRQ_BASE 5 +#define VIRTIO_NUM_TRANSPORTS 8 +#define VIRTIO_CMDLINE_MAXLEN 64 + +/* Machine type options */ +#define MICROVM_MACHINE_RTC "rtc" +#define MICROVM_MACHINE_ISA_SERIAL "isa-serial" +#define MICROVM_MACHINE_OPTION_ROMS "option-roms" +#define MICROVM_MACHINE_KERNEL_CMDLINE "kernel-cmdline" + +typedef struct { + X86MachineClass parent; + HotplugHandler *(*orig_hotplug_handler)(MachineState *machine, + DeviceState *dev); +} MicrovmMachineClass; + +typedef struct { + X86MachineState parent; + + /* Machine type options */ + bool rtc_enabled; + bool isa_serial_enabled; + bool option_roms_enabled; + bool kernel_cmdline_enabled; + + + /* Machine state */ + bool kernel_cmdline_fixed; +} MicrovmMachineState; + +#define TYPE_MICROVM_MACHINE MACHINE_TYPE_NAME("microvm") +#define MICROVM_MACHINE(obj) \ + OBJECT_CHECK(MicrovmMachineState, (obj), TYPE_MICROVM_MACHINE) +#define MICROVM_MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(MicrovmMachineClass, obj, TYPE_MICROVM_MACHINE) +#define MICROVM_MACHINE_CLASS(class) \ + OBJECT_CLASS_CHECK(MicrovmMachineClass, class, TYPE_MICROVM_MACHINE) + +#endif --=20 2.21.0