From nobody Fri May 10 06:14:25 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=1561994201; cv=none; d=zoho.com; s=zohoarc; b=h4iIq6cclQOsoxZh5IOW7ZVwIAprX7egDRYhXcKuKuArXSzWI5+zeGX7i2GR83N9GmFAUSHEGPtAu95VpX62lJq/rxxUvNyfwbC5CPcDa5BamSWiZql6yMr/ZLdoEgPW1lwbWXSytLsB1zpFKlRQHKknsp5oIQAYajQhfWZSriA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1561994201; 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=349cEXHiM10/yfMs2Tbw/4YGjeVXqqouOkUvPS8sTzM=; b=oWqCUqNENhrNk3f0IoKNF2cuBFGRGSG8/9SE8fd9H2qLniTAjX7TU0vYWZzZ7NlRChmzN1So7V9FBHmBLV8LKsi4yBRaHncCP+io2IoDOeJoCq0WG3YL7QDxrLGr/QLwsGjKrv3WIFaXj+mmg490APFeusLuhbWcgitFmlYJZFU= 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 (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1561994201675835.314984995832; Mon, 1 Jul 2019 08:16:41 -0700 (PDT) Received: from localhost ([::1]:59888 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhy2l-0004Sy-Gw for importer@patchew.org; Mon, 01 Jul 2019 11:16:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59525) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhxar-0000vD-Qc for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hhxap-000610-IN for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:45 -0400 Received: from mx1.redhat.com ([209.132.183.28]:34306) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hhxao-0005jq-Ke for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:43 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B132AC1EB207; Mon, 1 Jul 2019 14:47:22 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id E6865BA4D; Mon, 1 Jul 2019 14:47:16 +0000 (UTC) From: Sergio Lopez To: mst@redhat.com, marcel.apfelbaum@gmail.com, pbonzini@redhat.com, rth@twiddle.net, ehabkost@redhat.com, maran.wilson@oracle.com Date: Mon, 1 Jul 2019 16:47:02 +0200 Message-Id: <20190701144705.102615-2-slp@redhat.com> In-Reply-To: <20190701144705.102615-1-slp@redhat.com> References: <20190701144705.102615-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Mon, 01 Jul 2019 14:47:26 +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 Subject: [Qemu-devel] [PATCH v2 1/4] hw/virtio: Factorize virtio-mmio headers 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: qemu-devel@nongnu.org, Sergio Lopez 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 accesed from other components. This is needed for the microvm machine type implementation. Signed-off-by: Sergio Lopez --- hw/virtio/virtio-mmio.c | 35 +----------------------- hw/virtio/virtio-mmio.h | 60 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 hw/virtio/virtio-mmio.h diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 97b7f35496..87c7fe4d8d 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -26,44 +26,11 @@ #include "qemu/host-utils.h" #include "qemu/module.h" #include "sysemu/kvm.h" -#include "hw/virtio/virtio-bus.h" +#include "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/hw/virtio/virtio-mmio.h b/hw/virtio/virtio-mmio.h new file mode 100644 index 0000000000..2f3973f8c7 --- /dev/null +++ b/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 Fri May 10 06:14:25 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=1561992763; cv=none; d=zoho.com; s=zohoarc; b=gAvmUNG5k1u9/NWaQQ47WCQeFksB1s4PoHBwzuY6/I14geBhavD9w/AALffdp98f4iYN74zI0X1czpmfiZGoSqQmVLPGn3gybnAX1pcW2RE0ihIvQKH8eAa+B6FmMPhdEnDjMcVtHrnrf8md3KSgQTjDBcqKbFuEMEyogzFlXSs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1561992763; 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=JYTSa0GSETsR9y/W+28KdMIVGDsEzQJY+6vhNu+XE+Y=; b=QZE9GL/cWNuJ9OuVvS+KzCarQCB0KsceInI/hbZyxFqGXXYwuuN2sN51IrDJn5/LphalH0/hxW8eyaypWbPYGMyUoNxwhc8rTyh7t20xagIW/hJSMRUHm4h3bYUyxX09gV1zlANIHRRH0ks+e/smJt7ktTknLCdJUewZrLw5Q6g= 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 (209.51.188.17 [209.51.188.17]) by mx.zohomail.com with SMTPS id 1561992763166710.122515702995; Mon, 1 Jul 2019 07:52:43 -0700 (PDT) Received: from localhost ([::1]:59618 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhxfX-0004SJ-BW for importer@patchew.org; Mon, 01 Jul 2019 10:52:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59693) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhxb9-000131-48 for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:48:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hhxb3-0006Or-Cg for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:48:01 -0400 Received: from mx1.redhat.com ([209.132.183.28]:57397) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hhxb2-0005h3-N9 for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:57 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E90D93082E69; Mon, 1 Jul 2019 14:47:25 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id 13C0C7E5B9; Mon, 1 Jul 2019 14:47:22 +0000 (UTC) From: Sergio Lopez To: mst@redhat.com, marcel.apfelbaum@gmail.com, pbonzini@redhat.com, rth@twiddle.net, ehabkost@redhat.com, maran.wilson@oracle.com Date: Mon, 1 Jul 2019 16:47:03 +0200 Message-Id: <20190701144705.102615-3-slp@redhat.com> In-Reply-To: <20190701144705.102615-1-slp@redhat.com> References: <20190701144705.102615-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.46]); Mon, 01 Jul 2019 14:47:26 +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 Subject: [Qemu-devel] [PATCH v2 2/4] hw/i386: Add an Intel MPTable generator 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: qemu-devel@nongnu.org, Sergio Lopez Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Add a helper function (mptable_generate) for generating an Intel MPTable according to version 1.4 of the specification. This is needed for the microvm machine type implementation. Signed-off-by: Sergio Lopez --- hw/i386/mptable.c | 156 +++++++++++++++++ include/hw/i386/mptable.h | 36 ++++ include/standard-headers/linux/mpspec_def.h | 182 ++++++++++++++++++++ 3 files changed, 374 insertions(+) create mode 100644 hw/i386/mptable.c create mode 100644 include/hw/i386/mptable.h create mode 100644 include/standard-headers/linux/mpspec_def.h diff --git a/hw/i386/mptable.c b/hw/i386/mptable.c new file mode 100644 index 0000000000..cf1e0eef3a --- /dev/null +++ b/hw/i386/mptable.c @@ -0,0 +1,156 @@ +/* + * Intel MPTable generator + * + * Copyright (C) 2019 Red Hat, Inc. + * + * Authors: + * Sergio Lopez + * + * 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 "hw/i386/mptable.h" +#include "standard-headers/linux/mpspec_def.h" + +static int mptable_checksum(char *buf, int size) +{ + int i; + int checksum =3D 0; + + for (i =3D 0; i < size; i++) { + checksum +=3D buf[i]; + } + + return checksum; +} + +/* + * Generate an MPTable for "ncpus". "apic_id" must be the next available + * APIC ID (last CPU apic_id + 1). "table_base" is the physical location + * in the Guest where the caller intends to write the table, needed to + * fill the "physptr" field from the "mpf_intel" structure. + * + * On success, return a newly allocated buffer, that must be freed by the + * caller using "g_free" when it's no longer needed, and update + * "mptable_size" with the size of the buffer. + */ +char *mptable_generate(int ncpus, int table_base, int *mptable_size) +{ + struct mpf_intel *mpf; + struct mpc_table *table; + struct mpc_cpu *cpu; + struct mpc_bus *bus; + struct mpc_ioapic *ioapic; + struct mpc_intsrc *intsrc; + struct mpc_lintsrc *lintsrc; + const char mpc_signature[] =3D MPC_SIGNATURE; + const char smp_magic_ident[] =3D "_MP_"; + char *mptable; + int checksum =3D 0; + int offset =3D 0; + int ssize; + int i; + + ssize =3D sizeof(struct mpf_intel); + mptable =3D g_malloc0(ssize); + + mpf =3D (struct mpf_intel *) mptable; + memcpy(mpf->signature, smp_magic_ident, sizeof(smp_magic_ident) - 1); + mpf->length =3D 1; + mpf->specification =3D 4; + mpf->physptr =3D table_base + ssize; + mpf->checksum -=3D mptable_checksum((char *) mpf, ssize); + offset =3D ssize + sizeof(struct mpc_table); + + ssize =3D sizeof(struct mpc_cpu); + for (i =3D 0; i < ncpus; i++) { + mptable =3D g_realloc(mptable, offset + ssize); + cpu =3D (struct mpc_cpu *) (mptable + offset); + cpu->type =3D MP_PROCESSOR; + cpu->apicid =3D i; + cpu->apicver =3D APIC_VERSION; + cpu->cpuflag =3D CPU_ENABLED; + if (i =3D=3D 0) { + cpu->cpuflag |=3D CPU_BOOTPROCESSOR; + } + cpu->cpufeature =3D CPU_STEPPING; + cpu->featureflag =3D CPU_FEATURE_APIC | CPU_FEATURE_FPU; + checksum +=3D mptable_checksum((char *) cpu, ssize); + offset +=3D ssize; + } + + ssize =3D sizeof(struct mpc_bus); + mptable =3D g_realloc(mptable, offset + ssize); + bus =3D (struct mpc_bus *) (mptable + offset); + bus->type =3D MP_BUS; + bus->busid =3D 0; + memcpy(bus->bustype, BUS_TYPE_ISA, sizeof(BUS_TYPE_ISA) - 1); + checksum +=3D mptable_checksum((char *) bus, ssize); + offset +=3D ssize; + + ssize =3D sizeof(struct mpc_ioapic); + mptable =3D g_realloc(mptable, offset + ssize); + ioapic =3D (struct mpc_ioapic *) (mptable + offset); + ioapic->type =3D MP_IOAPIC; + ioapic->apicid =3D ncpus + 1; + ioapic->apicver =3D APIC_VERSION; + ioapic->flags =3D MPC_APIC_USABLE; + ioapic->apicaddr =3D IO_APIC_DEFAULT_PHYS_BASE; + checksum +=3D mptable_checksum((char *) ioapic, ssize); + offset +=3D ssize; + + ssize =3D sizeof(struct mpc_intsrc); + for (i =3D 0; i < 16; i++) { + mptable =3D g_realloc(mptable, offset + ssize); + intsrc =3D (struct mpc_intsrc *) (mptable + offset); + intsrc->type =3D MP_INTSRC; + intsrc->irqtype =3D mp_INT; + intsrc->irqflag =3D MP_IRQDIR_DEFAULT; + intsrc->srcbus =3D 0; + intsrc->srcbusirq =3D i; + intsrc->dstapic =3D ncpus + 1; + intsrc->dstirq =3D i; + checksum +=3D mptable_checksum((char *) intsrc, ssize); + offset +=3D ssize; + } + + ssize =3D sizeof(struct mpc_lintsrc); + mptable =3D g_realloc(mptable, offset + (ssize * 2)); + lintsrc =3D (struct mpc_lintsrc *) (mptable + offset); + lintsrc->type =3D MP_LINTSRC; + lintsrc->irqtype =3D mp_ExtINT; + lintsrc->irqflag =3D MP_IRQDIR_DEFAULT; + lintsrc->srcbusid =3D 0; + lintsrc->srcbusirq =3D 0; + lintsrc->destapic =3D 0; + lintsrc->destapiclint =3D 0; + checksum +=3D mptable_checksum((char *) lintsrc, ssize); + offset +=3D ssize; + + lintsrc =3D (struct mpc_lintsrc *) (mptable + offset); + lintsrc->type =3D MP_LINTSRC; + lintsrc->irqtype =3D mp_NMI; + lintsrc->irqflag =3D MP_IRQDIR_DEFAULT; + lintsrc->srcbusid =3D 0; + lintsrc->srcbusirq =3D 0; + lintsrc->destapic =3D 0xFF; + lintsrc->destapiclint =3D 1; + checksum +=3D mptable_checksum((char *) lintsrc, ssize); + offset +=3D ssize; + + ssize =3D sizeof(struct mpc_table); + table =3D (struct mpc_table *) (mptable + sizeof(struct mpf_intel)); + memcpy(table->signature, mpc_signature, sizeof(mpc_signature) - 1); + table->length =3D offset - sizeof(struct mpf_intel); + table->spec =3D MPC_SPEC; + memcpy(table->oem, MPC_OEM, sizeof(MPC_OEM) - 1); + memcpy(table->productid, MPC_PRODUCT_ID, sizeof(MPC_PRODUCT_ID) - 1); + table->lapic =3D APIC_DEFAULT_PHYS_BASE; + checksum +=3D mptable_checksum((char *) table, ssize); + table->checksum -=3D checksum; + + *mptable_size =3D offset; + return mptable; +} diff --git a/include/hw/i386/mptable.h b/include/hw/i386/mptable.h new file mode 100644 index 0000000000..96a9778bba --- /dev/null +++ b/include/hw/i386/mptable.h @@ -0,0 +1,36 @@ +/* + * Intel MPTable generator + * + * Copyright (C) 2019 Red Hat, Inc. + * + * Authors: + * Sergio Lopez + * + * 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. + */ + +#ifndef HW_I386_MPTABLE_H +#define HW_I386_MPTABLE_H + +#define APIC_VERSION 0x14 +#define CPU_STEPPING 0x600 +#define CPU_FEATURE_APIC 0x200 +#define CPU_FEATURE_FPU 0x001 +#define MPC_SPEC 0x4 + +#define MP_IRQDIR_DEFAULT 0 +#define MP_IRQDIR_HIGH 1 +#define MP_IRQDIR_LOW 3 + +static const char MPC_OEM[] =3D "QEMU "; +static const char MPC_PRODUCT_ID[] =3D "000000000000"; +static const char BUS_TYPE_ISA[] =3D "ISA "; + +#define IO_APIC_DEFAULT_PHYS_BASE 0xfec00000 +#define APIC_DEFAULT_PHYS_BASE 0xfee00000 +#define APIC_VERSION 0x14 + +char *mptable_generate(int ncpus, int table_base, int *mptable_size); + +#endif diff --git a/include/standard-headers/linux/mpspec_def.h b/include/standard= -headers/linux/mpspec_def.h new file mode 100644 index 0000000000..6fb923a343 --- /dev/null +++ b/include/standard-headers/linux/mpspec_def.h @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_MPSPEC_DEF_H +#define _ASM_X86_MPSPEC_DEF_H + +/* + * Structure definitions for SMP machines following the + * Intel Multiprocessing Specification 1.1 and 1.4. + */ + +/* + * This tag identifies where the SMP configuration + * information is. + */ + +#define SMP_MAGIC_IDENT (('_'<<24) | ('P'<<16) | ('M'<<8) | '_') + +#ifdef CONFIG_X86_32 +# define MAX_MPC_ENTRY 1024 +#endif + +/* Intel MP Floating Pointer Structure */ +struct mpf_intel { + char signature[4]; /* "_MP_" */ + unsigned int physptr; /* Configuration table address */ + unsigned char length; /* Our length (paragraphs) */ + unsigned char specification; /* Specification version */ + unsigned char checksum; /* Checksum (makes sum 0) */ + unsigned char feature1; /* Standard or configuration ? */ + unsigned char feature2; /* Bit7 set for IMCR|PIC */ + unsigned char feature3; /* Unused (0) */ + unsigned char feature4; /* Unused (0) */ + unsigned char feature5; /* Unused (0) */ +}; + +#define MPC_SIGNATURE "PCMP" + +struct mpc_table { + char signature[4]; + unsigned short length; /* Size of table */ + char spec; /* 0x01 */ + char checksum; + char oem[8]; + char productid[12]; + unsigned int oemptr; /* 0 if not present */ + unsigned short oemsize; /* 0 if not present */ + unsigned short oemcount; + unsigned int lapic; /* APIC address */ + unsigned int reserved; +}; + +/* Followed by entries */ + +#define MP_PROCESSOR 0 +#define MP_BUS 1 +#define MP_IOAPIC 2 +#define MP_INTSRC 3 +#define MP_LINTSRC 4 +/* Used by IBM NUMA-Q to describe node locality */ +#define MP_TRANSLATION 192 + +#define CPU_ENABLED 1 /* Processor is available */ +#define CPU_BOOTPROCESSOR 2 /* Processor is the boot CPU */ + +#define CPU_STEPPING_MASK 0x000F +#define CPU_MODEL_MASK 0x00F0 +#define CPU_FAMILY_MASK 0x0F00 + +struct mpc_cpu { + unsigned char type; + unsigned char apicid; /* Local APIC number */ + unsigned char apicver; /* Its versions */ + unsigned char cpuflag; + unsigned int cpufeature; + unsigned int featureflag; /* CPUID feature value */ + unsigned int reserved[2]; +}; + +struct mpc_bus { + unsigned char type; + unsigned char busid; + unsigned char bustype[6]; +}; + +/* List of Bus Type string values, Intel MP Spec. */ +#define BUSTYPE_EISA "EISA" +#define BUSTYPE_ISA "ISA" +#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ +#define BUSTYPE_MCA "MCA" /* Obsolete */ +#define BUSTYPE_VL "VL" /* Local bus */ +#define BUSTYPE_PCI "PCI" +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_CBUS "CBUS" +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_MBI "MBI" +#define BUSTYPE_MBII "MBII" +#define BUSTYPE_MPI "MPI" +#define BUSTYPE_MPSA "MPSA" +#define BUSTYPE_NUBUS "NUBUS" +#define BUSTYPE_TC "TC" +#define BUSTYPE_VME "VME" +#define BUSTYPE_XPRESS "XPRESS" + +#define MPC_APIC_USABLE 0x01 + +struct mpc_ioapic { + unsigned char type; + unsigned char apicid; + unsigned char apicver; + unsigned char flags; + unsigned int apicaddr; +}; + +struct mpc_intsrc { + unsigned char type; + unsigned char irqtype; + unsigned short irqflag; + unsigned char srcbus; + unsigned char srcbusirq; + unsigned char dstapic; + unsigned char dstirq; +}; + +enum mp_irq_source_types { + mp_INT =3D 0, + mp_NMI =3D 1, + mp_SMI =3D 2, + mp_ExtINT =3D 3 +}; + +#define MP_IRQPOL_DEFAULT 0x0 +#define MP_IRQPOL_ACTIVE_HIGH 0x1 +#define MP_IRQPOL_RESERVED 0x2 +#define MP_IRQPOL_ACTIVE_LOW 0x3 +#define MP_IRQPOL_MASK 0x3 + +#define MP_IRQTRIG_DEFAULT 0x0 +#define MP_IRQTRIG_EDGE 0x4 +#define MP_IRQTRIG_RESERVED 0x8 +#define MP_IRQTRIG_LEVEL 0xc +#define MP_IRQTRIG_MASK 0xc + +#define MP_APIC_ALL 0xFF + +struct mpc_lintsrc { + unsigned char type; + unsigned char irqtype; + unsigned short irqflag; + unsigned char srcbusid; + unsigned char srcbusirq; + unsigned char destapic; + unsigned char destapiclint; +}; + +#define MPC_OEM_SIGNATURE "_OEM" + +struct mpc_oemtable { + char signature[4]; + unsigned short length; /* Size of table */ + char rev; /* 0x01 */ + char checksum; + char mpc[8]; +}; + +/* + * Default configurations + * + * 1 2 CPU ISA 82489DX + * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining + * 3 2 CPU EISA 82489DX + * 4 2 CPU MCA 82489DX + * 5 2 CPU ISA+PCI + * 6 2 CPU EISA+PCI + * 7 2 CPU MCA+PCI + */ + +enum mp_bustype { + MP_BUS_ISA =3D 1, + MP_BUS_EISA, + MP_BUS_PCI, +}; +#endif /* _ASM_X86_MPSPEC_DEF_H */ --=20 2.21.0 From nobody Fri May 10 06:14:25 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=1561993438; cv=none; d=zoho.com; s=zohoarc; b=G0Jsdw4hKonHil0NxOhNmz2htw2enyPg9kNSobFvaOALP34k6ix3uDVhqZu5taX9kJSaYVPd5KL4fdFMyaCZxBuyTdwul4iZhfIoB2tzylRwSAHPfkJ6SKsuKRXhMJDaMNA+dQmHDVIjMl2tWLlDp3oDo5hjXN9hBHczYOZcNI4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1561993438; 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=Nx/prUpw6NRdoYd4k3298P0WW4zz1KUeFylqbwemIhA=; b=jNAV165CxalzayxDElep1hwBzCYKdBlFTts1v7gpy7Fg1lNk756qUccBNZRA/yAK+rwQ5cSST6NwDeA0QxtXt+7H265nZ3VEWS305wdY8ehMvikeJlDV4AQwGhu48mOEdDh6+ZKHhyvAx2Jzlzu0CC6O+G1n4S/Kkbw/CLVSR50= 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 1561993438667405.9617229321643; Mon, 1 Jul 2019 08:03:58 -0700 (PDT) Received: from localhost ([::1]:59764 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhxqX-0003kf-JY for importer@patchew.org; Mon, 01 Jul 2019 11:03:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59576) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhxat-0000y9-TE for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hhxar-00063t-SD for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:27338) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hhxap-0005t0-LH for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:45 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id E6F3F308621F; Mon, 1 Jul 2019 14:47:37 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id 726CB7DF69; Mon, 1 Jul 2019 14:47:26 +0000 (UTC) From: Sergio Lopez To: mst@redhat.com, marcel.apfelbaum@gmail.com, pbonzini@redhat.com, rth@twiddle.net, ehabkost@redhat.com, maran.wilson@oracle.com Date: Mon, 1 Jul 2019 16:47:04 +0200 Message-Id: <20190701144705.102615-4-slp@redhat.com> In-Reply-To: <20190701144705.102615-1-slp@redhat.com> References: <20190701144705.102615-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Mon, 01 Jul 2019 14:47:38 +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 Subject: [Qemu-devel] [PATCH v2 3/4] hw/i386: Factorize PVH related functions 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: qemu-devel@nongnu.org, Sergio Lopez 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 3983621f1c..325ec2c1c8 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -42,6 +42,7 @@ #include "hw/loader.h" #include "elf.h" #include "multiboot.h" +#include "pvh.h" #include "hw/timer/mc146818rtc.h" #include "hw/dma/i8257.h" #include "hw/timer/i8254.h" @@ -108,9 +109,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_0[] =3D {}; const size_t pc_compat_4_0_len =3D G_N_ELEMENTS(pc_compat_4_0); =20 @@ -1061,109 +1059,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) { @@ -1203,6 +1098,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. @@ -1220,10 +1118,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..61623b4533 --- /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 =3D 0; + +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 Fri May 10 06:14:25 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=1561994326; cv=none; d=zoho.com; s=zohoarc; b=fac+M4+or0Z79TaB7IhHZ0keZ7DyBwEtaWpMdGGlvhpJDUOLgdnfvKjoL5RrZSJhkWQfarolKef2Yu7LSBj+skA/4sQOg/+uhyYqXVoiWuf9MEQDlys3hyfcI4tZuq+89T0FHVhCqzv1y5DKGkC5uFxeHFXTN9PtN+qB8sC0oFM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1561994326; 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=mw+xObIMGFy7zdUpyKYuagUy7trvebrb6ZKfXdHd2f4=; b=LDmOjm2pCykR9MX9Vp0LEXpkS1kbsr16n6hog7uRygkR9J4/CzH2kWXOfO8uQruVhBpjxZ/dM4+vh1ETz2ix+3u8lA7MIB2LMGAXk4+zBVXb0rPTzqzIsMo0jbHX6B1REvjS6ZzXJp36gFqER0EHrrE9E6x7fU2FHA3C040Vio0= 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 1561994326121359.7759743796663; Mon, 1 Jul 2019 08:18:46 -0700 (PDT) Received: from localhost ([::1]:59900 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhy4k-0005tj-6R for importer@patchew.org; Mon, 01 Jul 2019 11:18:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:59655) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hhxb0-000122-4g for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:48:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hhxaw-0006CJ-0q for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:53 -0400 Received: from mx1.redhat.com ([209.132.183.28]:47714) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hhxat-00064S-PR for qemu-devel@nongnu.org; Mon, 01 Jul 2019 10:47:49 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CA76B316291C; Mon, 1 Jul 2019 14:47:45 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.165]) by smtp.corp.redhat.com (Postfix) with ESMTP id DCECFBA4D; Mon, 1 Jul 2019 14:47:38 +0000 (UTC) From: Sergio Lopez To: mst@redhat.com, marcel.apfelbaum@gmail.com, pbonzini@redhat.com, rth@twiddle.net, ehabkost@redhat.com, maran.wilson@oracle.com Date: Mon, 1 Jul 2019 16:47:05 +0200 Message-Id: <20190701144705.102615-5-slp@redhat.com> In-Reply-To: <20190701144705.102615-1-slp@redhat.com> References: <20190701144705.102615-1-slp@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.41]); Mon, 01 Jul 2019 14:47:45 +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 Subject: [Qemu-devel] [PATCH v2 4/4] hw/i386: Introduce the microvm machine type 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: qemu-devel@nongnu.org, Sergio Lopez 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 KVM-only machine type with fast boot times, minimal attack surface (measured as the number of IO ports and MMIO regions exposed to the Guest) and small footprint (specially when combined with the ongoing QEMU modularization effort). Normally, other than the device support provided by KVM itself, microvm only supports virtio-mmio devices. Microvm also includes a legacy mode, which adds an ISA bus with a 16550A serial port, useful for being able to see the early boot kernel messages. Microvm only supports booting PVH-enabled Linux ELF images. Booting other PVH-enabled kernels may be possible, but due to the lack of ACPI and firmware, we're relying on the command line for specifying the location of the virtio-mmio transports. If there's an interest on using this machine type with other kernels, we'll try to find some kind of middle ground solution. Signed-off-by: Sergio Lopez --- default-configs/i386-softmmu.mak | 1 + hw/i386/Kconfig | 4 + hw/i386/Makefile.objs | 1 + hw/i386/microvm.c | 500 +++++++++++++++++++++++++++++++ include/hw/i386/microvm.h | 77 +++++ 5 files changed, 583 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..338f07420f 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 diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index 9817888216..94c565d8db 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -87,6 +87,10 @@ config Q35 select VMMOUSE 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 c5f20bbd72..7bffca413e 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -4,6 +4,7 @@ obj-y +=3D pvh.o obj-y +=3D pc.o obj-$(CONFIG_I440FX) +=3D pc_piix.o obj-$(CONFIG_Q35) +=3D pc_q35.o +obj-$(CONFIG_MICROVM) +=3D mptable.o 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..8b5efe9e45 --- /dev/null +++ b/hw/i386/microvm.c @@ -0,0 +1,500 @@ +/* + * 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 "qapi/error.h" +#include "qapi/visitor.h" +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "sysemu/numa.h" + +#include "hw/loader.h" +#include "hw/nmi.h" +#include "hw/kvm/clock.h" +#include "hw/i386/microvm.h" +#include "hw/i386/pc.h" +#include "target/i386/cpu.h" +#include "hw/timer/i8254.h" +#include "hw/char/serial.h" +#include "hw/i386/topology.h" +#include "hw/virtio/virtio-mmio.h" +#include "hw/i386/mptable.h" + +#include "cpu.h" +#include "elf.h" +#include "pvh.h" +#include "kvm_i386.h" +#include "hw/xen/start_info.h" + +static void microvm_gsi_handler(void *opaque, int n, int level) +{ + qemu_irq *ioapic_irq =3D opaque; + + qemu_set_irq(ioapic_irq[n], level); +} + +static void microvm_legacy_init(MicrovmMachineState *mms) +{ + ISABus *isa_bus; + GSIState *gsi_state; + qemu_irq *i8259; + int i; + + assert(kvm_irqchip_in_kernel()); + gsi_state =3D g_malloc0(sizeof(*gsi_state)); + mms->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, mms->gsi); + + assert(kvm_pic_in_kernel()); + i8259 =3D kvm_i8259_init(isa_bus); + + for (i =3D 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] =3D i8259[i]; + } + + kvm_pit_init(isa_bus, 0x40); + + 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, + mms->gsi[VIRTIO_IRQ_BASE + i]); + } + + g_free(i8259); + + serial_hds_isa_init(isa_bus, 0, 1); +} + +static void microvm_ioapic_init(MicrovmMachineState *mms) +{ + qemu_irq *ioapic_irq; + DeviceState *ioapic_dev; + SysBusDevice *d; + int i; + + assert(kvm_irqchip_in_kernel()); + ioapic_irq =3D g_new0(qemu_irq, IOAPIC_NUM_PINS); + kvm_pc_setup_irq_routing(true); + + assert(kvm_ioapic_in_kernel()); + ioapic_dev =3D qdev_create(NULL, "kvm-ioapic"); + + object_property_add_child(qdev_get_machine(), + "ioapic", OBJECT(ioapic_dev), NULL); + + qdev_init_nofail(ioapic_dev); + d =3D SYS_BUS_DEVICE(ioapic_dev); + sysbus_mmio_map(d, 0, IO_APIC_DEFAULT_ADDRESS); + + for (i =3D 0; i < IOAPIC_NUM_PINS; i++) { + ioapic_irq[i] =3D qdev_get_gpio_in(ioapic_dev, i); + } + + mms->gsi =3D qemu_allocate_irqs(microvm_gsi_handler, + ioapic_irq, IOAPIC_NUM_PINS); + + for (i =3D 0; i < VIRTIO_NUM_TRANSPORTS; i++) { + sysbus_create_simple("virtio-mmio", + VIRTIO_MMIO_BASE + i * 512, + mms->gsi[VIRTIO_IRQ_BASE + i]); + } +} + +static void microvm_memory_init(MicrovmMachineState *mms) +{ + MachineState *machine =3D MACHINE(mms); + MemoryRegion *ram, *ram_below_4g, *ram_above_4g; + MemoryRegion *system_memory =3D get_system_memory(); + + if (machine->ram_size > MICROVM_MAX_BELOW_4G) { + mms->above_4g_mem_size =3D machine->ram_size - MICROVM_MAX_BELOW_4= G; + mms->below_4g_mem_size =3D MICROVM_MAX_BELOW_4G; + } else { + mms->above_4g_mem_size =3D 0; + mms->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, mms->below_4g_mem_size); + memory_region_add_subregion(system_memory, 0, ram_below_4g); + + e820_add_entry(0, mms->below_4g_mem_size, E820_RAM); + + if (mms->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, + mms->below_4g_mem_size, + mms->above_4g_mem_size); + memory_region_add_subregion(system_memory, 0x100000000ULL, + ram_above_4g); + e820_add_entry(0x100000000ULL, mms->above_4g_mem_size, E820_RAM); + } +} + +static void microvm_cpus_init(const char *typename, Error **errp) +{ + int i; + + for (i =3D 0; i < smp_cpus; i++) { + Object *cpu =3D NULL; + Error *local_err =3D NULL; + + cpu =3D object_new(typename); + + object_property_set_uint(cpu, i, "apic-id", &local_err); + object_property_set_bool(cpu, true, "realized", &local_err); + + object_unref(cpu); + error_propagate(errp, local_err); + } +} + +static void microvm_machine_state_init(MachineState *machine) +{ + MicrovmMachineState *mms =3D MICROVM_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); + + microvm_cpus_init(machine->cpu_type, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + + if (mms->legacy) { + microvm_legacy_init(mms); + } else { + microvm_ioapic_init(mms); + } + + kvmclock_create(); + + if (!pvh_load_elfboot(machine->kernel_filename, NULL, NULL)) { + error_report("Error while loading elf kernel"); + exit(1); + } + + mms->elf_entry =3D pvh_get_start_addr(); +} + +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_setup_pvh(MicrovmMachineState *mms, + const gchar *kernel_cmdline) +{ + struct hvm_memmap_table_entry *memmap_table; + struct hvm_start_info *start_info; + BusState *bus; + BusChild *kid; + gchar *cmdline; + int cmdline_len; + int memmap_entries; + int i; + + cmdline =3D g_strdup(kernel_cmdline); + + /* + * Find MMIO transports with attached devices, and add them to the ker= nel + * command line. + */ + 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; + } + } + } + } + + cmdline_len =3D strlen(cmdline); + + address_space_write(&address_space_memory, + KERNEL_CMDLINE_START, MEMTXATTRS_UNSPECIFIED, + (uint8_t *) cmdline, cmdline_len); + + g_free(cmdline); + + memmap_entries =3D e820_get_num_entries(); + memmap_table =3D g_new0(struct hvm_memmap_table_entry, memmap_entries); + for (i =3D 0; i < memmap_entries; i++) { + uint64_t address, length; + struct hvm_memmap_table_entry *entry =3D &memmap_table[i]; + + if (e820_get_entry(i, E820_RAM, &address, &length)) { + entry->addr =3D address; + entry->size =3D length; + entry->type =3D E820_RAM; + entry->reserved =3D 0; + } + } + + address_space_write(&address_space_memory, + MEMMAP_START, MEMTXATTRS_UNSPECIFIED, + (uint8_t *) memmap_table, + memmap_entries * sizeof(struct hvm_memmap_table_en= try)); + + g_free(memmap_table); + + start_info =3D g_malloc0(sizeof(struct hvm_start_info)); + + start_info->magic =3D XEN_HVM_START_MAGIC_VALUE; + start_info->version =3D 1; + start_info->nr_modules =3D 0; + start_info->cmdline_paddr =3D KERNEL_CMDLINE_START; + start_info->memmap_entries =3D memmap_entries; + start_info->memmap_paddr =3D MEMMAP_START; + + address_space_write(&address_space_memory, + PVH_START_INFO, MEMTXATTRS_UNSPECIFIED, + (uint8_t *) start_info, + sizeof(struct hvm_start_info)); + + g_free(start_info); +} + +static void microvm_init_page_tables(void) +{ + uint64_t val =3D 0; + int i; + + val =3D PDPTE_START | 0x03; + address_space_write(&address_space_memory, + PML4_START, MEMTXATTRS_UNSPECIFIED, + (uint8_t *) &val, 8); + val =3D PDE_START | 0x03; + address_space_write(&address_space_memory, + PDPTE_START, MEMTXATTRS_UNSPECIFIED, + (uint8_t *) &val, 8); + + for (i =3D 0; i < 512; i++) { + val =3D (i << 21) + 0x83; + address_space_write(&address_space_memory, + PDE_START + (i * 8), MEMTXATTRS_UNSPECIFIED, + (uint8_t *) &val, 8); + } +} + +static void microvm_cpu_reset(CPUState *cs, uint64_t elf_entry) +{ + X86CPU *cpu =3D X86_CPU(cs); + CPUX86State *env =3D &cpu->env; + struct SegmentCache seg_code =3D { .selector =3D 0x8, + .base =3D 0x0, + .limit =3D 0xffffffff, + .flags =3D 0xc09b00 }; + struct SegmentCache seg_data =3D { .selector =3D 0x10, + .base =3D 0x0, + .limit =3D 0xffffffff, + .flags =3D 0xc09300 }; + struct SegmentCache seg_tr =3D { .selector =3D 0x18, + .base =3D 0x0, + .limit =3D 0xffff, + .flags =3D 0x8b00 }; + + memcpy(&env->segs[R_CS], &seg_code, sizeof(struct SegmentCache)); + memcpy(&env->segs[R_DS], &seg_data, sizeof(struct SegmentCache)); + memcpy(&env->segs[R_ES], &seg_data, sizeof(struct SegmentCache)); + memcpy(&env->segs[R_FS], &seg_data, sizeof(struct SegmentCache)); + memcpy(&env->segs[R_GS], &seg_data, sizeof(struct SegmentCache)); + memcpy(&env->segs[R_SS], &seg_data, sizeof(struct SegmentCache)); + memcpy(&env->tr, &seg_tr, sizeof(struct SegmentCache)); + + env->regs[R_EBX] =3D PVH_START_INFO; + + cpu_set_pc(cs, elf_entry); + cpu_x86_update_cr3(env, 0); + cpu_x86_update_cr4(env, 0); + cpu_x86_update_cr0(env, CR0_PE_MASK); + + x86_update_hflags(env); +} + +static void microvm_mptable_setup(MicrovmMachineState *mms) +{ + char *mptable; + int size; + + mptable =3D mptable_generate(smp_cpus, EBDA_START, &size); + address_space_write(&address_space_memory, + EBDA_START, MEMTXATTRS_UNSPECIFIED, + (uint8_t *) mptable, size); + g_free(mptable); +} + +static bool microvm_machine_get_legacy(Object *obj, Error **errp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + return mms->legacy; +} + +static void microvm_machine_set_legacy(Object *obj, bool value, Error **er= rp) +{ + MicrovmMachineState *mms =3D MICROVM_MACHINE(obj); + + mms->legacy =3D value; +} + +static void microvm_machine_reset(void) +{ + MachineState *machine =3D MACHINE(qdev_get_machine()); + MicrovmMachineState *mms =3D MICROVM_MACHINE(machine); + CPUState *cs; + X86CPU *cpu; + + qemu_devices_reset(); + + microvm_mptable_setup(mms); + microvm_setup_pvh(mms, machine->kernel_cmdline); + microvm_init_page_tables(); + + CPU_FOREACH(cs) { + cpu =3D X86_CPU(cs); + + if (cpu->apic_state) { + device_reset(cpu->apic_state); + } + + microvm_cpu_reset(cs, mms->elf_entry); + } +} + +static void x86_nmi(NMIState *n, int cpu_index, Error **errp) +{ + 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 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 X86_CPU_TYPE_NAME("host"); + mc->nvdimm_supported =3D false; + mc->default_machine_opts =3D "accel=3Dkvm"; + + /* 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_LEGACY, + microvm_machine_get_legacy, + microvm_machine_set_legacy, + &error_abort); +} + +static const TypeInfo microvm_machine_info =3D { + .name =3D TYPE_MICROVM_MACHINE, + .parent =3D TYPE_MACHINE, + .instance_size =3D sizeof(MicrovmMachineState), + .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..72c89db669 --- /dev/null +++ b/include/hw/i386/microvm.h @@ -0,0 +1,77 @@ +/* + * 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" + +/* Microvm memory layout */ +#define PVH_START_INFO 0x6000 +#define MEMMAP_START 0x7000 +#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 +#define MICROVM_MAX_BELOW_4G 0xe0000000 + +/* Platform virtio definitions */ +#define VIRTIO_MMIO_BASE 0xd0000000 +#define VIRTIO_IRQ_BASE 5 +#define VIRTIO_NUM_TRANSPORTS 8 +#define VIRTIO_CMDLINE_MAXLEN 64 + +/* Machine type options */ +#define MICROVM_MACHINE_LEGACY "legacy" + +typedef struct { + MachineClass parent; + HotplugHandler *(*orig_hotplug_handler)(MachineState *machine, + DeviceState *dev); +} MicrovmMachineClass; + +typedef struct { + MachineState parent; + qemu_irq *gsi; + + /* RAM size */ + ram_addr_t below_4g_mem_size; + ram_addr_t above_4g_mem_size; + + /* Kernel ELF entry. On reset, vCPUs RIP will be set to this */ + uint64_t elf_entry; + + /* Legacy mode based on an ISA bus. Useful for debugging */ + bool legacy; +} 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