diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index c0c6069247a8..6b19553b6d10 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -46,6 +46,12 @@ dependencies = [
  "either",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
 [[package]]
 name = "pl011"
 version = "0.1.0"
@@ -92,6 +98,7 @@ dependencies = [
 name = "qemu_api"
 version = "0.1.0"
 dependencies = [
+ "once_cell",
  "qemu_api_macros",
  "version_check",
 ]
diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml
index 4aa22f319860..265e00f97176 100644
--- a/rust/qemu-api/Cargo.toml
+++ b/rust/qemu-api/Cargo.toml
@@ -14,6 +14,7 @@ keywords = []
 categories = []
 
 [dependencies]
+once_cell = { version = "1.20.2" }
 qemu_api_macros = { path = "../qemu-api-macros" }
 
 [build-dependencies]
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 00e86a679d8a..508986948883 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -10,6 +10,9 @@ if get_option('debug_mutex')
   _qemu_api_cfg += ['--feature', 'debug_cell']
 endif
 
+subproject('once_cell-1.20-rs', required: true)
+once_cell_dep = dependency('once_cell-1.20-rs')
+
 _qemu_api_rs = static_library(
   'qemu_api',
   structured_sources(
@@ -20,6 +23,7 @@ _qemu_api_rs = static_library(
       'src/cell.rs',
       'src/c_str.rs',
       'src/irq.rs',
+      'src/memattrs.rs',
       'src/module.rs',
       'src/offset_of.rs',
       'src/qdev.rs',
@@ -33,6 +37,7 @@ _qemu_api_rs = static_library(
   override_options: ['rust_std=2021', 'build.rust_std=2021'],
   rust_abi: 'rust',
   rust_args: _qemu_api_cfg,
+  dependencies: once_cell_dep,
 )
 
 rust.test('rust-qemu-api-tests', _qemu_api_rs,
@@ -40,7 +45,7 @@ rust.test('rust-qemu-api-tests', _qemu_api_rs,
 
 qemu_api = declare_dependency(
   link_with: _qemu_api_rs,
-  dependencies: qemu_api_macros,
+  dependencies: [qemu_api_macros, once_cell_dep],
 )
 
 # Rust executables do not support objects, so add an intermediate step.
@@ -56,7 +61,7 @@ test('rust-qemu-api-integration',
         override_options: ['rust_std=2021', 'build.rust_std=2021'],
         rust_args: ['--test'],
         install: false,
-        dependencies: [qemu_api, qemu_api_macros],
+        dependencies: [qemu_api, qemu_api_macros, once_cell_dep],
         link_whole: [rust_qemu_api_objs, libqemuutil]),
     args: [
         '--test',
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index 009906c907e7..e60c9ac16409 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -11,6 +11,7 @@
 pub mod c_str;
 pub mod cell;
 pub mod irq;
+pub mod memattrs;
 pub mod module;
 pub mod offset_of;
 pub mod qdev;
diff --git a/rust/qemu-api/src/memattrs.rs b/rust/qemu-api/src/memattrs.rs
new file mode 100644
index 000000000000..7cc8aea4b7b7
--- /dev/null
+++ b/rust/qemu-api/src/memattrs.rs
@@ -0,0 +1,21 @@
+// Copyright (C) 2024 Intel Corporation.
+// Author(s): Zhao Liu <zhai1.liu@intel.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+use once_cell::sync::Lazy;
+
+use crate::bindings::MemTxAttrs;
+
+impl MemTxAttrs {
+    fn memtxattrs_unspecified() -> Self {
+        let mut attrs = MemTxAttrs::default();
+        attrs.set_unspecified(1);
+        attrs
+    }
+}
+
+/// Bus masters which don't specify any attributes will get this,
+/// which has all attribute bits clear except the topmost one
+/// (so that we can distinguish "all attributes deliberately clear"
+/// from "didn't specify" if necessary).
+pub static MEMTXATTRS_UNSPECIFIED: Lazy<MemTxAttrs> = Lazy::new(MemTxAttrs::memtxattrs_unspecified);
diff --git a/rust/wrapper.h b/rust/wrapper.h
index 285d0eb6ad01..033f3e9cf32c 100644
--- a/rust/wrapper.h
+++ b/rust/wrapper.h
@@ -62,3 +62,4 @@ typedef enum memory_order {
 #include "qapi/error.h"
 #include "migration/vmstate.h"
 #include "chardev/char-serial.h"
+#include "exec/memattrs.h"
diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh
index 30677c3ec903..59e72d92498a 100755
--- a/scripts/archive-source.sh
+++ b/scripts/archive-source.sh
@@ -30,7 +30,7 @@ subprojects="keycodemapdb libvfio-user berkeley-softfloat-3
   berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
   bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
   proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
-  syn-2-rs unicode-ident-1-rs"
+  syn-2-rs unicode-ident-1-rs once_cell-1.20-rs"
 sub_deinit=""
 
 function cleanup() {
diff --git a/scripts/make-release b/scripts/make-release
index 8dc939124c4f..b6b48bdf6f08 100755
--- a/scripts/make-release
+++ b/scripts/make-release
@@ -21,7 +21,7 @@ SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3
   berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
   bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
   proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
-  syn-2-rs unicode-ident-1-rs"
+  syn-2-rs unicode-ident-1-rs once_cell-1.20-rs"
 
 src="$1"
 version="$2"
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index 50f173f90dbe..dba8ea74b823 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -11,6 +11,7 @@
 /bilge-impl-0.2.0
 /either-1.12.0
 /itertools-0.11.0
+/once_cell-1.20.2
 /proc-macro-error-1.0.4
 /proc-macro-error-attr-1.0.4
 /proc-macro2-1.0.84
diff --git a/subprojects/once_cell-1.20-rs.wrap b/subprojects/once_cell-1.20-rs.wrap
new file mode 100644
index 000000000000..b13ba81a22b1
--- /dev/null
+++ b/subprojects/once_cell-1.20-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = once_cell-1.20.2
+source_url = https://crates.io/api/v1/crates/once_cell/1.20.2/download
+source_filename = once_cell-1.20.2.tar.gz
+source_hash = 1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775
+#method = cargo
+patch_directory = once_cell-1.20-rs
diff --git a/subprojects/packagefiles/once_cell-1.20-rs/meson.build b/subprojects/packagefiles/once_cell-1.20-rs/meson.build
new file mode 100644
index 000000000000..0b81f8e76250
--- /dev/null
+++ b/subprojects/packagefiles/once_cell-1.20-rs/meson.build
@@ -0,0 +1,23 @@
+project('once_cell-1.20-rs', 'rust',
+  version: '1.20.2',
+  license: 'MIT OR Apache-2.0',
+  default_options: [])
+
+_once_cell_rs = static_library(
+  'once_cell',
+  files('src/lib.rs'),
+  gnu_symbol_visibility: 'hidden',
+  override_options: ['rust_std=2021', 'build.rust_std=2021'],
+  rust_abi: 'rust',
+  rust_args: [
+    '--cfg', 'feature="std"'
+  ],
+  dependencies: [],
+  native: true,
+)
+
+once_cell_dep = declare_dependency(
+  link_with: _once_cell_rs,
+)
+
+meson.override_dependency('once_cell-1.20-rs', once_cell_dep, native: true)
