From: Sergio Lopez <slp@redhat.com>
To: mst@redhat.com, marcel.apfelbaum@gmail.com, pbonzini@redhat.com,
rth@twiddle.net, ehabkost@redhat.com, maran.wilson@oracle.com
Cc: qemu-devel@nongnu.org, Sergio Lopez <slp@redhat.com>
Subject: [Qemu-devel] [PATCH v2 2/4] hw/i386: Add an Intel MPTable generator
Date: Mon, 1 Jul 2019 16:47:03 +0200 [thread overview]
Message-ID: <20190701144705.102615-3-slp@redhat.com> (raw)
In-Reply-To: <20190701144705.102615-1-slp@redhat.com>
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 <slp@redhat.com>
---
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 <slp@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * 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 = 0;
+
+ for (i = 0; i < size; i++) {
+ checksum += 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[] = MPC_SIGNATURE;
+ const char smp_magic_ident[] = "_MP_";
+ char *mptable;
+ int checksum = 0;
+ int offset = 0;
+ int ssize;
+ int i;
+
+ ssize = sizeof(struct mpf_intel);
+ mptable = g_malloc0(ssize);
+
+ mpf = (struct mpf_intel *) mptable;
+ memcpy(mpf->signature, smp_magic_ident, sizeof(smp_magic_ident) - 1);
+ mpf->length = 1;
+ mpf->specification = 4;
+ mpf->physptr = table_base + ssize;
+ mpf->checksum -= mptable_checksum((char *) mpf, ssize);
+ offset = ssize + sizeof(struct mpc_table);
+
+ ssize = sizeof(struct mpc_cpu);
+ for (i = 0; i < ncpus; i++) {
+ mptable = g_realloc(mptable, offset + ssize);
+ cpu = (struct mpc_cpu *) (mptable + offset);
+ cpu->type = MP_PROCESSOR;
+ cpu->apicid = i;
+ cpu->apicver = APIC_VERSION;
+ cpu->cpuflag = CPU_ENABLED;
+ if (i == 0) {
+ cpu->cpuflag |= CPU_BOOTPROCESSOR;
+ }
+ cpu->cpufeature = CPU_STEPPING;
+ cpu->featureflag = CPU_FEATURE_APIC | CPU_FEATURE_FPU;
+ checksum += mptable_checksum((char *) cpu, ssize);
+ offset += ssize;
+ }
+
+ ssize = sizeof(struct mpc_bus);
+ mptable = g_realloc(mptable, offset + ssize);
+ bus = (struct mpc_bus *) (mptable + offset);
+ bus->type = MP_BUS;
+ bus->busid = 0;
+ memcpy(bus->bustype, BUS_TYPE_ISA, sizeof(BUS_TYPE_ISA) - 1);
+ checksum += mptable_checksum((char *) bus, ssize);
+ offset += ssize;
+
+ ssize = sizeof(struct mpc_ioapic);
+ mptable = g_realloc(mptable, offset + ssize);
+ ioapic = (struct mpc_ioapic *) (mptable + offset);
+ ioapic->type = MP_IOAPIC;
+ ioapic->apicid = ncpus + 1;
+ ioapic->apicver = APIC_VERSION;
+ ioapic->flags = MPC_APIC_USABLE;
+ ioapic->apicaddr = IO_APIC_DEFAULT_PHYS_BASE;
+ checksum += mptable_checksum((char *) ioapic, ssize);
+ offset += ssize;
+
+ ssize = sizeof(struct mpc_intsrc);
+ for (i = 0; i < 16; i++) {
+ mptable = g_realloc(mptable, offset + ssize);
+ intsrc = (struct mpc_intsrc *) (mptable + offset);
+ intsrc->type = MP_INTSRC;
+ intsrc->irqtype = mp_INT;
+ intsrc->irqflag = MP_IRQDIR_DEFAULT;
+ intsrc->srcbus = 0;
+ intsrc->srcbusirq = i;
+ intsrc->dstapic = ncpus + 1;
+ intsrc->dstirq = i;
+ checksum += mptable_checksum((char *) intsrc, ssize);
+ offset += ssize;
+ }
+
+ ssize = sizeof(struct mpc_lintsrc);
+ mptable = g_realloc(mptable, offset + (ssize * 2));
+ lintsrc = (struct mpc_lintsrc *) (mptable + offset);
+ lintsrc->type = MP_LINTSRC;
+ lintsrc->irqtype = mp_ExtINT;
+ lintsrc->irqflag = MP_IRQDIR_DEFAULT;
+ lintsrc->srcbusid = 0;
+ lintsrc->srcbusirq = 0;
+ lintsrc->destapic = 0;
+ lintsrc->destapiclint = 0;
+ checksum += mptable_checksum((char *) lintsrc, ssize);
+ offset += ssize;
+
+ lintsrc = (struct mpc_lintsrc *) (mptable + offset);
+ lintsrc->type = MP_LINTSRC;
+ lintsrc->irqtype = mp_NMI;
+ lintsrc->irqflag = MP_IRQDIR_DEFAULT;
+ lintsrc->srcbusid = 0;
+ lintsrc->srcbusirq = 0;
+ lintsrc->destapic = 0xFF;
+ lintsrc->destapiclint = 1;
+ checksum += mptable_checksum((char *) lintsrc, ssize);
+ offset += ssize;
+
+ ssize = sizeof(struct mpc_table);
+ table = (struct mpc_table *) (mptable + sizeof(struct mpf_intel));
+ memcpy(table->signature, mpc_signature, sizeof(mpc_signature) - 1);
+ table->length = offset - sizeof(struct mpf_intel);
+ table->spec = MPC_SPEC;
+ memcpy(table->oem, MPC_OEM, sizeof(MPC_OEM) - 1);
+ memcpy(table->productid, MPC_PRODUCT_ID, sizeof(MPC_PRODUCT_ID) - 1);
+ table->lapic = APIC_DEFAULT_PHYS_BASE;
+ checksum += mptable_checksum((char *) table, ssize);
+ table->checksum -= checksum;
+
+ *mptable_size = 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 <slp@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * 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[] = "QEMU ";
+static const char MPC_PRODUCT_ID[] = "000000000000";
+static const char BUS_TYPE_ISA[] = "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 = 0,
+ mp_NMI = 1,
+ mp_SMI = 2,
+ mp_ExtINT = 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 = 1,
+ MP_BUS_EISA,
+ MP_BUS_PCI,
+};
+#endif /* _ASM_X86_MPSPEC_DEF_H */
--
2.21.0
next prev parent reply other threads:[~2019-07-01 14:52 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-07-01 14:47 [Qemu-devel] [PATCH v2 0/4] Introduce the microvm machine type Sergio Lopez
2019-07-01 14:47 ` [Qemu-devel] [PATCH v2 1/4] hw/virtio: Factorize virtio-mmio headers Sergio Lopez
2019-07-01 14:47 ` Sergio Lopez [this message]
2019-07-02 8:02 ` [Qemu-devel] [PATCH v2 2/4] hw/i386: Add an Intel MPTable generator Gerd Hoffmann
2019-07-02 8:37 ` Sergio Lopez
2019-07-02 9:33 ` Gerd Hoffmann
2019-07-01 14:47 ` [Qemu-devel] [PATCH v2 3/4] hw/i386: Factorize PVH related functions Sergio Lopez
2019-07-01 14:47 ` [Qemu-devel] [PATCH v2 4/4] hw/i386: Introduce the microvm machine type Sergio Lopez
2019-07-02 8:17 ` Gerd Hoffmann
2019-07-02 8:42 ` Sergio Lopez
2019-07-02 10:16 ` Gerd Hoffmann
2019-07-02 10:52 ` Sergio Lopez
2019-07-02 11:50 ` Gerd Hoffmann
2019-07-02 14:06 ` Paolo Bonzini
2019-07-02 14:41 ` Sergio Lopez
2019-07-18 14:34 ` Sergio Lopez
2019-07-18 15:48 ` Paolo Bonzini
2019-07-19 10:30 ` Sergio Lopez
2019-07-19 11:49 ` Paolo Bonzini
2019-07-02 8:19 ` Stefano Garzarella
2019-07-02 8:47 ` Sergio Lopez
2019-07-02 10:37 ` Paolo Bonzini
2019-07-02 11:16 ` Sergio Lopez
2019-07-01 18:32 ` [Qemu-devel] [PATCH v2 0/4] " no-reply
2019-07-01 19:06 ` no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190701144705.102615-3-slp@redhat.com \
--to=slp@redhat.com \
--cc=ehabkost@redhat.com \
--cc=maran.wilson@oracle.com \
--cc=marcel.apfelbaum@gmail.com \
--cc=mst@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=rth@twiddle.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).