qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Sergio Lopez <slp@redhat.com>
To: mst@redhat.com, marcel.apfelbaum@gmail.com, pbonzini@redhat.com,
	rth@twiddle.net, ehabkost@redhat.com
Cc: qemu-devel@nongnu.org, Sergio Lopez <slp@redhat.com>
Subject: [Qemu-devel] [PATCH 3/4] hw/i386: Add an Intel MPTable generator
Date: Fri, 28 Jun 2019 13:53:48 +0200	[thread overview]
Message-ID: <20190628115349.60293-4-slp@redhat.com> (raw)
In-Reply-To: <20190628115349.60293-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                           | 157 +++++++++++++++++
 include/hw/i386/mptable.h                   |  37 ++++
 include/standard-headers/linux/mpspec_def.h | 182 ++++++++++++++++++++
 3 files changed, 376 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..c5cb57dd18
--- /dev/null
+++ b/hw/i386/mptable.c
@@ -0,0 +1,157 @@
+/*
+ * 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 apic_id,
+                        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..9f9eb82618
--- /dev/null
+++ b/include/hw/i386/mptable.h
@@ -0,0 +1,37 @@
+/*
+ * 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 apic_id,
+                       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



  parent reply	other threads:[~2019-06-28 14:17 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-28 11:53 [Qemu-devel] [PATCH 0/4] Introduce the microvm machine type Sergio Lopez
2019-06-28 11:53 ` [Qemu-devel] [PATCH 1/4] hw/i386: Factorize CPU routine Sergio Lopez
2019-06-28 20:03   ` Eduardo Habkost
2019-06-28 21:44     ` Sergio Lopez
2019-07-01  9:25       ` Michael S. Tsirkin
2019-06-28 11:53 ` [Qemu-devel] [PATCH 2/4] hw/virtio: Factorize virtio-mmio headers Sergio Lopez
2019-06-28 14:03   ` Michael S. Tsirkin
2019-06-28 20:50     ` Sergio Lopez
2019-06-30 21:36       ` Michael S. Tsirkin
2019-07-02  8:19         ` Gerd Hoffmann
2019-07-02 13:22           ` Michael S. Tsirkin
2019-06-28 11:53 ` Sergio Lopez [this message]
2019-06-28 11:53 ` [Qemu-devel] [PATCH 4/4] hw/i386: Introduce the microvm machine type Sergio Lopez
2019-06-28 14:06   ` Michael S. Tsirkin
2019-06-28 20:56     ` Sergio Lopez
2019-06-28 22:17     ` Paolo Bonzini
2019-06-30 21:37       ` Michael S. Tsirkin
2019-06-28 19:15   ` Maran Wilson
2019-06-28 21:05     ` Sergio Lopez
2019-06-28 21:54       ` Maran Wilson
2019-06-28 22:23         ` Sergio Lopez
2019-06-28 21:56       ` Paolo Bonzini
2019-06-28 19:47   ` Eduardo Habkost
2019-06-28 21:42     ` Sergio Lopez
2019-06-28 21:57       ` Paolo Bonzini
2019-06-28 13:21 ` [Qemu-devel] [PATCH 0/4] " Paolo Bonzini
2019-06-28 20:49   ` Sergio Lopez
2019-06-28 16:32 ` no-reply
2019-06-28 18:16 ` 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=20190628115349.60293-4-slp@redhat.com \
    --to=slp@redhat.com \
    --cc=ehabkost@redhat.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).