mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
Merge tag 'pull-tpm-2026-06-01-1' of https://github.com/stefanberger/qemu-tpm into staging
Merge tpm 2026/06/01 v1 # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEuBi5yt+QicLVzsZrda1lgCoLQhEFAmod/1EACgkQda1lgCoL # QhGFmwf/SDA8DQGekVksB+TiDV11a+2I8FzBHJmQ2RhKbSGxY77ZbWei+Z45fU9/ # 2e0aDizw7GDRPGthKChjOYA5SAVf7gwUaSkhv21xDNgsddcdCr05y1RljOfShtbw # S55XOk6Tx2zX/00nTqskyw9bqz2YwnAh5vPjfDWy6TV5k7Q3BlMyooFeJu/19pU7 # RnMLfHdJHlYSQ2Bn4ZT6agXsoQIvnJK51Poq0TJQo0PW8kWFwcp13Ic+uyvRfkF3 # U6JdTGBXJxCHMgIkO4EG4o5PT7Dy8miKFepJCUgyjHesi7iFYQlIAnsJth9anMjL # zoqnMVNN1jVrcuzVLG9oNHB7+hZ/Eg== # =Wlez # -----END PGP SIGNATURE----- # gpg: Signature made Mon 01 Jun 2026 17:53:21 EDT # gpg: using RSA key B818B9CADF9089C2D5CEC66B75AD65802A0B4211 # gpg: Good signature from "Stefan Berger <stefanb@linux.vnet.ibm.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: B818 B9CA DF90 89C2 D5CE C66B 75AD 6580 2A0B 4211 * tag 'pull-tpm-2026-06-01-1' of https://github.com/stefanberger/qemu-tpm: tpm_emulator: Disconnect if response exceeds negotiated buffer size tpm_emulator: Reject a buffer size different than what was requested hw/tpm: Add support for VM migration with TPM CRB chunking test/qtest: Add test for tpm crb chunking hw/tpm: Implement TPM CRB chunking logic hw/tpm: Add internal buffer state for chunking hw/tpm: Refactor CRB_CTRL_START register access hw/tpm: Add TPM CRB chunking fields ui/vdagent: Use VMSTATE_GBYTEARRAY to safely migrate outbuf migration/vmstate: Add VMState support for GByteArray tests: Add a TPM TIS I2C swtpm test tests: Check whether the I2C master flag is set tests: Rename id of tpmdev to tpm0 tests: Convert string arrays to byte arrays tests: Have TPM I2C read/write functions take QTestState as first parameter tests: Move TPM I2C bus read/write functions to common files Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
@@ -176,8 +176,10 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
|
||||
bool *selftest_done,
|
||||
Error **errp)
|
||||
{
|
||||
ssize_t ret;
|
||||
bool is_selftest = false;
|
||||
Error *local_err = NULL;
|
||||
uint32_t to_read;
|
||||
ssize_t ret;
|
||||
|
||||
if (selftest_done) {
|
||||
*selftest_done = false;
|
||||
@@ -195,9 +197,25 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Size of response from emulator must be <= out_len (= negotiated buffer
|
||||
* size)
|
||||
*/
|
||||
to_read = tpm_cmd_get_size(out);
|
||||
if (to_read > out_len) {
|
||||
if (qio_channel_shutdown(tpm_emu->data_ioc, QIO_CHANNEL_SHUTDOWN_BOTH,
|
||||
&local_err) < 0) {
|
||||
error_report_err(local_err);
|
||||
}
|
||||
error_setg(errp, "tpm-emulator: Disconnected after receiving "
|
||||
"unacceptable large response (%u > %u)",
|
||||
to_read, out_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = qio_channel_read_all(tpm_emu->data_ioc,
|
||||
(char *)out + sizeof(struct tpm_resp_hdr),
|
||||
tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp);
|
||||
to_read - sizeof(struct tpm_resp_hdr), errp);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -364,6 +382,7 @@ static int tpm_emulator_set_buffer_size(TPMBackend *tb,
|
||||
{
|
||||
TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
|
||||
ptm_setbuffersize psbs;
|
||||
size_t tpm_buffersize;
|
||||
|
||||
if (tpm_emulator_stop_tpm(tb, errp) < 0) {
|
||||
return -1;
|
||||
@@ -387,8 +406,18 @@ static int tpm_emulator_set_buffer_size(TPMBackend *tb,
|
||||
return -1;
|
||||
}
|
||||
|
||||
tpm_buffersize = be32_to_cpu(psbs.u.resp.buffersize);
|
||||
/* Reject different buffer size used by the TPM than what was requested. */
|
||||
if (wanted_size != 0 && wanted_size != tpm_buffersize) {
|
||||
error_setg(errp,
|
||||
"tpm-emulator: TPM did not accept the requested buffer size "
|
||||
"of %zu bytes but adjusted it to %zu bytes",
|
||||
wanted_size, tpm_buffersize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (actual_size) {
|
||||
*actual_size = be32_to_cpu(psbs.u.resp.buffersize);
|
||||
*actual_size = tpm_buffersize;
|
||||
}
|
||||
|
||||
trace_tpm_emulator_set_buffer_size(
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
|
||||
GlobalProperty hw_compat_11_0[] = {
|
||||
{ "chardev-vc", "encoding", "cp437" },
|
||||
{ "tpm-crb", "cap-chunk", "off" },
|
||||
{ "tpm-crb", "x-allow-chunk-migration", "off" },
|
||||
};
|
||||
const size_t hw_compat_11_0_len = G_N_ELEMENTS(hw_compat_11_0);
|
||||
|
||||
|
||||
253
hw/tpm/tpm_crb.c
253
hw/tpm/tpm_crb.c
@@ -17,12 +17,14 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "hw/core/qdev-properties.h"
|
||||
#include "hw/pci/pci_ids.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "migration/blocker.h"
|
||||
#include "system/tpm_backend.h"
|
||||
#include "system/tpm_util.h"
|
||||
#include "system/reset.h"
|
||||
@@ -38,12 +40,19 @@ struct CRBState {
|
||||
TPMBackend *tpmbe;
|
||||
TPMBackendCmd cmd;
|
||||
uint32_t regs[TPM_CRB_R_MAX];
|
||||
size_t be_buffer_size;
|
||||
MemoryRegion mmio;
|
||||
MemoryRegion cmdmem;
|
||||
|
||||
size_t be_buffer_size;
|
||||
GByteArray *command_buffer;
|
||||
GByteArray *response_buffer;
|
||||
uint32_t response_offset;
|
||||
|
||||
TPMPPI ppi;
|
||||
|
||||
bool cap_chunk;
|
||||
bool allow_chunk_migration;
|
||||
Error *migration_blocker;
|
||||
};
|
||||
typedef struct CRBState CRBState;
|
||||
|
||||
@@ -58,8 +67,10 @@ DECLARE_INSTANCE_CHECKER(CRBState, CRB,
|
||||
#define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
|
||||
#define CRB_INTF_CAP_CRB_SUPPORTED 0b1
|
||||
#define CRB_INTF_IF_SELECTOR_CRB 0b1
|
||||
#define CRB_INTF_CAP_CRB_CHUNK 0b1
|
||||
|
||||
#define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
|
||||
#define TPM_HEADER_SIZE 10
|
||||
|
||||
enum crb_loc_ctrl {
|
||||
CRB_LOC_CTRL_REQUEST_ACCESS = BIT(0),
|
||||
@@ -75,6 +86,8 @@ enum crb_ctrl_req {
|
||||
|
||||
enum crb_start {
|
||||
CRB_START_INVOKE = BIT(0),
|
||||
CRB_START_RSP_RETRY = BIT(1),
|
||||
CRB_START_NEXT_CHUNK = BIT(2),
|
||||
};
|
||||
|
||||
enum crb_cancel {
|
||||
@@ -83,6 +96,13 @@ enum crb_cancel {
|
||||
|
||||
#define TPM_CRB_NO_LOCALITY 0xff
|
||||
|
||||
static void tpm_crb_clear_internal_buffers(CRBState *s)
|
||||
{
|
||||
g_byte_array_set_size(s->response_buffer, 0);
|
||||
g_byte_array_set_size(s->command_buffer, 0);
|
||||
s->response_offset = 0;
|
||||
}
|
||||
|
||||
static uint64_t tpm_crb_mmio_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -110,6 +130,69 @@ static uint8_t tpm_crb_get_active_locty(CRBState *s)
|
||||
return ARRAY_FIELD_EX32(s->regs, CRB_LOC_STATE, activeLocality);
|
||||
}
|
||||
|
||||
static bool tpm_crb_append_command_request(CRBState *s)
|
||||
{
|
||||
/*
|
||||
* The linux guest writes the TPM command to the MMIO region in chunks.
|
||||
* This function appends a chunk from the MMIO region to internal
|
||||
* command_buffer.
|
||||
*/
|
||||
void *mem = memory_region_get_ram_ptr(&s->cmdmem);
|
||||
uint32_t to_copy = 0;
|
||||
uint32_t total_request_size = 0;
|
||||
|
||||
/*
|
||||
* The initial call extracts the total TPM command size
|
||||
* from its header. For the subsequent calls, the data already
|
||||
* appended in the command_buffer is used to calculate the total
|
||||
* size, as its header stays the same.
|
||||
*/
|
||||
if (s->command_buffer->len == 0) {
|
||||
total_request_size = tpm_cmd_get_size(mem);
|
||||
if (total_request_size < TPM_HEADER_SIZE) {
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, tpmSts, 1);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 0);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
|
||||
tpm_crb_clear_internal_buffers(s);
|
||||
error_report("Command size %" PRIu32 " less than "
|
||||
"TPM header size %" PRIu32,
|
||||
total_request_size, (uint32_t)TPM_HEADER_SIZE);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
total_request_size = tpm_cmd_get_size(s->command_buffer->data);
|
||||
}
|
||||
total_request_size = MIN(total_request_size, s->be_buffer_size);
|
||||
|
||||
if (total_request_size > s->command_buffer->len) {
|
||||
uint32_t remaining = total_request_size - s->command_buffer->len;
|
||||
to_copy = MIN(remaining, CRB_CTRL_CMD_SIZE);
|
||||
g_byte_array_append(s->command_buffer, (guint8 *)mem, to_copy);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void tpm_crb_fill_command_response(CRBState *s)
|
||||
{
|
||||
/*
|
||||
* Response from the tpm backend will be stored in the internal
|
||||
* response_buffer. This function will serve that accumulated response
|
||||
* to the linux guest in chunks by writing it back to MMIO region.
|
||||
*/
|
||||
void *mem = memory_region_get_ram_ptr(&s->cmdmem);
|
||||
uint32_t remaining = s->response_buffer->len - s->response_offset;
|
||||
uint32_t to_copy = MIN(CRB_CTRL_CMD_SIZE, remaining);
|
||||
|
||||
memcpy(mem, s->response_buffer->data + s->response_offset, to_copy);
|
||||
|
||||
if (to_copy < CRB_CTRL_CMD_SIZE) {
|
||||
memset((guint8 *)mem + to_copy, 0, CRB_CTRL_CMD_SIZE - to_copy);
|
||||
}
|
||||
|
||||
s->response_offset += to_copy;
|
||||
memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE);
|
||||
}
|
||||
|
||||
static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
@@ -132,26 +215,66 @@ static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
break;
|
||||
case A_CRB_CTRL_CANCEL:
|
||||
if (val == CRB_CANCEL_INVOKE &&
|
||||
s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
|
||||
tpm_backend_cancel_cmd(s->tpmbe);
|
||||
if (val == CRB_CANCEL_INVOKE) {
|
||||
if (s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
|
||||
tpm_backend_cancel_cmd(s->tpmbe);
|
||||
}
|
||||
tpm_crb_clear_internal_buffers(s);
|
||||
}
|
||||
break;
|
||||
case A_CRB_CTRL_START:
|
||||
if (val == CRB_START_INVOKE &&
|
||||
!(s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) &&
|
||||
tpm_crb_get_active_locty(s) == locty) {
|
||||
void *mem = memory_region_get_ram_ptr(&s->cmdmem);
|
||||
|
||||
s->regs[R_CRB_CTRL_START] |= CRB_START_INVOKE;
|
||||
if (tpm_crb_get_active_locty(s) != locty) {
|
||||
break;
|
||||
}
|
||||
if (s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
|
||||
/*
|
||||
* Backend TPM is busy processing a request.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (val & CRB_START_INVOKE) {
|
||||
if (!tpm_crb_append_command_request(s)) {
|
||||
break;
|
||||
}
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 1);
|
||||
g_byte_array_set_size(s->response_buffer, s->be_buffer_size);
|
||||
s->cmd = (TPMBackendCmd) {
|
||||
.in = mem,
|
||||
.in_len = MIN(tpm_cmd_get_size(mem), s->be_buffer_size),
|
||||
.out = mem,
|
||||
.out_len = s->be_buffer_size,
|
||||
.in = s->command_buffer->data,
|
||||
.in_len = s->command_buffer->len,
|
||||
.out = s->response_buffer->data,
|
||||
.out_len = s->response_buffer->len,
|
||||
};
|
||||
|
||||
tpm_backend_deliver_request(s->tpmbe, &s->cmd);
|
||||
} else if (val & CRB_START_NEXT_CHUNK) {
|
||||
if (!s->cap_chunk) {
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* nextChunk is used both while sending and receiving data.
|
||||
* To distinguish between the two, response_buffer is checked.
|
||||
* If it does not have data, then that means we have not yet
|
||||
* sent the command to the tpm backend, and therefore call
|
||||
* tpm_crb_append_command_request().
|
||||
*/
|
||||
if (s->response_buffer->len > 0 &&
|
||||
s->response_offset < s->response_buffer->len) {
|
||||
tpm_crb_fill_command_response(s);
|
||||
} else {
|
||||
if (!tpm_crb_append_command_request(s)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
|
||||
} else if (val & CRB_START_RSP_RETRY) {
|
||||
if (!s->cap_chunk) {
|
||||
break;
|
||||
}
|
||||
if (s->response_buffer->len > 0) {
|
||||
s->response_offset = 0;
|
||||
tpm_crb_fill_command_response(s);
|
||||
}
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, crbRspRetry, 0);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
|
||||
}
|
||||
break;
|
||||
case A_CRB_LOC_CTRL:
|
||||
@@ -192,12 +315,25 @@ static void tpm_crb_request_completed(TPMIf *ti, int ret)
|
||||
{
|
||||
CRBState *s = CRB(ti);
|
||||
|
||||
s->regs[R_CRB_CTRL_START] &= ~CRB_START_INVOKE;
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 0);
|
||||
if (ret != 0) {
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
|
||||
tpmSts, 1); /* fatal error */
|
||||
tpm_crb_clear_internal_buffers(s);
|
||||
} else {
|
||||
uint32_t actual_resp_size = tpm_cmd_get_size(s->response_buffer->data);
|
||||
uint32_t total_resp_size = MIN(actual_resp_size, s->be_buffer_size);
|
||||
g_byte_array_set_size(s->response_buffer, total_resp_size);
|
||||
s->response_offset = 0;
|
||||
}
|
||||
memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE);
|
||||
/*
|
||||
* Send the first chunk. Subsequent chunks will be sent
|
||||
* on receiving nextChunk from the guest
|
||||
*/
|
||||
tpm_crb_fill_command_response(s);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, crbRspRetry, 0);
|
||||
g_byte_array_set_size(s->command_buffer, 0);
|
||||
}
|
||||
|
||||
static enum TPMVersion tpm_crb_get_version(TPMIf *ti)
|
||||
@@ -216,17 +352,68 @@ static int tpm_crb_pre_save(void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tpm_crb_chunk_needed(void *opaque)
|
||||
{
|
||||
CRBState *s = opaque;
|
||||
|
||||
if (!s->allow_chunk_migration) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((s->command_buffer && s->command_buffer->len > 0) ||
|
||||
(s->response_buffer && s->response_buffer->len > 0));
|
||||
}
|
||||
|
||||
static bool tpm_crb_chunk_post_load(void *opaque, int version_id, Error **errp)
|
||||
{
|
||||
CRBState *s = opaque;
|
||||
|
||||
/*
|
||||
* The external TPM emulator (example swtpm) determines the backend
|
||||
* buffer capacity (s->be_buffer_size). This check ensures that if we
|
||||
* migrate from a source with a PQC-enabled emulator that supports
|
||||
* larger buffers to a destination with a non-PQC emulator, the
|
||||
* migrated data does not exceed the destination's capacity.
|
||||
*/
|
||||
if (s->response_buffer->len > s->be_buffer_size ||
|
||||
s->command_buffer->len > s->be_buffer_size) {
|
||||
error_setg(errp, "tpm-crb: Buffer sizes exceed backend capacity");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_tpm_crb_chunk = {
|
||||
.name = "tpm-crb/chunk",
|
||||
.version_id = 0,
|
||||
.needed = tpm_crb_chunk_needed,
|
||||
.post_load_errp = tpm_crb_chunk_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_GBYTEARRAY(command_buffer, CRBState, 0),
|
||||
VMSTATE_GBYTEARRAY(response_buffer, CRBState, 0),
|
||||
VMSTATE_UINT32(response_offset, CRBState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_tpm_crb = {
|
||||
.name = "tpm-crb",
|
||||
.pre_save = tpm_crb_pre_save,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, CRBState, TPM_CRB_R_MAX),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
.subsections = (const VMStateDescription * const []) {
|
||||
&vmstate_tpm_crb_chunk,
|
||||
NULL,
|
||||
}
|
||||
};
|
||||
|
||||
static const Property tpm_crb_properties[] = {
|
||||
DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
|
||||
DEFINE_PROP_BOOL("cap-chunk", CRBState, cap_chunk, true),
|
||||
DEFINE_PROP_BOOL("x-allow-chunk-migration", CRBState,
|
||||
allow_chunk_migration, true),
|
||||
};
|
||||
|
||||
static void tpm_crb_reset(void *dev)
|
||||
@@ -235,6 +422,7 @@ static void tpm_crb_reset(void *dev)
|
||||
|
||||
tpm_ppi_reset(&s->ppi);
|
||||
tpm_backend_reset(s->tpmbe);
|
||||
tpm_crb_clear_internal_buffers(s);
|
||||
|
||||
memset(s->regs, 0, sizeof(s->regs));
|
||||
|
||||
@@ -258,6 +446,8 @@ static void tpm_crb_reset(void *dev)
|
||||
CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
|
||||
InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
|
||||
CapCRBChunk, s->cap_chunk ? CRB_INTF_CAP_CRB_CHUNK : 0);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
|
||||
RID, 0b0000);
|
||||
ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID2,
|
||||
@@ -268,8 +458,7 @@ static void tpm_crb_reset(void *dev)
|
||||
s->regs[R_CRB_CTRL_RSP_SIZE] = CRB_CTRL_CMD_SIZE;
|
||||
s->regs[R_CRB_CTRL_RSP_ADDR] = TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFER;
|
||||
|
||||
s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->tpmbe),
|
||||
CRB_CTRL_CMD_SIZE);
|
||||
s->be_buffer_size = tpm_backend_get_buffer_size(s->tpmbe);
|
||||
|
||||
if (tpm_backend_startup_tpm(s->tpmbe, s->be_buffer_size) < 0) {
|
||||
exit(1);
|
||||
@@ -279,6 +468,7 @@ static void tpm_crb_reset(void *dev)
|
||||
static void tpm_crb_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CRBState *s = CRB(dev);
|
||||
int ret;
|
||||
|
||||
if (!tpm_find()) {
|
||||
error_setg(errp, "at most one TPM device is permitted");
|
||||
@@ -288,6 +478,15 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
|
||||
error_setg(errp, "'tpmdev' property is required");
|
||||
return;
|
||||
}
|
||||
if (s->cap_chunk && !s->allow_chunk_migration) {
|
||||
error_setg(&s->migration_blocker,
|
||||
"The tpm-crb device does not support chunk migration with "
|
||||
"machine version less than 11.1");
|
||||
ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
|
||||
if (ret < 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &tpm_crb_memory_ops, s,
|
||||
"tpm-crb-mmio", sizeof(s->regs));
|
||||
@@ -299,6 +498,9 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion(get_system_memory(),
|
||||
TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
|
||||
|
||||
s->command_buffer = g_byte_array_new();
|
||||
s->response_buffer = g_byte_array_new();
|
||||
|
||||
tpm_ppi_init(&s->ppi, get_system_memory(),
|
||||
TPM_PPI_ADDR_BASE, OBJECT(s));
|
||||
|
||||
@@ -309,12 +511,25 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void tpm_crb_unrealize(DeviceState *dev)
|
||||
{
|
||||
CRBState *s = CRB(dev);
|
||||
|
||||
g_clear_pointer(&s->command_buffer, g_byte_array_unref);
|
||||
g_clear_pointer(&s->response_buffer, g_byte_array_unref);
|
||||
|
||||
if (s->migration_blocker) {
|
||||
migrate_del_blocker(&s->migration_blocker);
|
||||
}
|
||||
}
|
||||
|
||||
static void tpm_crb_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
TPMIfClass *tc = TPM_IF_CLASS(klass);
|
||||
|
||||
dc->realize = tpm_crb_realize;
|
||||
dc->unrealize = tpm_crb_unrealize;
|
||||
device_class_set_props(dc, tpm_crb_properties);
|
||||
dc->vmsd = &vmstate_tpm_crb;
|
||||
dc->user_creatable = true;
|
||||
|
||||
@@ -150,7 +150,7 @@ REG32(CRB_INTF_ID, 0x30)
|
||||
FIELD(CRB_INTF_ID, InterfaceVersion, 4, 4)
|
||||
FIELD(CRB_INTF_ID, CapLocality, 8, 1)
|
||||
FIELD(CRB_INTF_ID, CapCRBIdleBypass, 9, 1)
|
||||
FIELD(CRB_INTF_ID, Reserved1, 10, 1)
|
||||
FIELD(CRB_INTF_ID, CapCRBChunk, 10, 1)
|
||||
FIELD(CRB_INTF_ID, CapDataXferSizeSupport, 11, 2)
|
||||
FIELD(CRB_INTF_ID, CapFIFO, 13, 1)
|
||||
FIELD(CRB_INTF_ID, CapCRB, 14, 1)
|
||||
@@ -169,6 +169,9 @@ REG32(CRB_CTRL_STS, 0x44)
|
||||
FIELD(CRB_CTRL_STS, tpmIdle, 1, 1)
|
||||
REG32(CRB_CTRL_CANCEL, 0x48)
|
||||
REG32(CRB_CTRL_START, 0x4C)
|
||||
FIELD(CRB_CTRL_START, Start, 0, 1)
|
||||
FIELD(CRB_CTRL_START, crbRspRetry, 1, 1)
|
||||
FIELD(CRB_CTRL_START, nextChunk, 2, 1)
|
||||
REG32(CRB_INT_ENABLED, 0x50)
|
||||
REG32(CRB_INT_STS, 0x54)
|
||||
REG32(CRB_CTRL_CMD_SIZE, 0x58)
|
||||
|
||||
@@ -308,6 +308,7 @@ extern const VMStateInfo vmstate_info_bitmap;
|
||||
extern const VMStateInfo vmstate_info_qtailq;
|
||||
extern const VMStateInfo vmstate_info_gtree;
|
||||
extern const VMStateInfo vmstate_info_qlist;
|
||||
extern const VMStateInfo vmstate_info_g_byte_array;
|
||||
|
||||
#define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0)
|
||||
/*
|
||||
@@ -957,6 +958,15 @@ extern const VMStateInfo vmstate_info_qlist;
|
||||
.start = offsetof(_type, _next), \
|
||||
}
|
||||
|
||||
#define VMSTATE_GBYTEARRAY(_field, _state, _version) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.size = sizeof(GByteArray), \
|
||||
.info = &vmstate_info_g_byte_array, \
|
||||
.flags = VMS_SINGLE, \
|
||||
.offset = vmstate_offset_pointer(_state, _field, GByteArray), \
|
||||
}
|
||||
|
||||
/* _f : field name
|
||||
_f_n : num of elements field_name
|
||||
_n : num of elements
|
||||
|
||||
@@ -924,3 +924,31 @@ const VMStateInfo vmstate_info_qlist = {
|
||||
.load = load_qlist,
|
||||
.save = save_qlist,
|
||||
};
|
||||
|
||||
static int get_g_byte_array(QEMUFile *f, void *pv, size_t size,
|
||||
const VMStateField *field)
|
||||
{
|
||||
GByteArray *byte_array = *(GByteArray **)pv;
|
||||
uint32_t len = qemu_get_be32(f);
|
||||
|
||||
g_byte_array_set_size(byte_array, len);
|
||||
qemu_get_buffer(f, byte_array->data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int put_g_byte_array(QEMUFile *f, void *pv, size_t size,
|
||||
const VMStateField *field, JSONWriter *vmdesc)
|
||||
{
|
||||
GByteArray *byte_array = *(GByteArray **)pv;
|
||||
|
||||
qemu_put_be32(f, byte_array->len);
|
||||
qemu_put_buffer(f, byte_array->data, byte_array->len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VMStateInfo vmstate_info_g_byte_array = {
|
||||
.name = "GByteArray",
|
||||
.get = get_g_byte_array,
|
||||
.put = put_g_byte_array,
|
||||
};
|
||||
|
||||
@@ -244,7 +244,7 @@ qtests_arm = \
|
||||
(config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed : []) + \
|
||||
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
|
||||
(config_all_devices.has_key('CONFIG_GENERIC_LOADER') ? ['hexloader-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test', 'tpm-tis-i2c-swtpm-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_VEXPRESS') ? ['test-arm-mptimer'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_MICROBIT') ? ['microbit-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_STM32L4X5_SOC') ? qtests_stm32l4x5 : []) + \
|
||||
@@ -263,7 +263,7 @@ qtests_aarch64 = \
|
||||
(config_all_devices.has_key('CONFIG_XLNX_VERSAL') ? ['xlnx-canfd-test', 'xlnx-versal-trng-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_RASPI') ? ['bcm2835-dma-test', 'bcm2835-i2c-test'] : []) + \
|
||||
(config_all_accel.has_key('CONFIG_TCG') and \
|
||||
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
|
||||
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test', 'tpm-tis-i2c-swtpm-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
|
||||
(config_all_devices.has_key('CONFIG_NPCM8XX') ? qtests_npcm8xx : []) + \
|
||||
(config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
|
||||
@@ -401,7 +401,8 @@ qtests = {
|
||||
'tpm-crb-test': [io, tpmemu_files],
|
||||
'tpm-tis-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'],
|
||||
'tpm-tis-test': [io, tpmemu_files, 'tpm-tis-util.c'],
|
||||
'tpm-tis-i2c-test': [io, tpmemu_files, 'qtest_aspeed.c'],
|
||||
'tpm-tis-i2c-test': [io, tpmemu_files, 'tpm-tis-i2c-util.c', 'qtest_aspeed.c'],
|
||||
'tpm-tis-i2c-swtpm-test': [io, tpmemu_files, 'tpm-tis-i2c-util.c', 'qtest_aspeed.c'],
|
||||
'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'],
|
||||
'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'],
|
||||
'virtio-net-failover': test_migration_files,
|
||||
|
||||
@@ -15,18 +15,21 @@
|
||||
#include "qtest_aspeed.h"
|
||||
#include "hw/i2c/aspeed_i2c.h"
|
||||
|
||||
static bool aspeed_i2c_is_master_enabled(QTestState *s, uint32_t baseaddr)
|
||||
{
|
||||
return qtest_readl(s, baseaddr + A_I2CC_FUN_CTRL) & A_I2CD_MASTER_EN;
|
||||
}
|
||||
|
||||
static void aspeed_i2c_startup(QTestState *s, uint32_t baseaddr,
|
||||
uint8_t slave_addr, uint8_t reg)
|
||||
{
|
||||
uint32_t v;
|
||||
static int once;
|
||||
|
||||
if (!once) {
|
||||
if (!aspeed_i2c_is_master_enabled(s, baseaddr)) {
|
||||
/* one time: enable master */
|
||||
qtest_writel(s, baseaddr + A_I2CC_FUN_CTRL, 0);
|
||||
v = qtest_readl(s, baseaddr + A_I2CC_FUN_CTRL) | A_I2CD_MASTER_EN;
|
||||
qtest_writel(s, baseaddr + A_I2CC_FUN_CTRL, v);
|
||||
once = 1;
|
||||
}
|
||||
|
||||
/* select device */
|
||||
|
||||
@@ -33,6 +33,14 @@ static void tpm_crb_swtpm_test(const void *data)
|
||||
"tpm-crb", NULL);
|
||||
}
|
||||
|
||||
static void tpm_crb_chunk_swtpm_test(const void *data)
|
||||
{
|
||||
const TestState *ts = data;
|
||||
|
||||
tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_chunk_transfer,
|
||||
"tpm-crb", NULL);
|
||||
}
|
||||
|
||||
static void tpm_crb_swtpm_migration_test(const void *data)
|
||||
{
|
||||
const TestState *ts = data;
|
||||
@@ -54,6 +62,8 @@ int main(int argc, char **argv)
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_add_data_func("/tpm/crb-swtpm/test", &ts, tpm_crb_swtpm_test);
|
||||
qtest_add_data_func("/tpm/crb-chunk-swtpm/test", &ts,
|
||||
tpm_crb_chunk_swtpm_test);
|
||||
qtest_add_data_func("/tpm/crb-swtpm-migration/test", &ts,
|
||||
tpm_crb_swtpm_migration_test);
|
||||
ret = g_test_run();
|
||||
|
||||
@@ -49,8 +49,8 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
|
||||
args = g_strdup_printf(
|
||||
"%s "
|
||||
"-chardev socket,id=chr,path=%s "
|
||||
"-tpmdev emulator,id=dev,chardev=chr "
|
||||
"-device %s,tpmdev=dev",
|
||||
"-tpmdev emulator,id=tpm0,chardev=chr "
|
||||
"-device %s,tpmdev=tpm0",
|
||||
machine_options ? : "", addr->u.q_unix.path, ifmodel);
|
||||
|
||||
s = qtest_start(args);
|
||||
@@ -59,11 +59,16 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx,
|
||||
tpm_util_startup(s, tx);
|
||||
tpm_util_pcrextend(s, tx);
|
||||
|
||||
static const unsigned char tpm_pcrread_resp[] =
|
||||
"\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
|
||||
"\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
|
||||
"\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
|
||||
"\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
|
||||
static const unsigned char tpm_pcrread_resp[] = {
|
||||
0x80, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x0b, 0x03, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0xf6, 0x85,
|
||||
0x98, 0xe5, 0x86, 0x8d, 0xe6, 0x8b, 0x97, 0x29,
|
||||
0x99, 0x60, 0xf2, 0x71, 0x7d, 0x17, 0x67, 0x89,
|
||||
0xa4, 0x2f, 0x9a, 0xae, 0xa8, 0xc7, 0xb7, 0xaa,
|
||||
0x79, 0xa8, 0x62, 0x56, 0xc1, 0xde
|
||||
};
|
||||
tpm_util_pcrread(s, tx, tpm_pcrread_resp,
|
||||
sizeof(tpm_pcrread_resp));
|
||||
|
||||
@@ -105,11 +110,16 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
|
||||
tpm_util_startup(src_qemu, tx);
|
||||
tpm_util_pcrextend(src_qemu, tx);
|
||||
|
||||
static const unsigned char tpm_pcrread_resp[] =
|
||||
"\x80\x01\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00"
|
||||
"\x00\x01\x00\x0b\x03\x00\x04\x00\x00\x00\x00\x01\x00\x20\xf6\x85"
|
||||
"\x98\xe5\x86\x8d\xe6\x8b\x97\x29\x99\x60\xf2\x71\x7d\x17\x67\x89"
|
||||
"\xa4\x2f\x9a\xae\xa8\xc7\xb7\xaa\x79\xa8\x62\x56\xc1\xde";
|
||||
static const unsigned char tpm_pcrread_resp[] = {
|
||||
0x80, 0x01, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x0b, 0x03, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0xf6, 0x85,
|
||||
0x98, 0xe5, 0x86, 0x8d, 0xe6, 0x8b, 0x97, 0x29,
|
||||
0x99, 0x60, 0xf2, 0x71, 0x7d, 0x17, 0x67, 0x89,
|
||||
0xa4, 0x2f, 0x9a, 0xae, 0xa8, 0xc7, 0xb7, 0xaa,
|
||||
0x79, 0xa8, 0x62, 0x56, 0xc1, 0xde,
|
||||
};
|
||||
tpm_util_pcrread(src_qemu, tx, tpm_pcrread_resp,
|
||||
sizeof(tpm_pcrread_resp));
|
||||
|
||||
|
||||
82
tests/qtest/tpm-tis-i2c-swtpm-test.c
Normal file
82
tests/qtest/tpm-tis-i2c-swtpm-test.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* QTest testcase for TPM TIS over I2C talking to external swtpm
|
||||
*
|
||||
* Copyright (c) 2018, 2026 IBM Corporation
|
||||
* with parts borrowed from migration-test.c that is:
|
||||
* Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Berger <stefanb@linux.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "libqtest.h"
|
||||
#include "qemu/module.h"
|
||||
#include "tpm-tests.h"
|
||||
#include "tpm-tis-i2c-util.h"
|
||||
#include "qtest_aspeed.h"
|
||||
|
||||
typedef struct TestState {
|
||||
char *src_tpm_path;
|
||||
char *dst_tpm_path;
|
||||
char *uri;
|
||||
const char *machine_options;
|
||||
char *ifmodel;
|
||||
} TestState;
|
||||
|
||||
static void tpm_tis_i2c_swtpm_test(const void *data)
|
||||
{
|
||||
const TestState *ts = data;
|
||||
|
||||
tpm_test_swtpm_test(ts->src_tpm_path, tpm_tis_i2c_transfer,
|
||||
ts->ifmodel, ts->machine_options);
|
||||
}
|
||||
|
||||
static void tpm_tis_swtpm_migration_test(const void *data)
|
||||
{
|
||||
const TestState *ts = data;
|
||||
|
||||
tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path,
|
||||
ts->uri, tpm_tis_i2c_transfer,
|
||||
ts->ifmodel, ts->machine_options);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
TestState ts;
|
||||
|
||||
ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-i2c-swtpm-test.XXXXXX",
|
||||
NULL);
|
||||
ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-i2c-swtpm-test.XXXXXX",
|
||||
NULL);
|
||||
ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);
|
||||
ts.machine_options = "-machine rainier-bmc -accel tcg";
|
||||
ts.ifmodel = g_strdup_printf(
|
||||
"tpm-tis-i2c,bus=aspeed.i2c.bus.%d,address=0x%x",
|
||||
I2C_DEV_BUS_NUM, I2C_SLAVE_ADDR);
|
||||
|
||||
module_call_init(MODULE_INIT_QOM);
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
aspeed_bus_addr = ast2600_i2c_calc_bus_addr(I2C_DEV_BUS_NUM);
|
||||
|
||||
qtest_add_data_func("/tpm/tis-i2c-swtpm/test", &ts, tpm_tis_i2c_swtpm_test);
|
||||
qtest_add_data_func("/tpm/tis-i2c-swtpm-migration/test", &ts,
|
||||
tpm_tis_swtpm_migration_test);
|
||||
ret = g_test_run();
|
||||
|
||||
tpm_util_rmdir(ts.dst_tpm_path);
|
||||
g_free(ts.dst_tpm_path);
|
||||
tpm_util_rmdir(ts.src_tpm_path);
|
||||
g_free(ts.src_tpm_path);
|
||||
g_free(ts.uri);
|
||||
g_free(ts.ifmodel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "hw/pci/pci_ids.h"
|
||||
#include "qtest_aspeed.h"
|
||||
#include "tpm-emu.h"
|
||||
#include "tpm-tis-i2c-util.h"
|
||||
|
||||
#define DEBUG_TIS_TEST 0
|
||||
|
||||
@@ -36,58 +37,9 @@
|
||||
#define DPRINTF_STS \
|
||||
DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts)
|
||||
|
||||
#define I2C_SLAVE_ADDR 0x2e
|
||||
#define I2C_DEV_BUS_NUM 10
|
||||
|
||||
static const uint8_t TPM_CMD[12] =
|
||||
"\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
|
||||
|
||||
static uint32_t aspeed_bus_addr;
|
||||
|
||||
static uint8_t cur_locty = 0xff;
|
||||
|
||||
static void tpm_tis_i2c_set_locty(uint8_t locty)
|
||||
{
|
||||
if (cur_locty != locty) {
|
||||
cur_locty = locty;
|
||||
aspeed_i2c_writeb(global_qtest, aspeed_bus_addr, I2C_SLAVE_ADDR,
|
||||
TPM_I2C_REG_LOC_SEL, locty);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t tpm_tis_i2c_readb(uint8_t locty, uint8_t reg)
|
||||
{
|
||||
tpm_tis_i2c_set_locty(locty);
|
||||
return aspeed_i2c_readb(global_qtest, aspeed_bus_addr, I2C_SLAVE_ADDR, reg);
|
||||
}
|
||||
|
||||
static uint16_t tpm_tis_i2c_readw(uint8_t locty, uint8_t reg)
|
||||
{
|
||||
tpm_tis_i2c_set_locty(locty);
|
||||
return aspeed_i2c_readw(global_qtest, aspeed_bus_addr, I2C_SLAVE_ADDR, reg);
|
||||
}
|
||||
|
||||
static uint32_t tpm_tis_i2c_readl(uint8_t locty, uint8_t reg)
|
||||
{
|
||||
tpm_tis_i2c_set_locty(locty);
|
||||
return aspeed_i2c_readl(global_qtest, aspeed_bus_addr, I2C_SLAVE_ADDR, reg);
|
||||
}
|
||||
|
||||
static void tpm_tis_i2c_writeb(uint8_t locty, uint8_t reg, uint8_t v)
|
||||
{
|
||||
if (reg != TPM_I2C_REG_LOC_SEL) {
|
||||
tpm_tis_i2c_set_locty(locty);
|
||||
}
|
||||
aspeed_i2c_writeb(global_qtest, aspeed_bus_addr, I2C_SLAVE_ADDR, reg, v);
|
||||
}
|
||||
|
||||
static void tpm_tis_i2c_writel(uint8_t locty, uint8_t reg, uint32_t v)
|
||||
{
|
||||
if (reg != TPM_I2C_REG_LOC_SEL) {
|
||||
tpm_tis_i2c_set_locty(locty);
|
||||
}
|
||||
aspeed_i2c_writel(global_qtest, aspeed_bus_addr, I2C_SLAVE_ADDR, reg, v);
|
||||
}
|
||||
|
||||
static void tpm_tis_i2c_test_basic(const void *data)
|
||||
{
|
||||
@@ -98,62 +50,64 @@ static void tpm_tis_i2c_test_basic(const void *data)
|
||||
* All register accesses below must work without locality 0 being the
|
||||
* active locality. Therefore, ensure access is released.
|
||||
*/
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
access = tpm_tis_i2c_readb(0, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* read interrupt capability -- none are supported */
|
||||
v = tpm_tis_i2c_readl(0, TPM_I2C_REG_INT_CAPABILITY);
|
||||
v = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_INT_CAPABILITY);
|
||||
g_assert_cmpint(v, ==, 0);
|
||||
|
||||
/* try to enable all interrupts */
|
||||
tpm_tis_i2c_writel(0, TPM_I2C_REG_INT_ENABLE, 0xffffffff);
|
||||
v = tpm_tis_i2c_readl(0, TPM_I2C_REG_INT_ENABLE);
|
||||
tpm_tis_i2c_writel(global_qtest, 0, TPM_I2C_REG_INT_ENABLE, 0xffffffff);
|
||||
v = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_INT_ENABLE);
|
||||
/* none could be enabled */
|
||||
g_assert_cmpint(v, ==, 0);
|
||||
|
||||
/* enable csum */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_DATA_CSUM_ENABLE, TPM_DATA_CSUM_ENABLED);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE,
|
||||
TPM_DATA_CSUM_ENABLED);
|
||||
/* check csum enable register has bit 0 set */
|
||||
v = tpm_tis_i2c_readb(0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
v = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
g_assert_cmpint(v, ==, TPM_DATA_CSUM_ENABLED);
|
||||
/* reading it as 32bit register returns same result */
|
||||
v = tpm_tis_i2c_readl(0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
v = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
g_assert_cmpint(v, ==, TPM_DATA_CSUM_ENABLED);
|
||||
|
||||
/* disable csum */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_DATA_CSUM_ENABLE, 0);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE, 0);
|
||||
/* check csum enable register has bit 0 clear */
|
||||
v = tpm_tis_i2c_readb(0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
v = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
g_assert_cmpint(v, ==, 0);
|
||||
|
||||
/* write to unsupported register '1' */
|
||||
tpm_tis_i2c_writel(0, 1, 0x12345678);
|
||||
v = tpm_tis_i2c_readl(0, 1);
|
||||
tpm_tis_i2c_writel(global_qtest, 0, 1, 0x12345678);
|
||||
v = tpm_tis_i2c_readl(global_qtest, 0, 1);
|
||||
g_assert_cmpint(v, ==, 0xffffffff);
|
||||
|
||||
/* request use of locality */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_REQUEST_USE);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_REQUEST_USE);
|
||||
|
||||
/* read byte from STS + 3 */
|
||||
v = tpm_tis_i2c_readb(0, TPM_I2C_REG_STS + 3);
|
||||
v = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_STS + 3);
|
||||
g_assert_cmpint(v, ==, 0);
|
||||
|
||||
/* check STS after writing to STS + 3 */
|
||||
v = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_STS + 3, 0xf);
|
||||
v2 = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
v = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_STS + 3, 0xf);
|
||||
v2 = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
g_assert_cmpint(v, ==, v2);
|
||||
|
||||
/* release access */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
|
||||
/* select locality 5 -- must not be possible */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_LOC_SEL, 5);
|
||||
v = tpm_tis_i2c_readb(0, TPM_I2C_REG_LOC_SEL);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_LOC_SEL, 5);
|
||||
v = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_LOC_SEL);
|
||||
g_assert_cmpint(v, ==, 0);
|
||||
}
|
||||
|
||||
@@ -166,11 +120,12 @@ static void tpm_tis_i2c_test_check_localities(const void *data)
|
||||
uint32_t rid;
|
||||
|
||||
for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) {
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
capability = tpm_tis_i2c_readl(locty, TPM_I2C_REG_INTF_CAPABILITY);
|
||||
capability = tpm_tis_i2c_readl(global_qtest, locty,
|
||||
TPM_I2C_REG_INTF_CAPABILITY);
|
||||
i2c_cap = (TPM_I2C_CAP_INTERFACE_TYPE |
|
||||
TPM_I2C_CAP_INTERFACE_VER |
|
||||
TPM_I2C_CAP_TPM2_FAMILY |
|
||||
@@ -179,15 +134,15 @@ static void tpm_tis_i2c_test_check_localities(const void *data)
|
||||
TPM_I2C_CAP_DEV_ADDR_CHANGE);
|
||||
g_assert_cmpint(capability, ==, i2c_cap);
|
||||
|
||||
didvid = tpm_tis_i2c_readl(locty, TPM_I2C_REG_DID_VID);
|
||||
didvid = tpm_tis_i2c_readl(global_qtest, locty, TPM_I2C_REG_DID_VID);
|
||||
g_assert_cmpint(didvid, ==, (1 << 16) | PCI_VENDOR_ID_IBM);
|
||||
|
||||
rid = tpm_tis_i2c_readl(locty, TPM_I2C_REG_RID);
|
||||
rid = tpm_tis_i2c_readl(global_qtest, locty, TPM_I2C_REG_RID);
|
||||
g_assert_cmpint(rid, !=, 0);
|
||||
g_assert_cmpint(rid, !=, 0xffffffff);
|
||||
|
||||
/* locality selection must be at locty */
|
||||
l = tpm_tis_i2c_readb(locty, TPM_I2C_REG_LOC_SEL);
|
||||
l = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_LOC_SEL);
|
||||
g_assert_cmpint(l, ==, locty);
|
||||
}
|
||||
}
|
||||
@@ -199,23 +154,23 @@ static void tpm_tis_i2c_test_check_access_reg(const void *data)
|
||||
|
||||
/* do not test locality 4 (hw only) */
|
||||
for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* request use of locality */
|
||||
tpm_tis_i2c_writeb(locty, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, locty, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_REQUEST_USE);
|
||||
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* release access */
|
||||
tpm_tis_i2c_writeb(locty, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, locty, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
}
|
||||
@@ -234,14 +189,14 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) {
|
||||
pending_request_flag = 0;
|
||||
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* request use of locality */
|
||||
tpm_tis_i2c_writeb(locty,
|
||||
tpm_tis_i2c_writeb(global_qtest, locty,
|
||||
TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_REQUEST_USE);
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
@@ -249,14 +204,14 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
/* lower localities cannot seize access */
|
||||
for (l = 0; l < locty; l++) {
|
||||
/* lower locality is not active */
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
pending_request_flag |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* try to request use from 'l' */
|
||||
tpm_tis_i2c_writeb(l,
|
||||
tpm_tis_i2c_writeb(global_qtest, l,
|
||||
TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_REQUEST_USE);
|
||||
|
||||
@@ -264,7 +219,7 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
* requesting use from 'l' was not possible;
|
||||
* we must see REQUEST_USE and possibly PENDING_REQUEST
|
||||
*/
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_REQUEST_USE |
|
||||
@@ -275,17 +230,17 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
* locality 'locty' must be unchanged;
|
||||
* we must see PENDING_REQUEST
|
||||
*/
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
TPM_TIS_ACCESS_PENDING_REQUEST |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* try to seize from 'l' */
|
||||
tpm_tis_i2c_writeb(l,
|
||||
tpm_tis_i2c_writeb(global_qtest, l,
|
||||
TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_SEIZE);
|
||||
/* seize from 'l' was not possible */
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_REQUEST_USE |
|
||||
@@ -293,7 +248,7 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* locality 'locty' must be unchanged */
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
TPM_TIS_ACCESS_PENDING_REQUEST |
|
||||
@@ -312,14 +267,14 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
*/
|
||||
for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
|
||||
/* try to 'request use' from 'l' */
|
||||
tpm_tis_i2c_writeb(l, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, l, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_REQUEST_USE);
|
||||
|
||||
/*
|
||||
* requesting use from 'l' was not possible; we should see
|
||||
* REQUEST_USE and may see PENDING_REQUEST
|
||||
*/
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_REQUEST_USE |
|
||||
@@ -330,7 +285,7 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
* locality 'l-1' must be unchanged; we should always
|
||||
* see PENDING_REQUEST from 'l' requesting access
|
||||
*/
|
||||
access = tpm_tis_i2c_readb(l - 1, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l - 1, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
@@ -338,10 +293,11 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* try to seize from 'l' */
|
||||
tpm_tis_i2c_writeb(l, TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_SEIZE);
|
||||
tpm_tis_i2c_writeb(global_qtest, l, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_SEIZE);
|
||||
|
||||
/* seize from 'l' was possible */
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
@@ -349,7 +305,7 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* l - 1 should show that it has BEEN_SEIZED */
|
||||
access = tpm_tis_i2c_readb(l - 1, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l - 1, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_BEEN_SEIZED |
|
||||
@@ -357,10 +313,10 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* clear the BEEN_SEIZED flag and make sure it's gone */
|
||||
tpm_tis_i2c_writeb(l - 1, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, l - 1, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_BEEN_SEIZED);
|
||||
|
||||
access = tpm_tis_i2c_readb(l - 1, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l - 1, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
pending_request_flag |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
@@ -378,22 +334,22 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
/* release access from l - 1; this activates locty - 1 */
|
||||
l--;
|
||||
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
|
||||
DPRINTF("%s: %d: relinquishing control on l = %d\n",
|
||||
__func__, __LINE__, l);
|
||||
tpm_tis_i2c_writeb(l, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, l, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
pending_request_flag |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
for (l = locty - 1; l >= 0; l--) {
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
@@ -401,7 +357,7 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* release this locality */
|
||||
tpm_tis_i2c_writeb(l, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, l, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
|
||||
if (l == 1) {
|
||||
@@ -411,7 +367,7 @@ static void tpm_tis_i2c_test_check_access_reg_seize(const void *data)
|
||||
|
||||
/* no locality may be active now */
|
||||
for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) {
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
@@ -432,14 +388,14 @@ static void tpm_tis_i2c_test_check_access_reg_release(const void *data)
|
||||
for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) {
|
||||
pending_request_flag = 0;
|
||||
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
/* request use of locality */
|
||||
tpm_tis_i2c_writeb(locty, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, locty, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_REQUEST_USE);
|
||||
access = tpm_tis_i2c_readb(locty, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, locty, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
@@ -453,9 +409,9 @@ static void tpm_tis_i2c_test_check_access_reg_release(const void *data)
|
||||
* request use of locality 'l' -- we MUST see REQUEST USE and
|
||||
* may see PENDING_REQUEST
|
||||
*/
|
||||
tpm_tis_i2c_writeb(l, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, l, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_REQUEST_USE);
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_REQUEST_USE |
|
||||
@@ -464,7 +420,7 @@ static void tpm_tis_i2c_test_check_access_reg_release(const void *data)
|
||||
pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST;
|
||||
}
|
||||
/* release locality 'locty' */
|
||||
tpm_tis_i2c_writeb(locty, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, locty, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
/*
|
||||
* highest locality should now be active; release it and make sure the
|
||||
@@ -475,16 +431,16 @@ static void tpm_tis_i2c_test_check_access_reg_release(const void *data)
|
||||
continue;
|
||||
}
|
||||
/* 'l' should be active now */
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
pending_request_flag |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
/* 'l' relinquishes access */
|
||||
tpm_tis_i2c_writeb(l, TPM_I2C_REG_ACCESS,
|
||||
tpm_tis_i2c_writeb(global_qtest, l, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
access = tpm_tis_i2c_readb(l, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, l, TPM_I2C_REG_ACCESS);
|
||||
DPRINTF_ACCESS;
|
||||
if (l == 1 || (locty <= 1 && l == 2)) {
|
||||
pending_request_flag = 0;
|
||||
@@ -508,22 +464,24 @@ static void tpm_tis_i2c_test_check_transmit(const void *data)
|
||||
size_t i;
|
||||
|
||||
/* enable csum */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_DATA_CSUM_ENABLE, TPM_DATA_CSUM_ENABLED);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE,
|
||||
TPM_DATA_CSUM_ENABLED);
|
||||
/* check csum enable register has bit 0 set */
|
||||
v = tpm_tis_i2c_readb(0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
v = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
g_assert_cmpint(v, ==, TPM_DATA_CSUM_ENABLED);
|
||||
/* reading it as 32bit register returns same result */
|
||||
v = tpm_tis_i2c_readl(0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
v = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_ENABLE);
|
||||
g_assert_cmpint(v, ==, TPM_DATA_CSUM_ENABLED);
|
||||
|
||||
/* request use of locality 0 */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_REQUEST_USE);
|
||||
access = tpm_tis_i2c_readb(0, TPM_I2C_REG_ACCESS);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_ACCESS,
|
||||
TPM_TIS_ACCESS_REQUEST_USE);
|
||||
access = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_ACCESS);
|
||||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS |
|
||||
TPM_TIS_ACCESS_ACTIVE_LOCALITY |
|
||||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT);
|
||||
|
||||
sts = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
sts = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
DPRINTF_STS;
|
||||
|
||||
g_assert_cmpint(sts & 0xff, ==, 0);
|
||||
@@ -532,21 +490,22 @@ static void tpm_tis_i2c_test_check_transmit(const void *data)
|
||||
g_assert_cmpint(bcount, >=, 128);
|
||||
|
||||
/* read bcount from STS + 1 must work also */
|
||||
bcount2 = tpm_tis_i2c_readw(0, TPM_I2C_REG_STS + 1);
|
||||
bcount2 = tpm_tis_i2c_readw(global_qtest, 0, TPM_I2C_REG_STS + 1);
|
||||
g_assert_cmpint(bcount, ==, bcount2);
|
||||
|
||||
/* ic2 must have bits 26-31 zero */
|
||||
g_assert_cmpint(sts & (0x1f << 26), ==, 0);
|
||||
|
||||
tpm_tis_i2c_writel(0, TPM_I2C_REG_STS, TPM_TIS_STS_COMMAND_READY);
|
||||
sts = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
tpm_tis_i2c_writel(global_qtest, 0, TPM_I2C_REG_STS,
|
||||
TPM_TIS_STS_COMMAND_READY);
|
||||
sts = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
DPRINTF_STS;
|
||||
g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY);
|
||||
|
||||
/* transmit command */
|
||||
for (i = 0; i < sizeof(TPM_CMD); i++) {
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_DATA_FIFO, TPM_CMD[i]);
|
||||
sts = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_DATA_FIFO, TPM_CMD[i]);
|
||||
sts = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
DPRINTF_STS;
|
||||
if (i < sizeof(TPM_CMD) - 1) {
|
||||
g_assert_cmpint(sts & 0xff, ==,
|
||||
@@ -557,21 +516,21 @@ static void tpm_tis_i2c_test_check_transmit(const void *data)
|
||||
g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
|
||||
}
|
||||
/* read the checksum */
|
||||
csum = tpm_tis_i2c_readw(0, TPM_I2C_REG_DATA_CSUM_GET);
|
||||
csum = tpm_tis_i2c_readw(global_qtest, 0, TPM_I2C_REG_DATA_CSUM_GET);
|
||||
g_assert_cmpint(csum, ==, 0x6733);
|
||||
|
||||
/* start processing */
|
||||
tpm_tis_i2c_writeb(0, TPM_I2C_REG_STS, TPM_TIS_STS_TPM_GO);
|
||||
tpm_tis_i2c_writeb(global_qtest, 0, TPM_I2C_REG_STS, TPM_TIS_STS_TPM_GO);
|
||||
|
||||
uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
|
||||
do {
|
||||
sts = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
sts = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
|
||||
break;
|
||||
}
|
||||
} while (g_get_monotonic_time() < end_time);
|
||||
|
||||
sts = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
sts = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
DPRINTF_STS;
|
||||
g_assert_cmpint(sts & 0xff, == ,
|
||||
TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
|
||||
@@ -582,8 +541,8 @@ static void tpm_tis_i2c_test_check_transmit(const void *data)
|
||||
g_assert_cmpint(sizeof(tpm_msg), ==, bcount);
|
||||
|
||||
for (i = 0; i < sizeof(tpm_msg); i++) {
|
||||
tpm_msg[i] = tpm_tis_i2c_readb(0, TPM_I2C_REG_DATA_FIFO);
|
||||
sts = tpm_tis_i2c_readl(0, TPM_I2C_REG_STS);
|
||||
tpm_msg[i] = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_DATA_FIFO);
|
||||
sts = tpm_tis_i2c_readl(global_qtest, 0, TPM_I2C_REG_STS);
|
||||
DPRINTF_STS;
|
||||
if (sts & TPM_TIS_STS_DATA_AVAILABLE) {
|
||||
g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount);
|
||||
@@ -592,9 +551,9 @@ static void tpm_tis_i2c_test_check_transmit(const void *data)
|
||||
g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg));
|
||||
|
||||
/* relinquish use of locality 0 */
|
||||
tpm_tis_i2c_writeb(0,
|
||||
tpm_tis_i2c_writeb(global_qtest, 0,
|
||||
TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
access = tpm_tis_i2c_readb(0, TPM_I2C_REG_ACCESS);
|
||||
access = tpm_tis_i2c_readb(global_qtest, 0, TPM_I2C_REG_ACCESS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
||||
102
tests/qtest/tpm-tis-i2c-util.c
Normal file
102
tests/qtest/tpm-tis-i2c-util.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* QTest utilities for TPM TIS over I2C
|
||||
*
|
||||
* Copyright (c) 2018, 2026 IBM Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Berger <stefanb@linux.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "libqtest-single.h"
|
||||
#include "qtest_aspeed.h"
|
||||
#include "tpm-tis-i2c-util.h"
|
||||
#include "tpm-emu.h"
|
||||
|
||||
uint32_t aspeed_bus_addr;
|
||||
|
||||
static uint8_t cur_locty = 0xff;
|
||||
|
||||
static void tpm_tis_i2c_set_locty(QTestState *s, uint8_t locty)
|
||||
{
|
||||
if (cur_locty != locty) {
|
||||
cur_locty = locty;
|
||||
aspeed_i2c_writeb(s, aspeed_bus_addr, I2C_SLAVE_ADDR,
|
||||
TPM_I2C_REG_LOC_SEL, locty);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t tpm_tis_i2c_readb(QTestState *s, uint8_t locty, uint8_t reg)
|
||||
{
|
||||
tpm_tis_i2c_set_locty(s, locty);
|
||||
return aspeed_i2c_readb(s, aspeed_bus_addr, I2C_SLAVE_ADDR, reg);
|
||||
}
|
||||
|
||||
uint16_t tpm_tis_i2c_readw(QTestState *s, uint8_t locty, uint8_t reg)
|
||||
{
|
||||
tpm_tis_i2c_set_locty(s, locty);
|
||||
return aspeed_i2c_readw(global_qtest, aspeed_bus_addr, I2C_SLAVE_ADDR, reg);
|
||||
}
|
||||
|
||||
uint32_t tpm_tis_i2c_readl(QTestState *s, uint8_t locty, uint8_t reg)
|
||||
{
|
||||
tpm_tis_i2c_set_locty(s, locty);
|
||||
return aspeed_i2c_readl(s, aspeed_bus_addr, I2C_SLAVE_ADDR, reg);
|
||||
}
|
||||
|
||||
void tpm_tis_i2c_writeb(QTestState *s, uint8_t locty, uint8_t reg, uint8_t v)
|
||||
{
|
||||
if (reg != TPM_I2C_REG_LOC_SEL) {
|
||||
tpm_tis_i2c_set_locty(s, locty);
|
||||
}
|
||||
aspeed_i2c_writeb(s, aspeed_bus_addr, I2C_SLAVE_ADDR, reg, v);
|
||||
}
|
||||
|
||||
void tpm_tis_i2c_writel(QTestState *s, uint8_t locty, uint8_t reg, uint32_t v)
|
||||
{
|
||||
if (reg != TPM_I2C_REG_LOC_SEL) {
|
||||
tpm_tis_i2c_set_locty(s, locty);
|
||||
}
|
||||
aspeed_i2c_writel(s, aspeed_bus_addr, I2C_SLAVE_ADDR, reg, v);
|
||||
}
|
||||
|
||||
void tpm_tis_i2c_transfer(QTestState *s,
|
||||
const unsigned char *req, size_t req_size,
|
||||
unsigned char *rsp, size_t rsp_size)
|
||||
{
|
||||
uint32_t sts;
|
||||
size_t i;
|
||||
|
||||
/* request use of locality 0 */
|
||||
tpm_tis_i2c_writeb(s, 0, TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_REQUEST_USE);
|
||||
|
||||
tpm_tis_i2c_writel(s, 0, TPM_I2C_REG_STS, TPM_TIS_STS_COMMAND_READY);
|
||||
|
||||
/* transmit command */
|
||||
for (i = 0; i < req_size; i++) {
|
||||
tpm_tis_i2c_writeb(s, 0, TPM_I2C_REG_DATA_FIFO, req[i]);
|
||||
}
|
||||
|
||||
/* start processing */
|
||||
tpm_tis_i2c_writeb(s, 0, TPM_I2C_REG_STS, TPM_TIS_STS_TPM_GO);
|
||||
|
||||
uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND;
|
||||
do {
|
||||
sts = tpm_tis_i2c_readl(s, 0, TPM_I2C_REG_STS);
|
||||
if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
|
||||
break;
|
||||
}
|
||||
} while (g_get_monotonic_time() < end_time);
|
||||
|
||||
/* read response */
|
||||
for (i = 0; i < rsp_size; i++) {
|
||||
rsp[i] = tpm_tis_i2c_readb(s, 0, TPM_I2C_REG_DATA_FIFO);
|
||||
}
|
||||
/* relinquish use of locality 0 */
|
||||
tpm_tis_i2c_writeb(s, 0,
|
||||
TPM_I2C_REG_ACCESS, TPM_TIS_ACCESS_ACTIVE_LOCALITY);
|
||||
}
|
||||
34
tests/qtest/tpm-tis-i2c-util.h
Normal file
34
tests/qtest/tpm-tis-i2c-util.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* QTest TPM TIS I2C: Common test functions used for TPM I2C on Aspeed bus
|
||||
*
|
||||
* Copyright (c) 2026 IBM Corporation
|
||||
*
|
||||
* Authors:
|
||||
* Stefan Berger <stefanb@linux.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TESTS_TPM_TIS_I2C_UTIL_H
|
||||
#define TESTS_TPM_TIS_I2C_UTIL_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
extern uint32_t aspeed_bus_addr;
|
||||
|
||||
#define I2C_SLAVE_ADDR 0x2e
|
||||
#define I2C_DEV_BUS_NUM 10
|
||||
|
||||
uint8_t tpm_tis_i2c_readb(QTestState *s, uint8_t locty, uint8_t reg);
|
||||
uint16_t tpm_tis_i2c_readw(QTestState *s, uint8_t locty, uint8_t reg);
|
||||
uint32_t tpm_tis_i2c_readl(QTestState *s, uint8_t locty, uint8_t reg);
|
||||
|
||||
void tpm_tis_i2c_writeb(QTestState *s, uint8_t locty, uint8_t reg, uint8_t v);
|
||||
void tpm_tis_i2c_writel(QTestState *s, uint8_t locty, uint8_t reg, uint32_t v);
|
||||
|
||||
void tpm_tis_i2c_transfer(QTestState *s,
|
||||
const unsigned char *req, size_t req_size,
|
||||
unsigned char *rsp, size_t rsp_size);
|
||||
|
||||
#endif /* TESTS_TPM_TIS_I2C_UTIL_H */
|
||||
@@ -14,16 +14,44 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <glib/gstdio.h>
|
||||
#include "qemu/bswap.h"
|
||||
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "libqtest.h"
|
||||
#include "tpm-util.h"
|
||||
#include "qobject/qdict.h"
|
||||
|
||||
#define CRB_ADDR_START (TPM_CRB_ADDR_BASE + A_CRB_CTRL_START)
|
||||
#define CRB_ADDR_CTRL_STS (TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS)
|
||||
#define CRB_ADDR_CTRL_CMD_SIZE \
|
||||
(TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_SIZE)
|
||||
|
||||
#define CRB_START_INVOKE (1 << 0)
|
||||
#define CRB_START_RSP_RETRY (1 << 1)
|
||||
#define CRB_START_NEXT_CHUNK (1 << 2)
|
||||
|
||||
void tpm_wait_till_bit_clear(QTestState *s, uint64_t addr, uint32_t mask)
|
||||
{
|
||||
uint32_t sts;
|
||||
uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
|
||||
|
||||
while (true) {
|
||||
sts = qtest_readl(s, addr);
|
||||
if ((sts & mask) == 0) {
|
||||
break;
|
||||
}
|
||||
if (g_get_monotonic_time() >= end_time) {
|
||||
g_assert_cmphex(sts & mask, ==, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tpm_util_crb_transfer(QTestState *s,
|
||||
const unsigned char *req, size_t req_size,
|
||||
unsigned char *rsp, size_t rsp_size)
|
||||
{
|
||||
uint32_t tpm_sts;
|
||||
uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
|
||||
uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
|
||||
|
||||
@@ -31,33 +59,88 @@ void tpm_util_crb_transfer(QTestState *s,
|
||||
|
||||
qtest_memwrite(s, caddr, req, req_size);
|
||||
|
||||
uint32_t sts, start = 1;
|
||||
uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
|
||||
qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
|
||||
while (true) {
|
||||
start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
|
||||
if ((start & 1) == 0) {
|
||||
break;
|
||||
}
|
||||
if (g_get_monotonic_time() >= end_time) {
|
||||
break;
|
||||
}
|
||||
};
|
||||
start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
|
||||
g_assert_cmpint(start & 1, ==, 0);
|
||||
sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
|
||||
g_assert_cmpint(sts & 1, ==, 0);
|
||||
qtest_writel(s, CRB_ADDR_START, CRB_START_INVOKE);
|
||||
tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_INVOKE);
|
||||
|
||||
tpm_sts = qtest_readl(s, CRB_ADDR_CTRL_STS);
|
||||
g_assert_cmpint(tpm_sts & 1, ==, 0);
|
||||
|
||||
qtest_memread(s, raddr, rsp, rsp_size);
|
||||
}
|
||||
|
||||
void tpm_util_crb_chunk_transfer(QTestState *s,
|
||||
const unsigned char *req, size_t req_size,
|
||||
unsigned char *rsp, size_t rsp_size)
|
||||
{
|
||||
uint32_t tpm_sts;
|
||||
size_t chunk_size;
|
||||
unsigned char header[10];
|
||||
uint32_t actual_response_size = 0;
|
||||
|
||||
uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
|
||||
uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
|
||||
uint32_t crb_ctrl_cmd_size = qtest_readl(s, CRB_ADDR_CTRL_CMD_SIZE);
|
||||
|
||||
chunk_size = crb_ctrl_cmd_size;
|
||||
|
||||
qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
|
||||
|
||||
for (size_t i = 0; i < req_size; i += chunk_size) {
|
||||
bool last_chunk = false;
|
||||
size_t current_chunk_size = chunk_size;
|
||||
|
||||
if (i + chunk_size > req_size) {
|
||||
last_chunk = true;
|
||||
current_chunk_size = req_size - i;
|
||||
}
|
||||
|
||||
qtest_memwrite(s, caddr, req + i, current_chunk_size);
|
||||
|
||||
if (last_chunk) {
|
||||
qtest_writel(s, CRB_ADDR_START, CRB_START_INVOKE);
|
||||
tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_INVOKE);
|
||||
} else {
|
||||
qtest_writel(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
|
||||
tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
|
||||
}
|
||||
}
|
||||
tpm_sts = qtest_readl(s, CRB_ADDR_CTRL_STS);
|
||||
g_assert_cmpint(tpm_sts & 1, ==, 0);
|
||||
|
||||
/*
|
||||
* Read response in chunks
|
||||
*/
|
||||
|
||||
qtest_memread(s, raddr, header, sizeof(header));
|
||||
actual_response_size = ldl_be_p(&header[2]);
|
||||
|
||||
if (actual_response_size > rsp_size) {
|
||||
actual_response_size = rsp_size;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < actual_response_size; i += chunk_size) {
|
||||
size_t to_read = i + chunk_size > actual_response_size
|
||||
? actual_response_size - i
|
||||
: chunk_size;
|
||||
if (i > 0) {
|
||||
qtest_writel(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
|
||||
tpm_wait_till_bit_clear(s, CRB_ADDR_START, CRB_START_NEXT_CHUNK);
|
||||
}
|
||||
qtest_memread(s, raddr, rsp + i, to_read);
|
||||
}
|
||||
}
|
||||
|
||||
void tpm_util_startup(QTestState *s, tx_func *tx)
|
||||
{
|
||||
unsigned char buffer[1024];
|
||||
static const unsigned char tpm_startup[] =
|
||||
"\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
|
||||
static const unsigned char tpm_startup_resp[] =
|
||||
"\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
|
||||
static const unsigned char tpm_startup[] = {
|
||||
0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
|
||||
0x01, 0x44, 0x00, 0x00
|
||||
};
|
||||
static const unsigned char tpm_startup_resp[] = {
|
||||
0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
|
||||
tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
|
||||
|
||||
@@ -68,16 +151,23 @@ void tpm_util_startup(QTestState *s, tx_func *tx)
|
||||
void tpm_util_pcrextend(QTestState *s, tx_func *tx)
|
||||
{
|
||||
unsigned char buffer[1024];
|
||||
static const unsigned char tpm_pcrextend[] =
|
||||
"\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
|
||||
"\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
|
||||
"\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00";
|
||||
static const unsigned char tpm_pcrextend[] = {
|
||||
0x80, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00,
|
||||
0x01, 0x82, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
|
||||
0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x0b, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00
|
||||
};
|
||||
|
||||
static const unsigned char tpm_pcrextend_resp[] =
|
||||
"\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x01\x00\x00";
|
||||
static const unsigned char tpm_pcrextend_resp[] = {
|
||||
0x80, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00
|
||||
};
|
||||
|
||||
tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
|
||||
|
||||
@@ -89,9 +179,11 @@ void tpm_util_pcrread(QTestState *s, tx_func *tx,
|
||||
const unsigned char *exp_resp, size_t exp_resp_size)
|
||||
{
|
||||
unsigned char buffer[1024];
|
||||
static const unsigned char tpm_pcrread[] =
|
||||
"\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
|
||||
"\x03\x00\x04\x00";
|
||||
static const unsigned char tpm_pcrread[] = {
|
||||
0x80, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
|
||||
0x01, 0x7e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b,
|
||||
0x03, 0x00, 0x04, 0x00
|
||||
};
|
||||
|
||||
tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
|
||||
|
||||
@@ -227,8 +319,8 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu,
|
||||
src_qemu_args = g_strdup_printf(
|
||||
"%s "
|
||||
"-chardev socket,id=chr,path=%s "
|
||||
"-tpmdev emulator,id=dev,chardev=chr "
|
||||
"-device %s,tpmdev=dev ",
|
||||
"-tpmdev emulator,id=tpm0,chardev=chr "
|
||||
"-device %s,tpmdev=tpm0 ",
|
||||
machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel);
|
||||
|
||||
*src_qemu = qtest_init(src_qemu_args);
|
||||
@@ -236,8 +328,8 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu,
|
||||
dst_qemu_args = g_strdup_printf(
|
||||
"%s "
|
||||
"-chardev socket,id=chr,path=%s "
|
||||
"-tpmdev emulator,id=dev,chardev=chr "
|
||||
"-device %s,tpmdev=dev "
|
||||
"-tpmdev emulator,id=tpm0,chardev=chr "
|
||||
"-device %s,tpmdev=tpm0 "
|
||||
"-incoming %s",
|
||||
machine_options ? : "",
|
||||
dst_tpm_addr->u.q_unix.path,
|
||||
|
||||
@@ -24,10 +24,15 @@ typedef void (tx_func)(QTestState *s,
|
||||
const unsigned char *req, size_t req_size,
|
||||
unsigned char *rsp, size_t rsp_size);
|
||||
|
||||
void tpm_wait_till_bit_clear(QTestState *s, uint64_t addr, uint32_t mask);
|
||||
void tpm_util_crb_transfer(QTestState *s,
|
||||
const unsigned char *req, size_t req_size,
|
||||
unsigned char *rsp, size_t rsp_size);
|
||||
|
||||
void tpm_util_crb_chunk_transfer(QTestState *s,
|
||||
const unsigned char *req, size_t req_size,
|
||||
unsigned char *rsp, size_t rsp_size);
|
||||
|
||||
void tpm_util_startup(QTestState *s, tx_func *tx);
|
||||
void tpm_util_pcrextend(QTestState *s, tx_func *tx);
|
||||
void tpm_util_pcrread(QTestState *s, tx_func *tx,
|
||||
|
||||
13
ui/vdagent.c
13
ui/vdagent.c
@@ -964,17 +964,6 @@ static const VMStateDescription vmstate_chunk = {
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_vdba = {
|
||||
.name = "vdagent/bytearray",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(len, GByteArray),
|
||||
VMSTATE_VBUFFER_ALLOC_UINT32(data, GByteArray, 0, 0, len),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
struct CBInfoArray {
|
||||
uint32_t n;
|
||||
QemuClipboardInfo cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT];
|
||||
@@ -1064,7 +1053,7 @@ static const VMStateDescription vmstate_vdagent = {
|
||||
VMSTATE_UINT32(xsize, VDAgentChardev),
|
||||
VMSTATE_UINT32(xoff, VDAgentChardev),
|
||||
VMSTATE_VBUFFER_ALLOC_UINT32(xbuf, VDAgentChardev, 0, 0, xsize),
|
||||
VMSTATE_STRUCT_POINTER(outbuf, VDAgentChardev, vmstate_vdba, GByteArray),
|
||||
VMSTATE_GBYTEARRAY(outbuf, VDAgentChardev, 0),
|
||||
VMSTATE_UINT32(mouse_x, VDAgentChardev),
|
||||
VMSTATE_UINT32(mouse_y, VDAgentChardev),
|
||||
VMSTATE_UINT32(mouse_btn, VDAgentChardev),
|
||||
|
||||
Reference in New Issue
Block a user