{"id":2229158,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2229158/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260427200134.453022-1-armenon@redhat.com/","project":{"id":14,"url":"http://patchwork.ozlabs.org/api/1.1/projects/14/?format=json","name":"QEMU Development","link_name":"qemu-devel","list_id":"qemu-devel.nongnu.org","list_email":"qemu-devel@nongnu.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20260427200134.453022-1-armenon@redhat.com>","date":"2026-04-27T20:01:34","name":"tpm: Dynamically allocate tpm-tis buffer","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"e795c2c5858276c67850d850df7b7521f8b4ef20","submitter":{"id":91136,"url":"http://patchwork.ozlabs.org/api/1.1/people/91136/?format=json","name":"Arun Menon","email":"armenon@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/qemu-devel/patch/20260427200134.453022-1-armenon@redhat.com/mbox/","series":[{"id":501719,"url":"http://patchwork.ozlabs.org/api/1.1/series/501719/?format=json","web_url":"http://patchwork.ozlabs.org/project/qemu-devel/list/?series=501719","date":"2026-04-27T20:01:34","name":"tpm: Dynamically allocate tpm-tis buffer","version":1,"mbox":"http://patchwork.ozlabs.org/series/501719/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2229158/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2229158/checks/","tags":{},"headers":{"Return-Path":"<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=hA1J1vfp;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=google header.b=nTayf0VG;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org\n (client-ip=209.51.188.17; helo=lists1p.gnu.org;\n envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n receiver=patchwork.ozlabs.org)"],"Received":["from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4Dyn2VhXz1xvV\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 06:03:27 +1000 (AEST)","from localhost ([::1] helo=lists1p.gnu.org)\n\tby lists1p.gnu.org with esmtp (Exim 4.90_1)\n\t(envelope-from <qemu-devel-bounces@nongnu.org>)\n\tid 1wHSAn-0002Fz-8K; Mon, 27 Apr 2026 16:03:17 -0400","from eggs.gnu.org ([2001:470:142:3::10])\n by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <armenon@redhat.com>)\n id 1wHS9V-00085k-58\n for qemu-devel@nongnu.org; Mon, 27 Apr 2026 16:01:57 -0400","from us-smtp-delivery-124.mimecast.com ([170.10.133.124])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <armenon@redhat.com>)\n id 1wHS9Q-00044U-6f\n for qemu-devel@nongnu.org; Mon, 27 Apr 2026 16:01:56 -0400","from mail-pl1-f198.google.com (mail-pl1-f198.google.com\n [209.85.214.198]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-314-c5_tPNCAMLqTjYSETGRjFA-1; Mon, 27 Apr 2026 16:01:46 -0400","by mail-pl1-f198.google.com with SMTP id\n d9443c01a7336-2b24a00d12cso107844965ad.1\n for <qemu-devel@nongnu.org>; Mon, 27 Apr 2026 13:01:46 -0700 (PDT)","from fedora.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.110.6])\n by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-2b97ac8ca3dsm2700175ad.58.2026.04.27.13.01.42\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 27 Apr 2026 13:01:44 -0700 (PDT)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1777320108;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:\n content-transfer-encoding:content-transfer-encoding;\n bh=X7FwrTnmcrnLZ1g6A6+lc8za4SrCyBFRmudCXBW+310=;\n b=hA1J1vfpoIniHCworqrAV5Q8YAaZYNsLNVsAHlSATzrqQf4hsyaD0bNskTWukuF3520lGj\n f1DKC/PnbS24eZct/UXDkT9uc3KUbS5JPjONOdvQJtHnpOYAEpUzzbCE5JgQtKdgPE+Wf4\n ihCsxrvPQ3ZsZSnZXXJltqTLQiCTja8=","v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=redhat.com; s=google; t=1777320105; x=1777924905; darn=nongnu.org;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:from:to:cc:subject:date:message-id:reply-to;\n bh=X7FwrTnmcrnLZ1g6A6+lc8za4SrCyBFRmudCXBW+310=;\n b=nTayf0VG0mG0+jbndKhUguRe37FPrl7LWWClquo80tunLAQrRKk7y6gJGq9/H0dboL\n Nq37R1PuzmmUVmXey2xab/yAxswl7GIvOUNPxOOcJFl44BoQCfr6LULPYCXNFB0eIwvK\n DwUyGFZ23C/VH3NmhX+ebH6s6puOeVgZwfC8bdv8h1MzOSIocunKrimO+UDBZ6dhIzTz\n m2cm/mB7o2OLkekibXbCVm6Q5QgtQteaW8h5Rs9VMa9hGhrUvgpwAMZ47WZwh1WzS9aK\n SeWSTdcGQeGRteUFdBjEKfCESp3TsUSuFfke//DKjHoRbkuQmmiNHoAbos+rC7b5Ibkf\n pJuA=="],"X-MC-Unique":"c5_tPNCAMLqTjYSETGRjFA-1","X-Mimecast-MFC-AGG-ID":"c5_tPNCAMLqTjYSETGRjFA_1777320106","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777320105; x=1777924905;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=X7FwrTnmcrnLZ1g6A6+lc8za4SrCyBFRmudCXBW+310=;\n b=ZtjxOEznWNiOXJTDrQywmWTP45+AUgQ9DsNBpCDHbyn7HXeN+HJ+QBg3OFEnNen39r\n pErBER9cg44ZSI9oH2JW2M1ltZ6JIx9Z95gPWqqVafR7CDenNdasJrB3lHr3KN41sWVb\n OfexkSPDWssiKakngOe/zAXrgxOmMf3agz03udZnmbOVnYDSsJbFf+3j3fCP3fAbPP2l\n n77TBY02RavtZfwHARAsiaUwusCfWjb1d6lKFyMyuod9nSXAepBChSm8Npe3852fy2sg\n xQh3HtiE3WV6FMysg17bB0U4NQ5/zjOujn3JouT47X+dkAeP+XUqkcQkqg9cXoLmsL3s\n OL/g==","X-Gm-Message-State":"AOJu0YxhIggV6Tv5NssaVyS6vwN9LUC4K/zbPb6tsJwyQRiAr0qVbcsK\n hH4XTan2bgau66Jk8+RdueD2SeA9KbxelZ5CBeNQrUEuGsMuCwC+OddNGdjt4EKzu43JI5P5LeR\n Ied0djF8HZhGpBVuYIK84L2rOSmIzQ0wesxQ9+7pCwa4KfdoWq6WvFXRC97kHm6R+6JA2pZ+kCG\n /Qg/TbpCuBHpTbkWx2NDyQtmJx+m/XnWikyFn1rsk=","X-Gm-Gg":"AeBDievtVyw+7v4ICmoq7NqEyHINStTIOUVoW+2+Fhy1kRaB1m4oEmrTKMG3cmFqVXQ\n Ns6l5/ndLdcBPq4H/wAIMEUKDVTdqaL4Ab9MifkML4EQI1Zx1U6qU5Cleuc/40KKpnu8sDuvS6f\n Ewe8yKWMLpaDiKWTgZ0I52lhhQxrU0ZaN9u2ZOBXpZMxxhQJ8zEhgVxgSxU87KNBBCSEGwF58b6\n zizjczMMG5QHkJmgxEacnuAz4lQw7u/xQFGfJJ46kh7avMXFBI+NZb1goMHULWRIj7PjUdJ/qzY\n ALR3bmVUdpP9bDuKz3+4BU9JGtEkoBFluBx2/N+rdRHI9FfvT90Ug1WsRLuYQ0nqYFPk/0Lwhya\n OCDajnd5/Q19h3ycjvEYcE3pjVkI2CzC4SAI86HtawR0snLiDXExyUeAooPGJgU8i0vFfJB0=","X-Received":["by 2002:a17:902:d2c7:b0:2b7:af0e:5942 with SMTP id\n d9443c01a7336-2b97c4b232amr197815ad.26.1777320105049;\n Mon, 27 Apr 2026 13:01:45 -0700 (PDT)","by 2002:a17:902:d2c7:b0:2b7:af0e:5942 with SMTP id\n d9443c01a7336-2b97c4b232amr197315ad.26.1777320104282;\n Mon, 27 Apr 2026 13:01:44 -0700 (PDT)"],"From":"Arun Menon <armenon@redhat.com>","To":"qemu-devel@nongnu.org","Cc":"Stefan Berger <stefanb@linux.vnet.ibm.com>,\n Arun Menon <armenon@redhat.com>","Subject":"[PATCH] tpm: Dynamically allocate tpm-tis buffer","Date":"Tue, 28 Apr 2026 01:31:34 +0530","Message-ID":"<20260427200134.453022-1-armenon@redhat.com>","X-Mailer":"git-send-email 2.53.0","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Received-SPF":"pass client-ip=170.10.133.124; envelope-from=armenon@redhat.com;\n helo=us-smtp-delivery-124.mimecast.com","X-Spam_score_int":"-20","X-Spam_score":"-2.1","X-Spam_bar":"--","X-Spam_report":"(-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001,\n DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1,\n RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_PASS=-0.001,\n SPF_PASS=-0.001 autolearn=ham autolearn_force=no","X-Spam_action":"no action","X-BeenThere":"qemu-devel@nongnu.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"qemu development <qemu-devel.nongnu.org>","List-Unsubscribe":"<https://lists.nongnu.org/mailman/options/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>","List-Archive":"<https://lists.nongnu.org/archive/html/qemu-devel>","List-Post":"<mailto:qemu-devel@nongnu.org>","List-Help":"<mailto:qemu-devel-request@nongnu.org?subject=help>","List-Subscribe":"<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n <mailto:qemu-devel-request@nongnu.org?subject=subscribe>","Errors-To":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org","Sender":"qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org"},"content":"From: Arun Menon <armenon@redhat.com>\n\nThe TPM TIS buffer is currently a fixed-size static array. Change this\nto a dynamically allocated heap block. The buffer size is now determined\nat runtime by querying the TPM backend.\n\nTo support VM migration,\n1. Replace the static VMSTATE_BUFFER macro with pointer-based variant\n   VMSTATE_BUFFER_POINTER_UNSAFE, explicitly mentioning the size.\n2. Introduce ext_buffer and ext_size in the migration subsection to\n   track allocation exceeding TPM_TIS_BUFFER_MAX. Allocate ext_buffer\n   using VMSTATE_VBUFFER_ALLOC_UINT32 only to be freed later after it is\n   appended to the main buffer.\n\nThis allows us to migrate to a destination host without breaking\nbackward compatibility. Old QEMU does not include a size field along\nwith the buffer in the migration stream, and therefore the\nnew QEMU is also forced to keep expecting exactly 4096 bytes.\n\nImplement a post_load hook that will validate the incoming data size\nfrom the migration stream, failing the migration if it exceeds the\ndestination backend capacity. Add unrealize functions for the TIS interface\ntypes ISA, SysBus and I2C to ensure that the buffer is safely freed on\ndevice destruction.\n\nSigned-off-by: Arun Menon <armenon@redhat.com>\n---\nDependencies:\nThis patch depends on the following patch currently in the mailing list:\nhttps://lore.kernel.org/qemu-devel/20260422103018.123608-10-armenon@redhat.com/\n\nDepends-on: <20260422103018.123608-10-armenon@redhat.com>\n\n hw/tpm/tpm_tis.h        |  6 ++++-\n hw/tpm/tpm_tis_common.c | 56 +++++++++++++++++++++++++++++++++++------\n hw/tpm/tpm_tis_i2c.c    | 28 +++++++++++++++++++--\n hw/tpm/tpm_tis_isa.c    | 31 +++++++++++++++++++++--\n hw/tpm/tpm_tis_sysbus.c | 32 +++++++++++++++++++++--\n 5 files changed, 138 insertions(+), 15 deletions(-)","diff":"diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h\nindex b2d9c0116c..c736ecedc1 100644\n--- a/hw/tpm/tpm_tis.h\n+++ b/hw/tpm/tpm_tis.h\n@@ -56,7 +56,9 @@ typedef struct TPMLocality {\n typedef struct TPMState {\n     MemoryRegion mmio;\n \n-    unsigned char buffer[TPM_TIS_BUFFER_MAX];\n+    uint8_t *buffer;\n+    uint8_t *ext_buffer;\n+    uint32_t ext_size;\n     uint16_t rw_offset;\n \n     uint8_t active_locty;\n@@ -82,6 +84,8 @@ extern const VMStateDescription vmstate_locty;\n extern const MemoryRegionOps tpm_tis_memory_ops;\n \n int tpm_tis_pre_save(TPMState *s);\n+int tpm_tis_post_load(TPMState *s);\n+int tpm_tis_ext_buffer_post_load(TPMState *s);\n void tpm_tis_reset(TPMState *s, bool ppi_enabled);\n enum TPMVersion tpm_tis_get_tpm_version(TPMState *s);\n void tpm_tis_request_completed(TPMState *s, int ret);\ndiff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c\nindex 43e68410f8..c9c4dd1190 100644\n--- a/hw/tpm/tpm_tis_common.c\n+++ b/hw/tpm/tpm_tis_common.c\n@@ -270,7 +270,7 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)\n     uint16_t len;\n \n     if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {\n-        len = MIN(tpm_cmd_get_size(&s->buffer),\n+        len = MIN(tpm_cmd_get_size(s->buffer),\n                   s->be_buffer_size);\n \n         ret = s->buffer[s->rw_offset++];\n@@ -317,7 +317,7 @@ static void tpm_tis_dump_state(TPMState *s, hwaddr addr)\n            \"tpm_tis: result buffer : \",\n            s->rw_offset);\n     for (idx = 0;\n-         idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size);\n+         idx < MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size);\n          idx++) {\n         printf(\"%c%02x%s\",\n                s->rw_offset == idx ? '>' : ' ',\n@@ -383,7 +383,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,\n         if (s->active_locty == locty) {\n             if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {\n                 val = TPM_TIS_BURST_COUNT(\n-                       MIN(tpm_cmd_get_size(&s->buffer),\n+                       MIN(tpm_cmd_get_size(s->buffer),\n                            s->be_buffer_size)\n                        - s->rw_offset) | s->loc[locty].sts;\n             } else {\n@@ -754,7 +754,7 @@ static void tpm_tis_mmio_write(void *opaque, hwaddr addr,\n                 /* we have a packet length - see if we have all of it */\n                 bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID);\n \n-                len = tpm_cmd_get_size(&s->buffer);\n+                len = tpm_cmd_get_size(s->buffer);\n                 if (len > s->rw_offset) {\n                     tpm_tis_sts_set(&s->loc[locty],\n                                     TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);\n@@ -818,9 +818,10 @@ void tpm_tis_reset(TPMState *s, bool ppi_enabled)\n     int c;\n \n     s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);\n-    s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),\n-                            TPM_TIS_BUFFER_MAX);\n \n+    s->be_buffer_size = tpm_backend_get_buffer_size(s->be_driver);\n+    s->buffer = g_realloc(s->buffer, MAX(s->be_buffer_size,\n+                          TPM_TIS_BUFFER_MAX));\n     if (ppi_enabled) {\n         tpm_ppi_reset(&s->ppi);\n     }\n@@ -873,6 +874,45 @@ int tpm_tis_pre_save(TPMState *s)\n      */\n     tpm_backend_finish_sync(s->be_driver);\n \n+    if (s->be_buffer_size > TPM_TIS_BUFFER_MAX) {\n+        s->ext_size = s->be_buffer_size - TPM_TIS_BUFFER_MAX;\n+        s->ext_buffer = s->buffer + TPM_TIS_BUFFER_MAX;\n+    } else {\n+        s->ext_size = 0;\n+        s->ext_buffer = NULL;\n+    }\n+    return 0;\n+}\n+\n+int tpm_tis_post_load(TPMState *s)\n+{\n+    if (s->rw_offset > s->be_buffer_size) {\n+        return -EINVAL;\n+    }\n+    return 0;\n+}\n+\n+int tpm_tis_ext_buffer_post_load(TPMState *s)\n+{\n+    /*\n+     * Calculate the maximum extension buffer size allowed, by comparing\n+     * the destination VM's backend capacity with TPM_TIS_BUFFER_MAX.\n+     */\n+    uint32_t max_ext = s->be_buffer_size > TPM_TIS_BUFFER_MAX ?\n+                       s->be_buffer_size - TPM_TIS_BUFFER_MAX : 0;\n+\n+    if (s->ext_size > max_ext) {\n+        /*\n+         * Source buffer size is greater than what the destination backend\n+         * allows\n+         */\n+        g_clear_pointer(&s->ext_buffer, g_free);\n+        return -EINVAL;\n+    }\n+    if (s->ext_size > 0) {\n+        memcpy(s->buffer + TPM_TIS_BUFFER_MAX, s->ext_buffer, s->ext_size);\n+        g_clear_pointer(&s->ext_buffer, g_free);\n+    }\n     return 0;\n }\n \n@@ -901,7 +941,7 @@ bool tpm_tis_ext_buffer_migration_needed(struct TPMState *s)\n     case TPM_TIS_STATE_READY:\n         return false;\n     case TPM_TIS_STATE_RECEPTION:\n-        return s->rw_offset >= 4096;\n+        return s->rw_offset >= TPM_TIS_BUFFER_MAX;\n     case TPM_TIS_STATE_EXECUTION:\n         /*\n          * TPM is executing: we cannot know the size of TPM response.\n@@ -909,7 +949,7 @@ bool tpm_tis_ext_buffer_migration_needed(struct TPMState *s)\n          */\n         return false;\n     case TPM_TIS_STATE_COMPLETION:\n-        return (tpm_cmd_get_size(&s->buffer) >= 4096);\n+        return (tpm_cmd_get_size(s->buffer) >= TPM_TIS_BUFFER_MAX);\n     }\n     return false;\n }\ndiff --git a/hw/tpm/tpm_tis_i2c.c b/hw/tpm/tpm_tis_i2c.c\nindex f48938e3a1..41a5486497 100644\n--- a/hw/tpm/tpm_tis_i2c.c\n+++ b/hw/tpm/tpm_tis_i2c.c\n@@ -103,6 +103,10 @@ static int tpm_tis_i2c_post_load(void *opaque, int version_id)\n {\n     TPMStateI2C *i2cst = opaque;\n \n+    if (tpm_tis_post_load(&i2cst->state) < 0) {\n+        return -1;\n+    }\n+\n     if (i2cst->offset >= 1) {\n         tpm_tis_i2c_to_tis_reg(i2cst, i2cst->data[0]);\n     }\n@@ -117,13 +121,23 @@ static bool tpm_tis_ext_buffer_migration_needed_i2c(void *opaque)\n     return tpm_tis_ext_buffer_migration_needed(&i2cst->state);\n }\n \n+static int tpm_tis_ext_buffer_post_load_i2c(void *opaque, int version_id)\n+{\n+    TPMStateI2C *i2cst = opaque;\n+\n+    return tpm_tis_ext_buffer_post_load(&i2cst->state);\n+}\n+\n static const VMStateDescription vmstate_tpm_tis_ext_buffer_i2c = {\n     .name = \"tpm-tis/ext_buffer\",\n     .version_id = 0,\n     .needed = tpm_tis_ext_buffer_migration_needed_i2c,\n     .pre_save = tpm_tis_i2c_pre_save,\n+    .post_load = tpm_tis_ext_buffer_post_load_i2c,\n     .fields = (const VMStateField[]) {\n-        VMSTATE_BUFFER_START_MIDDLE(state.buffer, TPMStateI2C, 4096),\n+        VMSTATE_UINT32(state.ext_size, TPMStateI2C),\n+        VMSTATE_VBUFFER_ALLOC_UINT32(state.ext_buffer, TPMStateI2C, 0, NULL,\n+                                     state.ext_size),\n         VMSTATE_END_OF_LIST()\n     }\n };\n@@ -134,7 +148,8 @@ static const VMStateDescription vmstate_tpm_tis_i2c = {\n     .pre_save  = tpm_tis_i2c_pre_save,\n     .post_load  = tpm_tis_i2c_post_load,\n     .fields = (const VMStateField[]) {\n-        VMSTATE_PARTIAL_BUFFER(state.buffer, TPMStateI2C, 4096),\n+        VMSTATE_BUFFER_POINTER_UNSAFE(state.buffer, TPMStateI2C, 0,\n+                                      TPM_TIS_BUFFER_MAX),\n         VMSTATE_UINT16(state.rw_offset, TPMStateI2C),\n         VMSTATE_UINT8(state.active_locty, TPMStateI2C),\n         VMSTATE_UINT8(state.aborting_locty, TPMStateI2C),\n@@ -535,6 +550,14 @@ static void tpm_tis_i2c_realizefn(DeviceState *dev, Error **errp)\n     }\n }\n \n+static void tpm_tis_i2c_unrealizefn(DeviceState *dev)\n+{\n+    TPMStateI2C *i2cst = TPM_TIS_I2C(dev);\n+    TPMState *state = &i2cst->state;\n+\n+    g_clear_pointer(&state->buffer, g_free);\n+}\n+\n static void tpm_tis_i2c_reset(DeviceState *dev)\n {\n     TPMStateI2C *i2cst = TPM_TIS_I2C(dev);\n@@ -555,6 +578,7 @@ static void tpm_tis_i2c_class_init(ObjectClass *klass, const void *data)\n     TPMIfClass *tc = TPM_IF_CLASS(klass);\n \n     dc->realize = tpm_tis_i2c_realizefn;\n+    dc->unrealize = tpm_tis_i2c_unrealizefn;\n     device_class_set_legacy_reset(dc, tpm_tis_i2c_reset);\n     dc->vmsd = &vmstate_tpm_tis_i2c;\n     device_class_set_props(dc, tpm_tis_i2c_properties);\ndiff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c\nindex 4999de1c61..7fbdfb96e6 100644\n--- a/hw/tpm/tpm_tis_isa.c\n+++ b/hw/tpm/tpm_tis_isa.c\n@@ -49,6 +49,12 @@ static int tpm_tis_pre_save_isa(void *opaque)\n     return tpm_tis_pre_save(&isadev->state);\n }\n \n+static int tpm_tis_post_load_isa(void *opaque, int version_id)\n+{\n+    TPMStateISA *isadev = opaque;\n+    return tpm_tis_post_load(&isadev->state);\n+}\n+\n static bool tpm_tis_ext_buffer_migration_needed_isa(void *opaque)\n {\n     TPMStateISA *isadev = opaque;\n@@ -56,13 +62,23 @@ static bool tpm_tis_ext_buffer_migration_needed_isa(void *opaque)\n     return tpm_tis_ext_buffer_migration_needed(&isadev->state);\n }\n \n+static int tpm_tis_ext_buffer_post_load_isa(void *opaque, int version_id)\n+{\n+    TPMStateISA *isadev = opaque;\n+\n+    return tpm_tis_ext_buffer_post_load(&isadev->state);\n+}\n+\n static const VMStateDescription vmstate_tpm_tis_ext_buffer_isa = {\n     .name = \"tpm-tis/ext_buffer\",\n     .version_id = 0,\n     .needed = tpm_tis_ext_buffer_migration_needed_isa,\n     .pre_save = tpm_tis_pre_save_isa,\n+    .post_load = tpm_tis_ext_buffer_post_load_isa,\n     .fields = (const VMStateField[]) {\n-        VMSTATE_BUFFER_START_MIDDLE(state.buffer, TPMStateISA, 4096),\n+        VMSTATE_UINT32(state.ext_size, TPMStateISA),\n+        VMSTATE_VBUFFER_ALLOC_UINT32(state.ext_buffer, TPMStateISA, 0, NULL,\n+                                     state.ext_size),\n         VMSTATE_END_OF_LIST()\n     }\n };\n@@ -71,8 +87,10 @@ static const VMStateDescription vmstate_tpm_tis_isa = {\n     .name = \"tpm-tis\",\n     .version_id = 0,\n     .pre_save  = tpm_tis_pre_save_isa,\n+    .post_load = tpm_tis_post_load_isa,\n     .fields = (const VMStateField[]) {\n-        VMSTATE_PARTIAL_BUFFER(state.buffer, TPMStateISA, 4096),\n+        VMSTATE_BUFFER_POINTER_UNSAFE(state.buffer, TPMStateISA, 0,\n+                                      TPM_TIS_BUFFER_MAX),\n         VMSTATE_UINT16(state.rw_offset, TPMStateISA),\n         VMSTATE_UINT8(state.active_locty, TPMStateISA),\n         VMSTATE_UINT8(state.aborting_locty, TPMStateISA),\n@@ -157,6 +175,14 @@ static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp)\n                  TPM_PPI_ADDR_BASE, OBJECT(dev));\n }\n \n+static void tpm_tis_isa_unrealizefn(DeviceState *dev)\n+{\n+    TPMStateISA *isadev = TPM_TIS_ISA(dev);\n+    TPMState *state = &isadev->state;\n+\n+    g_clear_pointer(&state->buffer, g_free);\n+}\n+\n static void build_tpm_tis_isa_aml(AcpiDevAmlIf *adev, Aml *scope)\n {\n     Aml *dev, *crs;\n@@ -196,6 +222,7 @@ static void tpm_tis_isa_class_init(ObjectClass *klass, const void *data)\n     tc->model = TPM_MODEL_TPM_TIS;\n     tc->ppi_enabled = true;\n     dc->realize = tpm_tis_isa_realizefn;\n+    dc->unrealize = tpm_tis_isa_unrealizefn;\n     device_class_set_legacy_reset(dc, tpm_tis_isa_reset);\n     tc->request_completed = tpm_tis_isa_request_completed;\n     tc->get_version = tpm_tis_isa_get_tpm_version;\ndiff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c\nindex c29f43bdce..ad8cfa85b1 100644\n--- a/hw/tpm/tpm_tis_sysbus.c\n+++ b/hw/tpm/tpm_tis_sysbus.c\n@@ -49,6 +49,13 @@ static int tpm_tis_pre_save_sysbus(void *opaque)\n     return tpm_tis_pre_save(&sbdev->state);\n }\n \n+static int tpm_tis_post_load_sysbus(void *opaque, int version_id)\n+{\n+    TPMStateSysBus *sbdev = opaque;\n+\n+    return tpm_tis_post_load(&sbdev->state);\n+}\n+\n static bool tpm_tis_ext_buffer_migration_needed_sysbus(void *opaque)\n {\n     TPMStateSysBus *sbdev = opaque;\n@@ -56,13 +63,23 @@ static bool tpm_tis_ext_buffer_migration_needed_sysbus(void *opaque)\n     return tpm_tis_ext_buffer_migration_needed(&sbdev->state);\n }\n \n+static int tpm_tis_ext_buffer_post_load_sysbus(void *opaque, int version_id)\n+{\n+    TPMStateSysBus *sbdev = opaque;\n+\n+    return tpm_tis_ext_buffer_post_load(&sbdev->state);\n+}\n+\n static const VMStateDescription vmstate_tpm_tis_ext_buffer_sysbus = {\n     .name = \"tpm-tis/ext_buffer\",\n     .version_id = 0,\n     .needed = tpm_tis_ext_buffer_migration_needed_sysbus,\n     .pre_save  = tpm_tis_pre_save_sysbus,\n+    .post_load = tpm_tis_ext_buffer_post_load_sysbus,\n     .fields = (const VMStateField[]) {\n-        VMSTATE_BUFFER_START_MIDDLE(state.buffer, TPMStateSysBus, 4096),\n+        VMSTATE_UINT32(state.ext_size, TPMStateSysBus),\n+        VMSTATE_VBUFFER_ALLOC_UINT32(state.ext_buffer, TPMStateSysBus, 0,\n+                                     NULL, state.ext_size),\n         VMSTATE_END_OF_LIST()\n     }\n };\n@@ -71,8 +88,10 @@ static const VMStateDescription vmstate_tpm_tis_sysbus = {\n     .name = \"tpm-tis\",\n     .version_id = 0,\n     .pre_save  = tpm_tis_pre_save_sysbus,\n+    .post_load = tpm_tis_post_load_sysbus,\n     .fields = (const VMStateField[]) {\n-        VMSTATE_PARTIAL_BUFFER(state.buffer, TPMStateSysBus, 4096),\n+        VMSTATE_BUFFER_POINTER_UNSAFE(state.buffer, TPMStateSysBus, 0,\n+                                      TPM_TIS_BUFFER_MAX),\n         VMSTATE_UINT16(state.rw_offset, TPMStateSysBus),\n         VMSTATE_UINT8(state.active_locty, TPMStateSysBus),\n         VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus),\n@@ -156,6 +175,14 @@ static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp)\n     vmstate_register_ram(&s->ppi.ram, dev);\n }\n \n+static void tpm_tis_sysbus_unrealizefn(DeviceState *dev)\n+{\n+    TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev);\n+    TPMState *state = &sbdev->state;\n+\n+    g_clear_pointer(&state->buffer, g_free);\n+}\n+\n static void tpm_tis_sysbus_class_init(ObjectClass *klass, const void *data)\n {\n     DeviceClass *dc = DEVICE_CLASS(klass);\n@@ -166,6 +193,7 @@ static void tpm_tis_sysbus_class_init(ObjectClass *klass, const void *data)\n     tc->model = TPM_MODEL_TPM_TIS;\n     tc->ppi_enabled = true;\n     dc->realize = tpm_tis_sysbus_realizefn;\n+    dc->unrealize = tpm_tis_sysbus_unrealizefn;\n     device_class_set_legacy_reset(dc, tpm_tis_sysbus_reset);\n     tc->request_completed = tpm_tis_sysbus_request_completed;\n     tc->get_version = tpm_tis_sysbus_get_tpm_version;\n","prefixes":[]}