From nobody Sat May 30 19:21:04 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1777525364; cv=none; d=zohomail.com; s=zohoarc; b=mcRv814KViP2BqI28iL3jjPKzHVUXbdxpCqFkFaqjcThAdKQfdvWyAUSl1eEnlH1+YcezYkP7Nk6fkjEiqagkKeN2IFXtqU3gwrvedG+2ItZrbxhBwvi7RwljUN2ldHMkAO93w8WVQboiqp7HBkzXnQcWMlg9i+9/ZhrcMe+IZc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1777525364; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=yQ10o/nhNMp9WiPLO3oSpqcfumGQlVQMd3hRta3eci0=; b=k/CYQYQgXM+2Hgq+ZrLmRh3t8wGqzutsEUxv7urmwrT1TziNfyUZcQTUyH7ni2KUuSb+hjINcSevckyVqf7yB2inLl+uDU3AWDKvJj5rkKpAe8yq2p5tLHuH+vUynplpX87SwdkQ7uxH06qRVG4lm4bSJ7WIYsRUXW6SX/CA2ds= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1777525364417129.97831520117654; Wed, 29 Apr 2026 22:02:44 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wIJXk-0000ak-4f; Thu, 30 Apr 2026 01:02:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wIJX7-0000FC-Br for qemu-devel@nongnu.org; Thu, 30 Apr 2026 01:01:57 -0400 Received: from mail-pl1-x632.google.com ([2607:f8b0:4864:20::632]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wIJWR-00057x-UA for qemu-devel@nongnu.org; Thu, 30 Apr 2026 01:01:50 -0400 Received: by mail-pl1-x632.google.com with SMTP id d9443c01a7336-2b24fede2acso3002405ad.3 for ; Wed, 29 Apr 2026 22:01:11 -0700 (PDT) Received: from localhost.localdomain ([114.249.134.218]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2b988963ed0sm39527405ad.65.2026.04.29.22.01.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2026 22:01:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777525270; x=1778130070; darn=nongnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=yQ10o/nhNMp9WiPLO3oSpqcfumGQlVQMd3hRta3eci0=; b=prk+x0crdHLN1fKm8sw9lNOCLlurerEG/Kv+XiJy/mPxH53gLKqCTQ69aC/1lC5WRw v3bgGr4JzQKn2Q63jhzGYaARJegu+7mIOfJwL5evAeOKB7g8L6hDe5Ry7S6UVmP/tB26 9dk05Nxk1b5+/I39bBwaB0BQeRcmYvnD8CMWGUTDxKST1cFdHiQp8bP34UB5v/iSDua3 okBckwqtMPXCafjzzh5ONI0P8bxXeemxNvP+tbhYxeDBrinY/xy8it+juojv8prD7UF7 7cJSenDo9xLQhnA+z7VZeX/KBABH1oqgmmcPVZas49PaPWkOuYdT9nTIitlNLOiDraJd x3qg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777525270; x=1778130070; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=yQ10o/nhNMp9WiPLO3oSpqcfumGQlVQMd3hRta3eci0=; b=LtRHJiIH23TpeEt/46v3l/HzXuX9umbcCV3lPWtHi1M3ghsEyFguNDvk1CfFqB27cs nvmnrLAAKt9NpyqizyjdADLlYo+aHrrNdPROxWf24THWH+RIy0xLb5/Vfi9VBzZ8tZuc cR6FaW7JzIFLa3dmt3i2OkdxRbAK5D5Sb8FsD+u02u2IO12vMch0GztiKK56B3TO7B4a pPMfKQXpjE7ryK9BRbANln563+9iujKnYCzen1Vv3J/NaCMsLMhiuMKpBSfSgl+29C+q 6wgw+tX8eQ/L8yzREB7PXfmoNuzI17hBVtT8t4GUW6JKo5Cizp8klEPpWXaJ0GBUR1V4 pK/A== X-Gm-Message-State: AOJu0YwH4lEJ2SXtKjWEp9jDQJf+cyWJ4fgbR+SqERqv9J8ud9M3McHL Mkkw4sjV0ZpUbtPBIfnahbfQjRvMRChxKUCLBwHrcMMH1MPnF0U2Zs0lr97Ql15bDPgKnQ== X-Gm-Gg: AeBDietN5x57hmtK6m8wIp6WUDtXlYq48Sgo2f2JlfYFi/YPJNRBiL/vHmsKu96+X23 UISGS/pYpEUME0Lf6W+6rU1eX4TY7zfwSNgeVuxKrOpwNgbU4IPEhrd2l1UXG6FbjHzYLnWH2iY j+wNH2otiFtkwqulGFHASonWY1rqecSoXviF7EynSHADMT1xIbLCfD5r2qQZN3j/gcqlQBiqNar CzFWc6njBS4Ru0LhSOqURppm/kYNYzoAV8erOn6Qtcks7aKvf9dkf+ZllOX5izzePrzGY2KtA+g w5geJ31l1nLN1L7BiBLmbLq2abJbk1hxKbOgoMSPtvhV1p6nu+zJasmew2bXZmH3SSoBzvbwrNe v7Z/Ck1+5P0o2PGp7amVo5w+V1i49gmU8u3Jm/5bqdmRkKdPqtNaW5PH8ati1E5sO3ytlqX702I Q2oIr07oX/xk0XQ3Y7Np7nqQ008PqkDgRCOfbLn3pmcQ1EHPU1m64= X-Received: by 2002:a17:903:3c4f:b0:2b0:6e6a:8504 with SMTP id d9443c01a7336-2b9a24b954fmr12675645ad.27.1777525269442; Wed, 29 Apr 2026 22:01:09 -0700 (PDT) From: Jia Jia To: qemu-devel@nongnu.org Cc: jonathan.cameron@huawei.com, fan.ni@samsung.com, farosas@suse.de, lvivier@redhat.com, pbonzini@redhat.com Subject: [PATCH] hw/cxl: bound Set Feature cleanup to written extent Date: Thu, 30 Apr 2026 13:01:03 +0800 Message-Id: <20260430050103.3172190-1-physicalmtea@gmail.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::632; envelope-from=physicalmtea@gmail.com; helo=mail-pl1-x632.google.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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, 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 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1777525366932154100 Content-Type: text/plain; charset="utf-8" cmd_features_set_feature() validates each fragment against the target write-attribute buffer, but it tracks data_size as the sum of every fragment copied so far. That becomes a problem at transfer completion. Cleanup uses data_size as its memset() length, so a sequence of legal partial transfers can keep rewriting the same small range while growing data_size far beyond the feature buffer that is actually being updated. On an ASan build, repeatedly sending 2-byte rank_sparing fragments at offset 0 and then finishing aborts the host with: ERROR: AddressSanitizer: heap-buffer-overflow WRITE of size 1144 #0 __interceptor_memset #1 cmd_features_set_feature ../hw/cxl/cxl-mailbox-utils.c:1961 #2 cxl_process_cci_message ../hw/cxl/cxl-mailbox-utils.c:4642 #3 mailbox_reg_write ../hw/cxl/cxl-device-utils.c:209 Fix this by tracking the maximum written extent instead of the cumulative number of copied bytes. That keeps cleanup bounded to the actual write-attribute window without changing the rest of the transfer flow. Add a qtest that confirms a multipart bank_sparing transfer does not clobber adjacent rank_sparing state during cleanup. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3461 Signed-off-by: Jia Jia --- hw/cxl/cxl-mailbox-utils.c | 11 +--- tests/qtest/cxl-test.c | 119 ++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 9 deletions(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index ce139e30eb..8346177b79 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -1769,7 +1769,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, memcpy((uint8_t *)&ct3d->patrol_scrub_wr_attrs + hdr->offset, ps_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TR= ANSFER) { @@ -1796,7 +1795,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, memcpy((uint8_t *)&ct3d->ecs_wr_attrs + hdr->offset, ecs_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TR= ANSFER) { @@ -1820,7 +1818,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, } memcpy((uint8_t *)&ct3d->soft_ppr_wr_attrs + hdr->offset, sppr_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TR= ANSFER) { @@ -1842,7 +1839,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, } memcpy((uint8_t *)&ct3d->hard_ppr_wr_attrs + hdr->offset, hppr_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TR= ANSFER) { @@ -1864,7 +1860,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, } memcpy((uint8_t *)&ct3d->cacheline_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TRA= NSFER) { @@ -1885,7 +1880,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, } memcpy((uint8_t *)&ct3d->row_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TRA= NSFER) { @@ -1906,7 +1900,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, } memcpy((uint8_t *)&ct3d->bank_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TRA= NSFER) { @@ -1927,7 +1920,6 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, } memcpy((uint8_t *)&ct3d->rank_sparing_wr_attrs + hdr->offset, mem_sparing_write_attrs, bytes_to_copy); - set_feat_info->data_size +=3D bytes_to_copy; =20 if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANS= FER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TRA= NSFER) { @@ -1938,6 +1930,9 @@ static CXLRetCode cmd_features_set_feature(const stru= ct cxl_cmd *cmd, return CXL_MBOX_UNSUPPORTED; } =20 + set_feat_info->data_size =3D MAX(set_feat_info->data_size, + (size_t)end_offset); + if (data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER = || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSF= ER || data_transfer_flag =3D=3D CXL_SET_FEATURE_FLAG_ABORT_DATA_TRANSFE= R) { diff --git a/tests/qtest/cxl-test.c b/tests/qtest/cxl-test.c index a9fcd98736..ed222aca4b 100644 --- a/tests/qtest/cxl-test.c +++ b/tests/qtest/cxl-test.c @@ -99,6 +99,21 @@ typedef struct QEMU_PACKED CXLSetFeatureInHeaderTest { uint8_t rsvd[9]; } CXLSetFeatureInHeaderTest; =20 +typedef struct QEMU_PACKED CXLGetFeatureInHeaderTest { + uint8_t uuid[16]; + uint16_t offset; + uint16_t count; + uint8_t selection; +} CXLGetFeatureInHeaderTest; + +enum { + CXL_TEST_GET_FEATURE_SEL_CURRENT_VALUE =3D 0, + CXL_TEST_SET_FEATURE_FLAG_FULL_DATA_TRANSFER =3D 0, + CXL_TEST_SET_FEATURE_FLAG_INITIATE_DATA_TRANSFER =3D 1, + CXL_TEST_SET_FEATURE_FLAG_CONTINUE_DATA_TRANSFER =3D 2, + CXL_TEST_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER =3D 3, +}; + static void cxl_basic_hb(void) { qtest_start("-machine q35,cxl=3Don"); @@ -177,15 +192,37 @@ static uint16_t cxl_test_t3d_mailbox_errno(void) =20 static void cxl_test_fill_set_feature_header(CXLSetFeatureInHeaderTest *hd= r, const uint8_t uuid[16], + uint32_t flags, uint16_t offset, uint8_t version) { memset(hdr, 0, sizeof(*hdr)); memcpy(hdr->uuid, uuid, 16); + hdr->flags =3D cpu_to_le32(flags); hdr->offset =3D cpu_to_le16(offset); hdr->version =3D version; } =20 +static void cxl_test_fill_get_feature_header(CXLGetFeatureInHeaderTest *hd= r, + const uint8_t uuid[16], + uint16_t offset, + uint16_t count) +{ + memset(hdr, 0, sizeof(*hdr)); + memcpy(hdr->uuid, uuid, 16); + hdr->offset =3D cpu_to_le16(offset); + hdr->count =3D cpu_to_le16(count); + hdr->selection =3D CXL_TEST_GET_FEATURE_SEL_CURRENT_VALUE; +} + +static void cxl_test_t3d_submit_get_feature(const void *payload, size_t le= n) +{ + memwrite(cxl_test_t3d_payload_base(), payload, len); + writeq(cxl_test_t3d_mailbox_base() + A_CXL_DEV_MAILBOX_CMD, + ((uint64_t)len << 16) | (0x05 << 8) | 0x01); + writel(cxl_test_t3d_mailbox_base() + A_CXL_DEV_MAILBOX_CTRL, 1); +} + static void cxl_t3d_set_feature_rejects_oversized_rank_sparing(void) { static const uint8_t rank_sparing_uuid[16] =3D { @@ -203,7 +240,7 @@ static void cxl_t3d_set_feature_rejects_oversized_rank_= sparing(void) qtest_start(cmdline->str); cxl_test_t3d_enable_bar2(); =20 - cxl_test_fill_set_feature_header(hdr, rank_sparing_uuid, 0, + cxl_test_fill_set_feature_header(hdr, rank_sparing_uuid, 0, 0, CXL_MEMDEV_SPARING_SET_FEATURE_VERSIO= N); memset(payload + sizeof(*hdr), 0x41, sizeof(payload) - sizeof(*hdr)); @@ -215,6 +252,84 @@ static void cxl_t3d_set_feature_rejects_oversized_rank= _sparing(void) rmdir(tmpfs); } =20 +static void cxl_t3d_set_feature_cleanup_stays_within_feature_state(void) +{ + static const uint8_t bank_sparing_uuid[16] =3D { + 0x36, 0x96, 0xb7, 0x78, 0xac, 0x90, 0x64, 0x4b, + 0xa4, 0xef, 0xfa, 0xac, 0x5d, 0x18, 0xa8, 0x63, + }; + static const uint8_t rank_sparing_uuid[16] =3D { + 0x34, 0xdb, 0xaf, 0xf5, 0x05, 0x52, 0x42, 0x81, + 0x8f, 0x76, 0xda, 0x0b, 0x5e, 0x7a, 0x76, 0xa7, + }; + g_autoptr(GString) cmdline =3D g_string_new(NULL); + g_autofree const char *tmpfs =3D NULL; + uint8_t set_payload[sizeof(CXLSetFeatureInHeaderTest) + 2] =3D { 0 }; + uint8_t get_payload[sizeof(CXLGetFeatureInHeaderTest)] =3D { 0 }; + uint8_t out[2]; + CXLSetFeatureInHeaderTest *set_hdr =3D (void *)set_payload; + CXLGetFeatureInHeaderTest *get_hdr =3D (void *)get_payload; + int i; + + tmpfs =3D g_dir_make_tmp("cxl-test-XXXXXX", NULL); + g_string_printf(cmdline, QEMU_T3D_DIRECT_PMEM, tmpfs, tmpfs); + + qtest_start(cmdline->str); + cxl_test_t3d_enable_bar2(); + + cxl_test_fill_set_feature_header( + set_hdr, rank_sparing_uuid, + CXL_TEST_SET_FEATURE_FLAG_FULL_DATA_TRANSFER, 0, + CXL_MEMDEV_SPARING_SET_FEATURE_VERSION); + set_payload[sizeof(*set_hdr)] =3D 0x34; + set_payload[sizeof(*set_hdr) + 1] =3D 0x12; + cxl_test_t3d_submit_set_feature(set_payload, sizeof(set_payload)); + g_assert_cmphex(cxl_test_t3d_mailbox_errno(), =3D=3D, CXL_MBOX_SUCCESS= ); + + cxl_test_fill_set_feature_header(set_hdr, bank_sparing_uuid, + CXL_TEST_SET_FEATURE_FLAG_INITIATE_DA= TA_TRANSFER, + 0, + CXL_MEMDEV_SPARING_SET_FEATURE_VERSIO= N); + set_payload[sizeof(*set_hdr)] =3D 0x78; + set_payload[sizeof(*set_hdr) + 1] =3D 0x56; + cxl_test_t3d_submit_set_feature(set_payload, sizeof(set_payload)); + g_assert_cmphex(cxl_test_t3d_mailbox_errno(), =3D=3D, CXL_MBOX_SUCCESS= ); + + /* Repeating the same 2-byte fragment must not clobber adjacent state.= */ + for (i =3D 0; i < 2; i++) { + cxl_test_fill_set_feature_header( + set_hdr, bank_sparing_uuid, + CXL_TEST_SET_FEATURE_FLAG_CONTINUE_DATA_TRANSFER, + 0, CXL_MEMDEV_SPARING_SET_FEATURE_VERSION); + set_payload[sizeof(*set_hdr)] =3D 0xaa; + set_payload[sizeof(*set_hdr) + 1] =3D 0xbb; + cxl_test_t3d_submit_set_feature(set_payload, sizeof(set_payload)); + g_assert_cmphex(cxl_test_t3d_mailbox_errno(), =3D=3D, CXL_MBOX_SUC= CESS); + } + + cxl_test_fill_set_feature_header(set_hdr, bank_sparing_uuid, + CXL_TEST_SET_FEATURE_FLAG_FINISH_DATA= _TRANSFER, + 0, + CXL_MEMDEV_SPARING_SET_FEATURE_VERSIO= N); + set_payload[sizeof(*set_hdr)] =3D 0xcc; + set_payload[sizeof(*set_hdr) + 1] =3D 0xdd; + cxl_test_t3d_submit_set_feature(set_payload, sizeof(set_payload)); + g_assert_cmphex(cxl_test_t3d_mailbox_errno(), =3D=3D, CXL_MBOX_SUCCESS= ); + + cxl_test_fill_get_feature_header(get_hdr, rank_sparing_uuid, + offsetof(CXLMemSparingReadAttrs, op_m= ode), + 2); + cxl_test_t3d_submit_get_feature(get_payload, sizeof(get_payload)); + g_assert_cmphex(cxl_test_t3d_mailbox_errno(), =3D=3D, CXL_MBOX_SUCCESS= ); + + memread(cxl_test_t3d_payload_base(), out, sizeof(out)); + g_assert_cmphex(out[0], =3D=3D, 0x34); + g_assert_cmphex(out[1], =3D=3D, 0x12); + + qtest_end(); + rmdir(tmpfs); +} + static void cxl_t3d_deprecated(void) { g_autoptr(GString) cmdline =3D g_string_new(NULL); @@ -337,6 +452,8 @@ int main(int argc, char **argv) qtest_add_func("/pci/cxl/type3_device_vmem_lsa", cxl_t3d_volatile_= lsa); qtest_add_func("/pci/cxl/type3_device_set_feature_rank_sparing_bou= nds", cxl_t3d_set_feature_rejects_oversized_rank_sparing); + qtest_add_func("/pci/cxl/type3_device_set_feature_cleanup_bounds", + cxl_t3d_set_feature_cleanup_stays_within_feature_st= ate); qtest_add_func("/pci/cxl/rp_x2_type3_x2", cxl_1pxb_2rp_2t3d); qtest_add_func("/pci/cxl/pxb_x2_root_port_x4_type3_x4", cxl_2pxb_4rp_4t3d); --=20 2.34.1