rust: move binding generation to bindings/

Move raw FFI bindings generation to separate crates.  This makes it
possible to reuse bindgen declarations for a header file in its
dependencies (this was not the case before this change), while keeping
multiple -sys crates to avoid rebuilding all the code whenever
something changes.

Because the -sys crates are generated in dependency order, this also
enforces that the crates are organized in something that resembles
the dependencies between C headers.

The meson.build for rust-safe crates becomes simpler, and it should be
possible in the future to let Meson's cargo support handle most of it.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
[General cleanup and Python script. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Marc-André Lureau
2025-12-03 16:46:16 +01:00
committed by Paolo Bonzini
parent f9bbbde1ed
commit c899071b5a
80 changed files with 918 additions and 719 deletions

View File

@@ -339,6 +339,63 @@ Here are some things to keep in mind when working on the QEMU Rust crate.
or a macro) where it can be documented and tested. If needed, include
toy versions of the code in the documentation.
FFI Binding Generation
''''''''''''''''''''''
QEMU's Rust integration uses multiple ``*-sys`` crates that contain raw FFI
bindings to different QEMU subsystems. These crates mirror the dependency
structure that meson.build uses for C code, and which is reflected in
``static_library()`` declarations. For example:
* util-sys: Basic utilities (no dependencies)
* qom-sys: QEMU Object Model (depends on util-sys)
* chardev-sys: Character devices (depends on qom-sys, util-sys)
* hwcore-sys: Hardware core (depends on qom-sys, util-sys)
* migration-sys: Migration (depends on util-sys)
* system-sys: System-level APIs (depends on all others)
Having multiple crates avoids massive rebuilds of all Rust code when C headers
are changed. On the other hand, bindgen is not aware of how headers are split
across crates, and therefore it would generate declarations for dependencies
again. These duplicate declarations are not only large, they create distinct
types and therefore they are incompatible with each other.
Bindgen Configuration
~~~~~~~~~~~~~~~~~~~~~
Bindgen options such as symbol blocklists or how to configure enums can be
defined in each crate's ``Cargo.toml`` via a ``[package.metadata.bindgen]`` section.
For example::
[package.metadata.bindgen]
header = "wrapper.h" # Main header file for this crate
rustified-enum = ["QEMUClockType"] # Enums to generate as Rust enums
bitfield-enum = ["VMStateFlags"] # Enums to treat as bitfields
blocklist-function = [ # Functions to exclude
"vmstate_register_ram",
"vmstate_unregister_ram"
]
additional-files = [ # Extra files to allowlist
"include/system/memory_ldst.*"
]
All bindgen options are supported in the metadata section. The complete list
can be found in ``rust/bindings/generate_bindgen_args.py``.
Dependency Management
~~~~~~~~~~~~~~~~~~~~~
By examining the dependency chain before bindgen creates the code for
the ``*-sys`` crates, the build system ensures that header files included in
one crate are blocked from appearing in dependent crates, thus avoiding
duplicate definitions. Dependent crates can import the definition via
"use" statements.
This dependency-aware binding generation is handled automatically by
``rust/bindings/generate_bindgen_args.py``, which processes the Cargo.toml
files in dependency order and generates appropriate ``--allowlist-file`` and
``--blocklist-file`` arguments for bindgen.
Writing procedural macros
'''''''''''''''''''''''''

View File

@@ -4169,9 +4169,8 @@ if have_rust
'--with-derive-default',
'--no-layout-tests',
'--no-prepend-enum-name',
'--allowlist-file', meson.project_source_root() + '/include/.*',
'--allowlist-file', meson.project_build_root() + '/.*',
'--blocklist-file', glib_pc.get_variable('includedir') + '/glib-2.0/.*',
'--blocklist-file', meson.project_source_root() + '/include/qemu/typedefs.h',
'--blocklist-type', '.*_([a-z]*autoptr)$',
]
if not rustfmt.found()

68
rust/Cargo.lock generated
View File

@@ -59,6 +59,7 @@ name = "bql"
version = "0.1.0"
dependencies = [
"glib-sys",
"util-sys",
]
[[package]]
@@ -76,6 +77,7 @@ name = "chardev"
version = "0.1.0"
dependencies = [
"bql",
"chardev-sys",
"common",
"glib-sys",
"migration",
@@ -83,6 +85,16 @@ dependencies = [
"util",
]
[[package]]
name = "chardev-sys"
version = "0.1.0"
dependencies = [
"common",
"glib-sys",
"qom-sys",
"util-sys",
]
[[package]]
name = "common"
version = "0.1.0"
@@ -156,6 +168,7 @@ dependencies = [
"chardev",
"common",
"glib-sys",
"hwcore-sys",
"migration",
"qemu_macros",
"qom",
@@ -163,6 +176,19 @@ dependencies = [
"util",
]
[[package]]
name = "hwcore-sys"
version = "0.1.0"
dependencies = [
"chardev-sys",
"common",
"glib-sys",
"migration-sys",
"qom-sys",
"system-sys",
"util-sys",
]
[[package]]
name = "indexmap"
version = "2.11.4"
@@ -201,10 +227,20 @@ dependencies = [
"bql",
"common",
"glib-sys",
"migration-sys",
"qemu_macros",
"util",
]
[[package]]
name = "migration-sys"
version = "0.1.0"
dependencies = [
"common",
"glib-sys",
"util-sys",
]
[[package]]
name = "pkg-config"
version = "0.3.32"
@@ -287,9 +323,18 @@ dependencies = [
"glib-sys",
"migration",
"qemu_macros",
"qom-sys",
"util",
]
[[package]]
name = "qom-sys"
version = "0.1.0"
dependencies = [
"glib-sys",
"util-sys",
]
[[package]]
name = "quote"
version = "1.0.36"
@@ -306,6 +351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
@@ -358,9 +404,12 @@ dependencies = [
name = "system"
version = "0.1.0"
dependencies = [
"bql",
"common",
"glib-sys",
"migration",
"qom",
"system-sys",
"util",
]
@@ -377,6 +426,17 @@ dependencies = [
"version-compare",
]
[[package]]
name = "system-sys"
version = "0.1.0"
dependencies = [
"common",
"glib-sys",
"migration-sys",
"qom-sys",
"util-sys",
]
[[package]]
name = "target-lexicon"
version = "0.13.2"
@@ -454,6 +514,14 @@ dependencies = [
"foreign",
"glib-sys",
"libc",
"util-sys",
]
[[package]]
name = "util-sys"
version = "0.1.0"
dependencies = [
"glib-sys",
]
[[package]]

View File

@@ -10,25 +10,25 @@ use std::{env, fs::remove_file, io::Result, path::Path};
fn main() -> Result<()> {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let file = if let Ok(root) = env::var("MESON_BUILD_ROOT") {
let sub = get_rust_subdir(manifest_dir).unwrap();
format!("{root}/{sub}/bindings.inc.rs")
} else {
// Placing bindings.inc.rs in the source directory is supported
// but not documented or encouraged.
format!("{manifest_dir}/src/bindings.inc.rs")
};
let root = env::var("MESON_BUILD_ROOT").expect(concat!(
"\n",
" MESON_BUILD_ROOT not found. Maybe you wanted one of\n",
" `make clippy`, `make rustfmt`, `make rustdoc`?\n",
"\n",
" For other uses of `cargo`, start a subshell with\n",
" `pyvenv/bin/meson devenv`, or point MESON_BUILD_ROOT to\n",
" the top of the build tree."
));
let sub = get_rust_subdir(manifest_dir).unwrap();
let file = format!("{root}/{sub}/bindings.inc.rs");
let file = Path::new(&file);
if !Path::new(&file).exists() {
if !file.exists() {
panic!(concat!(
"\n",
" No generated C bindings found! Maybe you wanted one of\n",
" `make clippy`, `make rustfmt`, `make rustdoc`?\n",
"\n",
" For other uses of `cargo`, start a subshell with\n",
" `pyvenv/bin/meson devenv`, or point MESON_BUILD_ROOT to\n",
" the top of the build tree."
" No generated C bindings found! Run `make` first; or maybe you\n",
" wanted one of `make clippy`, `make rustfmt`, `make rustdoc`?\n",
));
}

View File

@@ -0,0 +1,28 @@
[package]
name = "chardev-sys"
version = "0.1.0"
description = "Rust sys bindings for QEMU/chardev"
publish = false
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[lib]
path = "lib.rs"
[dependencies]
glib-sys = { workspace = true }
common = { path = "../../common" }
qom-sys = { path = "../qom-sys" }
util-sys = { path = "../util-sys" }
[lints]
workspace = true
[package.metadata.bindgen]
header = "wrapper.h"
rustified-enum = ["QEMUChrEvent"]

View File

@@ -0,0 +1 @@
../build.rs

View File

@@ -19,10 +19,9 @@
)]
use common::Zeroable;
use glib_sys::{
gboolean, guint, GArray, GHashTable, GHashTableIter, GIOCondition, GMainContext, GPollFD,
GPtrArray, GSList, GSource, GSourceFunc,
};
use glib_sys::{gboolean, guint, GIOCondition, GMainContext, GSource, GSourceFunc};
use qom_sys::{Object, ObjectClass};
use util_sys::{Error, IOCanReadHandler, IOReadHandler, QemuOpts};
#[cfg(MESON)]
include!("bindings.inc.rs");

View File

@@ -0,0 +1,12 @@
_bindgen_chardev_rs = rust.bindgen(
args: bindgen_args_common + bindgen_args_data['chardev-sys'].split(),
kwargs: bindgen_kwargs)
_chardev_sys_rs = static_library(
'chardev_sys',
structured_sources(['lib.rs', _bindgen_chardev_rs]),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
dependencies: [glib_sys_rs, common_rs, qom_sys_rs, util_sys_rs],
)
chardev_sys_rs = declare_dependency(link_with: [_chardev_sys_rs])

View File

@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#include "qemu/osdep.h"
#include "chardev/char.h"
#include "chardev/char-fe.h"
#include "chardev/char-serial.h"

View File

@@ -0,0 +1,164 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later
"""
Generate bindgen arguments from Cargo.toml metadata for QEMU's Rust FFI bindings.
Author: Paolo Bonzini <pbonzini@redhat.com>
Copyright (C) 2025 Red Hat, Inc.
This script processes Cargo.toml file for QEMU's bindings crates (util-sys,
chardev-sys, qom-sys, etc.); it generates bindgen command lines that allow
easy customization and that export the right headers in each bindings crate.
For detailed information, see docs/devel/rust.rst.
"""
import os
import re
import sys
import argparse
from pathlib import Path
from dataclasses import dataclass
from typing import Iterable, List, Dict, Any
try:
import tomllib
except ImportError:
import tomli as tomllib # type: ignore
INCLUDE_RE = re.compile(r'^#include\s+"([^"]+)"')
OPTIONS = [
"bitfield-enum",
"newtype-enum",
"newtype-global-enum",
"rustified-enum",
"rustified-non-exhaustive-enum",
"constified-enum",
"constified-enum-module",
"normal-alias",
"new-type-alias",
"new-type-alias-deref",
"bindgen-wrapper-union",
"manually-drop-union",
"blocklist-type",
"blocklist-function",
"blocklist-item",
"blocklist-file",
"blocklist-var",
"opaque-type",
"no-partialeq",
"no-copy",
"no-debug",
"no-default",
"no-hash",
"must-use-type",
"with-derive-custom",
"with-derive-custom-struct",
"with-derive-custom-enum",
"with-derive-custom-union",
"with-attribute-custom",
"with-attribute-custom-struct",
"with-attribute-custom-enum",
"with-attribute-custom-union",
]
@dataclass
class BindgenInfo:
cmd_args: List[str]
inputs: List[str]
def extract_includes(lines: Iterable[str]) -> List[str]:
"""Extract #include directives from a file."""
includes: List[str] = []
for line in lines:
match = INCLUDE_RE.match(line.strip())
if match:
includes.append(match.group(1))
return includes
def build_bindgen_args(metadata: Dict[str, Any]) -> List[str]:
"""Build command line arguments from [package.metadata.bindgen]."""
args: List[str] = []
for key, values in metadata.items():
if key in OPTIONS:
flag = f"--{key}"
assert isinstance(values, list)
for value in values:
args.append(flag)
args.append(value)
return args
def main() -> int:
parser = argparse.ArgumentParser(
description="Generate bindgen arguments from Cargo.toml metadata"
)
parser.add_argument(
"directories", nargs="+", help="Directories containing Cargo.toml files"
)
parser.add_argument(
"-I",
"--include-root",
default=None,
help="Base path for --allowlist-file/--blocklist-file",
)
parser.add_argument("--source-dir", default=os.getcwd(), help="Source directory")
parser.add_argument("-o", "--output", required=True, help="Output file")
parser.add_argument("--dep-file", help="Dependency file to write")
args = parser.parse_args()
prev_allowlist_files: Dict[str, object] = {}
bindgen_infos: Dict[str, BindgenInfo] = {}
os.chdir(args.source_dir)
include_root = args.include_root or args.source_dir
for directory in args.directories:
cargo_path = Path(directory) / "Cargo.toml"
inputs = [str(Path(args.source_dir) / cargo_path)]
with open(cargo_path, "rb") as f:
cargo_toml = tomllib.load(f)
metadata = cargo_toml.get("package", {}).get("metadata", {}).get("bindgen", {})
input_file = Path(directory) / metadata["header"]
inputs.append(str(Path(args.source_dir) / input_file))
cmd_args = build_bindgen_args(metadata)
# Each include file is allowed for this file and blocked in the
# next ones
for blocklist_path in prev_allowlist_files:
cmd_args.extend(["--blocklist-file", blocklist_path])
with open(input_file, "r", encoding="utf-8", errors="ignore") as f:
includes = extract_includes(f)
for allowlist_file in includes + metadata.get("additional-files", []):
allowlist_path = Path(include_root) / allowlist_file
cmd_args.extend(["--allowlist-file", str(allowlist_path)])
prev_allowlist_files.setdefault(str(allowlist_path), True)
bindgen_infos[directory] = BindgenInfo(cmd_args=cmd_args, inputs=inputs)
# now write the output
with open(args.output, "w") as f:
for directory, info in bindgen_infos.items():
args_sh = " ".join(info.cmd_args)
f.write(f"{directory}={args_sh}\n")
if args.dep_file:
with open(args.dep_file, "w") as f:
deps: List[str] = []
for info in bindgen_infos.values():
deps += info.inputs
f.write(f"{os.path.basename(args.output)}: {' '.join(deps)}\n")
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,32 @@
[package]
name = "hwcore-sys"
version = "0.1.0"
description = "Rust sys bindings for QEMU/hwcore"
publish = false
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[lib]
path = "lib.rs"
[dependencies]
glib-sys = { workspace = true }
common = { path = "../../common" }
chardev-sys = { path = "../chardev-sys" }
qom-sys = { path = "../qom-sys" }
migration-sys = { path = "../migration-sys" }
util-sys = { path = "../util-sys" }
system-sys = { path = "../system-sys" }
[lints]
workspace = true
[package.metadata.bindgen]
header = "wrapper.h"
rustified-enum = ["DeviceCategory", "GpioPolarity", "MachineInitPhase", "ResetType"]
bitfield-enum = ["ClockEvent"]

View File

@@ -0,0 +1 @@
../build.rs

View File

@@ -18,13 +18,15 @@
clippy::too_many_arguments
)]
use chardev::bindings::Chardev;
use chardev_sys::Chardev;
use common::Zeroable;
use glib_sys::{GHashTable, GHashTableIter, GList, GPtrArray, GSList};
use migration::bindings::VMStateDescription;
use qom::bindings::ObjectClass;
use system::bindings::MemoryRegion;
use util::bindings::Error;
use glib_sys::GSList;
use migration_sys::VMStateDescription;
use qom_sys::{
InterfaceClass, Object, ObjectClass, ObjectProperty, ObjectPropertyAccessor,
ObjectPropertyRelease,
};
use util_sys::{Error, QDict, QList};
#[cfg(MESON)]
include!("bindings.inc.rs");
@@ -35,8 +37,5 @@ include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs"));
unsafe impl Send for Property {}
unsafe impl Sync for Property {}
unsafe impl Send for TypeInfo {}
unsafe impl Sync for TypeInfo {}
unsafe impl Zeroable for Property__bindgen_ty_1 {}
unsafe impl Zeroable for Property {}

View File

@@ -0,0 +1,12 @@
_bindgen_hwcore_rs = rust.bindgen(
args: bindgen_args_common + bindgen_args_data['hwcore-sys'].split(),
kwargs: bindgen_kwargs)
_hwcore_sys_rs = static_library(
'hwcore_sys',
structured_sources(['lib.rs', _bindgen_hwcore_rs]),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
dependencies: [common_rs, glib_sys_rs, qom_sys_rs, util_sys_rs, migration_sys_rs, chardev_sys_rs],
)
hwcore_sys_rs = declare_dependency(link_with: [_hwcore_sys_rs])

View File

@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
/*
* We block include/qemu/typedefs.h from bindgen, add here symbols
* that are needed as opaque types by other functions.
*/
typedef struct Clock Clock;
typedef struct DeviceState DeviceState;
typedef struct IRQState *qemu_irq;
typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
/* Once bindings exist, these could move to a different *-sys crate. */
typedef struct BlockBackend BlockBackend;
typedef struct Monitor Monitor;
typedef struct NetClientState NetClientState;
#include "qemu/osdep.h"
#include "hw/core/clock.h"
#include "hw/core/irq.h"
#include "hw/core/qdev-clock.h"
#include "hw/core/qdev.h"
#include "hw/core/qdev-properties-system.h"
#include "hw/core/qdev-properties.h"
#include "hw/core/resettable.h"

37
rust/bindings/meson.build Normal file
View File

@@ -0,0 +1,37 @@
# Generate bindgen arguments from Cargo.toml metadata
# Sort these in dependency order, same as the subdir()
# invocations below.
bindgen_dirs = [
'util-sys',
'migration-sys',
'qom-sys',
'chardev-sys',
'hwcore-sys',
'system-sys',
]
bindgen_args_file = configure_file(
command: [files('generate_bindgen_args.py'),
'-I', meson.project_source_root() / 'include',
'--source-dir', meson.current_source_dir(),
'-o', '@OUTPUT@', '--dep-file', '@DEPFILE@'] + bindgen_dirs,
output: 'bindgen_args.mak',
depfile: 'bindgen_args.d'
)
# now generate all bindgen files
bindgen_args_data = keyval.load(bindgen_args_file)
bindgen_kwargs = {
'input': 'wrapper.h',
'dependencies': common_ss.all_dependencies(),
'output': 'bindings.inc.rs',
'include_directories': bindings_incdir,
'bindgen_version': ['>=0.60.0'],
'c_args': bindgen_c_args,
}
subdir('util-sys')
subdir('migration-sys')
subdir('qom-sys')
subdir('chardev-sys')
subdir('hwcore-sys')
subdir('system-sys')

View File

@@ -0,0 +1,28 @@
[package]
name = "migration-sys"
version = "0.1.0"
description = "Rust sys bindings for QEMU/migration"
publish = false
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[lib]
path = "lib.rs"
[dependencies]
glib-sys = { workspace = true }
common = { path = "../../common" }
util-sys = { path = "../util-sys" }
[lints]
workspace = true
[package.metadata.bindgen]
header = "wrapper.h"
bitfield-enum = ["MigrationPolicy", "MigrationPriority", "VMStateFlags"]
blocklist-function = ["vmstate_register_ram", "vmstate_register_ram_global", "vmstate_unregister_ram"]

View File

@@ -0,0 +1 @@
../build.rs

View File

@@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#![allow(
dead_code,
improper_ctypes_definitions,
improper_ctypes,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unnecessary_transmutes,
unsafe_op_in_unsafe_fn,
clippy::pedantic,
clippy::restriction,
clippy::style,
clippy::missing_const_for_fn,
clippy::ptr_offset_with_cast,
clippy::useless_transmute,
clippy::missing_safety_doc,
clippy::too_many_arguments
)]
use common::Zeroable;
use util_sys::{Error, JSONWriter, QEMUFile};
#[cfg(MESON)]
include!("bindings.inc.rs");
#[cfg(not(MESON))]
include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs"));
unsafe impl Send for VMStateDescription {}
unsafe impl Sync for VMStateDescription {}
unsafe impl Send for VMStateField {}
unsafe impl Sync for VMStateField {}
unsafe impl Send for VMStateInfo {}
unsafe impl Sync for VMStateInfo {}
// bindgen does not derive Default here
#[allow(clippy::derivable_impls)]
impl Default for VMStateFlags {
fn default() -> Self {
Self(0)
}
}
unsafe impl Zeroable for VMStateFlags {}
unsafe impl Zeroable for VMStateField {}
unsafe impl Zeroable for VMStateDescription {}
// The following higher-level helpers could be in "migration"
// crate when Rust has const trait impl.
pub trait VMStateFlagsExt {
const VMS_VARRAY_FLAGS: VMStateFlags;
}
impl VMStateFlagsExt for VMStateFlags {
const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
VMStateFlags::VMS_VARRAY_INT32.0
| VMStateFlags::VMS_VARRAY_UINT8.0
| VMStateFlags::VMS_VARRAY_UINT16.0
| VMStateFlags::VMS_VARRAY_UINT32.0,
);
}
// Add a couple builder-style methods to VMStateField, allowing
// easy derivation of VMStateField constants from other types.
impl VMStateField {
#[must_use]
pub const fn with_version_id(mut self, version_id: i32) -> Self {
assert!(version_id >= 0);
self.version_id = version_id;
self
}
#[must_use]
pub const fn with_array_flag(mut self, num: usize) -> Self {
assert!(num <= 0x7FFF_FFFFusize);
assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
// VMS_ARRAY_OF_POINTER flag stores the size of pointer.
// FIXME: *const, *mut, NonNull and Box<> have the same size as usize.
// Resize if more smart pointers are supported.
self.size = std::mem::size_of::<usize>();
}
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
self.num = num as i32;
self
}
#[must_use]
pub const fn with_pointer_flag(mut self) -> Self {
assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
self
}
#[must_use]
pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> Self {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
self.flags = VMStateFlags(self.flags.0 | flag.0);
self.num = 0; // varray uses num_offset instead of num.
self
}
#[must_use]
#[allow(unused_mut)]
pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> Self {
assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
self.with_varray_flag_unchecked(flag)
}
#[must_use]
pub const fn with_varray_multiply(mut self, num: u32) -> Self {
assert!(num <= 0x7FFF_FFFFu32);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
self.num = num as i32;
self
}
}

View File

@@ -0,0 +1,12 @@
_bindgen_migration_rs = rust.bindgen(
args: bindgen_args_common + bindgen_args_data['migration-sys'].split(),
kwargs: bindgen_kwargs)
_migration_sys_rs = static_library(
'migration_sys',
structured_sources(['lib.rs', _bindgen_migration_rs]),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
dependencies: [glib_sys_rs, common_rs, util_sys_rs],
)
migration_sys_rs = declare_dependency(link_with: [_migration_sys_rs])

View File

@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#include "qemu/osdep.h"
#include "migration/vmstate.h"

View File

@@ -0,0 +1,25 @@
[package]
name = "qom-sys"
version = "0.1.0"
description = "Rust sys bindings for QEMU/qom"
publish = false
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[lib]
path = "lib.rs"
[dependencies]
glib-sys = { workspace = true }
util-sys = { path = "../util-sys" }
[lints]
workspace = true
[package.metadata.bindgen]
header = "wrapper.h"

View File

@@ -0,0 +1 @@
../build.rs

View File

@@ -19,9 +19,13 @@
)]
use glib_sys::{GHashTable, GHashTableIter, GPtrArray, GSList};
use util_sys::{Error, QDict, QObject, Visitor};
#[cfg(MESON)]
include!("bindings.inc.rs");
#[cfg(not(MESON))]
include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs"));
unsafe impl Send for TypeInfo {}
unsafe impl Sync for TypeInfo {}

View File

@@ -0,0 +1,12 @@
_bindgen_qom_rs = rust.bindgen(
args: bindgen_args_common + bindgen_args_data['qom-sys'].split(),
kwargs: bindgen_kwargs)
_qom_sys_rs = static_library(
'qom_sys',
structured_sources(['lib.rs', _bindgen_qom_rs]),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
dependencies: [glib_sys_rs, util_sys_rs],
)
qom_sys_rs = declare_dependency(link_with: [_qom_sys_rs])

View File

@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
/*
* We block include/qemu/typedefs.h from bindgen, add here symbols
* that are needed as opaque types by other functions.
*/
typedef struct Object Object;
typedef struct ObjectClass ObjectClass;
#include "qemu/osdep.h"
#include "qom/object.h"

View File

@@ -0,0 +1,30 @@
[package]
name = "system-sys"
version = "0.1.0"
description = "Rust sys bindings for QEMU/system"
publish = false
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[lib]
path = "lib.rs"
[dependencies]
glib-sys = { workspace = true }
common = { path = "../../common" }
migration-sys = { path = "../migration-sys" }
util-sys = { path = "../util-sys" }
qom-sys = { path = "../qom-sys" }
[lints]
workspace = true
[package.metadata.bindgen]
header = "wrapper.h"
rustified-enum = ["device_endian"]
additional-files = ["system/memory.*"]

View File

@@ -0,0 +1 @@
../build.rs

View File

@@ -19,7 +19,9 @@
)]
use common::Zeroable;
use glib_sys::{guint, GHashTable, GHashTableIter, GList, GPollFD, GPtrArray, GSList};
use hwcore_sys::{qemu_irq, DeviceClass, DeviceState};
use qom_sys::{InterfaceClass, Object, ObjectClass};
use util_sys::{Error, EventNotifier, QEMUBH};
#[cfg(MESON)]
include!("bindings.inc.rs");

View File

@@ -0,0 +1,12 @@
_bindgen_system_rs = rust.bindgen(
args: bindgen_args_common + bindgen_args_data['system-sys'].split(),
kwargs: bindgen_kwargs)
_system_sys_rs = static_library(
'system_sys',
structured_sources(['lib.rs', _bindgen_system_rs]),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
dependencies: [common_rs, glib_sys_rs, hwcore_sys_rs, migration_sys_rs, qom_sys_rs, util_sys_rs],
)
system_sys_rs = declare_dependency(link_with: [_system_sys_rs])

View File

@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
/*
* We block include/qemu/typedefs.h from bindgen, add here symbols
* that are needed as opaque types by other functions.
*/
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
typedef struct MemoryRegion MemoryRegion;
typedef struct RAMBlock RAMBlock;
#include "qemu/osdep.h"
#include "exec/hwaddr.h"
#include "system/address-spaces.h"
#include "system/memory.h"
#include "hw/core/sysbus.h"

View File

@@ -0,0 +1,25 @@
[package]
name = "util-sys"
version = "0.1.0"
description = "Rust sys bindings for QEMU/util"
publish = false
authors.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[lib]
path = "lib.rs"
[dependencies]
glib-sys = { workspace = true }
[lints]
workspace = true
[package.metadata.bindgen]
header = "wrapper.h"
rustified-enum = ["module_init_type", "QEMUClockType"]

View File

@@ -0,0 +1 @@
../build.rs

View File

@@ -18,7 +18,7 @@
clippy::too_many_arguments
)]
use glib_sys::{guint, GPollFD, GString};
use glib_sys::{guint, GArray, GHashTable, GPollFD, GSList, GSource, GString};
#[cfg(MESON)]
include!("bindings.inc.rs");

View File

@@ -0,0 +1,12 @@
_bindgen_util_rs = rust.bindgen(
args: bindgen_args_common + bindgen_args_data['util-sys'].split(),
kwargs: bindgen_kwargs)
_util_sys_rs = static_library(
'util_sys',
structured_sources(['lib.rs', _bindgen_util_rs]),
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
dependencies: [glib_sys_rs],
)
util_sys_rs = declare_dependency(link_with: [_util_sys_rs])

View File

@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
/*
* We block include/qemu/typedefs.h from bindgen, add here symbols
* that are needed as opaque types by other functions.
*/
typedef struct QEMUBH QEMUBH;
typedef struct QEMUFile QEMUFile;
typedef struct QemuOpts QemuOpts;
typedef struct JSONWriter JSONWriter;
typedef struct Visitor Visitor;
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/error-internal.h"
#include "qemu/event_notifier.h"
#include "qemu/main-loop.h"
#include "qemu/aio.h"
#include "qemu/log-for-trace.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/option.h"
#include "qemu/timer.h"
#include "qapi/visitor.h"
#include "qobject/qbool.h"
#include "qobject/qdict.h"
#include "qobject/qjson.h"
#include "qobject/qlist.h"
#include "qobject/qnull.h"
#include "qobject/qnum.h"
#include "qobject/qobject.h"
#include "qobject/qstring.h"
#include "qobject/json-writer.h"

View File

@@ -14,6 +14,7 @@ rust-version.workspace = true
[dependencies]
glib-sys.workspace = true
util-sys = { path = "../bindings/util-sys" }
[features]
default = ["debug_cell"]

View File

@@ -1 +0,0 @@
../util/build.rs

View File

@@ -6,37 +6,11 @@ if get_option('debug_mutex')
_bql_cfg += ['--cfg', 'feature="debug_cell"']
endif
#
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_bql_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common,
c_args: bindgen_c_args,
)
_bql_rs = static_library(
'bql',
structured_sources(
[
'src/lib.rs',
'src/bindings.rs',
'src/cell.rs',
'src/prelude.rs',
],
{'.': _bql_bindings_inc_rs}
),
'src/lib.rs',
rust_args: _bql_cfg,
dependencies: [glib_sys_rs],
dependencies: [glib_sys_rs, util_sys_rs],
)
bql_rs = declare_dependency(link_with: [_bql_rs],

View File

@@ -1,27 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#![allow(
dead_code,
improper_ctypes_definitions,
improper_ctypes,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unnecessary_transmutes,
unsafe_op_in_unsafe_fn,
clippy::pedantic,
clippy::restriction,
clippy::style,
clippy::missing_const_for_fn,
clippy::ptr_offset_with_cast,
clippy::useless_transmute,
clippy::missing_safety_doc,
clippy::too_many_arguments
)]
use glib_sys::{guint, GArray, GHashTable, GHashTableIter, GPollFD, GPtrArray, GSList, GSource};
#[cfg(MESON)]
include!("bindings.inc.rs");
#[cfg(not(MESON))]
include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs"));

View File

@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
mod bindings;
use bindings::{bql_block_unlock, bql_locked, rust_bql_mock_lock};
use util_sys::{bql_block_unlock, bql_locked, rust_bql_mock_lock};
mod cell;
pub use cell::*;

View File

@@ -1,27 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#ifndef __CLANG_STDATOMIC_H
#define __CLANG_STDATOMIC_H
/*
* Fix potential missing stdatomic.h error in case bindgen does not insert the
* correct libclang header paths on its own. We do not use stdatomic.h symbols
* in QEMU code, so it's fine to declare dummy types instead.
*/
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#endif /* __CLANG_STDATOMIC_H */
#include "qemu/osdep.h"
#include "qemu/main-loop.h"

View File

@@ -14,6 +14,7 @@ rust-version.workspace = true
[dependencies]
glib-sys = { workspace = true }
chardev-sys = { path = "../bindings/chardev-sys" }
common = { path = "../common" }
bql = { path = "../bql" }
migration = { path = "../migration" }

View File

@@ -1 +0,0 @@
../util/build.rs

View File

@@ -1,41 +1,8 @@
c_enums = [
'QEMUChrEvent',
]
_chardev_bindgen_args = []
foreach enum : c_enums
_chardev_bindgen_args += ['--rustified-enum', enum]
endforeach
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_chardev_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common + _chardev_bindgen_args,
c_args: bindgen_c_args,
)
_chardev_rs = static_library(
'chardev',
structured_sources(
[
'src/lib.rs',
'src/bindings.rs',
'src/chardev.rs',
'src/prelude.rs',
],
{'.': _chardev_bindings_inc_rs}
),
'src/lib.rs',
link_with: [_bql_rs, _migration_rs, _qom_rs, _util_rs],
dependencies: [glib_sys_rs, common_rs, qemu_macros],
dependencies: [glib_sys_rs, common_rs, qemu_macros, chardev_sys_rs],
)
chardev_rs = declare_dependency(link_with: [_chardev_rs], dependencies: [chardev, qemuutil])

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pub mod bindings;
pub use chardev_sys as bindings;
mod chardev;
pub use chardev::*;

View File

@@ -1,28 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#ifndef __CLANG_STDATOMIC_H
#define __CLANG_STDATOMIC_H
/*
* Fix potential missing stdatomic.h error in case bindgen does not insert the
* correct libclang header paths on its own. We do not use stdatomic.h symbols
* in QEMU code, so it's fine to declare dummy types instead.
*/
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#endif /* __CLANG_STDATOMIC_H */
#include "qemu/osdep.h"
#include "chardev/char-fe.h"
#include "chardev/char-serial.h"

View File

@@ -1 +1 @@
../../../util/build.rs
../../../bindings/build.rs

View File

@@ -1,18 +1,11 @@
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_libpl011_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common,
c_args: bindgen_c_args,
args: bindgen_args_common + [
'--allowlist-file', meson.project_source_root() / 'include/hw/char/pl011.h',
'--blocklist-file',
meson.project_source_root() /
'include/(block\|chardev/|exec/|hw/core/|qemu/|qom/|system/).*',
],
kwargs: bindgen_kwargs,
)
_libpl011_rs = static_library(

View File

@@ -20,10 +20,9 @@
//! `bindgen`-generated declarations.
use glib_sys::{
gboolean, guint, GArray, GHashTable, GHashTableIter, GIOCondition, GList, GMainContext,
GPollFD, GPtrArray, GSList, GSource, GSourceFunc,
};
use chardev::bindings::{CharFrontend, Chardev};
use hwcore::bindings::{qemu_irq, Clock, DeviceState};
use system::bindings::{hwaddr, MemoryRegion, SysBusDevice};
#[cfg(MESON)]
include!("bindings.inc.rs");

View File

@@ -14,6 +14,7 @@ rust-version.workspace = true
[dependencies]
glib-sys.workspace = true
hwcore-sys = { path = "../../bindings/hwcore-sys" }
qemu_macros = { path = "../../qemu-macros" }
common = { path = "../../common" }
bql = { path = "../../bql" }

View File

@@ -1 +0,0 @@
../../util/build.rs

View File

@@ -1,66 +1,10 @@
_hwcore_bindgen_args = []
c_enums = [
'DeviceCategory',
'GpioPolarity',
'MachineInitPhase',
'ResetType',
]
foreach enum : c_enums
_hwcore_bindgen_args += ['--rustified-enum', enum]
endforeach
blocked_type = [
'Chardev',
'Error',
'ObjectClass',
'MemoryRegion',
'VMStateDescription',
]
foreach type: blocked_type
_hwcore_bindgen_args += ['--blocklist-type', type]
endforeach
c_bitfields = [
'ClockEvent',
]
foreach enum : c_bitfields
_hwcore_bindgen_args += ['--bitfield-enum', enum]
endforeach
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_hwcore_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common + _hwcore_bindgen_args,
c_args: bindgen_c_args,
)
_hwcore_rs = static_library(
'hwcore',
structured_sources(
[
'src/lib.rs',
'src/bindings.rs',
'src/irq.rs',
'src/prelude.rs',
'src/qdev.rs',
'src/sysbus.rs',
],
{'.': _hwcore_bindings_inc_rs}
),
'src/lib.rs',
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_abi: 'rust',
link_with: [_bql_rs, _chardev_rs, _migration_rs, _qom_rs, _system_rs, _util_rs],
dependencies: [glib_sys_rs, qemu_macros, common_rs],
dependencies: [glib_sys_rs, qemu_macros, common_rs, hwcore_sys_rs],
)
hwcore_rs = declare_dependency(link_with: [_hwcore_rs],

View File

@@ -1,10 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pub use hwcore_sys as bindings;
pub use qemu_macros::Device;
pub use qom;
pub mod bindings;
mod irq;
pub use irq::*;

View File

@@ -66,7 +66,7 @@ pub trait ResettablePhasesImpl {
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
obj: *mut bindings::Object,
obj: *mut qom::bindings::Object,
typ: ResetType,
) {
let state = NonNull::new(obj).unwrap().cast::<T>();
@@ -79,7 +79,7 @@ unsafe extern "C" fn rust_resettable_enter_fn<T: ResettablePhasesImpl>(
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
obj: *mut bindings::Object,
obj: *mut qom::bindings::Object,
typ: ResetType,
) {
let state = NonNull::new(obj).unwrap().cast::<T>();
@@ -92,7 +92,7 @@ unsafe extern "C" fn rust_resettable_hold_fn<T: ResettablePhasesImpl>(
/// can be downcasted to type `T`. We also expect the device is
/// readable/writeable from one thread at any time.
unsafe extern "C" fn rust_resettable_exit_fn<T: ResettablePhasesImpl>(
obj: *mut bindings::Object,
obj: *mut qom::bindings::Object,
typ: ResetType,
) {
let state = NonNull::new(obj).unwrap().cast::<T>();

View File

@@ -6,22 +6,21 @@
use std::ffi::CStr;
pub use bindings::SysBusDeviceClass;
use common::Opaque;
use qom::prelude::*;
use system::MemoryRegion;
pub use system_sys::SysBusDeviceClass;
use util::{Error, Result};
use crate::{
bindings,
irq::{IRQState, InterruptSource},
qdev::{DeviceClassExt, DeviceImpl, DeviceState},
};
/// A safe wrapper around [`bindings::SysBusDevice`].
/// A safe wrapper around [`system_sys::SysBusDevice`].
#[repr(transparent)]
#[derive(Debug, common::Wrapper)]
pub struct SysBusDevice(Opaque<bindings::SysBusDevice>);
pub struct SysBusDevice(Opaque<system_sys::SysBusDevice>);
unsafe impl Send for SysBusDevice {}
unsafe impl Sync for SysBusDevice {}
@@ -29,7 +28,7 @@ unsafe impl Sync for SysBusDevice {}
unsafe impl ObjectType for SysBusDevice {
type Class = SysBusDeviceClass;
const TYPE_NAME: &'static CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_SYS_BUS_DEVICE) };
unsafe { CStr::from_bytes_with_nul_unchecked(system_sys::TYPE_SYS_BUS_DEVICE) };
}
qom_isa!(SysBusDevice: DeviceState, Object);
@@ -62,7 +61,7 @@ where
fn init_mmio(&self, iomem: &MemoryRegion) {
assert!(bql::is_locked());
unsafe {
bindings::sysbus_init_mmio(self.upcast().as_mut_ptr(), iomem.as_mut_ptr());
system_sys::sysbus_init_mmio(self.upcast().as_mut_ptr(), iomem.as_mut_ptr());
}
}
@@ -73,7 +72,7 @@ where
fn init_irq(&self, irq: &InterruptSource) {
assert!(bql::is_locked());
unsafe {
bindings::sysbus_init_irq(self.upcast().as_mut_ptr(), irq.as_ptr());
system_sys::sysbus_init_irq(self.upcast().as_mut_ptr(), irq.as_ptr());
}
}
@@ -82,7 +81,7 @@ where
assert!(bql::is_locked());
// SAFETY: the BQL ensures that no one else writes to sbd.mmio[], and
// the SysBusDevice must be initialized to get an IsA<SysBusDevice>.
let sbd = unsafe { &*self.upcast().as_ptr() };
let sbd = unsafe { &*self.upcast().as_mut_ptr() };
let id: usize = id.try_into().unwrap();
if sbd.mmio[id].memory.is_null() {
None
@@ -96,7 +95,7 @@ where
assert!(bql::is_locked());
let id: i32 = id.try_into().unwrap();
unsafe {
bindings::sysbus_mmio_map(self.upcast().as_mut_ptr(), id, addr);
system_sys::sysbus_mmio_map(self.upcast().as_mut_ptr(), id, addr);
}
}
@@ -108,7 +107,7 @@ where
let id: i32 = id.try_into().unwrap();
let irq: &IRQState = irq;
unsafe {
bindings::sysbus_connect_irq(self.upcast().as_mut_ptr(), id, irq.as_mut_ptr());
system_sys::sysbus_connect_irq(self.upcast().as_mut_ptr(), id, irq.as_mut_ptr());
}
}
@@ -116,7 +115,7 @@ where
assert!(bql::is_locked());
unsafe {
Error::with_errp(|errp| {
bindings::sysbus_realize(self.upcast().as_mut_ptr(), errp);
system_sys::sysbus_realize(self.upcast().as_mut_ptr(), errp);
})
}
}

View File

@@ -1,32 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#ifndef __CLANG_STDATOMIC_H
#define __CLANG_STDATOMIC_H
/*
* Fix potential missing stdatomic.h error in case bindgen does not insert the
* correct libclang header paths on its own. We do not use stdatomic.h symbols
* in QEMU code, so it's fine to declare dummy types instead.
*/
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#endif /* __CLANG_STDATOMIC_H */
#include "qemu/osdep.h"
#include "hw/core/sysbus.h"
#include "hw/core/clock.h"
#include "hw/core/qdev-clock.h"
#include "hw/core/qdev-properties.h"
#include "hw/core/qdev-properties-system.h"
#include "hw/core/irq.h"

View File

@@ -35,6 +35,7 @@ genrs = []
subdir('qemu-macros')
subdir('common')
subdir('bindings')
subdir('bits')
subdir('util')

View File

@@ -17,6 +17,7 @@ bql = { path = "../bql" }
common = { path = "../common" }
qemu_macros = { path = "../qemu-macros" }
util = { path = "../util" }
migration-sys = { path = "../bindings/migration-sys" }
glib-sys.workspace = true
[lints]

View File

@@ -1 +0,0 @@
../util/build.rs

View File

@@ -1,44 +1,8 @@
_migration_bindgen_args = []
c_bitfields = [
'MigrationPolicy',
'MigrationPriority',
'VMStateFlags',
]
foreach enum : c_bitfields
_migration_bindgen_args += ['--bitfield-enum', enum]
endforeach
#
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_migration_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common + _migration_bindgen_args,
c_args: bindgen_c_args,
)
_migration_rs = static_library(
'migration',
structured_sources(
[
'src/lib.rs',
'src/bindings.rs',
'src/migratable.rs',
'src/prelude.rs',
'src/vmstate.rs',
],
{'.' : _migration_bindings_inc_rs},
),
'src/lib.rs',
link_with: [_util_rs, _bql_rs],
dependencies: [common_rs, glib_sys_rs, qemu_macros],
dependencies: [common_rs, glib_sys_rs, qemu_macros, migration_sys_rs],
)
migration_rs = declare_dependency(link_with: [_migration_rs],

View File

@@ -1,49 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#![allow(
dead_code,
improper_ctypes_definitions,
improper_ctypes,
non_camel_case_types,
non_snake_case,
non_upper_case_globals,
unnecessary_transmutes,
unsafe_op_in_unsafe_fn,
clippy::pedantic,
clippy::restriction,
clippy::style,
clippy::missing_const_for_fn,
clippy::ptr_offset_with_cast,
clippy::useless_transmute,
clippy::missing_safety_doc,
clippy::too_many_arguments
)]
use common::Zeroable;
use glib_sys::{GHashTable, GHashTableIter, GPtrArray, GSList};
#[cfg(MESON)]
include!("bindings.inc.rs");
#[cfg(not(MESON))]
include!(concat!(env!("OUT_DIR"), "/bindings.inc.rs"));
unsafe impl Send for VMStateDescription {}
unsafe impl Sync for VMStateDescription {}
unsafe impl Send for VMStateField {}
unsafe impl Sync for VMStateField {}
unsafe impl Send for VMStateInfo {}
unsafe impl Sync for VMStateInfo {}
// bindgen does not derive Default here
#[allow(clippy::derivable_impls)]
impl Default for VMStateFlags {
fn default() -> Self {
Self(0)
}
}
unsafe impl Zeroable for VMStateFlags {}
unsafe impl Zeroable for VMStateField {}
unsafe impl Zeroable for VMStateDescription {}

View File

@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pub mod bindings;
pub use migration_sys as bindings;
pub use qemu_macros::ToMigrationState;
pub mod migratable;

View File

@@ -165,79 +165,6 @@ macro_rules! vmstate_of {
};
}
pub trait VMStateFlagsExt {
const VMS_VARRAY_FLAGS: VMStateFlags;
}
impl VMStateFlagsExt for VMStateFlags {
const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
VMStateFlags::VMS_VARRAY_INT32.0
| VMStateFlags::VMS_VARRAY_UINT8.0
| VMStateFlags::VMS_VARRAY_UINT16.0
| VMStateFlags::VMS_VARRAY_UINT32.0,
);
}
// Add a couple builder-style methods to VMStateField, allowing
// easy derivation of VMStateField constants from other types.
impl VMStateField {
#[must_use]
pub const fn with_version_id(mut self, version_id: i32) -> Self {
assert!(version_id >= 0);
self.version_id = version_id;
self
}
#[must_use]
pub const fn with_array_flag(mut self, num: usize) -> Self {
assert!(num <= 0x7FFF_FFFFusize);
assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) == 0);
assert!((self.flags.0 & VMStateFlags::VMS_VARRAY_FLAGS.0) == 0);
if (self.flags.0 & VMStateFlags::VMS_POINTER.0) != 0 {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_POINTER.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0);
// VMS_ARRAY_OF_POINTER flag stores the size of pointer.
// FIXME: *const, *mut, NonNull and Box<> have the same size as usize.
// Resize if more smart pointers are supported.
self.size = std::mem::size_of::<usize>();
}
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_SINGLE.0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_ARRAY.0);
self.num = num as i32;
self
}
#[must_use]
pub const fn with_pointer_flag(mut self) -> Self {
assert!((self.flags.0 & VMStateFlags::VMS_POINTER.0) == 0);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_POINTER.0);
self
}
#[must_use]
pub const fn with_varray_flag_unchecked(mut self, flag: VMStateFlags) -> Self {
self.flags = VMStateFlags(self.flags.0 & !VMStateFlags::VMS_ARRAY.0);
self.flags = VMStateFlags(self.flags.0 | flag.0);
self.num = 0; // varray uses num_offset instead of num.
self
}
#[must_use]
#[allow(unused_mut)]
pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> Self {
assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0);
self.with_varray_flag_unchecked(flag)
}
#[must_use]
pub const fn with_varray_multiply(mut self, num: u32) -> Self {
assert!(num <= 0x7FFF_FFFFu32);
self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0);
self.num = num as i32;
self
}
}
/// This macro can be used (by just passing it a type) to forward the `VMState`
/// trait to the first field of a tuple. This is a workaround for lack of
/// support of nested [`offset_of`](core::mem::offset_of) until Rust 1.82.0.

View File

@@ -1,51 +0,0 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2024 Linaro Ltd.
*
* Authors: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#ifndef __CLANG_STDATOMIC_H
#define __CLANG_STDATOMIC_H
/*
* Fix potential missing stdatomic.h error in case bindgen does not insert the
* correct libclang header paths on its own. We do not use stdatomic.h symbols
* in QEMU code, so it's fine to declare dummy types instead.
*/
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#endif /* __CLANG_STDATOMIC_H */
#include "qemu/osdep.h"
#include "migration/vmstate.h"

View File

@@ -18,6 +18,7 @@ bql = { path = "../bql" }
migration = { path = "../migration" }
qemu_macros = { path = "../qemu-macros" }
util = { path = "../util" }
qom-sys = { path = "../bindings/qom-sys" }
glib-sys.workspace = true
[lints]

View File

@@ -1 +0,0 @@
../util/build.rs

View File

@@ -1,33 +1,8 @@
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_qom_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common,
c_args: bindgen_c_args,
)
_qom_rs = static_library(
'qom',
structured_sources(
[
'src/lib.rs',
'src/bindings.rs',
'src/prelude.rs',
'src/qom.rs',
],
{'.': _qom_bindings_inc_rs}
),
'src/lib.rs',
link_with: [_bql_rs, _migration_rs],
dependencies: [common_rs, glib_sys_rs, qemu_macros],
dependencies: [common_rs, glib_sys_rs, qemu_macros, qom_sys_rs],
)
qom_rs = declare_dependency(link_with: [_qom_rs], dependencies: [qemu_macros, qom, qemuutil])

View File

@@ -1,8 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pub use qemu_macros::Object;
pub mod bindings;
pub use qom_sys as bindings;
// preserve one-item-per-"use" syntax, it is clearer
// for prelude-like modules

View File

@@ -1,27 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#ifndef __CLANG_STDATOMIC_H
#define __CLANG_STDATOMIC_H
/*
* Fix potential missing stdatomic.h error in case bindgen does not insert the
* correct libclang header paths on its own. We do not use stdatomic.h symbols
* in QEMU code, so it's fine to declare dummy types instead.
*/
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#endif /* __CLANG_STDATOMIC_H */
#include "qemu/osdep.h"
#include "qom/object.h"

View File

@@ -14,6 +14,9 @@ rust-version.workspace = true
[dependencies]
common = { path = "../common" }
system-sys = { path = "../bindings/system-sys" }
bql = { path = "../bql" }
migration = { path = "../migration" }
qom = { path = "../qom" }
util = { path = "../util" }
glib-sys.workspace = true

View File

@@ -1 +0,0 @@
../util/build.rs

View File

@@ -1,41 +1,8 @@
c_enums = [
'device_endian',
]
_system_bindgen_args = []
foreach enum : c_enums
_system_bindgen_args += ['--rustified-enum', enum]
endforeach
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_system_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common + _system_bindgen_args,
c_args: bindgen_c_args,
)
_system_rs = static_library(
'system',
structured_sources(
[
'src/lib.rs',
'src/bindings.rs',
'src/memory.rs',
'src/prelude.rs',
],
{'.': _system_bindings_inc_rs}
),
'src/lib.rs',
link_with: [_bql_rs, _migration_rs, _qom_rs, _util_rs],
dependencies: [glib_sys_rs, common_rs, qemu_macros],
dependencies: [glib_sys_rs, common_rs, qemu_macros, system_sys_rs],
)
system_rs = declare_dependency(link_with: [_system_rs],

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pub mod bindings;
pub use system_sys as bindings;
mod memory;
pub use memory::*;

View File

@@ -132,7 +132,7 @@ unsafe impl Sync for MemoryRegion {}
impl MemoryRegion {
unsafe fn do_init_io(
slot: *mut bindings::MemoryRegion,
owner: *mut bindings::Object,
owner: *mut qom::bindings::Object,
ops: &'static bindings::MemoryRegionOps,
name: &'static str,
size: u64,

View File

@@ -1,29 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#ifndef __CLANG_STDATOMIC_H
#define __CLANG_STDATOMIC_H
/*
* Fix potential missing stdatomic.h error in case bindgen does not insert the
* correct libclang header paths on its own. We do not use stdatomic.h symbols
* in QEMU code, so it's fine to declare dummy types instead.
*/
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#endif /* __CLANG_STDATOMIC_H */
#include "qemu/osdep.h"
#include "system/system.h"
#include "system/memory.h"
#include "system/address-spaces.h"

View File

@@ -18,6 +18,7 @@ foreign = { workspace = true }
glib-sys = { workspace = true }
libc = { workspace = true }
common = { path = "../common" }
util-sys = { path = "../bindings/util-sys" }
[lints]
workspace = true

View File

@@ -1,45 +1,7 @@
_util_bindgen_args = []
c_enums = [
'module_init_type',
'QEMUClockType',
]
foreach enum : c_enums
_util_bindgen_args += ['--rustified-enum', enum]
endforeach
#
# TODO: Remove this comment when the clang/libclang mismatch issue is solved.
#
# Rust bindings generation with `bindgen` might fail in some cases where the
# detected `libclang` does not match the expected `clang` version/target. In
# this case you must pass the path to `clang` and `libclang` to your build
# command invocation using the environment variables CLANG_PATH and
# LIBCLANG_PATH
_util_bindings_inc_rs = rust.bindgen(
input: 'wrapper.h',
dependencies: common_ss.all_dependencies(),
output: 'bindings.inc.rs',
include_directories: bindings_incdir,
bindgen_version: ['>=0.60.0'],
args: bindgen_args_common + _util_bindgen_args,
c_args: bindgen_c_args,
)
_util_rs = static_library(
'util',
structured_sources(
[
'src/lib.rs',
'src/bindings.rs',
'src/error.rs',
'src/log.rs',
'src/module.rs',
'src/prelude.rs',
'src/timer.rs',
],
{'.': _util_bindings_inc_rs}
),
dependencies: [anyhow_rs, libc_rs, foreign_rs, glib_sys_rs, common_rs],
'src/lib.rs',
dependencies: [anyhow_rs, libc_rs, foreign_rs, glib_sys_rs, common_rs, util_sys_rs],
)
util_rs = declare_dependency(link_with: [_util_rs], dependencies: [qemuutil, qom])

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pub mod bindings;
pub use util_sys as bindings;
pub mod error;
pub mod log;
pub mod module;

View File

@@ -1,32 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This header file is meant to be used as input to the `bindgen` application
* in order to generate C FFI compatible Rust bindings.
*/
#ifndef __CLANG_STDATOMIC_H
#define __CLANG_STDATOMIC_H
/*
* Fix potential missing stdatomic.h error in case bindgen does not insert the
* correct libclang header paths on its own. We do not use stdatomic.h symbols
* in QEMU code, so it's fine to declare dummy types instead.
*/
typedef enum memory_order {
memory_order_relaxed,
memory_order_consume,
memory_order_acquire,
memory_order_release,
memory_order_acq_rel,
memory_order_seq_cst,
} memory_order;
#endif /* __CLANG_STDATOMIC_H */
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qapi/error-internal.h"
#include "qemu/log-for-trace.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/timer.h"