tpm_spapr: Support TPM for ppc64 using CRQ based interface
Implement support for TPM on ppc64 by implementing the vTPM CRQ interface as a frontend. It can use the tpm_emulator driver backend with the external swtpm. The Linux vTPM driver for ppc64 works with this emulation. This TPM emulator also handles the TPM 2 case. Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com> Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Message-Id: <20200121152935.649898-4-stefanb@linux.ibm.com> [dwg: Use device_class_set_props(), tweak Kconfig] Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
864674fa29
commit
3676bc69b3
@ -34,6 +34,12 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 -
|
||||
QEMU files related to TPM CRB interface:
|
||||
- hw/tpm/tpm_crb.c
|
||||
|
||||
|
||||
pSeries (ppc64) machines offer a tpm-spapr device model.
|
||||
|
||||
QEMU files related to the SPAPR interface:
|
||||
- hw/tpm/tpm_spapr.c
|
||||
|
||||
= fw_cfg interface =
|
||||
|
||||
The bios/firmware may read the "etc/tpm/config" fw_cfg entry for
|
||||
@ -281,7 +287,7 @@ swtpm socket --tpmstate dir=/tmp/mytpm1 \
|
||||
--log level=20
|
||||
|
||||
Command line to start QEMU with the TPM emulator device communicating with
|
||||
the swtpm:
|
||||
the swtpm (x86):
|
||||
|
||||
qemu-system-x86_64 -display sdl -accel kvm \
|
||||
-m 1024 -boot d -bios bios-256k.bin -boot menu=on \
|
||||
@ -289,6 +295,18 @@ qemu-system-x86_64 -display sdl -accel kvm \
|
||||
-tpmdev emulator,id=tpm0,chardev=chrtpm \
|
||||
-device tpm-tis,tpmdev=tpm0 test.img
|
||||
|
||||
In case a pSeries machine is emulated, use the following command line:
|
||||
|
||||
qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \
|
||||
-m 1024 -bios slof.bin -boot menu=on \
|
||||
-nodefaults -device VGA -device pci-ohci -device usb-kbd \
|
||||
-chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \
|
||||
-tpmdev emulator,id=tpm0,chardev=chrtpm \
|
||||
-device tpm-spapr,tpmdev=tpm0 \
|
||||
-device spapr-vscsi,id=scsi0,reg=0x00002000 \
|
||||
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \
|
||||
-drive file=test.img,format=raw,if=none,id=drive-virtio-disk0
|
||||
|
||||
|
||||
In case SeaBIOS is used as firmware, it should show the TPM menu item
|
||||
after entering the menu with 'ESC'.
|
||||
|
@ -22,3 +22,9 @@ config TPM_EMULATOR
|
||||
bool
|
||||
default y
|
||||
depends on TPMDEV
|
||||
|
||||
config TPM_SPAPR
|
||||
bool
|
||||
default n
|
||||
depends on TPM && PSERIES
|
||||
select TPMDEV
|
||||
|
@ -4,3 +4,4 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
|
||||
common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
|
||||
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
|
||||
common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o
|
||||
obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o
|
||||
|
379
hw/tpm/tpm_spapr.c
Normal file
379
hw/tpm/tpm_spapr.c
Normal file
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
|
||||
*
|
||||
* PAPR Virtual TPM
|
||||
*
|
||||
* Copyright (c) 2015, 2017, 2019 IBM Corporation.
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Berger <stefanb@linux.vnet.ibm.com>
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#include "sysemu/tpm_backend.h"
|
||||
#include "tpm_int.h"
|
||||
#include "tpm_util.h"
|
||||
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_vio.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define DEBUG_SPAPR 0
|
||||
|
||||
#define VIO_SPAPR_VTPM(obj) \
|
||||
OBJECT_CHECK(SpaprTpmState, (obj), TYPE_TPM_SPAPR)
|
||||
|
||||
typedef struct TpmCrq {
|
||||
uint8_t valid; /* 0x80: cmd; 0xc0: init crq */
|
||||
/* 0x81-0x83: CRQ message response */
|
||||
uint8_t msg; /* see below */
|
||||
uint16_t len; /* len of TPM request; len of TPM response */
|
||||
uint32_t data; /* rtce_dma_handle when sending TPM request */
|
||||
uint64_t reserved;
|
||||
} TpmCrq;
|
||||
|
||||
#define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND 0xC0
|
||||
#define SPAPR_VTPM_VALID_COMMAND 0x80
|
||||
#define SPAPR_VTPM_MSG_RESULT 0x80
|
||||
|
||||
/* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */
|
||||
#define SPAPR_VTPM_INIT_CRQ_RESULT 0x1
|
||||
#define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT 0x2
|
||||
|
||||
/* msg types for valid = SPAPR_VTPM_VALID_CMD */
|
||||
#define SPAPR_VTPM_GET_VERSION 0x1
|
||||
#define SPAPR_VTPM_TPM_COMMAND 0x2
|
||||
#define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3
|
||||
#define SPAPR_VTPM_PREPARE_TO_SUSPEND 0x4
|
||||
|
||||
/* response error messages */
|
||||
#define SPAPR_VTPM_VTPM_ERROR 0xff
|
||||
|
||||
/* error codes */
|
||||
#define SPAPR_VTPM_ERR_COPY_IN_FAILED 0x3
|
||||
#define SPAPR_VTPM_ERR_COPY_OUT_FAILED 0x4
|
||||
|
||||
#define TPM_SPAPR_BUFFER_MAX 4096
|
||||
|
||||
typedef struct {
|
||||
SpaprVioDevice vdev;
|
||||
|
||||
TpmCrq crq; /* track single TPM command */
|
||||
|
||||
uint8_t state;
|
||||
#define SPAPR_VTPM_STATE_NONE 0
|
||||
#define SPAPR_VTPM_STATE_EXECUTION 1
|
||||
#define SPAPR_VTPM_STATE_COMPLETION 2
|
||||
|
||||
unsigned char *buffer;
|
||||
|
||||
TPMBackendCmd cmd;
|
||||
|
||||
TPMBackend *be_driver;
|
||||
TPMVersion be_tpm_version;
|
||||
|
||||
size_t be_buffer_size;
|
||||
} SpaprTpmState;
|
||||
|
||||
/*
|
||||
* Send a request to the TPM.
|
||||
*/
|
||||
static void tpm_spapr_tpm_send(SpaprTpmState *s)
|
||||
{
|
||||
if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
|
||||
tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM");
|
||||
}
|
||||
|
||||
s->state = SPAPR_VTPM_STATE_EXECUTION;
|
||||
s->cmd = (TPMBackendCmd) {
|
||||
.locty = 0,
|
||||
.in = s->buffer,
|
||||
.in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size),
|
||||
.out = s->buffer,
|
||||
.out_len = s->be_buffer_size,
|
||||
};
|
||||
|
||||
tpm_backend_deliver_request(s->be_driver, &s->cmd);
|
||||
}
|
||||
|
||||
static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr)
|
||||
{
|
||||
long rc;
|
||||
|
||||
/* a max. of be_buffer_size bytes can be transported */
|
||||
rc = spapr_vio_dma_read(&s->vdev, dataptr,
|
||||
s->buffer, s->be_buffer_size);
|
||||
if (rc) {
|
||||
error_report("tpm_spapr_got_payload: DMA read failure");
|
||||
}
|
||||
/* let vTPM handle any malformed request */
|
||||
tpm_spapr_tpm_send(s);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq)
|
||||
{
|
||||
return spapr_vio_send_crq(dev, (uint8_t *)crq);
|
||||
}
|
||||
|
||||
static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
|
||||
{
|
||||
SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
|
||||
TpmCrq local_crq;
|
||||
TpmCrq *crq = &s->crq; /* requests only */
|
||||
int rc;
|
||||
uint8_t valid = crq_data[0];
|
||||
uint8_t msg = crq_data[1];
|
||||
|
||||
trace_tpm_spapr_do_crq(valid, msg);
|
||||
|
||||
switch (valid) {
|
||||
case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */
|
||||
|
||||
/* Respond to initialization request */
|
||||
switch (msg) {
|
||||
case SPAPR_VTPM_INIT_CRQ_RESULT:
|
||||
trace_tpm_spapr_do_crq_crq_result();
|
||||
memset(&local_crq, 0, sizeof(local_crq));
|
||||
local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
|
||||
local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT;
|
||||
spapr_tpm_send_crq(dev, &local_crq);
|
||||
break;
|
||||
|
||||
case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT:
|
||||
trace_tpm_spapr_do_crq_crq_complete_result();
|
||||
memset(&local_crq, 0, sizeof(local_crq));
|
||||
local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
|
||||
local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT;
|
||||
spapr_tpm_send_crq(dev, &local_crq);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case SPAPR_VTPM_VALID_COMMAND: /* Payloads */
|
||||
switch (msg) {
|
||||
case SPAPR_VTPM_TPM_COMMAND:
|
||||
trace_tpm_spapr_do_crq_tpm_command();
|
||||
if (s->state == SPAPR_VTPM_STATE_EXECUTION) {
|
||||
return H_BUSY;
|
||||
}
|
||||
memcpy(crq, crq_data, sizeof(*crq));
|
||||
|
||||
rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data));
|
||||
|
||||
if (rc == H_SUCCESS) {
|
||||
crq->valid = be16_to_cpu(0);
|
||||
} else {
|
||||
local_crq.valid = SPAPR_VTPM_MSG_RESULT;
|
||||
local_crq.msg = SPAPR_VTPM_VTPM_ERROR;
|
||||
local_crq.len = cpu_to_be16(0);
|
||||
local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED);
|
||||
spapr_tpm_send_crq(dev, &local_crq);
|
||||
}
|
||||
break;
|
||||
|
||||
case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE:
|
||||
trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size);
|
||||
local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
|
||||
local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE |
|
||||
SPAPR_VTPM_MSG_RESULT;
|
||||
local_crq.len = cpu_to_be16(s->be_buffer_size);
|
||||
spapr_tpm_send_crq(dev, &local_crq);
|
||||
break;
|
||||
|
||||
case SPAPR_VTPM_GET_VERSION:
|
||||
local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
|
||||
local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT;
|
||||
local_crq.len = cpu_to_be16(0);
|
||||
switch (s->be_tpm_version) {
|
||||
case TPM_VERSION_1_2:
|
||||
local_crq.data = cpu_to_be32(1);
|
||||
break;
|
||||
case TPM_VERSION_2_0:
|
||||
local_crq.data = cpu_to_be32(2);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data));
|
||||
spapr_tpm_send_crq(dev, &local_crq);
|
||||
break;
|
||||
|
||||
case SPAPR_VTPM_PREPARE_TO_SUSPEND:
|
||||
trace_tpm_spapr_do_crq_prepare_to_suspend();
|
||||
local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
|
||||
local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND |
|
||||
SPAPR_VTPM_MSG_RESULT;
|
||||
spapr_tpm_send_crq(dev, &local_crq);
|
||||
break;
|
||||
|
||||
default:
|
||||
trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
trace_tpm_spapr_do_crq_unknown_crq(valid, msg);
|
||||
};
|
||||
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static void tpm_spapr_request_completed(TPMIf *ti, int ret)
|
||||
{
|
||||
SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
|
||||
TpmCrq *crq = &s->crq;
|
||||
uint32_t len;
|
||||
int rc;
|
||||
|
||||
s->state = SPAPR_VTPM_STATE_COMPLETION;
|
||||
|
||||
/* a max. of be_buffer_size bytes can be transported */
|
||||
len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size);
|
||||
rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data),
|
||||
s->buffer, len);
|
||||
|
||||
if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
|
||||
tpm_util_show_buffer(s->buffer, len, "From TPM");
|
||||
}
|
||||
|
||||
crq->valid = SPAPR_VTPM_MSG_RESULT;
|
||||
if (rc == H_SUCCESS) {
|
||||
crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT;
|
||||
crq->len = cpu_to_be16(len);
|
||||
} else {
|
||||
error_report("%s: DMA write failure", __func__);
|
||||
crq->msg = SPAPR_VTPM_VTPM_ERROR;
|
||||
crq->len = cpu_to_be16(0);
|
||||
crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED);
|
||||
}
|
||||
|
||||
rc = spapr_tpm_send_crq(&s->vdev, crq);
|
||||
if (rc) {
|
||||
error_report("%s: Error sending response", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize)
|
||||
{
|
||||
return tpm_backend_startup_tpm(s->be_driver, buffersize);
|
||||
}
|
||||
|
||||
static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev)
|
||||
{
|
||||
SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
|
||||
|
||||
switch (s->be_tpm_version) {
|
||||
case TPM_VERSION_1_2:
|
||||
return "IBM,vtpm";
|
||||
case TPM_VERSION_2_0:
|
||||
return "IBM,vtpm20";
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void tpm_spapr_reset(SpaprVioDevice *dev)
|
||||
{
|
||||
SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
|
||||
|
||||
s->state = SPAPR_VTPM_STATE_NONE;
|
||||
|
||||
s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
|
||||
|
||||
s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
|
||||
TPM_SPAPR_BUFFER_MAX);
|
||||
|
||||
tpm_backend_reset(s->be_driver);
|
||||
tpm_spapr_do_startup_tpm(s, s->be_buffer_size);
|
||||
}
|
||||
|
||||
static enum TPMVersion tpm_spapr_get_version(TPMIf *ti)
|
||||
{
|
||||
SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
|
||||
|
||||
if (tpm_backend_had_startup_error(s->be_driver)) {
|
||||
return TPM_VERSION_UNSPEC;
|
||||
}
|
||||
|
||||
return tpm_backend_get_tpm_version(s->be_driver);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_spapr_vtpm = {
|
||||
.name = "tpm-spapr",
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static Property tpm_spapr_properties[] = {
|
||||
DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev),
|
||||
DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
|
||||
{
|
||||
SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
|
||||
|
||||
if (!tpm_find()) {
|
||||
error_setg(errp, "at most one TPM device is permitted");
|
||||
return;
|
||||
}
|
||||
|
||||
dev->crq.SendFunc = tpm_spapr_do_crq;
|
||||
|
||||
if (!s->be_driver) {
|
||||
error_setg(errp, "'tpmdev' property is required");
|
||||
return;
|
||||
}
|
||||
s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX);
|
||||
}
|
||||
|
||||
static void tpm_spapr_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
|
||||
TPMIfClass *tc = TPM_IF_CLASS(klass);
|
||||
|
||||
k->realize = tpm_spapr_realizefn;
|
||||
k->reset = tpm_spapr_reset;
|
||||
k->dt_name = "vtpm";
|
||||
k->dt_type = "IBM,vtpm";
|
||||
k->get_dt_compatible = tpm_spapr_get_dt_compatible;
|
||||
k->signal_mask = 0x00000001;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
device_class_set_props(dc, tpm_spapr_properties);
|
||||
k->rtce_window_size = 0x10000000;
|
||||
dc->vmsd = &vmstate_spapr_vtpm;
|
||||
|
||||
tc->model = TPM_MODEL_TPM_SPAPR;
|
||||
tc->get_version = tpm_spapr_get_version;
|
||||
tc->request_completed = tpm_spapr_request_completed;
|
||||
}
|
||||
|
||||
static const TypeInfo tpm_spapr_info = {
|
||||
.name = TYPE_TPM_SPAPR,
|
||||
.parent = TYPE_VIO_SPAPR_DEVICE,
|
||||
.instance_size = sizeof(SpaprTpmState),
|
||||
.class_init = tpm_spapr_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_TPM_IF },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void tpm_spapr_register_types(void)
|
||||
{
|
||||
type_register_static(&tpm_spapr_info);
|
||||
}
|
||||
|
||||
type_init(tpm_spapr_register_types)
|
@ -55,3 +55,15 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u"
|
||||
|
||||
# tpm_ppi.c
|
||||
tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu"
|
||||
|
||||
# hw/tpm/tpm_spapr.c
|
||||
tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s"
|
||||
tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x"
|
||||
tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT"
|
||||
tpm_spapr_do_crq_crq_complete_result(void) "SPAPR_VTPM_INIT_CRQ_COMP_RESULT"
|
||||
tpm_spapr_do_crq_tpm_command(void) "got TPM command payload"
|
||||
tpm_spapr_do_crq_tpm_get_rtce_buffer_size(size_t buffersize) "response: buffer size is %zu"
|
||||
tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u"
|
||||
tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend"
|
||||
tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x"
|
||||
tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..."
|
||||
|
@ -45,11 +45,14 @@ typedef struct TPMIfClass {
|
||||
|
||||
#define TYPE_TPM_TIS "tpm-tis"
|
||||
#define TYPE_TPM_CRB "tpm-crb"
|
||||
#define TYPE_TPM_SPAPR "tpm-spapr"
|
||||
|
||||
#define TPM_IS_TIS(chr) \
|
||||
object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS)
|
||||
#define TPM_IS_CRB(chr) \
|
||||
object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB)
|
||||
#define TPM_IS_SPAPR(chr) \
|
||||
object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR)
|
||||
|
||||
/* returns NULL unless there is exactly one TPM device */
|
||||
static inline TPMIf *tpm_find(void)
|
||||
|
@ -12,11 +12,11 @@
|
||||
#
|
||||
# @tpm-tis: TPM TIS model
|
||||
# @tpm-crb: TPM CRB model (since 2.12)
|
||||
# @tpm-spapr: TPM SPAPR model (since 5.0)
|
||||
#
|
||||
# Since: 1.5
|
||||
##
|
||||
{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb' ] }
|
||||
|
||||
{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb', 'tpm-spapr' ] }
|
||||
##
|
||||
# @query-tpm-models:
|
||||
#
|
||||
@ -29,7 +29,7 @@
|
||||
# Example:
|
||||
#
|
||||
# -> { "execute": "query-tpm-models" }
|
||||
# <- { "return": [ "tpm-tis", "tpm-crb" ] }
|
||||
# <- { "return": [ "tpm-tis", "tpm-crb", "tpm-spapr" ] }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
|
||||
|
Loading…
Reference in New Issue
Block a user