dm: mmio_dev: add mmio device pass through support

We could add MMIO device pass through by two ways:
a) If the MMIO device only has MMIO regions and no ACPI Table touched, using
"--mmiodev_pt MMIO_regions",
b) If the MMIO device touches ACPI Table, using "--acpidev_pt HID"

Now only support TPM2 MSFT0101 MMIO device pass through through launch script
using "--acpidev_pt MSFT0101". When we want to pass through the TPM2 deivce,
we would not allow to emulate the vTPM2 at the same time. This is becuase
the ACRN-DM emulate the TPM2 as MSFT0101 too. Otherwise, the VM can't boot.

Besides, we could only support one TPM2 device PT and one MMIO device PT.
For TPM2 device PT, the MMIO resources are hard-coded. For the MMIO device PT,
we could pass through the MMIO resources on the cmdline.

ToDo:
1. We may use HID to discover the MMIO regions and ACPI Table instaed of
hard-coded.
2. To identify a MMIO device only by MMIO regions.
3. To allocate virtual MMIO regions in a reserved guest MMIO regions.

Tracked-On: #5053
Signed-off-by: Li Fei1 <fei1.li@intel.com>
This commit is contained in:
Li Fei1 2020-07-23 11:24:11 +08:00 committed by wenlingz
parent 158f3d17a2
commit f13d5c25b6
7 changed files with 237 additions and 7 deletions

View File

@ -132,6 +132,7 @@ SRCS += hw/pci/uart.c
SRCS += hw/pci/gvt.c
SRCS += hw/pci/npk.c
SRCS += hw/pci/ivshmem.c
SRCS += hw/mmio/core.c
# core
#SRCS += core/bootrom.c

View File

@ -62,6 +62,7 @@
#include "pm.h"
#include "atomic.h"
#include "tpm.h"
#include "mmio_dev.h"
#include "virtio.h"
#include "pm_vuart.h"
#include "log.h"
@ -87,6 +88,7 @@ char *mac_seed;
bool stdio_in_use;
bool lapic_pt;
bool is_rtvm;
bool pt_tpm2;
bool is_winvm;
bool skip_pci_mem64bar_workaround = false;
@ -138,6 +140,7 @@ usage(int code)
" %*s [-l lpc] [-m mem] [-r ramdisk_image_path]\n"
" %*s [-s pci] [-U uuid] [--vsbl vsbl_file_name] [--ovmf ovmf_file_path]\n"
" %*s [--part_info part_info_name] [--enable_trusty] [--intr_monitor param_setting]\n"
" %*s [--acpidev_pt HID] [--mmiodev_pt MMIO_Regions]\n"
" %*s [--vtpm2 sock_path] [--virtio_poll interval] [--mac_seed seed_string]\n"
" %*s [--vmcfg sub_options] [--dump vm_idx] [--debugexit] \n"
" %*s [--logger-setting param_setting] [--pm_notify_channel]\n"
@ -171,6 +174,8 @@ usage(int code)
" --intr_monitor: enable interrupt storm monitor\n"
" its params: threshold/s,probe-period(s),delay_time(ms),delay_duration(ms)\n"
" --virtio_poll: enable virtio poll mode with poll interval with ns\n"
" --acpidev_pt: acpi device ID args: HID in ACPI Table\n"
" --mmiodev_pt: MMIO resources args: physical MMIO regions\n"
" --vtpm2: Virtual TPM2 args: sock_path=$PATH_OF_SWTPM_SOCKET\n"
" --lapic_pt: enable local apic passthrough\n"
" --rtvm: indicate that the guest is rtvm\n"
@ -179,7 +184,8 @@ usage(int code)
" --pm_by_vuart:pty,/run/acrn/vuart_vmname or tty,/dev/ttySn\n"
" --windows: support Oracle virtio-blk, virtio-net and virtio-input devices\n"
" for windows guest with secure boot\n",
progname, (int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
progname, (int)strnlen(progname, PATH_MAX), "",
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "",
(int)strnlen(progname, PATH_MAX), "", (int)strnlen(progname, PATH_MAX), "");
@ -478,15 +484,22 @@ vm_init_vdevs(struct vmctx *ctx)
if (ret < 0)
goto monitor_fail;
ret = init_mmio_devs(ctx);
if (ret < 0)
goto mmio_dev_fail;
ret = init_pci(ctx);
if (ret < 0)
goto pci_fail;
/* FIXME: if we plan to support pass through a TPM device and emulate another b TPM device */
init_vtpm2(ctx);
return 0;
pci_fail:
deinit_mmio_devs(ctx);
mmio_dev_fail:
monitor_close();
monitor_fail:
if (debugexit_enabled)
@ -515,6 +528,7 @@ vm_deinit_vdevs(struct vmctx *ctx)
acrn_writeback_ovmf_nvstorage(ctx);
deinit_pci(ctx);
deinit_mmio_devs(ctx);
monitor_close();
if (debugexit_enabled)
@ -730,6 +744,8 @@ enum {
CMD_OPT_VMCFG,
CMD_OPT_DUMP,
CMD_OPT_INTR_MONITOR,
CMD_OPT_ACPIDEV_PT,
CMD_OPT_MMIODEV_PT,
CMD_OPT_VTPM2,
CMD_OPT_LAPIC_PT,
CMD_OPT_RTVM,
@ -769,6 +785,8 @@ static struct option long_options[] = {
{"mac_seed", required_argument, 0, CMD_OPT_MAC_SEED},
{"debugexit", no_argument, 0, CMD_OPT_DEBUGEXIT},
{"intr_monitor", required_argument, 0, CMD_OPT_INTR_MONITOR},
{"apcidev_pt", required_argument, 0, CMD_OPT_ACPIDEV_PT},
{"mmiodev_pt", required_argument, 0, CMD_OPT_MMIODEV_PT},
{"vtpm2", required_argument, 0, CMD_OPT_VTPM2},
{"lapic_pt", no_argument, 0, CMD_OPT_LAPIC_PT},
{"rtvm", no_argument, 0, CMD_OPT_RTVM},
@ -915,8 +933,16 @@ main(int argc, char *argv[])
case CMD_OPT_RTVM:
is_rtvm = true;
break;
case CMD_OPT_ACPIDEV_PT:
if (parse_pt_acpidev(optarg) != 0)
errx(EX_USAGE, "invalid pt acpi dev param %s", optarg);
break;
case CMD_OPT_MMIODEV_PT:
if (parse_pt_mmiodev(optarg) != 0)
errx(EX_USAGE, "invalid pt mmio dev param %s", optarg);
break;
case CMD_OPT_VTPM2:
if (acrn_parse_vtpm2(optarg) != 0)
if (pt_tpm2 || acrn_parse_vtpm2(optarg) != 0)
errx(EX_USAGE, "invalid vtpm2 param %s", optarg);
break;
case CMD_OPT_INTR_MONITOR:

185
devicemodel/hw/mmio/core.c Normal file
View File

@ -0,0 +1,185 @@
/*
* Copyright (C) 2020 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <stdbool.h>
#include "dm.h"
#include "vmmapi.h"
#include "acpi.h"
#include "inout.h"
#include "mem.h"
#include "log.h"
struct mmio_dev {
char name[16];
};
#define MAX_MMIO_DEV_NUM 2
static struct mmio_dev mmio_devs[MAX_MMIO_DEV_NUM];
struct mmio_dev_ops {
char *name;
uint64_t base_gpa;
uint64_t base_hpa;
uint64_t size;
int (*init)(struct vmctx *, struct acrn_mmiodev *);
void (*deinit)(struct vmctx *, struct acrn_mmiodev *);
};
SET_DECLARE(mmio_dev_ops_set, struct mmio_dev_ops);
#define DEFINE_MMIO_DEV(x) DATA_SET(mmio_dev_ops_set, x)
struct mmio_dev_ops pt_mmiodev;
int parse_pt_acpidev(char *opt)
{
int err = -EINVAL;
if (strncmp(opt, "MSFT0101", 8) == 0) {
strncpy(mmio_devs[0].name, "MSFT0101", 8);
pt_tpm2 = true;
err = 0;
}
return err;
}
int parse_pt_mmiodev(char *opt)
{
int err = -EINVAL;
uint64_t base_hpa, size;
char *cp;
if((!dm_strtoul(opt, &cp, 16, &base_hpa) && *cp == ',') &&
(!dm_strtoul(cp + 1, &cp, 16, &size))) {
printf("%s pt mmiodev base: 0x%lx, size: 0x%lx\n", __func__, base_hpa, size);
strncpy(mmio_devs[1].name, pt_mmiodev.name, 8);
pt_mmiodev.base_hpa = base_hpa;
pt_mmiodev.size = size;
} else {
printf("%s, %s invalid, please check!\n", __func__, opt);
}
return err;
}
static struct mmio_dev_ops *mmio_dev_finddev(char *name)
{
struct mmio_dev_ops **mdpp, *mdp;
SET_FOREACH(mdpp, mmio_dev_ops_set) {
mdp = *mdpp;
if (!strcmp(mdp->name, name))
return mdp;
}
return NULL;
}
int init_mmio_dev(struct vmctx *ctx, struct mmio_dev_ops *ops)
{
struct acrn_mmiodev mmiodev = {
.base_gpa = ops->base_gpa,
.base_hpa = ops->base_hpa,
.size = ops->size,
};
return ops->init(ctx, &mmiodev);
}
void deinit_mmio_dev(struct vmctx *ctx, struct mmio_dev_ops *ops)
{
struct acrn_mmiodev mmiodev = {
.base_gpa = ops->base_gpa,
.base_hpa = ops->base_hpa,
.size = ops->size,
};
ops->deinit(ctx, &mmiodev);
}
int init_mmio_devs(struct vmctx *ctx)
{
int i, err = 0;
struct mmio_dev_ops *ops;
for (i = 0; i < MAX_MMIO_DEV_NUM; i++) {
ops = mmio_dev_finddev(mmio_devs[i].name);
if (ops != NULL)
err = init_mmio_dev(ctx, ops);
if (err != 0)
goto init_mmio_devs_fail;
}
return 0;
init_mmio_devs_fail:
for (; i>=0; i--) {
ops = mmio_dev_finddev(mmio_devs[i].name);
if (ops != NULL)
deinit_mmio_dev(ctx, ops);
}
return err;
}
void deinit_mmio_devs(struct vmctx *ctx)
{
int i;
struct mmio_dev_ops *ops;
for (i = 0; i < MAX_MMIO_DEV_NUM; i++) {
ops = mmio_dev_finddev(mmio_devs[i].name);
if (ops != NULL)
deinit_mmio_dev(ctx, ops);
}
}
static int init_pt_mmiodev(struct vmctx *ctx, struct acrn_mmiodev *dev)
{
return vm_assign_mmiodev(ctx, dev);
}
static void deinit_pt_mmiodev(struct vmctx *ctx, struct acrn_mmiodev *dev)
{
vm_deassign_mmiodev(ctx, dev);
}
struct mmio_dev_ops tpm2 = {
.name = "MSFT0101",
/* ToDo: we may allocate the gpa MMIO resource in a reserved MMIO region
* rether than hard-coded here.
*/
.base_gpa = 0xFED40000UL,
.base_hpa = 0xFED40000UL,
.size = 0x00005000UL,
.init = init_pt_mmiodev,
.deinit = deinit_pt_mmiodev,
};
DEFINE_MMIO_DEV(tpm2);
struct mmio_dev_ops pt_mmiodev = {
.name = "MMIODEV",
/* ToDo: we may allocate the gpa MMIO resource in a reserved MMIO region
* rether than hard-coded here.
*/
.base_gpa = 0xF0000000UL,
.init = init_pt_mmiodev,
.deinit = deinit_pt_mmiodev,
};
DEFINE_MMIO_DEV(pt_mmiodev);

View File

@ -182,7 +182,7 @@ basl_fwrite_rsdt(FILE *fp, struct vmctx *ctx)
EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : %08X\n", num++,
basl_acpi_base + NHLT_OFFSET);
if (ctx->tpm_dev)
if (ctx->tpm_dev || pt_tpm2)
EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : %08X\n", num++,
basl_acpi_base + TPM2_OFFSET);
@ -224,7 +224,7 @@ basl_fwrite_xsdt(FILE *fp, struct vmctx *ctx)
EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : 00000000%08X\n", num++,
basl_acpi_base + NHLT_OFFSET);
if (ctx->tpm_dev)
if (ctx->tpm_dev || pt_tpm2)
EFPRINTF(fp, "[0004]\t\tACPI Table Address %u : 00000000%08X\n", num++,
basl_acpi_base + TPM2_OFFSET);
@ -859,7 +859,7 @@ basl_fwrite_dsdt(FILE *fp, struct vmctx *ctx)
pm_write_dsdt(ctx, basl_ncpu);
if (ctx->tpm_dev)
if (ctx->tpm_dev || pt_tpm2)
tpm2_crb_fwrite_dsdt();
dsdt_line("}");
@ -1124,7 +1124,7 @@ acpi_build(struct vmctx *ctx, int ncpu)
*/
while (!err && (i < ARRAY_SIZE(basl_ftables))) {
if ((basl_ftables[i].offset == TPM2_OFFSET) &&
(ctx->tpm_dev != NULL)) {
(ctx->tpm_dev != NULL || pt_tpm2)) {
basl_ftables[i].valid = true;
}

View File

@ -48,6 +48,7 @@ extern bool stdio_in_use;
extern char *mac_seed;
extern bool lapic_pt;
extern bool is_rtvm;
extern bool pt_tpm2;
extern bool is_winvm;
int vmexit_task_switch(struct vmctx *ctx, struct vhm_request *vhm_req,

View File

@ -0,0 +1,17 @@
/*
* Copyright (C) 2020 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _MMIO_DEV_H_
#define _MMIO_DEV_H_
int parse_pt_acpidev(char *arg);
int parse_pt_mmiodev(char *arg);
int init_mmio_devs(struct vmctx *ctx);
int deinit_mmio_devs(struct vmctx *ctx);
#endif /* _MMIO_DEV_H_ */

View File

@ -9,7 +9,7 @@
#define _TPM_H_
#define TPM_CRB_MMIO_ADDR 0xFED40000UL
#define TPM_CRB_MMIO_SIZE 0x1000U
#define TPM_CRB_MMIO_SIZE 0x5000U
/* TPM CRB registers */
enum {