mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-20 20:53:46 +00:00
dm: acpi_dev: Support more ACPI device pass through
In current implementation, --acpidev_pt parameter is a wrapper of MMIO device pass through, which only support TPM pass through with MMIO region. This patch extends --acpidev_pt to a fully functional parameter to support more ACPI device with multi resource, such as MMIO resource, PIO resource and IRQ resource. Device model will parse attributes of different type of resources and invoke corresponding hypercall to assign resource in hypervisor. Here is example of new --acpidev_pt command: --acpidev_pt PNP0501,uid=19,type=irq,irq=5 --acpidev_pt PNP0501,uid=19,type=io_port,min=0x258,len=8 --acpidev_pt INTC1055,uid=0,type=irq,irq=14,polarity=3,trigger_mode=3 --acpidev_pt INTC1055,uid=0,type=memory,min=0xfd6e0000,len=0x10000 The new added target device of ACPI device pass through function is legacy UART and GPIO controller. Before launching VMs, launch script should handle these device to avoid Service VM from access their resource. Driver of both legacy UART and GPIO controller provide unbind interface to unbind device instance from Service VM. This patch also refine TPM pass through to align with new ACPI device pass through framework. For TPM, tpm_tis driver also provide unbind interface to unbind TPM device instance from Service VM. All these unbinding operation should be executed by launch script before acrn-dm command. Tracked-On: #8635 Signed-off-by: Yichong Tang <yichong.tang@intel.com> Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com>
This commit is contained in:
parent
3b35a673e6
commit
b37f9c054b
@ -161,6 +161,7 @@ SRCS += hw/pci/gvt.c
|
||||
SRCS += hw/pci/npk.c
|
||||
SRCS += hw/pci/ivshmem.c
|
||||
SRCS += hw/mmio/core.c
|
||||
SRCS += hw/acpi/core.c
|
||||
|
||||
# core
|
||||
#SRCS += core/bootrom.c
|
||||
|
@ -45,7 +45,7 @@ static struct {
|
||||
void *arg;
|
||||
} inout_handlers[MAX_IOPORTS];
|
||||
|
||||
static int
|
||||
int
|
||||
default_inout(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
|
||||
uint32_t *eax, void *arg)
|
||||
{
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "atomic.h"
|
||||
#include "tpm.h"
|
||||
#include "mmio_dev.h"
|
||||
#include "acpi_dev.h"
|
||||
#include "virtio.h"
|
||||
#include "pm_vuart.h"
|
||||
#include "log.h"
|
||||
@ -178,7 +179,11 @@ usage(int code)
|
||||
" --cmd_monitor: enable command monitor\n"
|
||||
" its params: unix domain socket path\n"
|
||||
" --virtio_poll: enable virtio poll mode with poll interval with ns\n"
|
||||
" --acpidev_pt: ACPI device ID args: HID in ACPI Table\n"
|
||||
" --acpidev_pt: ACPI device pass through\n"
|
||||
" its params: HID[,uid=UID,type=Resource Type,Resouece config,...]\n"
|
||||
" e.g. --acpidev_pt INTC1055,uid=0,type=memory,min=0xfd6e0000,len=0x10000\n"
|
||||
" e.g. --acpidev_pt PNP0501,uid=19,type=io_port,min=0x2f8,len=8\n"
|
||||
" e.g. --acpidev_pt PNP0501,uid=19,type=irq,irq=5\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"
|
||||
@ -576,6 +581,10 @@ vm_init_vdevs(struct vmctx *ctx)
|
||||
if (ret < 0)
|
||||
goto mmio_dev_fail;
|
||||
|
||||
ret = init_acpi_devs(ctx);
|
||||
if (ret < 0)
|
||||
goto acpi_dev_fail;
|
||||
|
||||
ret = init_pci(ctx);
|
||||
if (ret < 0)
|
||||
goto pci_fail;
|
||||
@ -586,6 +595,8 @@ vm_init_vdevs(struct vmctx *ctx)
|
||||
return 0;
|
||||
|
||||
pci_fail:
|
||||
deinit_acpi_devs(ctx);
|
||||
acpi_dev_fail:
|
||||
deinit_mmio_devs(ctx);
|
||||
mmio_dev_fail:
|
||||
monitor_close();
|
||||
@ -620,6 +631,7 @@ vm_deinit_vdevs(struct vmctx *ctx)
|
||||
acrn_writeback_ovmf_nvstorage(ctx);
|
||||
|
||||
deinit_pci(ctx);
|
||||
deinit_acpi_devs(ctx);
|
||||
deinit_mmio_devs(ctx);
|
||||
monitor_close();
|
||||
|
||||
|
@ -614,6 +614,92 @@ vm_deassign_pio_region(struct vmctx *ctx, struct acrn_pio_region *pio_region)
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
vm_assign_acpidev(struct vmctx *ctx, struct acrn_acpidev *acpidev)
|
||||
{
|
||||
int i, error = -EINVAL;
|
||||
struct acrn_acpires *res;
|
||||
struct acrn_mmiodev mmiodev;
|
||||
struct acrn_pio_region pio_region;
|
||||
struct acrn_ptdev_irq ptirq;
|
||||
|
||||
for (i = 0; i < ACPIDEV_RES_NUM; i++) {
|
||||
res = &acpidev->res[i];
|
||||
if (res->type == MEMORY_RES) {
|
||||
memset(&mmiodev, 0, sizeof(struct acrn_mmiodev));
|
||||
strncpy(mmiodev.name, acpidev->name, 8);
|
||||
mmiodev.res[0] = res->mmio_res;
|
||||
error = ioctl(ctx->fd, ACRN_IOCTL_ASSIGN_MMIODEV, &mmiodev);
|
||||
if (error) {
|
||||
pr_err("ACRN_IOCTL_ASSIGN_MMIODEV ioctl() returned an error: %s\n", errormsg(errno));
|
||||
}
|
||||
} else if (res->type == IO_PORT_RES) {
|
||||
memset(&pio_region, 0, sizeof(struct acrn_pio_region));
|
||||
strncpy(pio_region.name, acpidev->name, 8);
|
||||
pio_region.res = res->pio_res;
|
||||
error = ioctl(ctx->fd, ACRN_IOCTL_ASSIGN_PIO_REGION, &pio_region);
|
||||
if (error) {
|
||||
pr_err("ACRN_IOCTL_ASSIGN_PIO_REGION ioctl() returned an error: %s\n", errormsg(errno));
|
||||
}
|
||||
} else if (res->type == IRQ_RES) {
|
||||
memset(&ptirq, 0, sizeof(struct acrn_ptdev_irq));
|
||||
ptirq.type = ACRN_PTDEV_IRQ_INTX;
|
||||
ptirq.virt_bdf = ACRN_PTDEV_NON_PCI_BDF;
|
||||
ptirq.phys_bdf = ACRN_PTDEV_NON_PCI_BDF;
|
||||
ptirq.intx.virt_pin = res->irq_res.irq;
|
||||
ptirq.intx.phys_pin = res->irq_res.irq;
|
||||
ptirq.intx.is_pic_pin = false;
|
||||
error = ioctl(ctx->fd, ACRN_IOCTL_SET_PTDEV_INTR, &ptirq);
|
||||
if (error) {
|
||||
pr_err("ACRN_IOCTL_SET_PTDEV_INTR ioctl() returned an error: %s\n", errormsg(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
vm_deassign_acpidev(struct vmctx *ctx, struct acrn_acpidev *acpidev)
|
||||
{
|
||||
int i, error = 0;
|
||||
struct acrn_acpires *res;
|
||||
struct acrn_mmiodev mmiodev;
|
||||
struct acrn_pio_region pio_region;
|
||||
struct acrn_ptdev_irq ptirq;
|
||||
|
||||
for (i = 0; i < ACPIDEV_RES_NUM; i++) {
|
||||
res = &acpidev->res[i];
|
||||
if (res->type == MEMORY_RES) {
|
||||
memset(&mmiodev, 0, sizeof(struct acrn_mmiodev));
|
||||
mmiodev.res[0] = res->mmio_res;
|
||||
error = ioctl(ctx->fd, ACRN_IOCTL_DEASSIGN_MMIODEV, &mmiodev);
|
||||
if (error) {
|
||||
pr_err("ACRN_IOCTL_DEASSIGN_MMIODEV ioctl() returned an error: %s\n", errormsg(errno));
|
||||
}
|
||||
} else if (res->type == IO_PORT_RES) {
|
||||
memset(&pio_region, 0, sizeof(struct acrn_pio_region));
|
||||
pio_region.res = res->pio_res;
|
||||
error = ioctl(ctx->fd, ACRN_IOCTL_DEASSIGN_PIO_REGION, &pio_region);
|
||||
if (error) {
|
||||
pr_err("ACRN_IOCTL_DEASSIGN_PIO_REGION ioctl() returned an error: %s\n", errormsg(errno));
|
||||
}
|
||||
} else if (res->type == IRQ_RES) {
|
||||
memset(&ptirq, 0, sizeof(struct acrn_ptdev_irq));
|
||||
ptirq.type = ACRN_PTDEV_IRQ_INTX;
|
||||
ptirq.virt_bdf = ACRN_PTDEV_NON_PCI_BDF;
|
||||
ptirq.phys_bdf = ACRN_PTDEV_NON_PCI_BDF;
|
||||
ptirq.intx.virt_pin = res->irq_res.irq;
|
||||
ptirq.intx.phys_pin = res->irq_res.irq;
|
||||
ptirq.intx.is_pic_pin = false;
|
||||
error = ioctl(ctx->fd, ACRN_IOCTL_RESET_PTDEV_INTR, &ptirq);
|
||||
if (error) {
|
||||
pr_err("ACRN_IOCTL_RESET_PTDEV_INTR ioctl() returned an error: %s\n", errormsg(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
vm_map_ptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
|
||||
vm_paddr_t gpa, size_t len, vm_paddr_t hpa)
|
||||
|
453
devicemodel/hw/acpi/core.c
Normal file
453
devicemodel/hw/acpi/core.c
Normal file
@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2024 Intel Corporation.
|
||||
*
|
||||
* 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 <sys/user.h>
|
||||
|
||||
#include "dm.h"
|
||||
#include "vmmapi.h"
|
||||
#include "acpi.h"
|
||||
#include "inout.h"
|
||||
#include "mem.h"
|
||||
#include "irq.h"
|
||||
#include "log.h"
|
||||
#include "acpi_dev.h"
|
||||
|
||||
#define MAX_ACPI_DEV_NUM 8
|
||||
|
||||
#define MAX_IOPORTS (1 << 16)
|
||||
|
||||
enum {
|
||||
TYPE_OPT = 0,
|
||||
MINIMUM_ADDRESS_OPT,
|
||||
LENGTH_OPT,
|
||||
IRQ_OPT,
|
||||
POLARTY_OPT,
|
||||
TRIGGER_MODE_OPT,
|
||||
DSDT_OPT
|
||||
};
|
||||
|
||||
char *const pt_acpi_token[] = {
|
||||
[TYPE_OPT] = "type",
|
||||
[MINIMUM_ADDRESS_OPT] = "min",
|
||||
[LENGTH_OPT] = "len",
|
||||
[IRQ_OPT] = "irq",
|
||||
[POLARTY_OPT] = "polarity",
|
||||
[TRIGGER_MODE_OPT] = "trigger_mode",
|
||||
[DSDT_OPT] = "dsdt",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct acpi_dev acpi_devs[MAX_ACPI_DEV_NUM];
|
||||
static uint32_t acpi_dev_idx = 0U;
|
||||
|
||||
struct acpi_dev *get_acpidev(char *hid, char *uid)
|
||||
{
|
||||
int i;
|
||||
struct acpi_dev *dev;
|
||||
|
||||
/* acpi_dev_idx is the current depth of acpi devices array */
|
||||
for (i = 0; i < acpi_dev_idx; i++) {
|
||||
dev = &acpi_devs[i];
|
||||
if ((!strcmp(dev->hid, hid)) && (!strcmp(dev->uid, uid))) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct acpi_dev *alloc_acpidev(char *hid, char *uid)
|
||||
{
|
||||
struct acpi_dev *dev = NULL;
|
||||
dev = get_acpidev(hid, uid);
|
||||
if (dev != NULL) {
|
||||
return dev;
|
||||
}
|
||||
|
||||
/* Check if ACPI device array is full */
|
||||
if (acpi_dev_idx == MAX_ACPI_DEV_NUM) {
|
||||
return NULL;
|
||||
} else if (hid && uid) {
|
||||
acpi_devs[acpi_dev_idx].hid = strdup(hid);
|
||||
acpi_devs[acpi_dev_idx].uid = strdup(uid);
|
||||
return &acpi_devs[acpi_dev_idx++];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int create_pt_acpidev(char *opts)
|
||||
{
|
||||
struct acpi_dev *dev;
|
||||
struct acpi_dev_ops **adops, *ops;
|
||||
char *devopts, *vtopts, *value;
|
||||
char *hid, *uid;
|
||||
uint32_t base_address, length;
|
||||
uint32_t buf;
|
||||
int i, ret = 0, index = -1;
|
||||
|
||||
SET_FOREACH(adops, acpi_dev_ops_set) {
|
||||
ops = *adops;
|
||||
if (ops->match && opts && ops->match(opts)) {
|
||||
devopts = vtopts = strdup(opts);
|
||||
hid = strsep(&vtopts, ",");
|
||||
if (!hid) {
|
||||
free(devopts);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uid = (char *)malloc(16);
|
||||
if (!uid) {
|
||||
pr_err(("UID malloc failed for ACPI device!\n"));
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (vtopts != NULL && !strncmp(vtopts, "uid=", 4)) {
|
||||
strcpy(uid, strsep(&vtopts, ",") + 4);
|
||||
} else {
|
||||
strcpy(uid, "0");
|
||||
}
|
||||
|
||||
dev = alloc_acpidev(hid, uid);
|
||||
if (!dev) {
|
||||
pr_err("Failed to create ACPI device %s:%s due to exceeding max ACPI device number\n", hid, uid);
|
||||
free(uid);
|
||||
free(devopts);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ops->create) {
|
||||
return ops->create(opts, dev);
|
||||
}
|
||||
|
||||
index = -1;
|
||||
for (i = 0; i < ACPIDEV_RES_NUM; i++) {
|
||||
if (dev->dev.res[i].type == INVALID_RES) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1) {
|
||||
pr_err("ACPI resource number for device %s:%s exceed limit.\n", hid, uid);
|
||||
free(uid);
|
||||
free(devopts);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (vtopts != NULL && strcmp(vtopts, "") && !ret)
|
||||
{
|
||||
switch (getsubopt(&vtopts, pt_acpi_token, &value)) {
|
||||
case TYPE_OPT:
|
||||
if (value == NULL) {
|
||||
pr_err("Missing value for --acpidev_pt suboption '%s'\n", pt_acpi_token[TYPE_OPT]);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!strcasecmp(value, "memory")) {
|
||||
dev->dev.res[index].type = MEMORY_RES;
|
||||
} else if (!strcasecmp(value, "io_port")) {
|
||||
dev->dev.res[index].type = IO_PORT_RES;
|
||||
} else if (!strcasecmp(value, "irq")) {
|
||||
dev->dev.res[index].type = IRQ_RES;
|
||||
} else {
|
||||
pr_err("Invalid ACPI device resource type: %s\n", value);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case MINIMUM_ADDRESS_OPT:
|
||||
if (value == NULL) {
|
||||
pr_err("Missing value for --acpidev_pt suboption '%s'\n", pt_acpi_token[MINIMUM_ADDRESS_OPT]);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!dm_strtoui(value, NULL, 16, &base_address)) {
|
||||
if (dev->dev.res[index].type == MEMORY_RES && (base_address & (PAGE_SIZE - 1UL)) == 0) {
|
||||
dev->dev.res[index].mmio_res.host_pa = base_address;
|
||||
} else if (dev->dev.res[index].type == IO_PORT_RES && base_address < MAX_IOPORTS) {
|
||||
dev->dev.res[index].pio_res.port_address = base_address;
|
||||
} else {
|
||||
pr_err("Invalid ACPI device resource address: %s for type %d\n",
|
||||
base_address, dev->dev.res[index].type);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
pr_err("Invalid ACPI device resource address: %s\n", value);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case LENGTH_OPT:
|
||||
if (value == NULL) {
|
||||
pr_err("Missing value for --acpidev_pt suboption '%s'\n", pt_acpi_token[LENGTH_OPT]);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!dm_strtoui(value, NULL, 16, &length)) {
|
||||
if (dev->dev.res[index].type == MEMORY_RES) {
|
||||
dev->dev.res[index].mmio_res.size = roundup2(length, PAGE_SIZE);
|
||||
if (!mmio_dev_alloc_gpa_resource32(&base_address, length)) {
|
||||
dev->dev.res[index].mmio_res.user_vm_pa = base_address;
|
||||
} else {
|
||||
pr_err("Cannot allocate GPA for ACPI device memory resource of length: %d\n", length);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
} else if (dev->dev.res[index].type == IO_PORT_RES) {
|
||||
dev->dev.res[index].pio_res.size = (uint16_t)length;
|
||||
}
|
||||
} else {
|
||||
pr_err("Invalid ACPI device resource length: %s\n", value);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case IRQ_OPT:
|
||||
if (value == NULL) {
|
||||
pr_err("Missing value for --acpidev_pt suboption '%s'\n", pt_acpi_token[IRQ_OPT]);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if(!dm_strtoui(value, NULL, 10, &buf)) {
|
||||
dev->dev.res[index].irq_res.irq = (uint8_t)buf;
|
||||
pci_irq_reserve(buf);
|
||||
pr_warn("ACPI device IRQ resource may be shared with other device. Please use with caution.\n");
|
||||
} else {
|
||||
pr_err("Invalid ACPI device IRQ resource number: %s\n", value);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case POLARTY_OPT:
|
||||
if (value == NULL) {
|
||||
pr_err("Missing value for --acpidev_pt suboption '%s'\n", pt_acpi_token[POLARTY_OPT]);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if(!dm_strtoui(value, NULL, 10, &buf) && (buf & ~(uint32_t)(0x3)) == 0) {
|
||||
dev->dev.res[index].irq_res.polarity = (uint8_t)buf;
|
||||
} else {
|
||||
pr_err("Invalid ACPI device IRQ resource polarity: %s\n", value);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case TRIGGER_MODE_OPT:
|
||||
if (value == NULL) {
|
||||
pr_err("Missing value for --acpidev_pt suboption '%s'\n", pt_acpi_token[TRIGGER_MODE_OPT]);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if(!dm_strtoui(value, NULL, 10, &buf) && (buf & ~(uint32_t)(0x3)) == 0) {
|
||||
dev->dev.res[index].irq_res.trigger_mode = (uint8_t)buf;
|
||||
} else {
|
||||
pr_err("Invalid ACPI device IRQ resource trigger mode: %s\n", value);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case DSDT_OPT:
|
||||
if (value == NULL) {
|
||||
pr_err("Missing value for --acpidev_pt suboption '%s'\n", pt_acpi_token[DSDT_OPT]);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
dev->dsdt = strdup(value);
|
||||
break;
|
||||
default:
|
||||
pr_err("No match found for pt_acpi_token: %s\n", vtopts);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
free(uid);
|
||||
free(devopts);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pr_err("Unrecognized or unsupported ACPI device: %s\n", opts);
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct acpi_dev_ops *acpi_dev_finddev(char *hid)
|
||||
{
|
||||
struct acpi_dev_ops **adpp, *adp;
|
||||
|
||||
SET_FOREACH(adpp, acpi_dev_ops_set) {
|
||||
adp = *adpp;
|
||||
if (adp->hid != NULL && !strcmp(adp->hid, hid))
|
||||
return adp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search /sys/bus/acpi/devices for given HID and fill modalias to ops.
|
||||
* (TODO: we may add more functionality later when we support pt
|
||||
* of other ACPI dev)
|
||||
* According to https://www.kernel.org/doc/Documentation/acpi/namespace.txt,
|
||||
*
|
||||
* The Linux ACPI subsystem converts ACPI namespace objects into a Linux
|
||||
* device tree under the /sys/devices/LNXSYSTEM:00 and updates it upon
|
||||
* receiving ACPI hotplug notification events. For each device object in this
|
||||
* hierarchy there is a corresponding symbolic link in the
|
||||
* /sys/bus/acpi/devices.
|
||||
*/
|
||||
int get_more_acpi_dev_info(char *hid, uint32_t instance, struct acpi_dev_ops *ptops)
|
||||
{
|
||||
char pathbuf[128], line[32];
|
||||
int ret = -1;
|
||||
size_t ch_read;
|
||||
FILE *fp;
|
||||
|
||||
snprintf(pathbuf, sizeof(pathbuf), "/sys/bus/acpi/devices/%s:%02x/modalias", hid, instance);
|
||||
fp = fopen(pathbuf, "r");
|
||||
if (!fp)
|
||||
return ret;
|
||||
|
||||
ch_read = fread(line, 1, sizeof(line), fp);
|
||||
if (!ch_read)
|
||||
goto out;
|
||||
|
||||
strcpy(ptops->hid, hid);
|
||||
memcpy(ptops->modalias, line, ch_read);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void acpi_dev_write_dsdt(struct vmctx *ctx)
|
||||
{
|
||||
int i;
|
||||
struct acpi_dev_ops *ops;
|
||||
|
||||
for (i = 0; i < acpi_dev_idx; i++) {
|
||||
ops = acpi_dev_finddev(acpi_devs[i].hid);
|
||||
if (ops != NULL && ops->write_dsdt) {
|
||||
ops->write_dsdt(ctx, &acpi_devs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void acpi_dev_write_madt(FILE *fp, struct vmctx *ctx)
|
||||
{
|
||||
int i;
|
||||
struct acpi_dev_ops *ops;
|
||||
|
||||
for (i = 0; i < acpi_dev_idx; i++) {
|
||||
ops = acpi_dev_finddev(acpi_devs[i].hid);
|
||||
if (ops != NULL && ops->write_madt) {
|
||||
ops->write_madt(ctx, fp, &acpi_devs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int init_acpi_dev(struct vmctx *ctx, struct acpi_dev_ops *ops, struct acrn_acpidev *acpidev)
|
||||
{
|
||||
struct inout_port iop;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ACPIDEV_RES_NUM; i++) {
|
||||
if (acpidev->res[i].type == IO_PORT_RES) {
|
||||
bzero(&iop, sizeof(iop));
|
||||
iop.name = "Passthrough";
|
||||
iop.port = acpidev->res[i].pio_res.port_address;
|
||||
iop.size = acpidev->res[i].pio_res.size;
|
||||
iop.flags = IOPORT_F_INOUT;
|
||||
iop.handler = default_inout;
|
||||
if (iop.port + iop.size >= MAX_IOPORTS) {
|
||||
pr_err("ACPI device port resource 0x%x-0x%x exceed valid range",
|
||||
iop.port, iop.port + iop.size);
|
||||
return -EINVAL;
|
||||
} else if(register_inout(&iop)) {
|
||||
pr_err("ACPI device port resource 0x%x-0x%x conflict with allocated port address",
|
||||
iop.port, iop.port + iop.size);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ops->init(ctx, acpidev);
|
||||
}
|
||||
|
||||
void deinit_acpi_dev(struct vmctx *ctx, struct acpi_dev_ops *ops, struct acrn_acpidev *acpidev)
|
||||
{
|
||||
struct inout_port iop;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < ACPIDEV_RES_NUM; i++) {
|
||||
if (acpidev->res[i].type == IO_PORT_RES) {
|
||||
bzero(&iop, sizeof(iop));
|
||||
iop.name = "Passthrough";
|
||||
iop.port = acpidev->res[i].pio_res.port_address;
|
||||
iop.size = acpidev->res[i].pio_res.size;
|
||||
unregister_inout(&iop);
|
||||
}
|
||||
}
|
||||
|
||||
ops->deinit(ctx, acpidev);
|
||||
}
|
||||
|
||||
int init_acpi_devs(struct vmctx *ctx)
|
||||
{
|
||||
int i, err = 0;
|
||||
struct acpi_dev_ops *ops;
|
||||
|
||||
for (i = 0; i < acpi_dev_idx; i++) {
|
||||
ops = acpi_dev_finddev(acpi_devs[i].hid);
|
||||
if (ops != NULL) {
|
||||
err = init_acpi_dev(ctx, ops, &acpi_devs[i].dev);
|
||||
pr_notice("pt acpidev[%d] hid:%s uid:%s err:%d\n", i,
|
||||
acpi_devs[i].hid, acpi_devs[i].uid, err);
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
goto init_acpi_devs_fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
init_acpi_devs_fail:
|
||||
for (; i>=0; i--) {
|
||||
ops = acpi_dev_finddev(acpi_devs[i].hid);
|
||||
if (ops != NULL)
|
||||
deinit_acpi_dev(ctx, ops, &acpi_devs[i].dev);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void deinit_acpi_devs(struct vmctx *ctx)
|
||||
{
|
||||
int i;
|
||||
struct acpi_dev_ops *ops;
|
||||
|
||||
for (i = 0; i < acpi_dev_idx; i++) {
|
||||
ops = acpi_dev_finddev(acpi_devs[i].hid);
|
||||
if (ops != NULL)
|
||||
deinit_acpi_dev(ctx, ops, &acpi_devs[i].dev);
|
||||
|
||||
free(acpi_devs[i].hid);
|
||||
free(acpi_devs[i].cid);
|
||||
free(acpi_devs[i].uid);
|
||||
free(acpi_devs[i].dsdt);
|
||||
}
|
||||
}
|
||||
|
||||
int init_pt_acpidev(struct vmctx *ctx, struct acrn_acpidev *dev)
|
||||
{
|
||||
return vm_assign_acpidev(ctx, dev);
|
||||
}
|
||||
|
||||
void deinit_pt_acpidev(struct vmctx *ctx, struct acrn_acpidev *dev)
|
||||
{
|
||||
vm_deassign_acpidev(ctx, dev);
|
||||
}
|
@ -37,8 +37,6 @@ struct mmio_dev_ops {
|
||||
SET_DECLARE(mmio_dev_ops_set, struct mmio_dev_ops);
|
||||
#define DEFINE_MMIO_DEV(x) DATA_SET(mmio_dev_ops_set, x)
|
||||
|
||||
SET_DECLARE(acpi_dev_pt_ops_set, struct acpi_dev_pt_ops);
|
||||
|
||||
struct mmio_dev_ops pt_mmiodev;
|
||||
|
||||
static uint32_t mmio_dev_base = MMIO_DEV_BASE;
|
||||
@ -85,28 +83,6 @@ int mmio_dev_alloc_gpa_resource32(uint32_t *addr, uint32_t size_in)
|
||||
}
|
||||
}
|
||||
|
||||
int create_pt_acpidev(char *opt)
|
||||
{
|
||||
struct mmio_dev *dev;
|
||||
struct acpi_dev_pt_ops **adptops, *ops;
|
||||
|
||||
SET_FOREACH(adptops, acpi_dev_pt_ops_set) {
|
||||
ops = *adptops;
|
||||
if (ops->match && ops->match(opt)) {
|
||||
dev = alloc_mmiodev();
|
||||
if (!dev) {
|
||||
pr_err("Failed to create MMIO device %s due to exceeding max MMIO device number\n", opt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ops->init ? ops->init(opt, dev) : -1;
|
||||
}
|
||||
}
|
||||
|
||||
pr_err("Unrecognized or unsupported ACPI device HID: %s\n", opt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse /proc/iomem to see if there's an entry that contains name.
|
||||
* Returns false if not found,
|
||||
@ -115,10 +91,11 @@ int create_pt_acpidev(char *opt)
|
||||
*
|
||||
* @pre (name != NULL) && (strlen(name) > 0)
|
||||
*/
|
||||
bool get_mmio_hpa_resource(char *name, uint64_t *res_start, uint64_t *res_size)
|
||||
bool get_mmio_hpa_resource(char *name, uint64_t *res_start, uint64_t *res_size, uint8_t region_index)
|
||||
{
|
||||
FILE *fp;
|
||||
uint64_t start, end;
|
||||
uint8_t region_count = 0;
|
||||
bool found = false;
|
||||
char line[128];
|
||||
char *cp;
|
||||
@ -142,11 +119,14 @@ bool get_mmio_hpa_resource(char *name, uint64_t *res_start, uint64_t *res_size)
|
||||
break;
|
||||
}
|
||||
|
||||
*res_start = start;
|
||||
/* proc/iomem displays regions like: 000-fff so we add 1 as size */
|
||||
*res_size = end - start + 1;
|
||||
found = true;
|
||||
break;
|
||||
if (region_count == region_index) {
|
||||
*res_start = start;
|
||||
/* proc/iomem displays regions like: 000-fff so we add 1 as size */
|
||||
*res_size = end - start + 1;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
region_count++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,54 +134,6 @@ bool get_mmio_hpa_resource(char *name, uint64_t *res_start, uint64_t *res_size)
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search /sys/bus/acpi/devices for given HID and fill modalias to ops.
|
||||
* (TODO: we may add more functionality later when we support pt
|
||||
* of other ACPI dev)
|
||||
* According to https://www.kernel.org/doc/Documentation/acpi/namespace.txt,
|
||||
*
|
||||
* The Linux ACPI subsystem converts ACPI namespace objects into a Linux
|
||||
* device tree under the /sys/devices/LNXSYSTEM:00 and updates it upon
|
||||
* receiving ACPI hotplug notification events. For each device object in this
|
||||
* hierarchy there is a corresponding symbolic link in the
|
||||
* /sys/bus/acpi/devices.
|
||||
*/
|
||||
int get_more_acpi_dev_info(char *hid, uint32_t instance, struct acpi_dev_pt_ops *ops)
|
||||
{
|
||||
char pathbuf[128], line[32];
|
||||
int ret = -1;
|
||||
size_t ch_read;
|
||||
FILE *fp;
|
||||
|
||||
snprintf(pathbuf, sizeof(pathbuf), "/sys/bus/acpi/devices/%s:%02x/modalias", hid, instance);
|
||||
fp = fopen(pathbuf, "r");
|
||||
if (!fp)
|
||||
return ret;
|
||||
|
||||
ch_read = fread(line, 1, sizeof(line), fp);
|
||||
if (!ch_read)
|
||||
goto out;
|
||||
|
||||
memcpy(ops->hid, hid, 8);
|
||||
memcpy(ops->modalias, line, ch_read);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void acpi_dev_write_dsdt(struct vmctx *ctx)
|
||||
{
|
||||
struct acpi_dev_pt_ops **adptops, *ops;
|
||||
|
||||
SET_FOREACH(adptops, acpi_dev_pt_ops_set) {
|
||||
ops = *adptops;
|
||||
if (ops->write_dsdt)
|
||||
ops->write_dsdt(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int create_pt_mmiodev(char *opt)
|
||||
{
|
||||
|
||||
@ -318,16 +250,6 @@ 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.
|
||||
*/
|
||||
.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
|
||||
|
@ -73,7 +73,7 @@
|
||||
#include "log.h"
|
||||
#include "vssram.h"
|
||||
#include "vmmapi.h"
|
||||
#include "mmio_dev.h"
|
||||
#include "acpi_dev.h"
|
||||
|
||||
/*
|
||||
* Define the base address of the ACPI tables, and the offsets to
|
||||
@ -383,6 +383,8 @@ basl_fwrite_madt(FILE *fp, struct vmctx *ctx)
|
||||
EFPRINTF(fp, "\n");
|
||||
}
|
||||
|
||||
acpi_dev_write_madt(fp, ctx);
|
||||
|
||||
/* Local APIC NMI is connected to LINT 1 on all CPUs */
|
||||
EFPRINTF(fp, "[0001]\t\tSubtable Type : 04\n");
|
||||
EFPRINTF(fp, "[0001]\t\tLength : 06\n");
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "tpm.h"
|
||||
#include "tpm_internal.h"
|
||||
#include "log.h"
|
||||
#include "mmio_dev.h"
|
||||
#include "dm.h"
|
||||
|
||||
static int tpm_debug;
|
||||
@ -28,7 +27,7 @@ static int tpm_debug;
|
||||
#define STR_MAX_LEN 1024U
|
||||
static char *sock_path = NULL;
|
||||
static uint32_t vtpm_crb_mmio_addr = 0U;
|
||||
struct acpi_dev_pt_ops pt_acpi_dev;
|
||||
struct acpi_dev_ops pt_acpi_dev;
|
||||
|
||||
#define TPM2_TABLE_SYSFS_PATH "/sys/firmware/acpi/tables/TPM2"
|
||||
|
||||
@ -76,7 +75,7 @@ static int is_tpm2_eventlog_supported(struct acpi_table_tpm2 *tpm2)
|
||||
static int is_hid_tpm2_device(char *opts)
|
||||
{
|
||||
int ret;
|
||||
struct acpi_dev_pt_ops *ops = &pt_acpi_dev;
|
||||
struct acpi_dev_ops *ops = &pt_acpi_dev;
|
||||
uint32_t uid = 0;
|
||||
char *devopts, *hid, *vtopts;
|
||||
|
||||
@ -102,7 +101,7 @@ static int is_hid_tpm2_device(char *opts)
|
||||
* @pre: hid should be a valid HID of the TPM2 device being passed-through.
|
||||
* @pre: tpm2dev != NULL
|
||||
*/
|
||||
static int init_tpm2_pt(char *opts, struct mmio_dev *tpm2dev)
|
||||
static int create_tpm2_pt(char *opts, struct acpi_dev *tpm2dev)
|
||||
{
|
||||
int err = 0;
|
||||
uint64_t tpm2_buffer_hpa, tpm2_buffer_size;
|
||||
@ -129,10 +128,13 @@ static int init_tpm2_pt(char *opts, struct mmio_dev *tpm2dev)
|
||||
*/
|
||||
if (vtopts != NULL ){
|
||||
vtopts[0] = ':';
|
||||
if(!strncmp(vtopts + 1, "uid=", 4)) {
|
||||
strcpy(vtopts + 1, vtopts + 5);
|
||||
}
|
||||
}
|
||||
|
||||
/* parse /proc/iomem to find the address and size of tpm buffer */
|
||||
if (!get_mmio_hpa_resource(devopts, &tpm2_buffer_hpa, &tpm2_buffer_size)) {
|
||||
if (!get_mmio_hpa_resource(devopts, &tpm2_buffer_hpa, &tpm2_buffer_size, 0)) {
|
||||
free(devopts);
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -163,16 +165,18 @@ static int init_tpm2_pt(char *opts, struct mmio_dev *tpm2dev)
|
||||
|
||||
strncpy(tpm2dev->name, "MSFT0101", 8);
|
||||
strncpy(tpm2dev->dev.name, "tpm2", 4);
|
||||
tpm2dev->dev.res[0].host_pa = tpm2_buffer_hpa;
|
||||
tpm2dev->dev.res[0].user_vm_pa = tpm2_buffer_hpa;
|
||||
tpm2dev->dev.res[0].size = tpm2_buffer_size;
|
||||
tpm2dev->dev.res[0].type = MEMORY_RES;
|
||||
tpm2dev->dev.res[0].mmio_res.host_pa = tpm2_buffer_hpa;
|
||||
tpm2dev->dev.res[0].mmio_res.user_vm_pa = tpm2_buffer_hpa;
|
||||
tpm2dev->dev.res[0].mmio_res.size = tpm2_buffer_size;
|
||||
|
||||
/* Search for eventlog */
|
||||
if (is_tpm2_eventlog_supported(&tpm2) &&
|
||||
!mmio_dev_alloc_gpa_resource32(&base, tpm2.laml)) {
|
||||
tpm2dev->dev.res[1].host_pa = tpm2.lasa;
|
||||
tpm2dev->dev.res[1].user_vm_pa = base;
|
||||
tpm2dev->dev.res[1].size = tpm2.laml;
|
||||
tpm2dev->dev.res[1].type = MEMORY_RES;
|
||||
tpm2dev->dev.res[1].mmio_res.host_pa = tpm2.lasa;
|
||||
tpm2dev->dev.res[1].mmio_res.user_vm_pa = base;
|
||||
tpm2dev->dev.res[1].mmio_res.size = tpm2.laml;
|
||||
}
|
||||
|
||||
pt_tpm2 = true;
|
||||
@ -180,13 +184,21 @@ static int init_tpm2_pt(char *opts, struct mmio_dev *tpm2dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_tpm2_pt(struct vmctx *ctx, struct acrn_acpidev *tmp2_dev)
|
||||
{
|
||||
if(!ctx || !tmp2_dev)
|
||||
return -EINVAL;
|
||||
|
||||
return init_pt_acpidev(ctx, tmp2_dev);
|
||||
}
|
||||
|
||||
uint32_t get_vtpm_crb_mmio_addr(void) {
|
||||
return vtpm_crb_mmio_addr;
|
||||
}
|
||||
|
||||
static struct acrn_mmiodev *get_tpm2_mmio_dev()
|
||||
static struct acrn_acpidev *get_tpm2_acpi_dev()
|
||||
{
|
||||
struct mmio_dev *dev = get_mmiodev("MSFT0101");
|
||||
struct acpi_dev *dev = get_acpidev("MSFT0101", "0");
|
||||
return dev ? &dev->dev : NULL;
|
||||
}
|
||||
|
||||
@ -195,8 +207,8 @@ uint32_t get_tpm_crb_mmio_addr(void)
|
||||
uint32_t base;
|
||||
|
||||
if (pt_tpm2) {
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
base = d ? (uint32_t)d->res[0].host_pa : 0U;
|
||||
struct acrn_acpidev *d = get_tpm2_acpi_dev();
|
||||
base = d ? (uint32_t)d->res[0].mmio_res.host_pa : 0U;
|
||||
} else {
|
||||
base = get_vtpm_crb_mmio_addr();
|
||||
}
|
||||
@ -206,20 +218,20 @@ uint32_t get_tpm_crb_mmio_addr(void)
|
||||
|
||||
static uint32_t get_tpm_crb_mmio_size(void)
|
||||
{
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
return (pt_tpm2 && d) ? d->res[0].size : TPM_CRB_MMIO_SIZE;
|
||||
struct acrn_acpidev *d = get_tpm2_acpi_dev();
|
||||
return (pt_tpm2 && d) ? d->res[0].mmio_res.size : TPM_CRB_MMIO_SIZE;
|
||||
}
|
||||
|
||||
static uint32_t get_tpm2_table_minimal_log_length(void)
|
||||
{
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
return (pt_tpm2 && d && d->res[1].host_pa) ? d->res[1].size : 0U;
|
||||
struct acrn_acpidev *d = get_tpm2_acpi_dev();
|
||||
return (pt_tpm2 && d && d->res[1].mmio_res.host_pa) ? d->res[1].mmio_res.size : 0U;
|
||||
}
|
||||
|
||||
static uint64_t get_tpm2_table_log_address(void)
|
||||
{
|
||||
struct acrn_mmiodev *d = get_tpm2_mmio_dev();
|
||||
return (pt_tpm2 && d && d->res[1].host_pa) ? d->res[1].user_vm_pa : 0UL;
|
||||
struct acrn_acpidev *d = get_tpm2_acpi_dev();
|
||||
return (pt_tpm2 && d && d->res[1].mmio_res.host_pa) ? d->res[1].mmio_res.user_vm_pa : 0UL;
|
||||
}
|
||||
|
||||
enum {
|
||||
@ -285,7 +297,7 @@ void deinit_vtpm2(struct vmctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static void tpm_write_dsdt(struct vmctx *ctx)
|
||||
static void tpm_write_dsdt(struct vmctx *ctx, struct acpi_dev *tpm_dev)
|
||||
{
|
||||
if (ctx->tpm_dev || pt_tpm2) {
|
||||
dsdt_line(" Scope (\\_SB)");
|
||||
@ -340,9 +352,10 @@ int basl_fwrite_tpm2(FILE *fp, struct vmctx *ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct acpi_dev_pt_ops pt_tpm2_dev_ops = {
|
||||
struct acpi_dev_ops pt_tpm2_dev_ops = {
|
||||
.match = is_hid_tpm2_device,
|
||||
.create = create_tpm2_pt,
|
||||
.init = init_tpm2_pt,
|
||||
.write_dsdt = tpm_write_dsdt,
|
||||
};
|
||||
DEFINE_ACPI_PT_DEV(pt_tpm2_dev_ops);
|
||||
DEFINE_ACPI_DEV(pt_tpm2_dev_ops);
|
||||
|
51
devicemodel/include/acpi_dev.h
Normal file
51
devicemodel/include/acpi_dev.h
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2022 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _ACPI_DEV_H_
|
||||
#define _ACPI_DEV_H_
|
||||
|
||||
#include "hsm_ioctl_defs.h"
|
||||
#include "mmio_dev.h"
|
||||
|
||||
struct acpi_dev {
|
||||
char name[8];
|
||||
char *hid;
|
||||
char *cid;
|
||||
char *uid;
|
||||
char *dsdt;
|
||||
struct acrn_acpidev dev;
|
||||
};
|
||||
|
||||
struct acpi_dev_ops {
|
||||
char hid[9];
|
||||
char modalias[32];
|
||||
int (*match)(char *);
|
||||
int (*create)(char *, struct acpi_dev *);
|
||||
int (*init)(struct vmctx *, struct acrn_acpidev *);
|
||||
void (*deinit)(struct vmctx *, struct acrn_acpidev *);
|
||||
void (*write_dsdt)(struct vmctx *, struct acpi_dev *);
|
||||
void (*write_madt)(struct vmctx *, FILE *fp, struct acpi_dev *);
|
||||
/* TODO: We may add more fields when we support other ACPI dev pt */
|
||||
};
|
||||
|
||||
SET_DECLARE(acpi_dev_ops_set, struct acpi_dev_ops);
|
||||
#define DEFINE_ACPI_DEV(x) DATA_SET(acpi_dev_ops_set, x);
|
||||
|
||||
struct acpi_dev *get_acpidev(char *hid, char *uid);
|
||||
int get_more_acpi_dev_info(char *hid, uint32_t instance, struct acpi_dev_ops *ops);
|
||||
void acpi_dev_write_dsdt(struct vmctx *ctx);
|
||||
void acpi_dev_write_madt(FILE *fp, struct vmctx *ctx);
|
||||
|
||||
int create_pt_acpidev(char *arg);
|
||||
|
||||
int init_acpi_devs(struct vmctx *ctx);
|
||||
void deinit_acpi_devs(struct vmctx *ctx);
|
||||
|
||||
int init_pt_acpidev(struct vmctx *ctx, struct acrn_acpidev *dev);
|
||||
void deinit_pt_acpidev(struct vmctx *ctx, struct acrn_acpidev *dev);
|
||||
|
||||
#endif /* _ACPI_DEV_H_ */
|
@ -69,6 +69,8 @@ struct inout_port {
|
||||
}; \
|
||||
DATA_SET(inout_port_set, __CONCAT(__inout_port, __LINE__))
|
||||
|
||||
int default_inout(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
|
||||
uint32_t *eax, void *arg);
|
||||
void init_inout(void);
|
||||
int emulate_inout(struct vmctx *ctx, int *pvcpu, struct acrn_pio_request *req);
|
||||
int register_inout(struct inout_port *iop);
|
||||
|
@ -15,23 +15,10 @@ struct mmio_dev {
|
||||
struct acrn_mmiodev dev;
|
||||
};
|
||||
|
||||
struct acpi_dev_pt_ops {
|
||||
char hid[8];
|
||||
char modalias[32];
|
||||
int (*match)(char *);
|
||||
int (*init)(char *, struct mmio_dev *);
|
||||
void (*write_dsdt)(struct vmctx *);
|
||||
/* TODO: We may add more fields when we support other ACPI dev pt */
|
||||
};
|
||||
|
||||
#define DEFINE_ACPI_PT_DEV(x) DATA_SET(acpi_dev_pt_ops_set, x);
|
||||
|
||||
struct mmio_dev *get_mmiodev(char *name);
|
||||
bool get_mmio_hpa_resource(char *name, uint64_t *res_start, uint64_t *res_size);
|
||||
int get_more_acpi_dev_info(char *hid, uint32_t instance, struct acpi_dev_pt_ops *ops);
|
||||
void acpi_dev_write_dsdt(struct vmctx *ctx);
|
||||
struct mmio_dev *alloc_mmiodev(void);
|
||||
bool get_mmio_hpa_resource(char *name, uint64_t *res_start, uint64_t *res_size, uint8_t region_index);
|
||||
|
||||
int create_pt_acpidev(char *arg);
|
||||
int create_pt_mmiodev(char *arg);
|
||||
|
||||
int init_mmio_devs(struct vmctx *ctx);
|
||||
|
@ -199,6 +199,8 @@ struct acrn_vm_memmap {
|
||||
#define ACRN_PTDEV_IRQ_MSI 1
|
||||
#define ACRN_PTDEV_IRQ_MSIX 2
|
||||
|
||||
#define ACRN_PTDEV_NON_PCI_BDF 0xFFFF
|
||||
|
||||
/**
|
||||
* @brief pass thru device irq data structure
|
||||
*/
|
||||
@ -261,4 +263,53 @@ struct acrn_irqfd {
|
||||
struct acrn_msi_entry msi;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Info to assign or deassign IRQ resource of ACPI device for a VM
|
||||
*/
|
||||
struct acrn_irqres {
|
||||
/** The irq number */
|
||||
uint8_t irq;
|
||||
/**
|
||||
* Polarity of the APIC I/O input signals written to MADT
|
||||
*
|
||||
* 00 Conforms to the specifications of the bus (for example, EISA is active-low for level-triggered interrupts)
|
||||
* 01 Active high
|
||||
* 10 Reserved
|
||||
* 11 Active low
|
||||
*/
|
||||
uint8_t polarity;
|
||||
/**
|
||||
* Trigger mode of the APIC I/O Input signals written to MADT
|
||||
*
|
||||
* 00 Conforms to specifications of the bus (For example, ISA is edge-triggered)
|
||||
* 01 Edge-triggered
|
||||
* 10 Reserved
|
||||
* 11 Level-triggered
|
||||
*/
|
||||
uint8_t trigger_mode;
|
||||
};
|
||||
|
||||
#define ACPIDEV_RES_NUM 8
|
||||
|
||||
/**
|
||||
* @brief Info to assign or deassign ACPI device resource for a VM
|
||||
*/
|
||||
struct acrn_acpidev {
|
||||
char name[8];
|
||||
struct acrn_acpires {
|
||||
/** acpi resource type */
|
||||
enum acpires_type {
|
||||
INVALID_RES = 0,
|
||||
MEMORY_RES,
|
||||
IO_PORT_RES,
|
||||
IRQ_RES
|
||||
} type;
|
||||
union {
|
||||
struct acrn_mmiores mmio_res;
|
||||
struct acrn_piores pio_res;
|
||||
struct acrn_irqres irq_res;
|
||||
};
|
||||
} res[ACPIDEV_RES_NUM];
|
||||
};
|
||||
|
||||
#endif /* VHM_IOCTL_DEFS_H */
|
||||
|
@ -7,7 +7,7 @@
|
||||
#ifndef _TPM_H_
|
||||
#define _TPM_H_
|
||||
|
||||
#include "mmio_dev.h"
|
||||
#include "acpi_dev.h"
|
||||
#include "acpi.h"
|
||||
|
||||
#define TPM_CRB_MMIO_ADDR 0xFED40000UL
|
||||
|
@ -139,6 +139,8 @@ int vm_assign_mmiodev(struct vmctx *ctx, struct acrn_mmiodev *mmiodev);
|
||||
int vm_deassign_mmiodev(struct vmctx *ctx, struct acrn_mmiodev *mmiodev);
|
||||
int vm_assign_pio_region(struct vmctx *ctx, struct acrn_pio_region *pio_region);
|
||||
int vm_deassign_pio_region(struct vmctx *ctx, struct acrn_pio_region *pio_region);
|
||||
int vm_assign_acpidev(struct vmctx *ctx, struct acrn_acpidev *acpidev);
|
||||
int vm_deassign_acpidev(struct vmctx *ctx, struct acrn_acpidev *acpidev);
|
||||
int vm_map_ptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
|
||||
vm_paddr_t gpa, size_t len, vm_paddr_t hpa);
|
||||
int vm_unmap_ptdev_mmio(struct vmctx *ctx, int bus, int slot, int func,
|
||||
|
Loading…
Reference in New Issue
Block a user