123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- /*
- * tpm_crb.c - QEMU's TPM CRB interface emulator
- *
- * Copyright (c) 2018 Red Hat, Inc.
- *
- * Authors:
- * Marc-André Lureau <marcandre.lureau@redhat.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- * tpm_crb is a device for TPM 2.0 Command Response Buffer (CRB) Interface
- * as defined in TCG PC Client Platform TPM Profile (PTP) Specification
- * Family “2.0” Level 00 Revision 01.03 v22
- */
- #include "qemu/osdep.h"
- #include "qemu/module.h"
- #include "qapi/error.h"
- #include "exec/address-spaces.h"
- #include "hw/qdev-properties.h"
- #include "hw/pci/pci_ids.h"
- #include "hw/acpi/tpm.h"
- #include "migration/vmstate.h"
- #include "system/tpm_backend.h"
- #include "system/tpm_util.h"
- #include "tpm_prop.h"
- #include "tpm_ppi.h"
- #include "trace.h"
- #include "qom/object.h"
- #include "tpm_crb.h"
- static uint8_t tpm_crb_get_active_locty(TPMCRBState *s, uint32_t *regs)
- {
- if (!ARRAY_FIELD_EX32(regs, CRB_LOC_STATE, locAssigned)) {
- return TPM_CRB_NO_LOCALITY;
- }
- return ARRAY_FIELD_EX32(regs, CRB_LOC_STATE, activeLocality);
- }
- static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
- {
- TPMCRBState *s = opaque;
- uint8_t locty = addr >> 12;
- uint32_t *regs;
- void *mem;
- trace_tpm_crb_mmio_write(addr, size, val);
- regs = memory_region_get_ram_ptr(&s->mmio);
- mem = ®s[R_CRB_DATA_BUFFER];
- assert(regs);
- /* receive TPM command bytes in DATA_BUFFER */
- if (addr >= A_CRB_DATA_BUFFER) {
- assert(addr + size <= TPM_CRB_ADDR_SIZE);
- assert(size <= sizeof(val));
- memcpy(mem + addr - A_CRB_DATA_BUFFER, &val, size);
- memory_region_set_dirty(&s->mmio, addr, size);
- return;
- }
- /* otherwise we are doing MMIO writes */
- switch (addr) {
- case A_CRB_CTRL_REQ:
- switch (val) {
- case CRB_CTRL_REQ_CMD_READY:
- ARRAY_FIELD_DP32(regs, CRB_CTRL_STS,
- tpmIdle, 0);
- break;
- case CRB_CTRL_REQ_GO_IDLE:
- ARRAY_FIELD_DP32(regs, CRB_CTRL_STS,
- tpmIdle, 1);
- break;
- }
- break;
- case A_CRB_CTRL_CANCEL:
- if (val == CRB_CANCEL_INVOKE &&
- regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
- tpm_backend_cancel_cmd(s->tpmbe);
- }
- break;
- case A_CRB_CTRL_START:
- if (val == CRB_START_INVOKE &&
- !(regs[R_CRB_CTRL_START] & CRB_START_INVOKE) &&
- tpm_crb_get_active_locty(s, regs) == locty) {
- regs[R_CRB_CTRL_START] |= CRB_START_INVOKE;
- 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,
- };
- tpm_backend_deliver_request(s->tpmbe, &s->cmd);
- }
- break;
- case A_CRB_LOC_CTRL:
- switch (val) {
- case CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT:
- /* not loc 3 or 4 */
- break;
- case CRB_LOC_CTRL_RELINQUISH:
- ARRAY_FIELD_DP32(regs, CRB_LOC_STATE,
- locAssigned, 0);
- ARRAY_FIELD_DP32(regs, CRB_LOC_STS,
- Granted, 0);
- break;
- case CRB_LOC_CTRL_REQUEST_ACCESS:
- ARRAY_FIELD_DP32(regs, CRB_LOC_STS,
- Granted, 1);
- ARRAY_FIELD_DP32(regs, CRB_LOC_STS,
- beenSeized, 0);
- ARRAY_FIELD_DP32(regs, CRB_LOC_STATE,
- locAssigned, 1);
- break;
- }
- break;
- }
- memory_region_set_dirty(&s->mmio, 0, A_CRB_DATA_BUFFER);
- }
- const MemoryRegionOps tpm_crb_memory_ops = {
- .write = tpm_crb_mmio_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 4,
- },
- };
- void tpm_crb_request_completed(TPMCRBState *s, int ret)
- {
- uint32_t *regs = memory_region_get_ram_ptr(&s->mmio);
- assert(regs);
- regs[R_CRB_CTRL_START] &= ~CRB_START_INVOKE;
- if (ret != 0) {
- ARRAY_FIELD_DP32(regs, CRB_CTRL_STS,
- tpmSts, 1); /* fatal error */
- }
- memory_region_set_dirty(&s->mmio, 0, TPM_CRB_ADDR_SIZE);
- }
- enum TPMVersion tpm_crb_get_version(TPMCRBState *s)
- {
- return tpm_backend_get_tpm_version(s->tpmbe);
- }
- int tpm_crb_pre_save(TPMCRBState *s)
- {
- tpm_backend_finish_sync(s->tpmbe);
- return 0;
- }
- void tpm_crb_reset(TPMCRBState *s, uint64_t baseaddr)
- {
- uint32_t *regs = memory_region_get_ram_ptr(&s->mmio);
- assert(regs);
- if (s->ppi_enabled) {
- tpm_ppi_reset(&s->ppi);
- }
- tpm_backend_reset(s->tpmbe);
- memset(regs, 0, TPM_CRB_ADDR_SIZE);
- ARRAY_FIELD_DP32(regs, CRB_LOC_STATE,
- tpmRegValidSts, 1);
- ARRAY_FIELD_DP32(regs, CRB_LOC_STATE,
- tpmEstablished, 1);
- ARRAY_FIELD_DP32(regs, CRB_CTRL_STS,
- tpmIdle, 1);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- InterfaceType, CRB_INTF_TYPE_CRB_ACTIVE);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- InterfaceVersion, CRB_INTF_VERSION_CRB);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- CapLocality, CRB_INTF_CAP_LOCALITY_0_ONLY);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- CapCRBIdleBypass, CRB_INTF_CAP_IDLE_FAST);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- CapDataXferSizeSupport, CRB_INTF_CAP_XFER_SIZE_64);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- CapFIFO, CRB_INTF_CAP_FIFO_NOT_SUPPORTED);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID,
- RID, 0b0000);
- ARRAY_FIELD_DP32(regs, CRB_INTF_ID2,
- VID, PCI_VENDOR_ID_IBM);
- baseaddr += A_CRB_DATA_BUFFER;
- regs[R_CRB_CTRL_CMD_SIZE] = CRB_CTRL_CMD_SIZE;
- regs[R_CRB_CTRL_CMD_LADDR] = (uint32_t)baseaddr;
- regs[R_CRB_CTRL_CMD_HADDR] = (uint32_t)(baseaddr >> 32);
- regs[R_CRB_CTRL_RSP_SIZE] = CRB_CTRL_CMD_SIZE;
- regs[R_CRB_CTRL_RSP_LADDR] = (uint32_t)baseaddr;
- regs[R_CRB_CTRL_RSP_HADDR] = (uint32_t)(baseaddr >> 32);
- s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->tpmbe),
- CRB_CTRL_CMD_SIZE);
- if (tpm_backend_startup_tpm(s->tpmbe, s->be_buffer_size) < 0) {
- exit(1);
- }
- memory_region_rom_device_set_romd(&s->mmio, true);
- memory_region_set_dirty(&s->mmio, 0, TPM_CRB_ADDR_SIZE);
- }
- void tpm_crb_init_memory(Object *obj, TPMCRBState *s, Error **errp)
- {
- uint64_t page_size = qemu_real_host_page_size();
- memory_region_init_rom_device_nomigrate(&s->mmio, obj, &tpm_crb_memory_ops,
- s, "tpm-crb-mem", ROUND_UP(TPM_CRB_ADDR_SIZE, page_size), errp);
- if (s->ppi_enabled) {
- tpm_ppi_init_memory(&s->ppi, obj);
- }
- }
- void tpm_crb_mem_save(TPMCRBState *s, uint32_t *saved_regs, void *saved_cmdmem)
- {
- uint32_t *regs = memory_region_get_ram_ptr(&s->mmio);
- memcpy(saved_regs, regs, A_CRB_DATA_BUFFER);
- memcpy(saved_cmdmem, ®s[R_CRB_DATA_BUFFER], CRB_CTRL_CMD_SIZE);
- }
- void tpm_crb_mem_load(TPMCRBState *s, const uint32_t *saved_regs,
- const void *saved_cmdmem)
- {
- uint32_t *regs = memory_region_get_ram_ptr(&s->mmio);
- memcpy(regs, saved_regs, A_CRB_DATA_BUFFER);
- memcpy(®s[R_CRB_DATA_BUFFER], saved_cmdmem, CRB_CTRL_CMD_SIZE);
- }
- void tpm_crb_build_aml(TPMIf *ti, Aml *scope, uint32_t baseaddr, uint32_t size,
- bool build_ppi)
- {
- Aml *dev, *crs;
- dev = aml_device("TPM");
- aml_append(dev, aml_name_decl("_HID", aml_string("MSFT0101")));
- aml_append(dev, aml_name_decl("_STR", aml_string("TPM 2.0 Device")));
- aml_append(dev, aml_name_decl("_UID", aml_int(1)));
- aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
- crs = aml_resource_template();
- aml_append(crs, aml_memory32_fixed(baseaddr, size, AML_READ_WRITE));
- aml_append(dev, aml_name_decl("_CRS", crs));
- if (build_ppi) {
- tpm_build_ppi_acpi(ti, dev);
- }
- aml_append(scope, dev);
- }
|