From patchwork Tue Jul 2 12:11:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergio Lopez X-Patchwork-Id: 1126236 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45dNcZ01V9z9sND for ; Tue, 2 Jul 2019 22:20:46 +1000 (AEST) Received: from localhost ([::1]:52418 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hiHm8-0000WC-1s for incoming@patchwork.ozlabs.org; Tue, 02 Jul 2019 08:20:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:40537) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hiHe9-00031G-04 for qemu-devel@nongnu.org; Tue, 02 Jul 2019 08:12:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hiHdx-0007Bl-7y for qemu-devel@nongnu.org; Tue, 02 Jul 2019 08:12:21 -0400 Received: from mx1.redhat.com ([209.132.183.28]:51861) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hiHdr-0006tR-5b for qemu-devel@nongnu.org; Tue, 02 Jul 2019 08:12: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 3935CA405A; Tue, 2 Jul 2019 12:11:53 +0000 (UTC) Received: from dritchie.redhat.com (unknown [10.33.36.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2A2AF78380; Tue, 2 Jul 2019 12:11:46 +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, sgarzare@redhat.com, kraxel@redhat.com Date: Tue, 2 Jul 2019 14:11:04 +0200 Message-Id: <20190702121106.28374-3-slp@redhat.com> In-Reply-To: <20190702121106.28374-1-slp@redhat.com> References: <20190702121106.28374-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.38]); Tue, 02 Jul 2019 12:11:58 +0000 (UTC) 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 v3 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" 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 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 + * + * 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 */