From patchwork Wed Aug 31 14:35:54 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 112556 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 8DBA7B6F76 for ; Thu, 1 Sep 2011 00:36:49 +1000 (EST) Received: from localhost ([::1]:37357 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QyluE-000326-Ui for incoming@patchwork.ozlabs.org; Wed, 31 Aug 2011 10:36:42 -0400 Received: from eggs.gnu.org ([140.186.70.92]:43110) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qylu4-0002zR-Ba for qemu-devel@nongnu.org; Wed, 31 Aug 2011 10:36:33 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Qylu2-0006Rr-Gu for qemu-devel@nongnu.org; Wed, 31 Aug 2011 10:36:32 -0400 Received: from e31.co.us.ibm.com ([32.97.110.149]:47858) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qylu2-0006RZ-7Z for qemu-devel@nongnu.org; Wed, 31 Aug 2011 10:36:30 -0400 Received: from /spool/local by us.ibm.com with XMail ESMTP for from ; Wed, 31 Aug 2011 08:36:29 -0600 Received: from d03relay03.boulder.ibm.com ([9.17.195.228]) by us.ibm.com ([192.168.1.131]) with XMail ESMTP; Wed, 31 Aug 2011 08:36:26 -0600 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d03relay03.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p7VEaNwK129364 for ; Wed, 31 Aug 2011 08:36:24 -0600 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p7V8ZqZW031953 for ; Wed, 31 Aug 2011 02:35:53 -0600 Received: from localhost.localdomain (d941e-10.watson.ibm.com [9.59.241.154]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p7V8ZpiD031868 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 31 Aug 2011 02:35:52 -0600 Received: from localhost.localdomain (d941e-10 [127.0.0.1]) by localhost.localdomain (8.14.4/8.14.3) with ESMTP id p7VEaIDS032401; Wed, 31 Aug 2011 10:36:18 -0400 Received: (from root@localhost) by localhost.localdomain (8.14.4/8.14.4/Submit) id p7VEaIWC032400; Wed, 31 Aug 2011 10:36:18 -0400 Message-Id: <20110831143618.248943092@linux.vnet.ibm.com> User-Agent: quilt/0.48-1 Date: Wed, 31 Aug 2011 10:35:54 -0400 From: Stefan Berger To: stefanb@linux.vnet.ibm.com, qemu-devel@nongnu.org References: <20110831143551.127339744@linux.vnet.ibm.com> Content-Disposition: inline; filename=qemu_tpm_tis_persist.diff x-cbid: 11083114-7282-0000-0000-00000101C333 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 32.97.110.149 Cc: chrisw@redhat.com, anbang.ruan@cs.ox.ac.uk, rrelyea@redhat.com, alevy@redhat.com, andreas.niederl@iaik.tugraz.at, serge@hallyn.com Subject: [Qemu-devel] [PATCH V8 03/14] Add persistent state handling to TPM TIS frontend driver X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds support for handling of persistent state to the TPM TIS frontend. The currently used buffer is determined (can only be in currently active locality and either be a read or a write buffer) and only that buffer's content is stored. The reverse is done when the state is restored from disk where the buffer's content are copied into the currently used buffer. To keep compatibility with existing Xen implementation the VMStateDescription was adapted to be compatible with existing state. For that I am adding Andreas Niederl as an author to the file. v5: - removing qdev.no_user=1 v4: - main thread releases the 'state' lock while periodically calling the backends function that may request it to write data into block storage. v3: - all functions prefixed with tis_ - while the main thread is waiting for an outstanding TPM command to finish, it periodically does some work (writes data to the block storage) Signed-off-by: Stefan Berger --- hw/tpm_tis.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) Index: qemu-git/hw/tpm_tis.c =================================================================== --- qemu-git.orig/hw/tpm_tis.c +++ qemu-git/hw/tpm_tis.c @@ -6,6 +6,8 @@ * Author: Stefan Berger * David Safford * + * Xen 4 support: Andrease Niederl + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2 of the @@ -839,3 +841,167 @@ static int tis_init(ISADevice *dev) err_exit: return -1; } + +/* persistent state handling */ + +static void tis_pre_save(void *opaque) +{ + TPMState *s = opaque; + uint8_t locty = s->active_locty; + + qemu_mutex_lock(&s->state_lock); + + /* wait for outstanding requests to complete */ + if (IS_VALID_LOCTY(locty) && s->loc[locty].state == STATE_EXECUTION) { + if (!s->be_driver->ops->job_for_main_thread) { + qemu_cond_wait(&s->from_tpm_cond, &s->state_lock); + } else { + while (s->loc[locty].state == STATE_EXECUTION) { + qemu_mutex_unlock(&s->state_lock); + + s->be_driver->ops->job_for_main_thread(NULL); + usleep(10000); + + qemu_mutex_lock(&s->state_lock); + } + } + } + +#ifdef DEBUG_TIS_SR + fprintf(stderr, + "tpm_tis: suspend: locty 0 : r_offset = %d, w_offset = %d\n", + s->loc[0].r_offset, s->loc[0].w_offset); + if (s->loc[0].r_offset) { + tis_dump_state(opaque, 0); + } +#endif + + qemu_mutex_unlock(&s->state_lock); + + /* copy current active read or write buffer into the buffer + written to disk */ + if (IS_VALID_LOCTY(locty)) { + switch (s->loc[locty].state) { + case STATE_RECEPTION: + memcpy(s->buf, + s->loc[locty].w_buffer.buffer, + MIN(sizeof(s->buf), + s->loc[locty].w_buffer.size)); + s->offset = s->loc[locty].w_offset; + break; + case STATE_COMPLETION: + memcpy(s->buf, + s->loc[locty].r_buffer.buffer, + MIN(sizeof(s->buf), + s->loc[locty].r_buffer.size)); + s->offset = s->loc[locty].r_offset; + break; + default: + /* leak nothing */ + memset(s->buf, 0x0, sizeof(s->buf)); + break; + } + } + + s->be_driver->ops->save_volatile_data(); +} + + +static int tis_post_load(void *opaque, + int version_id __attribute__((unused))) +{ + TPMState *s = opaque; + + uint8_t locty = s->active_locty; + + if (IS_VALID_LOCTY(locty)) { + switch (s->loc[locty].state) { + case STATE_RECEPTION: + memcpy(s->loc[locty].w_buffer.buffer, + s->buf, + MIN(sizeof(s->buf), + s->loc[locty].w_buffer.size)); + s->loc[locty].w_offset = s->offset; + break; + case STATE_COMPLETION: + memcpy(s->loc[locty].r_buffer.buffer, + s->buf, + MIN(sizeof(s->buf), + s->loc[locty].r_buffer.size)); + s->loc[locty].r_offset = s->offset; + break; + default: + break; + } + } + +#ifdef DEBUG_TIS_SR + fprintf(stderr, + "tpm_tis: resume : locty 0 : r_offset = %d, w_offset = %d\n", + s->loc[0].r_offset, s->loc[0].w_offset); +#endif + + return s->be_driver->ops->load_volatile_data(s); +} + + +static const VMStateDescription vmstate_locty = { + .name = "loc", + .version_id = 1, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .fields = (VMStateField[]) { + VMSTATE_UINT32(state, TPMLocality), + VMSTATE_UINT32(inte, TPMLocality), + VMSTATE_UINT32(ints, TPMLocality), + VMSTATE_UINT8(access, TPMLocality), + VMSTATE_UINT8(sts, TPMLocality), + VMSTATE_END_OF_LIST(), + } +}; + + +static const VMStateDescription vmstate_tis = { + .name = "tpm", + .version_id = 1, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .pre_save = tis_pre_save, + .post_load = tis_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(irq_num, TPMState), + VMSTATE_UINT32(offset, TPMState), + VMSTATE_BUFFER(buf, TPMState), + VMSTATE_UINT8(active_locty, TPMState), + VMSTATE_UINT8(aborting_locty, TPMState), + VMSTATE_UINT8(next_locty, TPMState), + + VMSTATE_STRUCT_ARRAY(loc, TPMState, NUM_LOCALITIES, 1, + vmstate_locty, TPMLocality), + + VMSTATE_END_OF_LIST() + } +}; + + +static ISADeviceInfo tis_device_info = { + .init = tis_init, + .qdev.name = "tpm-tis", + .qdev.size = sizeof(TPMState), + .qdev.vmsd = &vmstate_tis, + .qdev.reset = tis_reset, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("irq", TPMState, + irq_num, TPM_TIS_IRQ), + DEFINE_PROP_STRING("tpmdev", TPMState, backend), + DEFINE_PROP_END_OF_LIST(), + }, +}; + + +static void tis_register_device(void) +{ + isa_qdev_register(&tis_device_info); +} + +device_init(tis_register_device)