2 * SPAPR TPM Proxy/Hypercall
4 * Copyright IBM Corp. 2019
7 * Michael Roth <mdroth@linux.vnet.ibm.com>
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.
13 #include "qemu/osdep.h"
14 #include "qemu-common.h"
15 #include "qapi/error.h"
16 #include "qemu/error-report.h"
17 #include "sysemu/reset.h"
18 #include "hw/ppc/spapr.h"
19 #include "hw/qdev-properties.h"
22 #define TPM_SPAPR_BUFSIZE 4096
25 TPM_COMM_OP_EXECUTE
= 1,
26 TPM_COMM_OP_CLOSE_SESSION
= 2,
29 static void spapr_tpm_proxy_reset(void *opaque
)
31 SpaprTpmProxy
*tpm_proxy
= SPAPR_TPM_PROXY(opaque
);
33 if (tpm_proxy
->host_fd
!= -1) {
34 close(tpm_proxy
->host_fd
);
35 tpm_proxy
->host_fd
= -1;
39 static ssize_t
tpm_execute(SpaprTpmProxy
*tpm_proxy
, target_ulong
*args
)
41 uint64_t data_in
= ppc64_phys_to_real(args
[1]);
42 target_ulong data_in_size
= args
[2];
43 uint64_t data_out
= ppc64_phys_to_real(args
[3]);
44 target_ulong data_out_size
= args
[4];
45 uint8_t buf_in
[TPM_SPAPR_BUFSIZE
];
46 uint8_t buf_out
[TPM_SPAPR_BUFSIZE
];
49 trace_spapr_tpm_execute(data_in
, data_in_size
, data_out
, data_out_size
);
51 if (data_in_size
> TPM_SPAPR_BUFSIZE
) {
52 error_report("invalid TPM input buffer size: " TARGET_FMT_lu
,
57 if (data_out_size
< TPM_SPAPR_BUFSIZE
) {
58 error_report("invalid TPM output buffer size: " TARGET_FMT_lu
,
63 if (tpm_proxy
->host_fd
== -1) {
64 tpm_proxy
->host_fd
= open(tpm_proxy
->host_path
, O_RDWR
);
65 if (tpm_proxy
->host_fd
== -1) {
66 error_report("failed to open TPM device %s: %d",
67 tpm_proxy
->host_path
, errno
);
72 cpu_physical_memory_read(data_in
, buf_in
, data_in_size
);
75 ret
= write(tpm_proxy
->host_fd
, buf_in
, data_in_size
);
79 } while ((ret
>= 0 && data_in_size
> 0) || (ret
== -1 && errno
== EINTR
));
82 error_report("failed to write to TPM device %s: %d",
83 tpm_proxy
->host_path
, errno
);
88 ret
= read(tpm_proxy
->host_fd
, buf_out
, data_out_size
);
89 } while (ret
== 0 || (ret
== -1 && errno
== EINTR
));
92 error_report("failed to read from TPM device %s: %d",
93 tpm_proxy
->host_path
, errno
);
97 cpu_physical_memory_write(data_out
, buf_out
, ret
);
103 static target_ulong
h_tpm_comm(PowerPCCPU
*cpu
,
104 SpaprMachineState
*spapr
,
108 target_ulong op
= args
[0];
109 SpaprTpmProxy
*tpm_proxy
= spapr
->tpm_proxy
;
112 error_report("TPM proxy not available");
116 trace_spapr_h_tpm_comm(tpm_proxy
->host_path
, op
);
119 case TPM_COMM_OP_EXECUTE
:
120 return tpm_execute(tpm_proxy
, args
);
121 case TPM_COMM_OP_CLOSE_SESSION
:
122 spapr_tpm_proxy_reset(tpm_proxy
);
129 static void spapr_tpm_proxy_realize(DeviceState
*d
, Error
**errp
)
131 SpaprTpmProxy
*tpm_proxy
= SPAPR_TPM_PROXY(d
);
133 if (tpm_proxy
->host_path
== NULL
) {
134 error_setg(errp
, "must specify 'host-path' option for device");
138 tpm_proxy
->host_fd
= -1;
139 qemu_register_reset(spapr_tpm_proxy_reset
, tpm_proxy
);
142 static void spapr_tpm_proxy_unrealize(DeviceState
*d
)
144 SpaprTpmProxy
*tpm_proxy
= SPAPR_TPM_PROXY(d
);
146 qemu_unregister_reset(spapr_tpm_proxy_reset
, tpm_proxy
);
149 static Property spapr_tpm_proxy_properties
[] = {
150 DEFINE_PROP_STRING("host-path", SpaprTpmProxy
, host_path
),
151 DEFINE_PROP_END_OF_LIST(),
154 static void spapr_tpm_proxy_class_init(ObjectClass
*k
, void *data
)
156 DeviceClass
*dk
= DEVICE_CLASS(k
);
158 dk
->realize
= spapr_tpm_proxy_realize
;
159 dk
->unrealize
= spapr_tpm_proxy_unrealize
;
160 dk
->user_creatable
= true;
161 device_class_set_props(dk
, spapr_tpm_proxy_properties
);
164 static const TypeInfo spapr_tpm_proxy_info
= {
165 .name
= TYPE_SPAPR_TPM_PROXY
,
166 .parent
= TYPE_DEVICE
,
167 .instance_size
= sizeof(SpaprTpmProxy
),
168 .class_init
= spapr_tpm_proxy_class_init
,
171 static void spapr_tpm_proxy_register_types(void)
173 type_register_static(&spapr_tpm_proxy_info
);
174 spapr_register_hypercall(SVM_H_TPM_COMM
, h_tpm_comm
);
177 type_init(spapr_tpm_proxy_register_types
)