From nobody Fri Dec 19 02:51:19 2025 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=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1746439759; cv=none; d=zohomail.com; s=zohoarc; b=ne/9pxHq+XL5e3ALOEZRLnxHu4uxbnYa2a2u+1jDpmB2dU30l+x17A56QQlm7G+Tub9pVR6QK9PHxkoV7JWEANNqGcySR/5iLjoWkiIiI0OR7YEs9jkQxddEhmQvSvhsjAV/HdFrE4UVOJVADm9H5Lgt2VxLphbvklrmFltVfII= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746439759; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=CroMvl8kCwyNE0xpDuSk2NShdpGqc3f3DS0jey+inzY=; b=ZOpi83O67M/C3AZpqwKgeY34WGGhzdbpnbrLQNpPMF97DF3FcrFGsqHunilNX3ARc8R4tGYL4rONXuMUYmy2gwetSFsiWqbmYofFPqrZq0Fsu37vPCLEHN0pzPAmed8PcM8GRRzAmk5Aljh+30GUv2b362qiFoJbm1Co/Vm/mkM= 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=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1746439759772659.8798225636565; Mon, 5 May 2025 03:09:19 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uBsl0-0005PZ-K3; Mon, 05 May 2025 06:09:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsky-0005NV-Md for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:04 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBskw-0007Bn-S4 for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:04 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-447-e4YWNcq-MYOhWL8JX7z69Q-1; Mon, 05 May 2025 06:09:00 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-43d5ca7c86aso24931025e9.0 for ; Mon, 05 May 2025 03:09:00 -0700 (PDT) Received: from [192.168.10.48] ([151.95.54.106]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-441b2ad7ab1sm175087465e9.4.2025.05.05.03.08.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 May 2025 03:08:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1746439742; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CroMvl8kCwyNE0xpDuSk2NShdpGqc3f3DS0jey+inzY=; b=HA+MYEslRhbqCd36b3YleySSufqRvz9oSUNgN9/IUgzXYKU713KQNNYqSlFgYdeybLvuOO pL2AGvLNgNp2WQllZifR+ELrp7tHss7AjqAjdUwh+DOatrQrhv2Z1+2aTZlkNBooNambz7 m9nYGSEMr9H4SnR+ZJ56+seRqL4wskg= X-MC-Unique: e4YWNcq-MYOhWL8JX7z69Q-1 X-Mimecast-MFC-AGG-ID: e4YWNcq-MYOhWL8JX7z69Q_1746439739 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746439739; x=1747044539; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CroMvl8kCwyNE0xpDuSk2NShdpGqc3f3DS0jey+inzY=; b=sH5UNDOhK2zezj3ivzxhpvqizb/Kp8SXdmtJZYULmC7mUOH5oFpqVNVfECDCQuGgKD 69iGb5XDq0+NKeSnOCtSlKT/GJyHVKUbwiuND3PksmnTZnhMln/3vJqEKznOf/qG+gyq sbyGmfGCwAhyE9qwqiJ4VtvC0wt5VgHsL1A9alCrOsuUZnJCH6kqx3eyVeFpHnrQ8Dyc WlDgXQctAGSDqaFWbtSNRxnRxo0/7dtt06ZXcGN6/j7qa7w0yVH9S2ac7bo9bWGacr12 MJoEHe2otu9Djg8up7Se1NDT2KoZPUKS4Ht+8TwnlAKMzxQYVzWwz71xe5LTUUiLOzVD Vy/A== X-Gm-Message-State: AOJu0YwnbOt+wyN8zcDWMfX8XpTiCNvEXHuzUuYodCKNJjDeE7HpuSRv U/fD25nHzwh2VXsAa1eLCyxyj61eRXRNofEqASmgcAfig5W7rn5weLsdlGJbh1GN8ZE9KVawclm /4NHGtlbJEkuF0ht/9ccvv+dcF6aFwHnBfluOkbWewZuEFQbve2rf9LY8/sROo/rsCLwWPR8euN U1WYSjYl7MMsCjIsxk3jpWngZt4LAA7xUQDlQ7 X-Gm-Gg: ASbGnctbpV6obxcFWG0hUipeGtOZkRcO1ozmMmscriDw8nKBpGyTMIlhRa2a0EfmL4z /DmHp/KesYkLdz26fYN1fTQYZrH4D6RlxpOXdkH2hIIHXGpQrFUUf4oAu6VxpOe9adE3BIyWYJY CK0Y/hLeAqd+eyN+X3+lkMA5xkslc8zxdkyZClA6EKjCMBtn3ucn8nQn4TytmxuclRCxHrP4m8Q inmDcT/xCNz2nMRuScNIe44OS9ZwAKiO4SK9BKGlYop5jJnxTlsUr9R4V9zehJTlAVuwhAkB32k D5vDU2bIGuBbhH0= X-Received: by 2002:a05:600c:5022:b0:43c:e6d1:efe7 with SMTP id 5b1f17b1804b1-441bbf34052mr92335685e9.26.1746439738694; Mon, 05 May 2025 03:08:58 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGKJidQoTt4+ayt2dU/NIMwpYeHIty6OZncGOpBDDBs814dC8v7Vs0wTOPkWx99cFWBPV6ikw== X-Received: by 2002:a05:600c:5022:b0:43c:e6d1:efe7 with SMTP id 5b1f17b1804b1-441bbf34052mr92335485e9.26.1746439738288; Mon, 05 May 2025 03:08:58 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 1/5] meson, cargo: require Rust 1.83.0 Date: Mon, 5 May 2025 12:08:50 +0200 Message-ID: <20250505100854.73936-2-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250505100854.73936-1-pbonzini@redhat.com> References: <20250505100854.73936-1-pbonzini@redhat.com> 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=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.411, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=-1, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: 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 @redhat.com) X-ZM-MESSAGEID: 1746439761018019000 Content-Type: text/plain; charset="utf-8" Signed-off-by: Paolo Bonzini --- docs/devel/rust.rst | 14 +++++--------- meson.build | 6 +++--- rust/Cargo.toml | 2 +- rust/clippy.toml | 2 +- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 4de86375021..139c298d462 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -71,21 +71,17 @@ Building Rust code with ``--enable-modules`` is not sup= ported yet. Supported tools ''''''''''''''' =20 -QEMU supports rustc version 1.77.0 and newer. Notably, the following feat= ures -are missing: +QEMU supports rustc version 1.83.0 and newer. The following features +from relatively new versions of Rust are not used for historical reasons; +patches are welcome: =20 * inline const expression (stable in 1.79.0), currently worked around with associated constants in the ``FnCall`` trait. =20 -* associated constants have to be explicitly marked ``'static`` (`changed = in +* associated constants are still explicitly marked ``'static`` (`changed in 1.81.0`__) =20 -* ``&raw`` (stable in 1.82.0). Use ``addr_of!`` and ``addr_of_mut!`` inst= ead, - though hopefully the need for raw pointers will go down over time. - -* ``new_uninit`` (stable in 1.82.0). This is used internally by the ``pin= ned_init`` - crate, which is planned for inclusion in QEMU, but it can be easily patc= hed - out. +* ``&raw`` (stable in 1.82.0). =20 * referencing statics in constants (stable in 1.83.0). For now use a const function; this is an important limitation for QEMU's migration stream diff --git a/meson.build b/meson.build index e77da3f9b75..7afdae0ce90 100644 --- a/meson.build +++ b/meson.build @@ -94,12 +94,12 @@ have_rust =3D have_rust and add_languages('rust', nativ= e: true, required: get_option('rust').disable_auto_if(not have_system)) if have_rust rustc =3D meson.get_compiler('rust') - if rustc.version().version_compare('<1.77.0') + if rustc.version().version_compare('<1.83.0') if get_option('rust').enabled() - error('rustc version ' + rustc.version() + ' is unsupported. Please = upgrade to at least 1.77.0') + error('rustc version ' + rustc.version() + ' is unsupported. Please = upgrade to at least 1.83.0') else warning('rustc version ' + rustc.version() + ' is unsupported, disab= ling Rust compilation.') - message('Please upgrade to at least 1.77.0 to use Rust.') + message('Please upgrade to at least 1.83.0 to use Rust.') have_rust =3D false endif endif diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 4f6fe17b50f..b0f779986ab 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -12,7 +12,7 @@ edition =3D "2021" homepage =3D "https://www.qemu.org" license =3D "GPL-2.0-or-later" repository =3D "https://gitlab.com/qemu-project/qemu/" -rust-version =3D "1.77.0" +rust-version =3D "1.83.0" =20 [workspace.lints.rust] unexpected_cfgs =3D { level =3D "deny", check-cfg =3D [ diff --git a/rust/clippy.toml b/rust/clippy.toml index 933e46a2ffb..2fae76fb3f6 100644 --- a/rust/clippy.toml +++ b/rust/clippy.toml @@ -1,2 +1,2 @@ doc-valid-idents =3D ["PrimeCell", ".."] -msrv =3D "1.77.0" +msrv =3D "1.83.0" --=20 2.49.0 From nobody Fri Dec 19 02:51:19 2025 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=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1746439808; cv=none; d=zohomail.com; s=zohoarc; b=bHsJ375/ahEGbUMheIqlXLaFhvURs7cp70+TQ21mYLijSYldRL8wfcQb2o5QIx6bpi66gk5mE7W70Fv1ZACE8pzMIwQEdfhVAQCLjwScPyQl8JX5+d/H4lUrbZAvHNly4c5GozCEcV/aHEtrashs2aXvvwlseZgCBgndmvIZGX0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746439808; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=o4eJEJ6LUK5A+acUKlwgi0vs0hdZWNs63Wrhl4hER54=; b=MCcrL/Pq2G5EguW0qip1PpPIzlrpAr/8VysMxxKifvq2tk9A/labVT2HOuGC6pfZtTSYke/TPVnHd9tWRx99F8VmxOl+gpKYaHWC4nX78aBZHzXN+DmKOi5Wv/XGrcofYc+hwZQSA6hVa7NtIykbuHKJlQVqvQqKEFShtAdwFDc= 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=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1746439808836166.75159650288185; Mon, 5 May 2025 03:10:08 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uBsl3-0005S9-64; Mon, 05 May 2025 06:09:09 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsl2-0005Rk-33 for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:08 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBskz-0007CD-9J for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:07 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-534-sAB00WwaMly3wmtzPHqUug-1; Mon, 05 May 2025 06:09:03 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-43f251dc364so23994905e9.2 for ; Mon, 05 May 2025 03:09:02 -0700 (PDT) Received: from [192.168.10.48] ([151.95.54.106]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-441b2b20b36sm175419965e9.25.2025.05.05.03.08.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 May 2025 03:08:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1746439744; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=o4eJEJ6LUK5A+acUKlwgi0vs0hdZWNs63Wrhl4hER54=; b=HkvEsQNCoMIXIDSAYG4ZgW7HDl7Q3qwvUNyf0JFCoL0uU7ov68f0Lc3jwUUlYPNNBEyw3g 1XIpc+yCysng5ODHWPaokTvcc0XuENMeBuaEzodqz0E9Pl3r4xfiYOuAQNL8qWNQPZGmn6 MYsuHi09HIAXHHt2X1OFdrjVWA94s6c= X-MC-Unique: sAB00WwaMly3wmtzPHqUug-1 X-Mimecast-MFC-AGG-ID: sAB00WwaMly3wmtzPHqUug_1746439742 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746439741; x=1747044541; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=o4eJEJ6LUK5A+acUKlwgi0vs0hdZWNs63Wrhl4hER54=; b=pm/jFFQUxYydp5uUb20eG0pXk5Jctquu/L4NkfIN6RmmxwIgll79Qz5Ye9NTFOFb6z oriDsdroCyPU0IcuyiBGTxYrOt95HnlpZqpAkF74X6iqu1FBaklAlF+JWZQoLFaJG8Pe 6sGRy6Ege+XRjhxC5r714Kj7CBBIJByz5H4nysIEKRRmJAjyfmSrd0gbwsEo8wIC6J42 /4Habhk816FVDEi8MVx6UuPQXx2cMlngidtfK+vEMgWUXtAT93X24siDjVTiUHVCaTwv /qzy3dgKUccX6dNlBMNDMUnLGr2MqSdZhnItjkSboy95SKrU+MP0O/xwwuwWTFE/LqzI sgmA== X-Gm-Message-State: AOJu0YwTjXcJDmwqxqQBpXcHzLJRzzz7XMIL2EVS/qP6/pZXxw8K6mkS fW8D8CWG2hdG5gHyqa4r6+3l4X7U41fR8f0ZxMHsFfeZUNVaQHEHX+OeEz6utYiPhPpQYEAMC+f q78B9qCCwT7LtiyjlJgBkfcA4FHvLNZ0LLgyTw65e4CkMoK8OPv8mOxRNx4TMzdEsvAnpls/oW5 I/gHoTijWj4OalYzcWiLxIA1p0Hxofn0ZnJQ4t X-Gm-Gg: ASbGnct3LDJFxefWMBaG0K7UpiLvX6zVT4ypDVkEY+J1Cxt0oDlmpj7wOswPeYLbr1o +won4ZnJMWOkPo7xdyB5PXb8yCIzS6fM6RQQl1iYqoDyEYgJ8EpLg7F3xicy9s0SLKF9wjeiJB8 oJ7XIeXTgUJWWfC2TIrxV3crqiPP54Ey3WFj67bEB3m5tvZr86tnwMB6sqyFjYAEpaBRwAoz5RY NrKkKNOyht0FrEGBoYe4kBH7INYNMcnFcsgykNkc/KkOntuNtO6Yn2GxfFAzp6WVNwVE2UJmRll DgremB1BqotwVcU= X-Received: by 2002:a05:600c:3d8e:b0:43e:a7c9:8d2b with SMTP id 5b1f17b1804b1-441c4919de9mr53226045e9.24.1746439740870; Mon, 05 May 2025 03:09:00 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHNr2lFzAub5aEOX7AAocy2B9+yhvcltYQ3gJYxA/xfXsF1K8RluuFCzthU2kAVLvsSoDlJTQ== X-Received: by 2002:a05:600c:3d8e:b0:43e:a7c9:8d2b with SMTP id 5b1f17b1804b1-441c4919de9mr53225865e9.24.1746439740404; Mon, 05 May 2025 03:09:00 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 2/5] rust: use inline const expressions Date: Mon, 5 May 2025 12:08:51 +0200 Message-ID: <20250505100854.73936-3-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250505100854.73936-1-pbonzini@redhat.com> References: <20250505100854.73936-1-pbonzini@redhat.com> 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=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.411, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=-1, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: 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 @redhat.com) X-ZM-MESSAGEID: 1746439810692116600 Content-Type: text/plain; charset="utf-8" They were stabilized in Rust 1.79.0. Signed-off-by: Paolo Bonzini --- docs/devel/rust.rst | 9 +++------ rust/qemu-api/src/callbacks.rs | 27 +-------------------------- rust/qemu-api/src/chardev.rs | 2 +- rust/qemu-api/src/qdev.rs | 2 +- rust/qemu-api/src/timer.rs | 2 +- rust/qemu-api/src/vmstate.rs | 2 +- 6 files changed, 8 insertions(+), 36 deletions(-) diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 139c298d462..cc52adcfdbe 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -75,9 +75,6 @@ QEMU supports rustc version 1.83.0 and newer. The follow= ing features from relatively new versions of Rust are not used for historical reasons; patches are welcome: =20 -* inline const expression (stable in 1.79.0), currently worked around with - associated constants in the ``FnCall`` trait. - * associated constants are still explicitly marked ``'static`` (`changed in 1.81.0`__) =20 @@ -88,9 +85,9 @@ patches are welcome: architecture (VMState). Right now, VMState lacks type safety because it is hard to place the ``VMStateField`` definitions in traits. =20 -* associated const equality would be nice to have for some users of - ``callbacks::FnCall``, but is still experimental. ``ASSERT_IS_SOME`` - replaces it. +Associated const equality would be nice to have for some users of +``callbacks::FnCall``, but is still experimental. Const assertions +are used instead. =20 __ https://github.com/rust-lang/rust/pull/125258 =20 diff --git a/rust/qemu-api/src/callbacks.rs b/rust/qemu-api/src/callbacks.rs index 9642a16eb89..dbe2305f509 100644 --- a/rust/qemu-api/src/callbacks.rs +++ b/rust/qemu-api/src/callbacks.rs @@ -113,31 +113,6 @@ /// This is always true for zero-capture closures and function pointers, a= s long /// as the code is able to name the function in the first place. pub unsafe trait FnCall: 'static + Sync + Sized { - /// Referring to this internal constant asserts that the `Self` type is - /// zero-sized. Can be replaced by an inline const expression in - /// Rust 1.79.0+. - const ASSERT_ZERO_SIZED: () =3D { assert!(mem::size_of::() =3D= =3D 0) }; - - /// Referring to this constant asserts that the `Self` type is an actu= al - /// function type, which can be used to catch incorrect use of `()` - /// at compile time. - /// - /// # Examples - /// - /// ```compile_fail - /// # use qemu_api::callbacks::FnCall; - /// fn call_it FnCall<(&'a str,), String>>(_f: &F, s: &str)= -> String { - /// let _: () =3D F::ASSERT_IS_SOME; - /// F::call((s,)) - /// } - /// - /// let s: String =3D call_it((), "hello world"); // does not compile - /// ``` - /// - /// Note that this can be more simply `const { assert!(F::IS_SOME) }` = in - /// Rust 1.79.0 or newer. - const ASSERT_IS_SOME: () =3D { assert!(Self::IS_SOME) }; - /// `true` if `Self` is an actual function type and not `()`. /// /// # Examples @@ -195,7 +170,7 @@ unsafe impl FnCall<($($args,)*), R> fo= r F =20 #[inline(always)] fn call(a: ($($args,)*)) -> R { - let _: () =3D Self::ASSERT_ZERO_SIZED; + const { assert!(mem::size_of::() =3D=3D 0) }; =20 // SAFETY: the safety of this method is the condition for = implementing // `FnCall`. As to the `NonNull` idiom to create a zero-s= ized type, diff --git a/rust/qemu-api/src/chardev.rs b/rust/qemu-api/src/chardev.rs index 6e0590d758e..cb27be52569 100644 --- a/rust/qemu-api/src/chardev.rs +++ b/rust/qemu-api/src/chardev.rs @@ -138,7 +138,7 @@ pub fn enable_handlers< F::call((owner, event)) } =20 - let _: () =3D CanReceiveFn::ASSERT_IS_SOME; + const { assert!(CanReceiveFn::IS_SOME) }; let receive_cb: Option =3D if ReceiveFn::is_some() { Some(rust_receive_cb::) diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 1279d7a58d5..6c93805a742 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -358,7 +358,7 @@ fn do_init_gpio_in( } } =20 - let _: () =3D F::ASSERT_IS_SOME; + const { assert!(F::IS_SOME) }; unsafe extern "C" fn rust_irq_handler FnCall<(&'a T,= u32, u32)>>( opaque: *mut c_void, line: c_int, diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs index 868bd88575f..66d39df37d8 100644 --- a/rust/qemu-api/src/timer.rs +++ b/rust/qemu-api/src/timer.rs @@ -56,7 +56,7 @@ pub fn init_full<'timer, 'opaque: 'timer, T, F>( ) where F: for<'a> FnCall<(&'a T,)>, { - let _: () =3D F::ASSERT_IS_SOME; + const { assert!(F::IS_SOME) }; =20 /// timer expiration callback unsafe extern "C" fn rust_timer_handler FnCall<(&'a = T,)>>( diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 9c8b2398e9d..c564bd70308 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -457,7 +457,7 @@ macro_rules! vmstate_exist_fn { const fn test_cb_builder__ $crate::callbacks::FnCall= <(&'a T, u8), bool>>( _phantom: ::core::marker::PhantomData, ) -> $crate::vmstate::VMSFieldExistCb { - let _: () =3D F::ASSERT_IS_SOME; + const { assert!(F::IS_SOME) }; $crate::vmstate::rust_vms_test_field_exists:: } =20 --=20 2.49.0 From nobody Fri Dec 19 02:51:19 2025 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=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1746439806; cv=none; d=zohomail.com; s=zohoarc; b=IiGia+DalgaMzEZLg9Hz8gaSwdRcZsgkhfiSZtwrjaua3cCnxbZ4GnTr/GenwkZJriGNxc9kAC979vp4y2chTPcExM0Aq3Bvfcl9iYNQpwH0SyPJZs6kE61Kb3kYO+btDuX45cYc0LJA1K8ZlNiu9amt98gkdrLFXxLwVgPB3oU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746439806; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=ffCEryqi3v++ba2gcykphq5EzSm4zltztjzi50TmkME=; b=ZhvQO6ZDHppdX8ydKVOY9Pvz7cWbfiFm64p4gpCI/I+mFoSBSdGf7aCO9ny32JsMGK74PNDNtDpI9I9N+K9+Ru+9x+9E4Kpw1RDTbFEZC9clZGW8qf9I79WllxBeMP0ZrF3wFPsaR9qZ1F0T2Btpn6X9TohrxYVBwz6qNv/qJpw= 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=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1746439806971308.3013365879417; Mon, 5 May 2025 03:10:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uBslA-0005VF-8F; Mon, 05 May 2025 06:09:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsl8-0005UL-2J for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:14 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsl2-0007Cq-Fr for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:13 -0400 Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-448-d9pmakIvNa--7C5C3ymevg-1; Mon, 05 May 2025 06:09:06 -0400 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-441c122fa56so6589335e9.2 for ; Mon, 05 May 2025 03:09:05 -0700 (PDT) Received: from [192.168.10.48] ([151.95.54.106]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-441b89cc50esm131534755e9.8.2025.05.05.03.09.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 May 2025 03:09:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1746439747; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ffCEryqi3v++ba2gcykphq5EzSm4zltztjzi50TmkME=; b=d2MwEKfh0lRIPB24rKAQsjW3B/QhIxCuUMstQ0wyGw1/kql8c02NfiKmAAdAzh7PGEKbzo y9E/ueA0BSCZfS+3M70vwVgH0iDRX5AWjTSPQC1SWj2mN+7uMoS3vvQUmbytzGbGqYbXW4 u0JQZpH9he2DITqR90bo4rBbGv8dEs4= X-MC-Unique: d9pmakIvNa--7C5C3ymevg-1 X-Mimecast-MFC-AGG-ID: d9pmakIvNa--7C5C3ymevg_1746439745 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746439744; x=1747044544; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ffCEryqi3v++ba2gcykphq5EzSm4zltztjzi50TmkME=; b=gfh1cQwWcrCovsnWd/Uzuaz/0P4nu/hTgZa3moKlMUWosocV5YTjbr7euvRnAeMai5 20xi+1mmNbajJNz45g3xXRvQY7ipP1Mlp8IZ+a77Z8YXS4QwbI+ChPUm8s7Ouva6sluO kndTRzLdzffuSA7o/W+fd6iPYSAgYv3AAsXolhd6tWTJ+dxlMPbFublKrl10cB6C+son Ban+cRofz5++Z2Iu7mO92ceQTqfk4wNRVXCgeSS3qME96a3Sb9xLAlHld1PsefZnpqVl BR+mhw8gjR54wlgKBC6kMCebSGdncodb9tGLXQa6CVdtFL41u0LiNJLNtp8MFCfsNPmW 7hvA== X-Gm-Message-State: AOJu0YzoIvngd4Qrfl4xjoMc971JDrSjwT0P6SSoIpNh9VfGYsADBqiF r4fuVtGi2Hreu2G2iDfLd6k4VjN1en/BJ3USqGvxpJdRTiajSDYydB1j54twzrHq9fIf39Mz29T yBT3TLh/S8h3sBvjzRlJySvFP9onuWvR/N6y4MdJlu1cbLFvCZQ2IGGN10hoQvH1t2zsru4+Maw Qf+To1bEHvugOk5OPb6LQ04V0y1vfm1wvb/RrC X-Gm-Gg: ASbGnctn3XMvuA2SggCtdcsozhrlpFFhzePk1XwD2v0/2uq/7TMS95GCggY8nQf7690 q1D2TTTK54v4HUlbUDeW+J1Ah1kgrUQiBQoOBJdy4dIosbgm4G84KF6pLQpiqDg48aT06dtQEiO xhlfc1SIyJUGeFhoWWUwANMwmV80VUUjiU/bkTAA5xPU2H8EsfjoPtV+309BDQiZXyo5d+vNao9 w7OjE3UKeN40uUqyOJGzuYHu1blUguqnkUMWe5L+/1DwUj95Dlmn2RKeevUPkFZHnzCNTxMVcpM Y0iGj5TaERnhUN0= X-Received: by 2002:a05:600c:3ba1:b0:43c:ec4c:25b1 with SMTP id 5b1f17b1804b1-441c1d5c52bmr55011755e9.23.1746439743675; Mon, 05 May 2025 03:09:03 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGoK0zXn0WfD53VWkWl5Q8l71acqz8XrFamaFm5UWmII6Skn3fM/vzWdz0CksJmKc9D7eMUYQ== X-Received: by 2002:a05:600c:3ba1:b0:43c:ec4c:25b1 with SMTP id 5b1f17b1804b1-441c1d5c52bmr55011325e9.23.1746439742827; Mon, 05 May 2025 03:09:02 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org, Zhao Liu Subject: [PATCH 3/5] rust: vmstate: convert to use builder pattern Date: Mon, 5 May 2025 12:08:52 +0200 Message-ID: <20250505100854.73936-4-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250505100854.73936-1-pbonzini@redhat.com> References: <20250505100854.73936-1-pbonzini@redhat.com> 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=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.411, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=-1, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: 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 @redhat.com) X-ZM-MESSAGEID: 1746439808853116600 Content-Type: text/plain; charset="utf-8" Similar to MemoryRegionOps, the builder pattern has two advantages: 1) it makes it possible to build a VMStateDescription that knows which types it will be invoked on; 2) it provides a way to wrap the callbacks and let devices avoid "unsafe". Unfortunately, building a static VMStateDescription requires the builder methods to be "const", and because the VMStateFields are *also* static, this requires const_refs_to_static. So this requires Rust 1.83.0. Co-developed-by: Zhao Liu Signed-off-by: Paolo Bonzini Reviewed-by: Zhao Liu --- docs/devel/rust.rst | 2 +- rust/hw/char/pl011/src/device.rs | 16 +- rust/hw/char/pl011/src/device_class.rs | 117 ++++++-------- rust/hw/timer/hpet/src/hpet.rs | 163 ++++++++----------- rust/qemu-api/src/qdev.rs | 6 +- rust/qemu-api/src/vmstate.rs | 214 ++++++++++++++++++++++++- rust/qemu-api/tests/tests.rs | 16 +- rust/qemu-api/tests/vmstate_tests.rs | 124 +++++++------- 8 files changed, 413 insertions(+), 245 deletions(-) diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index cc52adcfdbe..ed1c765e722 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -152,7 +152,7 @@ module status ``qom`` stable ``sysbus`` stable ``timer`` stable -``vmstate`` proof of concept +``vmstate`` stable ``zeroable`` stable =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/devi= ce.rs index 7c563ade9cd..38373f54e7c 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -2,7 +2,7 @@ // Author(s): Manos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later =20 -use std::{ffi::CStr, mem::size_of, ptr::addr_of_mut}; +use std::{ffi::CStr, io, mem::size_of, ptr::addr_of_mut}; =20 use qemu_api::{ chardev::{CharBackend, Chardev, Event}, @@ -172,8 +172,8 @@ impl DeviceImpl for PL011State { fn properties() -> &'static [Property] { &device_class::PL011_PROPERTIES } - fn vmsd() -> Option<&'static VMStateDescription> { - Some(&device_class::VMSTATE_PL011) + fn vmsd() -> Option> { + Some(device_class::VMSTATE_PL011) } const REALIZE: Option =3D Some(Self::realize); } @@ -457,10 +457,10 @@ pub fn put_fifo(&mut self, value: registers::Data) ->= bool { false } =20 - pub fn post_load(&mut self) -> Result<(), ()> { + pub fn post_load(&mut self) -> Result<(), io::ErrorKind> { /* Sanity-check input state */ if self.read_pos >=3D self.read_fifo.len() || self.read_count > se= lf.read_fifo.len() { - return Err(()); + return Err(io::ErrorKind::InvalidInput); } =20 if !self.fifo_enabled() && self.read_count > 0 && self.read_pos > = 0 { @@ -524,6 +524,10 @@ const fn clock_update(&self, _event: ClockEvent) { /* pl011_trace_baudrate_change(s); */ } =20 + pub fn clock_needed(&self) -> bool { + self.migrate_clock + } + fn post_init(&self) { self.init_mmio(&self.iomem); for irq in self.interrupts.iter() { @@ -629,7 +633,7 @@ fn update(&self) { } } =20 - pub fn post_load(&self, _version_id: u32) -> Result<(), ()> { + pub fn post_load(&self, _version_id: u8) -> Result<(), io::ErrorKind> { self.regs.borrow_mut().post_load() } } diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/sr= c/device_class.rs index d328d846323..ed72bfad25f 100644 --- a/rust/hw/char/pl011/src/device_class.rs +++ b/rust/hw/char/pl011/src/device_class.rs @@ -2,86 +2,65 @@ // Author(s): Manos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later =20 -use std::{ - ffi::{c_int, c_void}, - ptr::NonNull, -}; - use qemu_api::{ bindings::{qdev_prop_bool, qdev_prop_chr}, prelude::*, - vmstate::VMStateDescription, + vmstate::{VMStateDescription, VMStateDescriptionBuilder}, vmstate_clock, vmstate_fields, vmstate_of, vmstate_struct, vmstate_sub= sections, vmstate_unused, - zeroable::Zeroable, }; =20 use crate::device::{PL011Registers, PL011State}; =20 -extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool { - let state =3D NonNull::new(opaque).unwrap().cast::(); - unsafe { state.as_ref().migrate_clock } -} - /// Migration subsection for [`PL011State`] clock. -static VMSTATE_PL011_CLOCK: VMStateDescription =3D VMStateDescription { - name: c"pl011/clock".as_ptr(), - version_id: 1, - minimum_version_id: 1, - needed: Some(pl011_clock_needed), - fields: vmstate_fields! { - vmstate_clock!(PL011State, clock), - }, - ..Zeroable::ZERO -}; +static VMSTATE_PL011_CLOCK: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"pl011/clock") + .version_id(1) + .minimum_version_id(1) + .needed(&PL011State::clock_needed) + .fields(vmstate_fields! { + vmstate_clock!(PL011State, clock), + }) + .build(); =20 -extern "C" fn pl011_post_load(opaque: *mut c_void, version_id: c_int) -> c= _int { - let state =3D NonNull::new(opaque).unwrap().cast::(); - let result =3D unsafe { state.as_ref().post_load(version_id as u32) }; - if result.is_err() { - -1 - } else { - 0 - } -} +static VMSTATE_PL011_REGS: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"pl011/regs") + .version_id(2) + .minimum_version_id(2) + .fields(vmstate_fields! { + vmstate_of!(PL011Registers, flags), + vmstate_of!(PL011Registers, line_control), + vmstate_of!(PL011Registers, receive_status_error_clear), + vmstate_of!(PL011Registers, control), + vmstate_of!(PL011Registers, dmacr), + vmstate_of!(PL011Registers, int_enabled), + vmstate_of!(PL011Registers, int_level), + vmstate_of!(PL011Registers, read_fifo), + vmstate_of!(PL011Registers, ilpr), + vmstate_of!(PL011Registers, ibrd), + vmstate_of!(PL011Registers, fbrd), + vmstate_of!(PL011Registers, ifl), + vmstate_of!(PL011Registers, read_pos), + vmstate_of!(PL011Registers, read_count), + vmstate_of!(PL011Registers, read_trigger), + }) + .build(); =20 -static VMSTATE_PL011_REGS: VMStateDescription =3D VMStateDescription { - name: c"pl011/regs".as_ptr(), - version_id: 2, - minimum_version_id: 2, - fields: vmstate_fields! { - vmstate_of!(PL011Registers, flags), - vmstate_of!(PL011Registers, line_control), - vmstate_of!(PL011Registers, receive_status_error_clear), - vmstate_of!(PL011Registers, control), - vmstate_of!(PL011Registers, dmacr), - vmstate_of!(PL011Registers, int_enabled), - vmstate_of!(PL011Registers, int_level), - vmstate_of!(PL011Registers, read_fifo), - vmstate_of!(PL011Registers, ilpr), - vmstate_of!(PL011Registers, ibrd), - vmstate_of!(PL011Registers, fbrd), - vmstate_of!(PL011Registers, ifl), - vmstate_of!(PL011Registers, read_pos), - vmstate_of!(PL011Registers, read_count), - vmstate_of!(PL011Registers, read_trigger), - }, - ..Zeroable::ZERO -}; - -pub static VMSTATE_PL011: VMStateDescription =3D VMStateDescription { - name: c"pl011".as_ptr(), - version_id: 2, - minimum_version_id: 2, - post_load: Some(pl011_post_load), - fields: vmstate_fields! { - vmstate_unused!(core::mem::size_of::()), - vmstate_struct!(PL011State, regs, &VMSTATE_PL011_REGS, BqlRefCell<= PL011Registers>), - }, - subsections: vmstate_subsections! { - VMSTATE_PL011_CLOCK - }, - ..Zeroable::ZERO -}; +pub const VMSTATE_PL011: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"pl011") + .version_id(2) + .minimum_version_id(2) + .post_load(&PL011State::post_load) + .fields(vmstate_fields! { + vmstate_unused!(core::mem::size_of::()), + vmstate_struct!(PL011State, regs, &VMSTATE_PL011_REGS, BqlRefC= ell), + }) + .subsections(vmstate_subsections! { + VMSTATE_PL011_CLOCK + }) + .build(); =20 qemu_api::declare_properties! { PL011_PROPERTIES, diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index 779681d6509..1ed1cb7dcaf 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -3,7 +3,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later =20 use std::{ - ffi::{c_int, c_void, CStr}, + ffi::CStr, + io, pin::Pin, ptr::{addr_of_mut, null_mut, NonNull}, slice::from_ref, @@ -25,9 +26,8 @@ qom_isa, sysbus::{SysBusDevice, SysBusDeviceImpl}, timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, - vmstate::VMStateDescription, + vmstate::{VMStateDescription, VMStateDescriptionBuilder}, vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmsta= te_validate, - zeroable::Zeroable, }; =20 use crate::fw_cfg::HPETFwConfig; @@ -211,6 +211,10 @@ pub struct HPETTimer { last: u64, } =20 +// SAFETY: Sync is not automatically derived due to the `state` field, +// which is always dereferenced to a shared reference. +unsafe impl Sync for HPETTimer {} + impl HPETTimer { fn init(&mut self, index: u8, state: &HPETState) { *self =3D HPETTimer { @@ -843,7 +847,7 @@ fn write(&self, addr: hwaddr, value: u64, size: u32) { } } =20 - fn pre_save(&self) -> i32 { + fn pre_save(&self) -> Result<(), io::ErrorKind> { if self.is_hpet_enabled() { self.counter.set(self.get_ticks()); } @@ -854,10 +858,10 @@ fn pre_save(&self) -> i32 { * that was configured. */ self.num_timers_save.set(self.num_timers.get()); - 0 + Ok(()) } =20 - fn post_load(&self, _version_id: u8) -> i32 { + fn post_load(&self, _version_id: u8) -> Result<(), io::ErrorKind> { for timer in self.timers.iter().take(self.get_num_timers()) { let mut t =3D timer.borrow_mut(); =20 @@ -871,7 +875,7 @@ fn post_load(&self, _version_id: u8) -> i32 { .set(ticks_to_ns(self.counter.get()) - CLOCK_VIRTUAL.get_n= s()); } =20 - 0 + Ok(()) } =20 fn is_rtc_irq_level_needed(&self) -> bool { @@ -941,105 +945,74 @@ impl ObjectImpl for HPETState { ), } =20 -unsafe extern "C" fn hpet_rtc_irq_level_needed(opaque: *mut c_void) -> boo= l { - // SAFETY: - // the pointer is convertible to a reference - let state: &HPETState =3D unsafe { NonNull::new(opaque.cast::()).unwrap().as_ref() }; - state.is_rtc_irq_level_needed() -} +static VMSTATE_HPET_RTC_IRQ_LEVEL: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"hpet/rtc_irq_level") + .version_id(1) + .minimum_version_id(1) + .needed(&HPETState::is_rtc_irq_level_needed) + .fields(vmstate_fields! { + vmstate_of!(HPETState, rtc_irq_level), + }) + .build(); =20 -unsafe extern "C" fn hpet_offset_needed(opaque: *mut c_void) -> bool { - // SAFETY: - // the pointer is convertible to a reference - let state: &HPETState =3D unsafe { NonNull::new(opaque.cast::()).unwrap().as_ref() }; - state.is_offset_needed() -} +static VMSTATE_HPET_OFFSET: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"hpet/offset") + .version_id(1) + .minimum_version_id(1) + .needed(&HPETState::is_offset_needed) + .fields(vmstate_fields! { + vmstate_of!(HPETState, hpet_offset), + }) + .build(); =20 -unsafe extern "C" fn hpet_pre_save(opaque: *mut c_void) -> c_int { - // SAFETY: - // the pointer is convertible to a reference - let state: &mut HPETState =3D - unsafe { NonNull::new(opaque.cast::()).unwrap().as_mut(= ) }; - state.pre_save() as c_int -} - -unsafe extern "C" fn hpet_post_load(opaque: *mut c_void, version_id: c_int= ) -> c_int { - // SAFETY: - // the pointer is convertible to a reference - let state: &mut HPETState =3D - unsafe { NonNull::new(opaque.cast::()).unwrap().as_mut(= ) }; - let version: u8 =3D version_id.try_into().unwrap(); - state.post_load(version) as c_int -} - -static VMSTATE_HPET_RTC_IRQ_LEVEL: VMStateDescription =3D VMStateDescripti= on { - name: c"hpet/rtc_irq_level".as_ptr(), - version_id: 1, - minimum_version_id: 1, - needed: Some(hpet_rtc_irq_level_needed), - fields: vmstate_fields! { - vmstate_of!(HPETState, rtc_irq_level), - }, - ..Zeroable::ZERO -}; - -static VMSTATE_HPET_OFFSET: VMStateDescription =3D VMStateDescription { - name: c"hpet/offset".as_ptr(), - version_id: 1, - minimum_version_id: 1, - needed: Some(hpet_offset_needed), - fields: vmstate_fields! { - vmstate_of!(HPETState, hpet_offset), - }, - ..Zeroable::ZERO -}; - -static VMSTATE_HPET_TIMER: VMStateDescription =3D VMStateDescription { - name: c"hpet_timer".as_ptr(), - version_id: 1, - minimum_version_id: 1, - fields: vmstate_fields! { - vmstate_of!(HPETTimer, index), - vmstate_of!(HPETTimer, config), - vmstate_of!(HPETTimer, cmp), - vmstate_of!(HPETTimer, fsb), - vmstate_of!(HPETTimer, period), - vmstate_of!(HPETTimer, wrap_flag), - vmstate_of!(HPETTimer, qemu_timer), - }, - ..Zeroable::ZERO -}; +static VMSTATE_HPET_TIMER: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"hpet_timer") + .version_id(1) + .minimum_version_id(1) + .fields(vmstate_fields! { + vmstate_of!(HPETTimer, index), + vmstate_of!(HPETTimer, config), + vmstate_of!(HPETTimer, cmp), + vmstate_of!(HPETTimer, fsb), + vmstate_of!(HPETTimer, period), + vmstate_of!(HPETTimer, wrap_flag), + vmstate_of!(HPETTimer, qemu_timer), + }) + .build(); =20 const VALIDATE_TIMERS_NAME: &CStr =3D c"num_timers must match"; =20 -static VMSTATE_HPET: VMStateDescription =3D VMStateDescription { - name: c"hpet".as_ptr(), - version_id: 2, - minimum_version_id: 1, - pre_save: Some(hpet_pre_save), - post_load: Some(hpet_post_load), - fields: vmstate_fields! { - vmstate_of!(HPETState, config), - vmstate_of!(HPETState, int_status), - vmstate_of!(HPETState, counter), - vmstate_of!(HPETState, num_timers_save).with_version_id(2), - vmstate_validate!(HPETState, VALIDATE_TIMERS_NAME, HPETState::vali= date_num_timers), - vmstate_struct!(HPETState, timers[0 .. num_timers], &VMSTATE_HPET_= TIMER, BqlRefCell, HPETState::validate_num_timers).with_version_= id(0), - }, - subsections: vmstate_subsections! { - VMSTATE_HPET_RTC_IRQ_LEVEL, - VMSTATE_HPET_OFFSET, - }, - ..Zeroable::ZERO -}; +const VMSTATE_HPET: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"hpet") + .version_id(2) + .minimum_version_id(1) + .pre_save(&HPETState::pre_save) + .post_load(&HPETState::post_load) + .fields(vmstate_fields! { + vmstate_of!(HPETState, config), + vmstate_of!(HPETState, int_status), + vmstate_of!(HPETState, counter), + vmstate_of!(HPETState, num_timers_save).with_version_id(2), + vmstate_validate!(HPETState, VALIDATE_TIMERS_NAME, HPETState::= validate_num_timers), + vmstate_struct!(HPETState, timers[0 .. num_timers], &VMSTATE_H= PET_TIMER, BqlRefCell, HPETState::validate_num_timers).with_vers= ion_id(0), + }) + .subsections(vmstate_subsections!( + VMSTATE_HPET_RTC_IRQ_LEVEL, + VMSTATE_HPET_OFFSET, + )) + .build(); =20 impl DeviceImpl for HPETState { fn properties() -> &'static [Property] { &HPET_PROPERTIES } =20 - fn vmsd() -> Option<&'static VMStateDescription> { - Some(&VMSTATE_HPET) + fn vmsd() -> Option> { + Some(VMSTATE_HPET) } =20 const REALIZE: Option =3D Some(Self::realize); diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 6c93805a742..09555bbd0e7 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -120,7 +120,7 @@ fn properties() -> &'static [Property] { /// A `VMStateDescription` providing the migration format for the devi= ce /// Not a `const` because referencing statics in constants is unstable /// until Rust 1.83.0. - fn vmsd() -> Option<&'static VMStateDescription> { + fn vmsd() -> Option> { None } } @@ -169,7 +169,9 @@ pub fn class_init(&mut self) { self.realize =3D Some(rust_realize_fn::); } if let Some(vmsd) =3D ::vmsd() { - self.vmsd =3D vmsd; + // Give a 'static lifetime to the return value of vmsd(). + // Temporary until vmsd() can be changed into a const. + self.vmsd =3D Box::leak(Box::new(vmsd.get())); } let prop =3D ::properties(); if !prop.is_empty() { diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index c564bd70308..228d748b6b7 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -25,11 +25,16 @@ //! functionality that is missing from `vmstate_of!`. =20 use core::{marker::PhantomData, mem, ptr::NonNull}; -use std::ffi::{c_int, c_void}; +use std::ffi::{c_int, c_void, CStr}; =20 -pub use crate::bindings::{VMStateDescription, VMStateField}; +pub use crate::bindings::{MigrationPriority, VMStateField}; use crate::{ - bindings::VMStateFlags, callbacks::FnCall, prelude::*, qom::Owned, zer= oable::Zeroable, + bindings::{self, VMStateFlags}, + callbacks::FnCall, + errno::{into_neg_errno, Errno}, + prelude::*, + qom::Owned, + zeroable::Zeroable, }; =20 /// This macro is used to call a function with a generic argument bound @@ -440,7 +445,7 @@ pub extern "C" fn rust_vms_test_field_exists bool { - // SAFETY: the opaque was passed as a reference to `T`. + // SAFETY: assumes vmstate_struct! is used correctly let owner: &T =3D unsafe { &*(opaque.cast::()) }; let version: u8 =3D version_id.try_into().unwrap(); F::call((owner, version)) @@ -490,7 +495,7 @@ macro_rules! vmstate_struct { }, size: ::core::mem::size_of::<$type>(), flags: $crate::bindings::VMStateFlags::VMS_STRUCT, - vmsd: $vmsd, + vmsd: $vmsd.as_ref(), $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_= fn),)? ..$crate::zeroable::Zeroable::ZERO } $(.with_varray_flag_unchecked( @@ -594,11 +599,206 @@ macro_rules! vmstate_subsections { ($($subsection:expr),*$(,)*) =3D> {{ static _SUBSECTIONS: $crate::vmstate::VMStateSubsectionsWrapper = =3D $crate::vmstate::VMStateSubsectionsWrapper(&[ $({ - static _SUBSECTION: $crate::bindings::VMStateDescription = =3D $subsection; + static _SUBSECTION: $crate::bindings::VMStateDescription = =3D $subsection.get(); ::core::ptr::addr_of!(_SUBSECTION) }),*, ::core::ptr::null() ]); - _SUBSECTIONS.0.as_ptr() + &_SUBSECTIONS }} } + +pub struct VMStateDescription(bindings::VMStateDescription, PhantomData= ); + +// SAFETY: When a *const T is passed to the callbacks, the call itself +// is done in a thread-safe manner. The invocation is okay as long as +// T itself is `Sync`. +unsafe impl Sync for VMStateDescription {} + +#[derive(Clone)] +pub struct VMStateDescriptionBuilder(bindings::VMStateDescription, Phan= tomData); + +unsafe extern "C" fn vmstate_pre_load_cb< + T, + F: for<'a> FnCall<(&'a T,), Result<(), impl Into>>, +>( + opaque: *mut c_void, +) -> c_int { + // SAFETY: assumes vmstate_struct! is used correctly + let result =3D F::call((unsafe { &*(opaque.cast::()) },)); + into_neg_errno(result) +} + +unsafe extern "C" fn vmstate_post_load_cb< + T, + F: for<'a> FnCall<(&'a T, u8), Result<(), impl Into>>, +>( + opaque: *mut c_void, + version_id: c_int, +) -> c_int { + // SAFETY: assumes vmstate_struct! is used correctly + let owner: &T =3D unsafe { &*(opaque.cast::()) }; + let version: u8 =3D version_id.try_into().unwrap(); + let result =3D F::call((owner, version)); + into_neg_errno(result) +} + +unsafe extern "C" fn vmstate_pre_save_cb< + T, + F: for<'a> FnCall<(&'a T,), Result<(), impl Into>>, +>( + opaque: *mut c_void, +) -> c_int { + // SAFETY: assumes vmstate_struct! is used correctly + let result =3D F::call((unsafe { &*(opaque.cast::()) },)); + into_neg_errno(result) +} + +unsafe extern "C" fn vmstate_post_save_cb< + T, + F: for<'a> FnCall<(&'a T,), Result<(), impl Into>>, +>( + opaque: *mut c_void, +) -> c_int { + // SAFETY: assumes vmstate_struct! is used correctly + let result =3D F::call((unsafe { &*(opaque.cast::()) },)); + into_neg_errno(result) +} + +unsafe extern "C" fn vmstate_needed_cb FnCall<(&'a T,), bool= >>( + opaque: *mut c_void, +) -> bool { + // SAFETY: assumes vmstate_struct! is used correctly + F::call((unsafe { &*(opaque.cast::()) },)) +} + +unsafe extern "C" fn vmstate_dev_unplug_pending_cb FnCall<(&= 'a T,), bool>>( + opaque: *mut c_void, +) -> bool { + // SAFETY: assumes vmstate_struct! is used correctly + F::call((unsafe { &*(opaque.cast::()) },)) +} + +impl VMStateDescriptionBuilder { + #[must_use] + pub const fn name(mut self, name_str: &CStr) -> Self { + self.0.name =3D ::std::ffi::CStr::as_ptr(name_str); + self + } + + #[must_use] + pub const fn unmigratable(mut self) -> Self { + self.0.unmigratable =3D true; + self + } + + #[must_use] + pub const fn early_setup(mut self) -> Self { + self.0.early_setup =3D true; + self + } + + #[must_use] + pub const fn version_id(mut self, version: u8) -> Self { + self.0.version_id =3D version as c_int; + self + } + + #[must_use] + pub const fn minimum_version_id(mut self, min_version: u8) -> Self { + self.0.minimum_version_id =3D min_version as c_int; + self + } + + #[must_use] + pub const fn priority(mut self, priority: MigrationPriority) -> Self { + self.0.priority =3D priority; + self + } + + #[must_use] + pub const fn pre_load FnCall<(&'a T,), Result<(), impl Into= >>>( + mut self, + _f: &F, + ) -> Self { + self.0.pre_load =3D Some(vmstate_pre_load_cb::); + self + } + + #[must_use] + pub const fn post_load FnCall<(&'a T, u8), Result<(), impl = Into>>>( + mut self, + _f: &F, + ) -> Self { + self.0.post_load =3D Some(vmstate_post_load_cb::); + self + } + + #[must_use] + pub const fn pre_save FnCall<(&'a T,), Result<(), impl Into= >>>( + mut self, + _f: &F, + ) -> Self { + self.0.pre_save =3D Some(vmstate_pre_save_cb::); + self + } + + #[must_use] + pub const fn post_save FnCall<(&'a T,), Result<(), impl Int= o>>>( + mut self, + _f: &F, + ) -> Self { + self.0.post_save =3D Some(vmstate_post_save_cb::); + self + } + + #[must_use] + pub const fn needed FnCall<(&'a T,), bool>>(mut self, _f: &= F) -> Self { + self.0.needed =3D Some(vmstate_needed_cb::); + self + } + + #[must_use] + pub const fn unplug_pending FnCall<(&'a T,), bool>>(mut sel= f, _f: &F) -> Self { + self.0.dev_unplug_pending =3D Some(vmstate_dev_unplug_pending_cb::= ); + self + } + + #[must_use] + pub const fn fields(mut self, fields: *const VMStateField) -> Self { + self.0.fields =3D fields; + self + } + + #[must_use] + pub const fn subsections(mut self, subs: &'static VMStateSubsectionsWr= apper) -> Self { + self.0.subsections =3D subs.0.as_ptr(); + self + } + + #[must_use] + pub const fn build(self) -> VMStateDescription { + VMStateDescription::(self.0, PhantomData) + } + + #[must_use] + pub const fn new() -> Self { + Self(bindings::VMStateDescription::ZERO, PhantomData) + } +} + +impl Default for VMStateDescriptionBuilder { + fn default() -> Self { + Self::new() + } +} + +impl VMStateDescription { + pub const fn get(&self) -> bindings::VMStateDescription { + self.0 + } + + pub const fn as_ref(&self) -> &bindings::VMStateDescription { + &self.0 + } +} diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index a658a49fcfd..3264641d128 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -12,18 +12,16 @@ qdev::{DeviceImpl, DeviceState, Property, ResettablePhasesImpl}, qom::{ObjectImpl, ParentField}, sysbus::SysBusDevice, - vmstate::VMStateDescription, - zeroable::Zeroable, + vmstate::{VMStateDescription, VMStateDescriptionBuilder}, }; =20 mod vmstate_tests; =20 // Test that macros can compile. -pub static VMSTATE: VMStateDescription =3D VMStateDescription { - name: c"name".as_ptr(), - unmigratable: true, - ..Zeroable::ZERO -}; +pub const VMSTATE: VMStateDescription =3D VMStateDescriptionBu= ilder::::new() + .name(c"name") + .unmigratable() + .build(); =20 #[repr(C)] #[derive(qemu_api_macros::Object)] @@ -72,8 +70,8 @@ impl DeviceImpl for DummyState { fn properties() -> &'static [Property] { &DUMMY_PROPERTIES } - fn vmsd() -> Option<&'static VMStateDescription> { - Some(&VMSTATE) + fn vmsd() -> Option> { + Some(VMSTATE) } } =20 diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vms= tate_tests.rs index ad0fc5cd5dd..12f852ef703 100644 --- a/rust/qemu-api/tests/vmstate_tests.rs +++ b/rust/qemu-api/tests/vmstate_tests.rs @@ -16,9 +16,8 @@ }, cell::{BqlCell, Opaque}, impl_vmstate_forward, - vmstate::{VMStateDescription, VMStateField}, + vmstate::{VMStateDescription, VMStateDescriptionBuilder, VMStateField}, vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_va= lidate, - zeroable::Zeroable, }; =20 const FOO_ARRAY_MAX: usize =3D 3; @@ -41,22 +40,22 @@ struct FooA { elem: i8, } =20 -static VMSTATE_FOOA: VMStateDescription =3D VMStateDescription { - name: c"foo_a".as_ptr(), - version_id: 1, - minimum_version_id: 1, - fields: vmstate_fields! { +static VMSTATE_FOOA: VMStateDescription =3D VMStateDescriptionBuilde= r::::new() + .name(c"foo_a") + .version_id(1) + .minimum_version_id(1) + .fields(vmstate_fields! { vmstate_of!(FooA, elem), vmstate_unused!(size_of::()), vmstate_of!(FooA, arr[0 .. num]).with_version_id(0), vmstate_of!(FooA, arr_mul[0 .. num_mul * 16]), - }, - ..Zeroable::ZERO -}; + }) + .build(); =20 #[test] fn test_vmstate_uint16() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; =20 // 1st VMStateField ("elem") in VMSTATE_FOOA (corresponding to VMSTATE= _UINT16) assert_eq!( @@ -76,7 +75,8 @@ fn test_vmstate_uint16() { =20 #[test] fn test_vmstate_unused() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; =20 // 2nd VMStateField ("unused") in VMSTATE_FOOA (corresponding to VMSTA= TE_UNUSED) assert_eq!( @@ -96,7 +96,8 @@ fn test_vmstate_unused() { =20 #[test] fn test_vmstate_varray_uint16_unsafe() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; =20 // 3rd VMStateField ("arr") in VMSTATE_FOOA (corresponding to // VMSTATE_VARRAY_UINT16_UNSAFE) @@ -117,7 +118,8 @@ fn test_vmstate_varray_uint16_unsafe() { =20 #[test] fn test_vmstate_varray_multiply() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOA.fields, 5) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; =20 // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to // VMSTATE_VARRAY_MULTIPLY) @@ -171,24 +173,25 @@ fn validate_foob(_state: &FooB, _version_id: u8) -> b= ool { true } =20 -static VMSTATE_FOOB: VMStateDescription =3D VMStateDescription { - name: c"foo_b".as_ptr(), - version_id: 2, - minimum_version_id: 1, - fields: vmstate_fields! { - vmstate_of!(FooB, val).with_version_id(2), - vmstate_of!(FooB, wrap), - vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with= _version_id(1), - vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOO= A, FooA).with_version_id(2), - vmstate_of!(FooB, arr_i64), - vmstate_struct!(FooB, arr_a_wrap[0 .. num_a_wrap], &VMSTATE_FOOA, = FooA, validate_foob), - }, - ..Zeroable::ZERO -}; +static VMSTATE_FOOB: VMStateDescription =3D + VMStateDescriptionBuilder::::new() + .name(c"foo_b") + .version_id(2) + .minimum_version_id(1) + .fields(vmstate_fields! { + vmstate_of!(FooB, val).with_version_id(2), + vmstate_of!(FooB, wrap), + vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).= with_version_id(1), + vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE= _FOOA, FooA).with_version_id(2), + vmstate_of!(FooB, arr_i64), + vmstate_struct!(FooB, arr_a_wrap[0 .. num_a_wrap], &VMSTATE_FO= OA, FooA, validate_foob), + }) + .build(); =20 #[test] fn test_vmstate_bool_v() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; =20 // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_= BOOL_V) assert_eq!( @@ -208,7 +211,8 @@ fn test_vmstate_bool_v() { =20 #[test] fn test_vmstate_uint64() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; =20 // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE= _U64) assert_eq!( @@ -228,7 +232,8 @@ fn test_vmstate_uint64() { =20 #[test] fn test_vmstate_struct_varray_uint8() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; =20 // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to // VMSTATE_STRUCT_VARRAY_UINT8) @@ -246,13 +251,14 @@ fn test_vmstate_struct_varray_uint8() { foo_fields[2].flags.0, VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0 ); - assert_eq!(foo_fields[2].vmsd, &VMSTATE_FOOA); + assert_eq!(foo_fields[2].vmsd, VMSTATE_FOOA.as_ref()); assert!(foo_fields[2].field_exists.is_none()); } =20 #[test] fn test_vmstate_struct_varray_uint32_multiply() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; =20 // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32) @@ -272,13 +278,14 @@ fn test_vmstate_struct_varray_uint32_multiply() { | VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 ); - assert_eq!(foo_fields[3].vmsd, &VMSTATE_FOOA); + assert_eq!(foo_fields[3].vmsd, VMSTATE_FOOA.as_ref()); assert!(foo_fields[3].field_exists.is_none()); } =20 #[test] fn test_vmstate_macro_array() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; =20 // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to // VMSTATE_ARRAY) @@ -299,7 +306,8 @@ fn test_vmstate_macro_array() { =20 #[test] fn test_vmstate_struct_varray_uint8_wrapper() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOB.fields, 7) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; let mut foo_b: FooB =3D Default::default(); let foo_b_p =3D std::ptr::addr_of_mut!(foo_b).cast::(); =20 @@ -335,26 +343,28 @@ struct FooC { arr_ptr_wrap: FooCWrapper, } =20 -static VMSTATE_FOOC: VMStateDescription =3D VMStateDescription { - name: c"foo_c".as_ptr(), - version_id: 3, - minimum_version_id: 1, - fields: vmstate_fields! { +unsafe impl Sync for FooC {} + +static VMSTATE_FOOC: VMStateDescription =3D VMStateDescriptionBuilde= r::::new() + .name(c"foo_c") + .version_id(3) + .minimum_version_id(1) + .fields(vmstate_fields! { vmstate_of!(FooC, ptr).with_version_id(2), // FIXME: Currently vmstate_struct doesn't support the pointer to = structure. // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FO= OA, NonNull) vmstate_unused!(size_of::>()), vmstate_of!(FooC, arr_ptr), vmstate_of!(FooC, arr_ptr_wrap), - }, - ..Zeroable::ZERO -}; + }) + .build(); =20 const PTR_SIZE: usize =3D size_of::<*mut ()>(); =20 #[test] fn test_vmstate_pointer() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOC.fields, 6) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOC.as_ref().fields, 6) }; =20 // 1st VMStateField ("ptr") in VMSTATE_FOOC (corresponding to VMSTATE_= POINTER) assert_eq!( @@ -377,7 +387,8 @@ fn test_vmstate_pointer() { =20 #[test] fn test_vmstate_macro_array_of_pointer() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOC.fields, 6) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOC.as_ref().fields, 6) }; =20 // 3rd VMStateField ("arr_ptr") in VMSTATE_FOOC (corresponding to // VMSTATE_ARRAY_OF_POINTER) @@ -401,7 +412,8 @@ fn test_vmstate_macro_array_of_pointer() { =20 #[test] fn test_vmstate_macro_array_of_pointer_wrapped() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOC.fields, 6) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOC.as_ref().fields, 6) }; =20 // 4th VMStateField ("arr_ptr_wrap") in VMSTATE_FOOC (corresponding to // VMSTATE_ARRAY_OF_POINTER) @@ -450,21 +462,21 @@ fn validate_food_2(_state: &FooD, _version_id: u8) ->= bool { true } =20 -static VMSTATE_FOOD: VMStateDescription =3D VMStateDescription { - name: c"foo_d".as_ptr(), - version_id: 3, - minimum_version_id: 1, - fields: vmstate_fields! { +static VMSTATE_FOOD: VMStateDescription =3D VMStateDescriptionBuilde= r::::new() + .name(c"foo_d") + .version_id(3) + .minimum_version_id(1) + .fields(vmstate_fields! { vmstate_validate!(FooD, c"foo_d_0", FooD::validate_food_0), vmstate_validate!(FooD, c"foo_d_1", FooD::validate_food_1), vmstate_validate!(FooD, c"foo_d_2", validate_food_2), - }, - ..Zeroable::ZERO -}; + }) + .build(); =20 #[test] fn test_vmstate_validate() { - let foo_fields: &[VMStateField] =3D unsafe { slice::from_raw_parts(VMS= TATE_FOOD.fields, 4) }; + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOD.as_ref().fields, 4) }; let mut foo_d =3D FooD; let foo_d_p =3D std::ptr::addr_of_mut!(foo_d).cast::(); =20 --=20 2.49.0 From nobody Fri Dec 19 02:51:19 2025 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=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1746439788; cv=none; d=zohomail.com; s=zohoarc; b=liNhFev97KVvPXTzJbdp0NiK501eRVeVIVxSbq0T+RylUA/ev6cF5F32aAtAdCO7hmnsaco1XxyudAKecBiCOc3ZBEw+QY5VmBzcw83tKpz0BDMGEWkLh6p4JueiFL65WlDPFh3JoWtdxIY3NBQ4W45shRvPujmPrMyrQ3XysHk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746439788; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=BorGBImVI/7cTxuUWUYqddAbu9Lfgm8O06Pniz/tT8g=; b=goI31AvLlVEuWbeMCwE41DNLoe4WJlA4k3NSV3ZwnkrXZns/Az0piUouc7rSMudyKebDkpNf96Ljguwdwj+be7qceKmqSoj8tcIVDiLc9ip+UPYg8X4LNHfp4VpapKIfQWGMw5SlA40CgI0lRyDS0ZkNrXQt4GVlmSck2Sv1u1U= 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=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1746439788298667.8081641037194; Mon, 5 May 2025 03:09:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uBslB-0005a5-Rl; Mon, 05 May 2025 06:09:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsl9-0005Uw-EO for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:15 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsl6-0007Dd-71 for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:15 -0400 Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-96-499r1iznP8ukgYB5LVmWog-1; Mon, 05 May 2025 06:09:08 -0400 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-43ceb011ea5so24546755e9.2 for ; Mon, 05 May 2025 03:09:07 -0700 (PDT) Received: from [192.168.10.48] ([151.95.54.106]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-441b8a286dasm127574805e9.31.2025.05.05.03.09.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 May 2025 03:09:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1746439751; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=BorGBImVI/7cTxuUWUYqddAbu9Lfgm8O06Pniz/tT8g=; b=WRqb0k+M9iGeJi9mpWp29bZYqxU/mSlc+5KD33ceL9IFOZQrApo2/mNayMEmLym8lMA/rf cBXgnjZ4uSqd0ErlZH+VpKomTEQFR4ZwspXB8a4tQu0ypCD4bJJsCoZjZfK4B4pL6Vq9hm pKZk3tO+wE8j8xYs9QfD9AK7S8LqJvI= X-MC-Unique: 499r1iznP8ukgYB5LVmWog-1 X-Mimecast-MFC-AGG-ID: 499r1iznP8ukgYB5LVmWog_1746439746 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746439745; x=1747044545; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BorGBImVI/7cTxuUWUYqddAbu9Lfgm8O06Pniz/tT8g=; b=CQ3BeCMI+geEpLlWEwRSyMnBJMqlW5hWeThhNw9woKfWgjZc5CO56jD9s2yXRPu1Nm j2VEqTZ05VOJrJ/wn2D4pmPnXBeNsTVXG2kiPbdwU3mNLraqzb5PaGaLYRNr51CqpSYT QG63HDuq4D5MmBWaEs/M1ZVVibaAgg+YgNAZ9yuwL0hdj8DZPkklaMWg9WqMaygEgs6r ACe880GLt8TPnsK5l38/QTsJHZyi7ceLxXJ/aHmRhpD//MAtAtqBck8gqW8XMTmjWVEz W/JZ1lreTAxa4eeLgKfDPXcX6wwQcJjQ9Oqr96Mji+G1jb1VgOqcOPUDEWcgwJQlMtvR xFOA== X-Gm-Message-State: AOJu0YxYgAqgg6+dUFtFJwln/d4ZjTO8/X+uzb8cRXprRuo2pRnqtmvH migjs2n3x4GjfBFtNDH2g447gUNhk0emzdJguxcdxYV7Tvg2qK8gAcOvXs090m3kD86qNkGDLye iUyfm0RBAUhRTI2EkziTAvhXVpnVmCCI4JHj5PhlxaUIj9E0KspW/SOlNH0aM7yxQ5Akk57VSQo tT7bEEiGnBZuSTiXcerqE5z5jNZVPDi221PwhX X-Gm-Gg: ASbGnctURQ04sS9KErSLX/KB20Z/4v8uN5ec9vepPAZ2O+rYG+msg6Fqh6P+PxlqBWJ ICs8ZUcWDZX9vMCISc9TVPkdGe85JMloCDfMec2Azg0dCnXnNdMttySDJYSdQIiCMPHL7vhvCHo 8D5rbDLzFtvaCGeWj/5Njj9dTsnqx36+fFCKRUUwqMXUkeGIwMP7Y8a0WA8hldxtGv3ogZydQ5X 9SSHpOAU21mbTH2rEsfBv/wCm5kWlFM57u00RE3/pQuWmCN743zhOXxxGtbA1cDrHwsFXcfBQn8 oHYWbAGbv9TmrzM= X-Received: by 2002:a05:600c:4e09:b0:43d:224:86b5 with SMTP id 5b1f17b1804b1-441c48b0213mr58978695e9.4.1746439744992; Mon, 05 May 2025 03:09:04 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFf6CNqtI6QDmb8EFVx474Yts26w12nj7KALfq9f+tuKkqGgqEWLce6CBFqyX6bUyRkZ9eVDg== X-Received: by 2002:a05:600c:4e09:b0:43d:224:86b5 with SMTP id 5b1f17b1804b1-441c48b0213mr58978345e9.4.1746439744348; Mon, 05 May 2025 03:09:04 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 4/5] rust: vmstate: use const_refs_to_static Date: Mon, 5 May 2025 12:08:53 +0200 Message-ID: <20250505100854.73936-5-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250505100854.73936-1-pbonzini@redhat.com> References: <20250505100854.73936-1-pbonzini@redhat.com> 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=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.411, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=-1, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: 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 @redhat.com) X-ZM-MESSAGEID: 1746439790618116600 Content-Type: text/plain; charset="utf-8" The VMStateDescriptionBuilder already needs const_refs_to_static, so use it to remove the need for vmstate_clock! and vmstate_struct!, as well as to simplify the implementation for scalars. If the consts in the VMState trait can reference to static VMStateDescription, scalars do not need the info_enum_to_ref! indirection and structs can implement the VMState trait themselves. Signed-off-by: Paolo Bonzini --- docs/devel/rust.rst | 5 - rust/hw/char/pl011/src/device_class.rs | 14 +- rust/hw/timer/hpet/src/hpet.rs | 8 +- rust/qemu-api/src/assertions.rs | 4 - rust/qemu-api/src/vmstate.rs | 232 +++++++------------------ rust/qemu-api/tests/vmstate_tests.rs | 65 ++++--- 6 files changed, 116 insertions(+), 212 deletions(-) diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index ed1c765e722..12c9bde4f5c 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -80,11 +80,6 @@ patches are welcome: =20 * ``&raw`` (stable in 1.82.0). =20 -* referencing statics in constants (stable in 1.83.0). For now use a const - function; this is an important limitation for QEMU's migration stream - architecture (VMState). Right now, VMState lacks type safety because - it is hard to place the ``VMStateField`` definitions in traits. - Associated const equality would be nice to have for some users of ``callbacks::FnCall``, but is still experimental. Const assertions are used instead. diff --git a/rust/hw/char/pl011/src/device_class.rs b/rust/hw/char/pl011/sr= c/device_class.rs index ed72bfad25f..e4a9499bda7 100644 --- a/rust/hw/char/pl011/src/device_class.rs +++ b/rust/hw/char/pl011/src/device_class.rs @@ -4,9 +4,9 @@ =20 use qemu_api::{ bindings::{qdev_prop_bool, qdev_prop_chr}, - prelude::*, + impl_vmstate_struct, vmstate::{VMStateDescription, VMStateDescriptionBuilder}, - vmstate_clock, vmstate_fields, vmstate_of, vmstate_struct, vmstate_sub= sections, vmstate_unused, + vmstate_fields, vmstate_of, vmstate_subsections, vmstate_unused, }; =20 use crate::device::{PL011Registers, PL011State}; @@ -19,11 +19,12 @@ .minimum_version_id(1) .needed(&PL011State::clock_needed) .fields(vmstate_fields! { - vmstate_clock!(PL011State, clock), + vmstate_of!(PL011State, clock), }) .build(); =20 -static VMSTATE_PL011_REGS: VMStateDescription =3D +impl_vmstate_struct!( + PL011Registers, VMStateDescriptionBuilder::::new() .name(c"pl011/regs") .version_id(2) @@ -45,7 +46,8 @@ vmstate_of!(PL011Registers, read_count), vmstate_of!(PL011Registers, read_trigger), }) - .build(); + .build() +); =20 pub const VMSTATE_PL011: VMStateDescription =3D VMStateDescriptionBuilder::::new() @@ -55,7 +57,7 @@ .post_load(&PL011State::post_load) .fields(vmstate_fields! { vmstate_unused!(core::mem::size_of::()), - vmstate_struct!(PL011State, regs, &VMSTATE_PL011_REGS, BqlRefC= ell), + vmstate_of!(PL011State, regs), }) .subsections(vmstate_subsections! { VMSTATE_PL011_CLOCK diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index 1ed1cb7dcaf..be3b9afa316 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -16,6 +16,7 @@ qdev_prop_uint32, qdev_prop_uint8, }, cell::{BqlCell, BqlRefCell}, + impl_vmstate_struct, irq::InterruptSource, memory::{ hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder, MEM= TXATTRS_UNSPECIFIED, @@ -27,7 +28,7 @@ sysbus::{SysBusDevice, SysBusDeviceImpl}, timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, vmstate::{VMStateDescription, VMStateDescriptionBuilder}, - vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmsta= te_validate, + vmstate_fields, vmstate_of, vmstate_subsections, vmstate_validate, }; =20 use crate::fw_cfg::HPETFwConfig; @@ -967,7 +968,7 @@ impl ObjectImpl for HPETState { }) .build(); =20 -static VMSTATE_HPET_TIMER: VMStateDescription =3D +const VMSTATE_HPET_TIMER: VMStateDescription =3D VMStateDescriptionBuilder::::new() .name(c"hpet_timer") .version_id(1) @@ -982,6 +983,7 @@ impl ObjectImpl for HPETState { vmstate_of!(HPETTimer, qemu_timer), }) .build(); +impl_vmstate_struct!(HPETTimer, VMSTATE_HPET_TIMER); =20 const VALIDATE_TIMERS_NAME: &CStr =3D c"num_timers must match"; =20 @@ -998,7 +1000,7 @@ impl ObjectImpl for HPETState { vmstate_of!(HPETState, counter), vmstate_of!(HPETState, num_timers_save).with_version_id(2), vmstate_validate!(HPETState, VALIDATE_TIMERS_NAME, HPETState::= validate_num_timers), - vmstate_struct!(HPETState, timers[0 .. num_timers], &VMSTATE_H= PET_TIMER, BqlRefCell, HPETState::validate_num_timers).with_vers= ion_id(0), + vmstate_of!(HPETState, timers[0 .. num_timers], HPETState::val= idate_num_timers).with_version_id(0), }) .subsections(vmstate_subsections!( VMSTATE_HPET_RTC_IRQ_LEVEL, diff --git a/rust/qemu-api/src/assertions.rs b/rust/qemu-api/src/assertions= .rs index a2d38c877df..80db0de099f 100644 --- a/rust/qemu-api/src/assertions.rs +++ b/rust/qemu-api/src/assertions.rs @@ -95,10 +95,6 @@ fn types_must_be_equal(_: &T) ($t:ty, $i:tt, $ti:ty) =3D> { $crate::assert_field_type!(@internal v, $ti, $t, v.$i); }; - - ($t:ty, $i:tt, $ti:ty, num =3D $num:ident) =3D> { - $crate::assert_field_type!(@internal v, $ti, $t, v.$i[0]); - }; } =20 /// Assert that an expression matches a pattern. This can also be diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 228d748b6b7..959d0a01fe3 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -11,10 +11,11 @@ //! migration format for a struct. This is based on the [`VMState`] tra= it, //! which is defined by all migrateable types. //! -//! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and +//! * [`impl_vmstate_forward`](crate::impl_vmstate_forward), +//! * [`impl_vmstate_struct`](crate::impl_vmstate_struct), //! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help = with -//! the definition of the [`VMState`] trait (respectively for transparent -//! structs and for `bilge`-defined types) +//! the definition of the [`VMState`] trait; they are respectively for +//! transparent structs, nested structs and `bilge`-defined types) //! //! * helper macros to declare a device model state struct, in particular //! [`vmstate_subsections`](crate::vmstate_subsections) and @@ -24,7 +25,11 @@ //! `include/migration/vmstate.h`. These are not type-safe and only prov= ide //! functionality that is missing from `vmstate_of!`. =20 -use core::{marker::PhantomData, mem, ptr::NonNull}; +use core::{ + marker::PhantomData, + mem, + ptr::{addr_of, NonNull}, +}; use std::ffi::{c_int, c_void, CStr}; =20 pub use crate::bindings::{MigrationPriority, VMStateField}; @@ -33,6 +38,7 @@ callbacks::FnCall, errno::{into_neg_errno, Errno}, prelude::*, + qdev, qom::Owned, zeroable::Zeroable, }; @@ -74,70 +80,6 @@ const fn phantom__(_: &T) -> ::core::marker::PhantomD= ata { ::core::marker: }; } =20 -/// Workaround for lack of `const_refs_static`: references to global varia= bles -/// can be included in a `static`, but not in a `const`; unfortunately, th= is -/// is exactly what would go in the `VMStateField`'s `info` member. -/// -/// This enum contains the contents of the `VMStateField`'s `info` member, -/// but as an `enum` instead of a pointer. -#[allow(non_camel_case_types)] -pub enum VMStateFieldType { - null, - vmstate_info_bool, - vmstate_info_int8, - vmstate_info_int16, - vmstate_info_int32, - vmstate_info_int64, - vmstate_info_uint8, - vmstate_info_uint16, - vmstate_info_uint32, - vmstate_info_uint64, - vmstate_info_timer, -} - -/// Workaround for lack of `const_refs_static`. Converts a `VMStateFieldT= ype` -/// to a `*const VMStateInfo`, for inclusion in a `VMStateField`. -#[macro_export] -macro_rules! info_enum_to_ref { - ($e:expr) =3D> { - unsafe { - match $e { - $crate::vmstate::VMStateFieldType::null =3D> ::core::ptr::= null(), - $crate::vmstate::VMStateFieldType::vmstate_info_bool =3D> { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_b= ool) - } - $crate::vmstate::VMStateFieldType::vmstate_info_int8 =3D> { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_i= nt8) - } - $crate::vmstate::VMStateFieldType::vmstate_info_int16 =3D>= { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_i= nt16) - } - $crate::vmstate::VMStateFieldType::vmstate_info_int32 =3D>= { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_i= nt32) - } - $crate::vmstate::VMStateFieldType::vmstate_info_int64 =3D>= { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_i= nt64) - } - $crate::vmstate::VMStateFieldType::vmstate_info_uint8 =3D>= { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_u= int8) - } - $crate::vmstate::VMStateFieldType::vmstate_info_uint16 =3D= > { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_u= int16) - } - $crate::vmstate::VMStateFieldType::vmstate_info_uint32 =3D= > { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_u= int32) - } - $crate::vmstate::VMStateFieldType::vmstate_info_uint64 =3D= > { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_u= int64) - } - $crate::vmstate::VMStateFieldType::vmstate_info_timer =3D>= { - ::core::ptr::addr_of!($crate::bindings::vmstate_info_t= imer) - } - } - } - }; -} - /// A trait for types that can be included in a device's migration stream.= It /// provides the base contents of a `VMStateField` (minus the name and off= set). /// @@ -148,12 +90,6 @@ macro_rules! info_enum_to_ref { /// to implement it except via macros that do it for you, such as /// `impl_vmstate_bitsized!`. pub unsafe trait VMState { - /// The `info` member of a `VMStateField` is a pointer and as such can= not - /// yet be included in the [`BASE`](VMState::BASE) associated constant; - /// this is only allowed by Rust 1.83.0 and newer. For now, include t= he - /// member as an enum which is stored in a separate constant. - const SCALAR_TYPE: VMStateFieldType =3D VMStateFieldType::null; - /// The base contents of a `VMStateField` (minus the name and offset) = for /// the type that is implementing the trait. const BASE: VMStateField; @@ -168,12 +104,6 @@ pub unsafe trait VMState { }; } =20 -/// Internal utility function to retrieve a type's `VMStateFieldType`; -/// used by [`vmstate_of!`](crate::vmstate_of). -pub const fn vmstate_scalar_type(_: PhantomData) -> VMState= FieldType { - T::SCALAR_TYPE -} - /// Internal utility function to retrieve a type's `VMStateField`; /// used by [`vmstate_of!`](crate::vmstate_of). pub const fn vmstate_base(_: PhantomData) -> VMStateField { @@ -201,7 +131,8 @@ pub const fn vmstate_varray_flag(_: Phantom= Data) -> VMStateFlags /// /// In order to support other types, the trait `VMState` must be implement= ed /// for them. The macros -/// [`impl_vmstate_bitsized!`](crate::impl_vmstate_bitsized) +/// [`impl_vmstate_bitsized!`](crate::impl_vmstate_bitsized), +/// [`impl_vmstate_struct!`](crate::impl_vmstate_struct), /// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with t= his. #[macro_export] macro_rules! vmstate_of { @@ -215,11 +146,6 @@ macro_rules! vmstate_of { $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_= fn),)? // The calls to `call_func_with_field!` are the magic that // computes most of the VMStateField from the type of the fiel= d. - info: $crate::info_enum_to_ref!($crate::call_func_with_field!( - $crate::vmstate::vmstate_scalar_type, - $struct_name, - $field_name - )), ..$crate::call_func_with_field!( $crate::vmstate::vmstate_base, $struct_name, @@ -320,8 +246,6 @@ macro_rules! impl_vmstate_forward { // the first field of the tuple ($tuple:ty) =3D> { unsafe impl $crate::vmstate::VMState for $tuple { - const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =3D - $crate::call_func_with_field!($crate::vmstate::vmstate_sca= lar_type, $tuple, 0); const BASE: $crate::bindings::VMStateField =3D $crate::call_func_with_field!($crate::vmstate::vmstate_bas= e, $tuple, 0); } @@ -333,7 +257,6 @@ unsafe impl $crate::vmstate::VMState for $tuple { macro_rules! impl_vmstate_transparent { ($type:ty where $base:tt: VMState $($where:tt)*) =3D> { unsafe impl<$base> VMState for $type where $base: VMState $($where= )* { - const SCALAR_TYPE: VMStateFieldType =3D <$base as VMState>::SC= ALAR_TYPE; const BASE: VMStateField =3D VMStateField { size: mem::size_of::<$type>(), ..<$base as VMState>::BASE @@ -354,10 +277,6 @@ unsafe impl<$base> VMState for $type where $base: VMSt= ate $($where)* { macro_rules! impl_vmstate_bitsized { ($type:ty) =3D> { unsafe impl $crate::vmstate::VMState for $type { - const SCALAR_TYPE: $crate::vmstate::VMStateFieldType =3D - <<<$type as ::bilge::prelude::Bits= ized>::ArbitraryInt - as ::bilge::prelude::Number>::Un= derlyingType - as $crate::vmstate::VMState>::SCA= LAR_TYPE; const BASE: $crate::bindings::VMStateField =3D <<<$type as ::bilge::prelude::Bits= ized>::ArbitraryInt as ::bilge::prelude::Number>::Un= derlyingType @@ -375,8 +294,8 @@ unsafe impl $crate::vmstate::VMState for $type { macro_rules! impl_vmstate_scalar { ($info:ident, $type:ty$(, $varray_flag:ident)?) =3D> { unsafe impl VMState for $type { - const SCALAR_TYPE: VMStateFieldType =3D VMStateFieldType::$inf= o; const BASE: VMStateField =3D VMStateField { + info: addr_of!(bindings::$info), size: mem::size_of::<$type>(), flags: VMStateFlags::VMS_SINGLE, ..Zeroable::ZERO @@ -397,6 +316,21 @@ unsafe impl VMState for $type { impl_vmstate_scalar!(vmstate_info_uint64, u64); impl_vmstate_scalar!(vmstate_info_timer, crate::timer::Timer); =20 +macro_rules! impl_vmstate_c_struct { + ($type:ty, $vmsd:expr) =3D> { + unsafe impl VMState for $type { + const BASE: VMStateField =3D $crate::bindings::VMStateField { + vmsd: addr_of!($vmsd), + size: mem::size_of::<$type>(), + flags: VMStateFlags::VMS_STRUCT, + ..Zeroable::ZERO + }; + } + }; +} + +impl_vmstate_c_struct!(qdev::Clock, bindings::vmstate_clock); + // Pointer types using the underlying type's VMState plus VMS_POINTER // Note that references are not supported, though references to cells // could be allowed. @@ -404,7 +338,6 @@ unsafe impl VMState for $type { macro_rules! impl_vmstate_pointer { ($type:ty where $base:tt: VMState $($where:tt)*) =3D> { unsafe impl<$base> VMState for $type where $base: VMState $($where= )* { - const SCALAR_TYPE: VMStateFieldType =3D ::SCALAR= _TYPE; const BASE: VMStateField =3D <$base as VMState>::BASE.with_poi= nter_flag(); } }; @@ -423,7 +356,6 @@ unsafe impl<$base> VMState for $type where $base: VMSta= te $($where)* { // VMS_ARRAY/VMS_ARRAY_OF_POINTER =20 unsafe impl VMState for [T; N] { - const SCALAR_TYPE: VMStateFieldType =3D ::SCALAR_TYPE; const BASE: VMStateField =3D ::BASE.with_array_flag(N); } =20 @@ -445,7 +377,7 @@ pub extern "C" fn rust_vms_test_field_exists bool { - // SAFETY: assumes vmstate_struct! is used correctly + // SAFETY: the function is used in T's implementation of VMState let owner: &T =3D unsafe { &*(opaque.cast::()) }; let version: u8 =3D version_id.try_into().unwrap(); F::call((owner, version)) @@ -473,76 +405,6 @@ const fn phantom__(_: &T) -> ::core::marker::Phanto= mData { }}; } =20 -// FIXME: including the `vmsd` field in a `const` is not possible without -// the const_refs_static feature (stabilized in Rust 1.83.0). Without it, -// it is not possible to use VMS_STRUCT in a transparent manner using -// `vmstate_of!`. While VMSTATE_CLOCK can at least try to be type-safe, -// VMSTATE_STRUCT includes $type only for documentation purposes; it -// is checked against $field_name and $struct_name, but not against $vmsd -// which is what really would matter. -#[doc(alias =3D "VMSTATE_STRUCT")] -#[macro_export] -macro_rules! vmstate_struct { - ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:exp= r)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) =3D> { - $crate::bindings::VMStateField { - name: ::core::concat!(::core::stringify!($field_name), "\0") - .as_bytes() - .as_ptr() as *const ::std::os::raw::c_char, - $(num_offset: ::std::mem::offset_of!($struct_name, $num),)? - offset: { - $crate::assert_field_type!($struct_name, $field_name, $typ= e $(, num =3D $num)?); - ::std::mem::offset_of!($struct_name, $field_name) - }, - size: ::core::mem::size_of::<$type>(), - flags: $crate::bindings::VMStateFlags::VMS_STRUCT, - vmsd: $vmsd.as_ref(), - $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_= fn),)? - ..$crate::zeroable::Zeroable::ZERO - } $(.with_varray_flag_unchecked( - $crate::call_func_with_field!( - $crate::vmstate::vmstate_varray_flag, - $struct_name, - $num - ) - ) - $(.with_varray_multiply($factor))?)? - }; -} - -#[doc(alias =3D "VMSTATE_CLOCK")] -#[macro_export] -macro_rules! vmstate_clock { - ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:exp= r)?])?) =3D> {{ - $crate::bindings::VMStateField { - name: ::core::concat!(::core::stringify!($field_name), "\0") - .as_bytes() - .as_ptr() as *const ::std::os::raw::c_char, - offset: { - $crate::assert_field_type!( - $struct_name, - $field_name, - $crate::qom::Owned<$crate::qdev::Clock> $(, num =3D $n= um)? - ); - ::std::mem::offset_of!($struct_name, $field_name) - }, - size: ::core::mem::size_of::<*const $crate::qdev::Clock>(), - flags: $crate::bindings::VMStateFlags( - $crate::bindings::VMStateFlags::VMS_STRUCT.0 - | $crate::bindings::VMStateFlags::VMS_POINTER.0, - ), - vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate= _clock) }, - ..$crate::zeroable::Zeroable::ZERO - } $(.with_varray_flag_unchecked( - $crate::call_func_with_field!( - $crate::vmstate::vmstate_varray_flag, - $struct_name, - $num - ) - ) - $(.with_varray_multiply($factor))?)? - }}; -} - /// Helper macro to declare a list of /// ([`VMStateField`](`crate::bindings::VMStateField`)) into a static and = return /// a pointer to the array of values it created. @@ -577,6 +439,30 @@ macro_rules! vmstate_validate { }; } =20 +/// Helper macro to allow using a struct in [`vmstate_field!`] +/// +/// # Safety +/// +/// The [`VMStateDescription`] constant `$vmsd` must be an accurate +/// description of the struct. +#[macro_export] +macro_rules! impl_vmstate_struct { + ($type:ty, $vmsd:expr) =3D> { + unsafe impl $crate::vmstate::VMState for $type { + const BASE: $crate::bindings::VMStateField =3D { + static VMSD: $crate::bindings::VMStateDescription =3D $vms= d.get(); + + $crate::bindings::VMStateField { + vmsd: ::core::ptr::addr_of!(VMSD), + size: ::core::mem::size_of::<$type>(), + flags: $crate::bindings::VMStateFlags::VMS_STRUCT, + ..$crate::zeroable::Zeroable::ZERO + } + }; + } + }; +} + /// A transparent wrapper type for the `subsections` field of /// [`VMStateDescription`]. /// @@ -624,7 +510,7 @@ unsafe impl Sync for VMStateDescription {} >( opaque: *mut c_void, ) -> c_int { - // SAFETY: assumes vmstate_struct! is used correctly + // SAFETY: the function is used in T's implementation of VMState let result =3D F::call((unsafe { &*(opaque.cast::()) },)); into_neg_errno(result) } @@ -636,7 +522,7 @@ unsafe impl Sync for VMStateDescription {} opaque: *mut c_void, version_id: c_int, ) -> c_int { - // SAFETY: assumes vmstate_struct! is used correctly + // SAFETY: the function is used in T's implementation of VMState let owner: &T =3D unsafe { &*(opaque.cast::()) }; let version: u8 =3D version_id.try_into().unwrap(); let result =3D F::call((owner, version)); @@ -649,7 +535,7 @@ unsafe impl Sync for VMStateDescription {} >( opaque: *mut c_void, ) -> c_int { - // SAFETY: assumes vmstate_struct! is used correctly + // SAFETY: the function is used in T's implementation of VMState let result =3D F::call((unsafe { &*(opaque.cast::()) },)); into_neg_errno(result) } @@ -660,7 +546,7 @@ unsafe impl Sync for VMStateDescription {} >( opaque: *mut c_void, ) -> c_int { - // SAFETY: assumes vmstate_struct! is used correctly + // SAFETY: the function is used in T's implementation of VMState let result =3D F::call((unsafe { &*(opaque.cast::()) },)); into_neg_errno(result) } @@ -668,14 +554,14 @@ unsafe impl Sync for VMStateDescription {} unsafe extern "C" fn vmstate_needed_cb FnCall<(&'a T,), bool= >>( opaque: *mut c_void, ) -> bool { - // SAFETY: assumes vmstate_struct! is used correctly + // SAFETY: the function is used in T's implementation of VMState F::call((unsafe { &*(opaque.cast::()) },)) } =20 unsafe extern "C" fn vmstate_dev_unplug_pending_cb FnCall<(&= 'a T,), bool>>( opaque: *mut c_void, ) -> bool { - // SAFETY: assumes vmstate_struct! is used correctly + // SAFETY: the function is used in T's implementation of VMState F::call((unsafe { &*(opaque.cast::()) },)) } =20 diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vms= tate_tests.rs index 12f852ef703..c73dba35fd3 100644 --- a/rust/qemu-api/tests/vmstate_tests.rs +++ b/rust/qemu-api/tests/vmstate_tests.rs @@ -15,9 +15,9 @@ vmstate_info_uint64, vmstate_info_uint8, vmstate_info_unused_buffe= r, VMStateFlags, }, cell::{BqlCell, Opaque}, - impl_vmstate_forward, + impl_vmstate_forward, impl_vmstate_struct, vmstate::{VMStateDescription, VMStateDescriptionBuilder, VMStateField}, - vmstate_fields, vmstate_of, vmstate_struct, vmstate_unused, vmstate_va= lidate, + vmstate_fields, vmstate_of, vmstate_unused, vmstate_validate, }; =20 const FOO_ARRAY_MAX: usize =3D 3; @@ -52,6 +52,8 @@ struct FooA { }) .build(); =20 +impl_vmstate_struct!(FooA, &VMSTATE_FOOA); + #[test] fn test_vmstate_uint16() { let foo_fields: &[VMStateField] =3D @@ -173,20 +175,19 @@ fn validate_foob(_state: &FooB, _version_id: u8) -> b= ool { true } =20 -static VMSTATE_FOOB: VMStateDescription =3D - VMStateDescriptionBuilder::::new() - .name(c"foo_b") - .version_id(2) - .minimum_version_id(1) - .fields(vmstate_fields! { - vmstate_of!(FooB, val).with_version_id(2), - vmstate_of!(FooB, wrap), - vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).= with_version_id(1), - vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE= _FOOA, FooA).with_version_id(2), - vmstate_of!(FooB, arr_i64), - vmstate_struct!(FooB, arr_a_wrap[0 .. num_a_wrap], &VMSTATE_FO= OA, FooA, validate_foob), - }) - .build(); +static VMSTATE_FOOB: VMStateDescription =3D VMStateDescriptionBuilde= r::::new() + .name(c"foo_b") + .version_id(2) + .minimum_version_id(1) + .fields(vmstate_fields! { + vmstate_of!(FooB, val).with_version_id(2), + vmstate_of!(FooB, wrap), + vmstate_of!(FooB, arr_a[0 .. num_a]).with_version_id(1), + vmstate_of!(FooB, arr_a_mul[0 .. num_a_mul * 32]).with_version_id(= 2), + vmstate_of!(FooB, arr_i64), + vmstate_of!(FooB, arr_a_wrap[0 .. num_a_wrap], validate_foob), + }) + .build(); =20 #[test] fn test_vmstate_bool_v() { @@ -351,9 +352,7 @@ unsafe impl Sync for FooC {} .minimum_version_id(1) .fields(vmstate_fields! { vmstate_of!(FooC, ptr).with_version_id(2), - // FIXME: Currently vmstate_struct doesn't support the pointer to = structure. - // VMSTATE_STRUCT_POINTER: vmstate_struct!(FooC, ptr_a, VMSTATE_FO= OA, NonNull) - vmstate_unused!(size_of::>()), + vmstate_of!(FooC, ptr_a), vmstate_of!(FooC, arr_ptr), vmstate_of!(FooC, arr_ptr_wrap), }) @@ -385,6 +384,31 @@ fn test_vmstate_pointer() { assert!(foo_fields[0].field_exists.is_none()); } =20 +#[test] +fn test_vmstate_struct_pointer() { + let foo_fields: &[VMStateField] =3D + unsafe { slice::from_raw_parts(VMSTATE_FOOC.as_ref().fields, 6) }; + + // 2st VMStateField ("ptr_a") in VMSTATE_FOOC (corresponding to + // VMSTATE_STRUCT_POINTER) + assert_eq!( + unsafe { CStr::from_ptr(foo_fields[1].name) }.to_bytes_with_nul(), + b"ptr\0" + ); + assert_eq!(foo_fields[1].offset, PTR_SIZE); + assert_eq!(foo_fields[1].num_offset, 0); + assert_eq!(foo_fields[1].vmsd, VMSTATE_FOOA.as_ref()); + assert_eq!(foo_fields[1].version_id, 0); + assert_eq!(foo_fields[1].size, PTR_SIZE); + assert_eq!(foo_fields[1].num, 0); + assert_eq!( + foo_fields[1].flags.0, + VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_POINTER.0 + ); + assert!(foo_fields[1].info.is_null()); + assert!(foo_fields[1].field_exists.is_none()); +} + #[test] fn test_vmstate_macro_array_of_pointer() { let foo_fields: &[VMStateField] =3D @@ -444,8 +468,7 @@ fn test_vmstate_macro_array_of_pointer_wrapped() { // * VMSTATE_FOOD: // - VMSTATE_VALIDATE =20 -// Add more member fields when vmstate_of/vmstate_struct support "test" -// parameter. +// Add more member fields when vmstate_of support "test" parameter. struct FooD; =20 impl FooD { --=20 2.49.0 From nobody Fri Dec 19 02:51:19 2025 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=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1746439776; cv=none; d=zohomail.com; s=zohoarc; b=D1xtOFrpZmsUpJgUV6rOUuxkbHmRN7lUCKMU4M0eT0WfdebUmsl99bNiVfgty5eL6fBhXUyK9XR3/+5R+WM9Q3co+8Iu/4qFsD08Bp+206yuxswj+Q5hitMrrZcS4bp+JxE5XeqKU/kRc6X9LGnStV9IdNwVK8+ooUHAEKQuTtw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1746439776; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=NziHDJPULqGSi476Eq607+qADlO5aBMunawIrs4CgEc=; b=Nc+3Iu6oXrwGLL8p5+xb0YeJvtbjgpK+6D+SJ6VCSoUrFyNs0pDVGbDD86D/9J4zPUtnhJ62Z5O8k7b8GINLaRoKzKrkhwJ0fJGqM1IMmsBKBVzCgVBmWDEMrQoZ3+WmTeQPFaMlSV5C46bWQQPntgAZwd4fl9Ee5tiYe0/Z5dM= 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=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1746439776161928.7083182127097; Mon, 5 May 2025 03:09:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uBslC-0005cz-GD; Mon, 05 May 2025 06:09:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsl8-0005Ui-Tb for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:14 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uBsl7-0007Dq-4t for qemu-devel@nongnu.org; Mon, 05 May 2025 06:09:14 -0400 Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-581-X4m2q-YlP8qBecovAPA2GA-1; Mon, 05 May 2025 06:09:10 -0400 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-440a4e2bad7so20339685e9.0 for ; Mon, 05 May 2025 03:09:10 -0700 (PDT) Received: from [192.168.10.48] ([151.95.54.106]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3a099b0fe9dsm9932263f8f.71.2025.05.05.03.09.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 May 2025 03:09:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1746439751; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=NziHDJPULqGSi476Eq607+qADlO5aBMunawIrs4CgEc=; b=jLID0sp2LgwQIMIgYXoh9PU1YwNCuxKNb30NRzR0B4+uc/b2b5l7Jh+Hwt2NNIz4xGNaRj pkIUFAWUxp4CbHIsnOmN4lh501VIqFpoQ2koTG9zmnmAq2OztgAtBwmku4ZhhCf9dPdAgj ar3ogi6cOYm/3/oKawVT/fyun6g7V+g= X-MC-Unique: X4m2q-YlP8qBecovAPA2GA-1 X-Mimecast-MFC-AGG-ID: X4m2q-YlP8qBecovAPA2GA_1746439749 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746439748; x=1747044548; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NziHDJPULqGSi476Eq607+qADlO5aBMunawIrs4CgEc=; b=qoUznOSZHNUwH+sEnaLJqLgTsG/rPXlOV7SYjU4o/8rlgKWZP6uuEEJrDusEHcPKMk ZArBiGfIC84mDUYaTm4EGLr4/kcKaS216btN6bYb62PLYNYFxP7xNwGbJyY8FfeGJYc9 xM9ocf/gz7Q4dY560tLusZATN88bfQ+PQ4vKN3r9wi4olloINXi8Ru01moRBuaXqxlhR VwkFlYU7OBcb9lA2NonUGVMwRpStYk000sAwbva2HIKkHfSGnHYE7Ewxo6UdviQGNR8g k8DsCNi6MbvjqGGRYM1pz6aPMw8SsrfzpGK+y6TRqEWqr/SzsDPLOuJn9nLtXL4efp48 5oCg== X-Gm-Message-State: AOJu0YzKt1Gb6wNG+aoCVFqKyDKM9HVY0VCKpxVgzVJzvuDRJuf7MFN2 ltn3o5kv5hCKWwOaPVYYEAERgQRL+mrnOnEN2yZZ+dX6j/KInSAVYLfmaW8dhirDkCr2+GIqjy8 LQ0Y9hLy0zb6H8ZWucGAZpdW0W7TtZzRiixdxIwO0zmi7w1hOY0orfi7aN5l1R2CfP+IL+zBWmw lesOrZ7+q6tgZVOs29eQr9GiMHbcOiTTjyfonm X-Gm-Gg: ASbGncsS13fu2rUTXrX+5g18bLUo2iI92sOmRCiG0SREAoJMrCWBUlM2blJSwZaVAIi WPy3aZSo+1sh37r6gsooMRSDFZNvGrbBFDzKFhN8nLP/QYHqEtnrtl3EWiQerRXGO2RYXf2ybGt h8h05TCAuW5GSgkKibE19LVtZDnWttrSatC+e1UOAjHZ8qkvlcDpLSPlsOk/eagFbr5xHOk9c4J 2Jysmym060OVFWhTkyL0W7xLxO90UQlzzWb264T1067VW7S5KKpRFJAc8o+33nHIaDHYcz0VSei uzptuTur9HB32IA= X-Received: by 2002:a05:6000:3105:b0:39f:bfa:7c90 with SMTP id ffacd0b85a97d-3a094038a8fmr11853799f8f.13.1746439748365; Mon, 05 May 2025 03:09:08 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEVCgB0iesXbV330i7mopdTNiGqzKhNVd/XqHbVgAl5Qzo/e0SFEWEcANn+y+gGUEJXt5Ue8w== X-Received: by 2002:a05:6000:3105:b0:39f:bfa:7c90 with SMTP id ffacd0b85a97d-3a094038a8fmr11853771f8f.13.1746439747977; Mon, 05 May 2025 03:09:07 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Cc: qemu-rust@nongnu.org Subject: [PATCH 5/5] rust: qdev: const_refs_to_static Date: Mon, 5 May 2025 12:08:54 +0200 Message-ID: <20250505100854.73936-6-pbonzini@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250505100854.73936-1-pbonzini@redhat.com> References: <20250505100854.73936-1-pbonzini@redhat.com> 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=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=pbonzini@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -44 X-Spam_score: -4.5 X-Spam_bar: ---- X-Spam_report: (-4.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.411, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=-1, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: 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 @redhat.com) X-ZM-MESSAGEID: 1746439778572116600 Content-Type: text/plain; charset="utf-8" Now that const_refs_to_static can be assumed, convert the members of the DeviceImpl trait from functions to constants. This lets the compiler know that they have a 'static lifetime, and removes the need for the weird "Box::leak()". Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 8 ++------ rust/hw/timer/hpet/src/hpet.rs | 10 ++-------- rust/qemu-api/src/qdev.rs | 16 +++++----------- rust/qemu-api/tests/tests.rs | 8 ++------ 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/devi= ce.rs index 38373f54e7c..34aa2bbabec 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -169,12 +169,8 @@ impl ObjectImpl for PL011State { } =20 impl DeviceImpl for PL011State { - fn properties() -> &'static [Property] { - &device_class::PL011_PROPERTIES - } - fn vmsd() -> Option> { - Some(device_class::VMSTATE_PL011) - } + const PROPERTIES: &'static [Property] =3D &device_class::PL011_PROPERT= IES; + const VMSTATE: Option> =3D Some(device_class:= :VMSTATE_PL011); const REALIZE: Option =3D Some(Self::realize); } =20 diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index be3b9afa316..48970a6f9c5 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -1009,14 +1009,8 @@ impl ObjectImpl for HPETState { .build(); =20 impl DeviceImpl for HPETState { - fn properties() -> &'static [Property] { - &HPET_PROPERTIES - } - - fn vmsd() -> Option> { - Some(VMSTATE_HPET) - } - + const PROPERTIES: &'static [Property] =3D &HPET_PROPERTIES; + const VMSTATE: Option> =3D Some(VMSTATE_HPET); const REALIZE: Option =3D Some(Self::realize); } =20 diff --git a/rust/qemu-api/src/qdev.rs b/rust/qemu-api/src/qdev.rs index 09555bbd0e7..9b2bfabdad2 100644 --- a/rust/qemu-api/src/qdev.rs +++ b/rust/qemu-api/src/qdev.rs @@ -113,16 +113,12 @@ pub trait DeviceImpl: ObjectImpl + ResettablePhasesIm= pl + IsA { /// An array providing the properties that the user can set on the /// device. Not a `const` because referencing statics in constants /// is unstable until Rust 1.83.0. - fn properties() -> &'static [Property] { - &[] - } + const PROPERTIES: &'static [Property] =3D &[]; =20 /// A `VMStateDescription` providing the migration format for the devi= ce /// Not a `const` because referencing statics in constants is unstable /// until Rust 1.83.0. - fn vmsd() -> Option> { - None - } + const VMSTATE: Option> =3D None; } =20 /// # Safety @@ -168,12 +164,10 @@ pub fn class_init(&mut self) { if ::REALIZE.is_some() { self.realize =3D Some(rust_realize_fn::); } - if let Some(vmsd) =3D ::vmsd() { - // Give a 'static lifetime to the return value of vmsd(). - // Temporary until vmsd() can be changed into a const. - self.vmsd =3D Box::leak(Box::new(vmsd.get())); + if let Some(ref vmsd) =3D ::VMSTATE { + self.vmsd =3D vmsd.as_ref(); } - let prop =3D ::properties(); + let prop =3D ::PROPERTIES; if !prop.is_empty() { unsafe { bindings::device_class_set_props_n(self, prop.as_ptr(), pr= op.len()); diff --git a/rust/qemu-api/tests/tests.rs b/rust/qemu-api/tests/tests.rs index 3264641d128..db0fd3de99b 100644 --- a/rust/qemu-api/tests/tests.rs +++ b/rust/qemu-api/tests/tests.rs @@ -67,12 +67,8 @@ impl ObjectImpl for DummyState { impl ResettablePhasesImpl for DummyState {} =20 impl DeviceImpl for DummyState { - fn properties() -> &'static [Property] { - &DUMMY_PROPERTIES - } - fn vmsd() -> Option> { - Some(VMSTATE) - } + const PROPERTIES: &'static [Property] =3D &DUMMY_PROPERTIES; + const VMSTATE: Option> =3D Some(VMSTATE); } =20 #[repr(C)] --=20 2.49.0