backends/tpm.c | 13 +- docs/specs/tpm.txt | 20 +- hw/ppc/Kconfig | 1 + hw/tpm/Kconfig | 6 + hw/tpm/Makefile.objs | 1 + hw/tpm/tpm_emulator.c | 12 + hw/tpm/tpm_passthrough.c | 6 + hw/tpm/tpm_spapr.c | 460 +++++++++++++++++++++++++++++++++++ hw/tpm/trace-events | 14 ++ include/sysemu/tpm.h | 3 + include/sysemu/tpm_backend.h | 16 +- qapi/tpm.json | 6 +- 12 files changed, 552 insertions(+), 6 deletions(-) create mode 100644 hw/tpm/tpm_spapr.c
The following series of patches adds vTPM emulator support for the ppc64 platform (pSeries). It can be tested as follows with swtpm/libtpms: mkdir /tmp/mytpm1 swtpm socket --tpmstate dir=/tmp/mytpm1 \ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ --log level=20 If TPM 2 is desired, add --tpm2 as parameter to the above. In another terminal start QEMU: sudo ./ppc64-softmmu/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 Links: - libtpms: https://github.com/stefanberger/libtpms/wiki - swtpm: https://github.com/stefanberger/swtpm/wiki Changes: v3->v4: - addressed comments to v3 - reworked suspend/resume support that requires extensions to backends v2->v3: - patch 1: a TPM 2 is identified by IBM,vtpm20 in the compatible node - patch 1: convert to tracing to display Tx and Rx buffers - added documentation patch - added patch to enable TPM device as part of pSeries v1->v2: - followed Cedric Le Goater's suggestions to patch 1 - send appropriate CRQ error responses if DMA read or write fails - renamed tpm_spapr_got_payload to tpm_spapr_process_cmd and pass endianess-adjusted data pointer from CRQ to it Regards, Stefan Stefan Berger (8): tpm_spapr: Support TPM for ppc64 using CRQ based interface tpm_backend: Implement check whether tpm backend is suspended tpm_emulator: Implement callback for whether we are suspended tpm_passthrough: Implement callback for whether we are suspended tpm: Return bool from tpm_backend_finish_sync tpm_spapr: Support suspend and resume hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES config docs: tpm: Add example command line for ppc64 and tpm-spapr backends/tpm.c | 13 +- docs/specs/tpm.txt | 20 +- hw/ppc/Kconfig | 1 + hw/tpm/Kconfig | 6 + hw/tpm/Makefile.objs | 1 + hw/tpm/tpm_emulator.c | 12 + hw/tpm/tpm_passthrough.c | 6 + hw/tpm/tpm_spapr.c | 460 +++++++++++++++++++++++++++++++++++ hw/tpm/trace-events | 14 ++ include/sysemu/tpm.h | 3 + include/sysemu/tpm_backend.h | 16 +- qapi/tpm.json | 6 +- 12 files changed, 552 insertions(+), 6 deletions(-) create mode 100644 hw/tpm/tpm_spapr.c -- 2.21.0
Implement the check whether the emulator backend is suspended. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c index 22f9113432..7be7d3a91b 100644 --- a/hw/tpm/tpm_emulator.c +++ b/hw/tpm/tpm_emulator.c @@ -80,6 +80,8 @@ typedef struct TPMEmulator { unsigned int established_flag_cached:1; TPMBlobBuffers state_blobs; + + bool is_suspended; } TPMEmulator; struct tpm_error { @@ -486,6 +488,13 @@ static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) return actual_size; } +static bool tpm_emulator_is_suspended(TPMBackend *tb) +{ + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); + + return tpm_emu->is_suspended; +} + static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) { Error *err = NULL; @@ -846,6 +855,8 @@ static int tpm_emulator_pre_save(void *opaque) TPMBackend *tb = opaque; TPMEmulator *tpm_emu = TPM_EMULATOR(tb); + tpm_emu->is_suspended = true; + trace_tpm_emulator_pre_save(); tpm_backend_finish_sync(tb); @@ -975,6 +986,7 @@ static void tpm_emulator_class_init(ObjectClass *klass, void *data) tbc->get_tpm_version = tpm_emulator_get_tpm_version; tbc->get_buffer_size = tpm_emulator_get_buffer_size; tbc->get_tpm_options = tpm_emulator_get_tpm_options; + tbc->is_suspended = tpm_emulator_is_suspended; tbc->handle_request = tpm_emulator_handle_request; } -- 2.21.0
On 12/12/19 1:07 PM, Stefan Berger wrote: > Implement the check whether the emulator backend is suspended. > > Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> > > diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c > index 22f9113432..7be7d3a91b 100644 > --- a/hw/tpm/tpm_emulator.c > +++ b/hw/tpm/tpm_emulator.c > @@ -80,6 +80,8 @@ typedef struct TPMEmulator { > unsigned int established_flag_cached:1; > > TPMBlobBuffers state_blobs; > + > + bool is_suspended; > } TPMEmulator; > > struct tpm_error { > @@ -486,6 +488,13 @@ static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) > return actual_size; > } > > +static bool tpm_emulator_is_suspended(TPMBackend *tb) > +{ > + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); > + > + return tpm_emu->is_suspended; > +} > + > static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) > { > Error *err = NULL; > @@ -846,6 +855,8 @@ static int tpm_emulator_pre_save(void *opaque) > TPMBackend *tb = opaque; > TPMEmulator *tpm_emu = TPM_EMULATOR(tb); > > + tpm_emu->is_suspended = true; This is the most critical part here. It must be true when we receive a response in the tpm_spapr_request_completed(). The problem is that what tpm_backend_finish_sync() does is not specific to this backend but more a global operation that another device could run as well -- none seem to do this today. So the point is that there could be a race here. This flag should really be set in '.pre_pre_save,' so before any other device could poll. Better would be calling a global function that indicates whether device suspension has started. In this case we could do away with this and just call that function from the spapr device.
On 12/12/19 1:33 PM, Stefan Berger wrote: > On 12/12/19 1:07 PM, Stefan Berger wrote: >> Implement the check whether the emulator backend is suspended. >> >> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> >> >> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c >> index 22f9113432..7be7d3a91b 100644 >> --- a/hw/tpm/tpm_emulator.c >> +++ b/hw/tpm/tpm_emulator.c >> @@ -80,6 +80,8 @@ typedef struct TPMEmulator { >> unsigned int established_flag_cached:1; >> TPMBlobBuffers state_blobs; >> + >> + bool is_suspended; >> } TPMEmulator; >> struct tpm_error { >> @@ -486,6 +488,13 @@ static size_t >> tpm_emulator_get_buffer_size(TPMBackend *tb) >> return actual_size; >> } >> +static bool tpm_emulator_is_suspended(TPMBackend *tb) >> +{ >> + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); >> + >> + return tpm_emu->is_suspended; >> +} >> + >> static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) >> { >> Error *err = NULL; >> @@ -846,6 +855,8 @@ static int tpm_emulator_pre_save(void *opaque) >> TPMBackend *tb = opaque; >> TPMEmulator *tpm_emu = TPM_EMULATOR(tb); >> + tpm_emu->is_suspended = true; > > This is the most critical part here. It must be true when we receive a > response in the tpm_spapr_request_completed(). The problem is that > what tpm_backend_finish_sync() does is not specific to this backend > but more a global operation that another device could run as well -- > none seem to do this today. So the point is that there could be a race > here. This flag should really be set in '.pre_pre_save,' so before any > other device could poll. Better would be calling a global function > that indicates whether device suspension has started. In this case we > could do away with this and just call that function from the spapr > device. runstate_check(RUN_STATE_FINISH_MIGRATE) seems to be what we need here... > > >
Implement the callback for whether the passthrough backend is suspended. We always respond with false. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c index f67244b5d4..b759c7d30c 100644 --- a/hw/tpm/tpm_passthrough.c +++ b/hw/tpm/tpm_passthrough.c @@ -203,6 +203,11 @@ static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb) return tpm_pt->tpm_buffersize; } +static bool tpm_passthrough_is_suspended(TPMBackend *tb) +{ + return false; +} + /* * Unless path or file descriptor set has been provided by user, * determine the sysfs cancel file following kernel documentation @@ -386,6 +391,7 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data) tbc->get_buffer_size = tpm_passthrough_get_buffer_size; tbc->get_tpm_options = tpm_passthrough_get_tpm_options; tbc->handle_request = tpm_passthrough_handle_request; + tbc->is_suspended = tpm_passthrough_is_suspended; } static const TypeInfo tpm_passthrough_info = { -- 2.21.0
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index f927ec9c74..b5b3519158 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -10,6 +10,7 @@ config PSERIES select XICS_SPAPR select XIVE_SPAPR select MSI_NONBROKEN + select TPM_SPAPR config SPAPR_RNG bool -- 2.21.0
Add an example to the TPM docs for how to add a TPM SPAPR device model to a QEMU VM emulating a pSeries machine. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt index 9c8cca042d..9c3e67d8a7 100644 --- a/docs/specs/tpm.txt +++ b/docs/specs/tpm.txt @@ -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'. -- 2.21.0
© 2016 - 2024 Red Hat, Inc.