qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

spapr_tpm_proxy.c (4803B)


      1 /*
      2  * SPAPR TPM Proxy/Hypercall
      3  *
      4  * Copyright IBM Corp. 2019
      5  *
      6  * Authors:
      7  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
      8  *
      9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10  * See the COPYING file in the top-level directory.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "qapi/error.h"
     15 #include "qemu/error-report.h"
     16 #include "sysemu/reset.h"
     17 #include "hw/ppc/spapr.h"
     18 #include "hw/qdev-properties.h"
     19 #include "trace.h"
     20 
     21 #define TPM_SPAPR_BUFSIZE 4096
     22 
     23 enum {
     24     TPM_COMM_OP_EXECUTE = 1,
     25     TPM_COMM_OP_CLOSE_SESSION = 2,
     26 };
     27 
     28 static void spapr_tpm_proxy_reset(void *opaque)
     29 {
     30     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(opaque);
     31 
     32     if (tpm_proxy->host_fd != -1) {
     33         close(tpm_proxy->host_fd);
     34         tpm_proxy->host_fd = -1;
     35     }
     36 }
     37 
     38 static ssize_t tpm_execute(SpaprTpmProxy *tpm_proxy, target_ulong *args)
     39 {
     40     uint64_t data_in = ppc64_phys_to_real(args[1]);
     41     target_ulong data_in_size = args[2];
     42     uint64_t data_out = ppc64_phys_to_real(args[3]);
     43     target_ulong data_out_size = args[4];
     44     uint8_t buf_in[TPM_SPAPR_BUFSIZE];
     45     uint8_t buf_out[TPM_SPAPR_BUFSIZE];
     46     ssize_t ret;
     47 
     48     trace_spapr_tpm_execute(data_in, data_in_size, data_out, data_out_size);
     49 
     50     if (data_in_size > TPM_SPAPR_BUFSIZE) {
     51         error_report("invalid TPM input buffer size: " TARGET_FMT_lu,
     52                      data_in_size);
     53         return H_P3;
     54     }
     55 
     56     if (data_out_size < TPM_SPAPR_BUFSIZE) {
     57         error_report("invalid TPM output buffer size: " TARGET_FMT_lu,
     58                      data_out_size);
     59         return H_P5;
     60     }
     61 
     62     if (tpm_proxy->host_fd == -1) {
     63         tpm_proxy->host_fd = open(tpm_proxy->host_path, O_RDWR);
     64         if (tpm_proxy->host_fd == -1) {
     65             error_report("failed to open TPM device %s: %d",
     66                          tpm_proxy->host_path, errno);
     67             return H_RESOURCE;
     68         }
     69     }
     70 
     71     cpu_physical_memory_read(data_in, buf_in, data_in_size);
     72 
     73     do {
     74         ret = write(tpm_proxy->host_fd, buf_in, data_in_size);
     75         if (ret > 0) {
     76             data_in_size -= ret;
     77         }
     78     } while ((ret >= 0 && data_in_size > 0) || (ret == -1 && errno == EINTR));
     79 
     80     if (ret == -1) {
     81         error_report("failed to write to TPM device %s: %d",
     82                      tpm_proxy->host_path, errno);
     83         return H_RESOURCE;
     84     }
     85 
     86     do {
     87         ret = read(tpm_proxy->host_fd, buf_out, data_out_size);
     88     } while (ret == 0 || (ret == -1 && errno == EINTR));
     89 
     90     if (ret == -1) {
     91         error_report("failed to read from TPM device %s: %d",
     92                      tpm_proxy->host_path, errno);
     93         return H_RESOURCE;
     94     }
     95 
     96     cpu_physical_memory_write(data_out, buf_out, ret);
     97     args[0] = ret;
     98 
     99     return H_SUCCESS;
    100 }
    101 
    102 static target_ulong h_tpm_comm(PowerPCCPU *cpu,
    103                                SpaprMachineState *spapr,
    104                                target_ulong opcode,
    105                                target_ulong *args)
    106 {
    107     target_ulong op = args[0];
    108     SpaprTpmProxy *tpm_proxy = spapr->tpm_proxy;
    109 
    110     if (!tpm_proxy) {
    111         error_report("TPM proxy not available");
    112         return H_FUNCTION;
    113     }
    114 
    115     trace_spapr_h_tpm_comm(tpm_proxy->host_path, op);
    116 
    117     switch (op) {
    118     case TPM_COMM_OP_EXECUTE:
    119         return tpm_execute(tpm_proxy, args);
    120     case TPM_COMM_OP_CLOSE_SESSION:
    121         spapr_tpm_proxy_reset(tpm_proxy);
    122         return H_SUCCESS;
    123     default:
    124         return H_PARAMETER;
    125     }
    126 }
    127 
    128 static void spapr_tpm_proxy_realize(DeviceState *d, Error **errp)
    129 {
    130     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d);
    131 
    132     if (tpm_proxy->host_path == NULL) {
    133         error_setg(errp, "must specify 'host-path' option for device");
    134         return;
    135     }
    136 
    137     tpm_proxy->host_fd = -1;
    138     qemu_register_reset(spapr_tpm_proxy_reset, tpm_proxy);
    139 }
    140 
    141 static void spapr_tpm_proxy_unrealize(DeviceState *d)
    142 {
    143     SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d);
    144 
    145     qemu_unregister_reset(spapr_tpm_proxy_reset, tpm_proxy);
    146 }
    147 
    148 static Property spapr_tpm_proxy_properties[] = {
    149     DEFINE_PROP_STRING("host-path", SpaprTpmProxy, host_path),
    150     DEFINE_PROP_END_OF_LIST(),
    151 };
    152 
    153 static void spapr_tpm_proxy_class_init(ObjectClass *k, void *data)
    154 {
    155     DeviceClass *dk = DEVICE_CLASS(k);
    156 
    157     dk->realize = spapr_tpm_proxy_realize;
    158     dk->unrealize = spapr_tpm_proxy_unrealize;
    159     dk->user_creatable = true;
    160     device_class_set_props(dk, spapr_tpm_proxy_properties);
    161 }
    162 
    163 static const TypeInfo spapr_tpm_proxy_info = {
    164     .name          = TYPE_SPAPR_TPM_PROXY,
    165     .parent        = TYPE_DEVICE,
    166     .instance_size = sizeof(SpaprTpmProxy),
    167     .class_init    = spapr_tpm_proxy_class_init,
    168 };
    169 
    170 static void spapr_tpm_proxy_register_types(void)
    171 {
    172     type_register_static(&spapr_tpm_proxy_info);
    173     spapr_register_hypercall(SVM_H_TPM_COMM, h_tpm_comm);
    174 }
    175 
    176 type_init(spapr_tpm_proxy_register_types)