acrn-hypervisor/hypervisor/arch/x86/guest/mptable.c
Sainath Grandhi c102c44c16 hv: Device MSIs in partition mode ACRN
VMs in partition mode uses a kernel patch to switch to physical mode xAPIC.
The kernel patch together with this patch makes sure device MSIs use
physical mode as DM and physical APIC IDs in Destination field.

Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
2018-09-03 09:32:15 +08:00

323 lines
7.8 KiB
C

/*
* Copyright (C) 2018 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <hv_lib.h>
#include <acrn_common.h>
#include <hv_arch.h>
#include <hv_debug.h>
#include <bsp_extern.h>
#include <mptable.h>
#define MPTABLE_BASE 0xF0000U
/*
* floating pointer length + maximum length of configuration table
* ACRN uses contiguous guest memory from 0xF0000 to place floating pointer
* structure and config table. Maximum length of config table is 64K. So the
* maximum length of combined floating pointer and config table can go up to
* 64K + 16 bytes.Since we are left with only 64K from 0xF0000 to 0x100000(1MB)
* max length is limited to 64K.
*/
#define MPTABLE_MAX_LENGTH 65536U
#define LAPIC_VERSION 16U
#define MP_SPECREV 4U
#define MPFP_SIG "_MP_"
/* Configuration header defines */
#define MPCH_SIG "PCMP"
#define MPCH_OEMID "BHyVe "
#define MPCH_OEMID_LEN 8U
#define MPCH_PRODID "Hypervisor "
#define MPCH_PRODID_LEN 12U
/* Processor entry defines */
#define MPEP_SIG_FAMILY 6U
#define MPEP_SIG_MODEL 26U
#define MPEP_SIG_STEPPING 5U
#define MPEP_SIG \
((MPEP_SIG_FAMILY << 8U) | \
(MPEP_SIG_MODEL << 4U) | \
(MPEP_SIG_STEPPING))
#define MPEP_FEATURES 0xBFEBFBFFU /* XXX Intel i7 */
/* Number of local intr entries */
#define MPEII_NUM_LOCAL_IRQ 2U
/* Bus entry defines */
#define MPE_NUM_BUSES 2U
#define MPE_BUSNAME_LEN 6U
#define MPE_BUSNAME_ISA "ISA "
#define MPE_BUSNAME_PCI "PCI "
/* Base table entries */
#define MPCT_ENTRY_PROCESSOR 0U
#define MPCT_ENTRY_BUS 1U
#define MPCT_ENTRY_LOCAL_INT 4U
#define PROCENTRY_FLAG_EN 0x01U
#define PROCENTRY_FLAG_BP 0x02U
#define INTENTRY_TYPE_NMI 1U
#define INTENTRY_TYPE_EXTINT 3U
#define INTENTRY_FLAGS_POLARITY_CONFORM 0x0U
#define INTENTRY_FLAGS_TRIGGER_CONFORM 0x0U
#define VM1_NUM_CPUS 2U
#define VM2_NUM_CPUS 2U
/* MP Floating Pointer Structure */
struct mpfps {
uint8_t signature[4];
uint32_t pap;
uint8_t length;
uint8_t spec_rev;
uint8_t checksum;
uint8_t config_type;
uint8_t mpfb2;
uint8_t mpfb3;
uint8_t mpfb4;
uint8_t mpfb5;
} __attribute__((packed));
/* MP Configuration Table Header */
struct mpcth {
uint8_t signature[4];
uint16_t base_table_length;
uint8_t spec_rev;
uint8_t checksum;
uint8_t oem_id[8];
uint8_t product_id[12];
uint32_t oem_table_pointer;
uint16_t oem_table_size;
uint16_t entry_count;
uint32_t apic_address;
uint16_t extended_table_length;
uint8_t extended_table_checksum;
uint8_t reserved;
} __attribute__((packed));
struct proc_entry {
uint8_t type;
uint8_t apic_id;
uint8_t apic_version;
uint8_t cpu_flags;
uint32_t cpu_signature;
uint32_t feature_flags;
uint32_t reserved1;
uint32_t reserved2;
} __attribute__((packed));
struct bus_entry {
uint8_t type;
uint8_t bus_id;
uint8_t bus_type[6];
} __attribute__((packed));
struct int_entry {
uint8_t type;
uint8_t int_type;
uint16_t int_flags;
uint8_t src_bus_id;
uint8_t src_bus_irq;
uint8_t dst_apic_id;
uint8_t dst_apic_int;
} __attribute__((packed));
struct mptable_info {
struct mpfps mpfp;
struct mpcth mpch;
struct bus_entry bus_entry_array[MPE_NUM_BUSES];
struct int_entry int_entry_array[MPEII_NUM_LOCAL_IRQ];
struct proc_entry proc_entry_array[];
};
struct mptable_info mptable_vm1 = {
.mpfp = {
.signature = MPFP_SIG,
.pap = MPTABLE_BASE + sizeof(struct mpfps),
.length = 1U,
.spec_rev = MP_SPECREV,
},
.mpch = {
.signature = MPCH_SIG,
.spec_rev = MP_SPECREV,
.oem_id = MPCH_OEMID,
.product_id = MPCH_PRODID,
.apic_address = LAPIC_BASE,
.entry_count = (VM1_NUM_CPUS + MPE_NUM_BUSES \
+ MPEII_NUM_LOCAL_IRQ),
.base_table_length = (sizeof(struct mpcth) \
+ VM1_NUM_CPUS * sizeof(struct proc_entry) \
+ MPE_NUM_BUSES * sizeof(struct bus_entry) \
+ MPEII_NUM_LOCAL_IRQ * sizeof(struct int_entry))
},
.proc_entry_array = {
{
.type = MPCT_ENTRY_PROCESSOR,
.apic_id = 0U,
.apic_version = LAPIC_VERSION,
.cpu_flags = PROCENTRY_FLAG_EN | PROCENTRY_FLAG_BP,
.cpu_signature = MPEP_SIG,
.feature_flags = MPEP_FEATURES
},
{
.type = MPCT_ENTRY_PROCESSOR,
.apic_id = 4U,
.apic_version = LAPIC_VERSION,
.cpu_flags = PROCENTRY_FLAG_EN,
.cpu_signature = MPEP_SIG,
.feature_flags = MPEP_FEATURES,
}
},
.bus_entry_array = {
{
.type = MPCT_ENTRY_BUS,
.bus_id = 0U,
.bus_type = MPE_BUSNAME_PCI,
},
{
.type = MPCT_ENTRY_BUS,
.bus_id = 1U,
.bus_type = MPE_BUSNAME_ISA,
},
},
.int_entry_array = {
{
.type = MPCT_ENTRY_LOCAL_INT,
.int_type = INTENTRY_TYPE_EXTINT,
.int_flags = INTENTRY_FLAGS_POLARITY_CONFORM \
| INTENTRY_FLAGS_TRIGGER_CONFORM,
.dst_apic_id = 0xFFU,
.dst_apic_int = 0U,
},
{
.type = MPCT_ENTRY_LOCAL_INT,
.int_type = INTENTRY_TYPE_NMI,
.int_flags = INTENTRY_FLAGS_POLARITY_CONFORM \
| INTENTRY_FLAGS_TRIGGER_CONFORM,
.dst_apic_id = 0xFFU,
.dst_apic_int = 1U,
},
},
};
struct mptable_info mptable_vm2 = {
.mpfp = {
.signature = MPFP_SIG,
.pap = MPTABLE_BASE + sizeof(struct mpfps),
.length = 1U,
.spec_rev = MP_SPECREV,
},
.mpch = {
.signature = MPCH_SIG,
.spec_rev = MP_SPECREV,
.oem_id = MPCH_OEMID,
.product_id = MPCH_PRODID,
.apic_address = LAPIC_BASE,
.entry_count = (VM2_NUM_CPUS + MPE_NUM_BUSES \
+ MPEII_NUM_LOCAL_IRQ),
.base_table_length = (sizeof(struct mpcth) \
+ VM2_NUM_CPUS * sizeof(struct proc_entry) \
+ MPE_NUM_BUSES * sizeof(struct bus_entry) \
+ MPEII_NUM_LOCAL_IRQ * sizeof(struct int_entry))
},
.proc_entry_array = {
{
.type = MPCT_ENTRY_PROCESSOR,
.apic_id = 6U,
.apic_version = LAPIC_VERSION,
.cpu_flags = PROCENTRY_FLAG_EN | PROCENTRY_FLAG_BP,
.cpu_signature = MPEP_SIG,
.feature_flags = MPEP_FEATURES
},
{
.type = MPCT_ENTRY_PROCESSOR,
.apic_id = 2U,
.apic_version = LAPIC_VERSION,
.cpu_flags = PROCENTRY_FLAG_EN,
.cpu_signature = MPEP_SIG,
.feature_flags = MPEP_FEATURES,
}
},
.bus_entry_array = {
{
.type = MPCT_ENTRY_BUS,
.bus_id = 0U,
.bus_type = MPE_BUSNAME_PCI,
},
{
.type = MPCT_ENTRY_BUS,
.bus_id = 1U,
.bus_type = MPE_BUSNAME_ISA,
},
},
.int_entry_array = {
{
.type = MPCT_ENTRY_LOCAL_INT,
.int_type = INTENTRY_TYPE_EXTINT,
.int_flags = INTENTRY_FLAGS_POLARITY_CONFORM \
| INTENTRY_FLAGS_TRIGGER_CONFORM,
.dst_apic_id = 0xFFU,
.dst_apic_int = 0U,
},
{
.type = MPCT_ENTRY_LOCAL_INT,
.int_type = INTENTRY_TYPE_NMI,
.int_flags = INTENTRY_FLAGS_POLARITY_CONFORM \
| INTENTRY_FLAGS_TRIGGER_CONFORM,
.dst_apic_id = 0xFFU,
.dst_apic_int = 1U,
},
},
};
static uint8_t mpt_compute_checksum(void *base, size_t len)
{
uint8_t *bytes;
uint8_t sum;
size_t length = len;
for (bytes = base, sum = 0U; length > 0U; length--) {
sum += *bytes;
bytes++;
}
return (256U - sum);
}
int mptable_build(struct vm *vm)
{
char *startaddr;
char *curraddr;
struct mpcth *mpch;
struct mpfps *mpfp;
size_t mptable_length, table_length;
startaddr = (char *)GPA2HVA(vm, MPTABLE_BASE);
table_length = vm->vm_desc->mptable->mpch.base_table_length;
mptable_length = sizeof(struct mpfps) + table_length;
/* Copy mptable info into guest memory */
(void)memcpy_s((void *)startaddr, MPTABLE_MAX_LENGTH,
(void *)vm->vm_desc->mptable,
mptable_length);
curraddr = startaddr;
mpfp = (struct mpfps *)curraddr;
mpfp->checksum = mpt_compute_checksum(mpfp, sizeof(struct mpfps));
curraddr += sizeof(struct mpfps);
mpch = (struct mpcth *)curraddr;
mpch->checksum = mpt_compute_checksum(mpch, mpch->base_table_length);
return 0U;
}