Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging

* rust: move binding generation to bindings/
* rust: fixes for Windows
* target/i386/tcg: fix a few instructions that do not support VEX.L=1
* target/i386/tcg: various cleanups

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCgAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAml4h1QUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroP56Qf/cqjdwUO8GUNP5Og2s/D2wjiTeSTq
# 9oer3Jq2OUyh5zqt6oVXLjWIV6GOjaak9aSa8b23Ej4jC+Zjc0RRN9s6qXkCfvM7
# yrfQWnbIkkSmCWIp5stsqtXtE11wMWh25gjVNzj0tuPxNEzgYG8lyZT3/vgZ3B/o
# OO6s8HxNdgGrP5zeIMNeaF0OkdyF/JADv5NrKH57HYRyYE0ZMmn0G/RPxecyS7se
# W0KW7H6F6RqFPNf7W0Y9+uQjDttrinQ9Ni2+IIgZ9GaoIRloqslclmof9fxMizK9
# aqxuC8XmJkgF13V/9mLy+iZKO9fhlaCJ0CsxZqscmrzPNs7QWlJ3L9nDng==
# =4pTP
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 27 Jan 2026 08:37:24 PM AEDT
# gpg:                using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg:                issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [unknown]
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* tag 'for-upstream' of https://gitlab.com/bonzini/qemu:
  rust/hpet: remove stale TODO comment
  target/i386/tcg: cleanup #ifdef TARGET_X86_64
  target/i386/tcg: replace havesib variable with the SIB byte itself
  target/i386/tcg: merge decode_modrm and decode_modrm_address split
  target/i386/tcg: remove dead constants
  target/i386/tcg: fix typo in dpps/dppd instructions
  target/i386/tcg: fix a few instructions that do not support VEX.L=1
  qdev: add hw/core/gpio.c to libhwcore
  rust: move hwcore::sysbus to system crate
  rust: move binding generation to bindings/
  rust: move class_init to an extension trait
  rust: hwcore: add chardev symbols to integration tests
  rust: trace: libc does not have syslog on windows

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2026-01-28 10:03:37 +11:00
92 changed files with 1025 additions and 846 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

@@ -1,6 +1,7 @@
# core qdev-related obj files, also used by *-user and unit tests
hwcore_ss.add(files(
'bus.c',
'gpio.c',
'qdev-properties.c',
'qdev.c',
'resetcontainer.c',
@@ -29,7 +30,6 @@ system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutl
system_ss.add(files(
'cpu-system.c',
'fw-path-provider.c',
'gpio.c',
'hotplug.c',
'loader.c',
'machine-hmp-cmds.c',

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,13 +14,13 @@ 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" }
qom = { path = "../../qom" }
chardev = { path = "../../chardev" }
migration = { path = "../../migration" }
system = { path = "../../system" }
util = { path = "../../util" }
[lints]

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],
link_with: [_bql_rs, _chardev_rs, _migration_rs, _qom_rs, _util_rs],
dependencies: [glib_sys_rs, qemu_macros, common_rs, hwcore_sys_rs],
)
hwcore_rs = declare_dependency(link_with: [_hwcore_rs],
@@ -73,7 +17,7 @@ test('rust-hwcore-rs-integration',
override_options: ['rust_std=2021', 'build.rust_std=2021'],
rust_args: ['--test'],
install: false,
dependencies: [common_rs, hwcore_rs, bql_rs, migration_rs, util_rs]),
dependencies: [chardev_rs, common_rs, hwcore_rs, bql_rs, migration_rs, util_rs]),
args: [
'--test', '--test-threads', '1',
'--format', 'pretty',

View File

@@ -33,10 +33,10 @@ pub struct IRQState(Opaque<bindings::IRQState>);
///
/// Interrupts are implemented as a pointer to the interrupt "sink", which has
/// type [`IRQState`]. A device exposes its source as a QOM link property using
/// a function such as [`crate::sysbus::SysBusDeviceMethods::init_irq`], and
/// a function such as [`crate::DeviceMethods::init_gpio_out`], and
/// initially leaves the pointer to a NULL value, representing an unconnected
/// interrupt. To connect it, whoever creates the device fills the pointer with
/// the sink's `IRQState *`, for example using `sysbus_connect_irq`. Because
/// the sink's `IRQState *`, for example using `qdev_connect_gpio_out`. Because
/// devices are generally shared objects, interrupt sources are an example of
/// the interior mutability pattern.
///
@@ -87,11 +87,11 @@ where
}
}
pub(crate) const fn as_ptr(&self) -> *mut *mut bindings::IRQState {
pub const fn as_ptr(&self) -> *mut *mut bindings::IRQState {
self.cell.as_ptr()
}
pub(crate) const fn slice_as_ptr(slice: &[Self]) -> *mut *mut bindings::IRQState {
pub const fn slice_as_ptr(slice: &[Self]) -> *mut *mut bindings::IRQState {
assert!(!slice.is_empty());
slice[0].as_ptr()
}

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::*;
@@ -15,6 +14,3 @@ pub mod prelude;
mod qdev;
pub use qdev::*;
mod sysbus;
pub use sysbus::*;

View File

@@ -1,14 +1,12 @@
//! Essential types and traits intended for blanket imports.
pub use crate::qdev::Clock;
pub use crate::qdev::DeviceClassExt;
pub use crate::qdev::DeviceState;
pub use crate::qdev::DeviceImpl;
pub use crate::qdev::DeviceMethods;
pub use crate::qdev::ResettablePhasesImpl;
pub use crate::qdev::ResetType;
pub use crate::sysbus::SysBusDevice;
pub use crate::sysbus::SysBusDeviceImpl;
pub use crate::sysbus::SysBusDeviceMethods;
pub use crate::irq::InterruptSource;

View File

@@ -15,9 +15,9 @@ use migration::{impl_vmstate_c_struct, VMStateDescription};
use qom::{prelude::*, ObjectClass};
use util::{Error, Result};
pub use crate::bindings::{ClockEvent, DeviceClass, Property, ResetType};
pub use crate::bindings::{ClockEvent, ResetType};
use crate::{
bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, ResettableClass},
bindings::{self, qdev_init_gpio_in, qdev_init_gpio_out, DeviceClass, Property},
irq::InterruptSource,
};
@@ -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>();
@@ -206,6 +206,9 @@ unsafe extern "C" fn rust_realize_fn<T: DeviceImpl>(
}
}
#[repr(transparent)]
pub struct ResettableClass(bindings::ResettableClass);
unsafe impl InterfaceType for ResettableClass {
const TYPE_NAME: &'static CStr =
unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_RESETTABLE_INTERFACE) };
@@ -214,23 +217,25 @@ unsafe impl InterfaceType for ResettableClass {
impl ResettableClass {
/// Fill in the virtual methods of `ResettableClass` based on the
/// definitions in the `ResettablePhasesImpl` trait.
pub fn class_init<T: ResettablePhasesImpl>(&mut self) {
fn class_init<T: ResettablePhasesImpl>(&mut self) {
if <T as ResettablePhasesImpl>::ENTER.is_some() {
self.phases.enter = Some(rust_resettable_enter_fn::<T>);
self.0.phases.enter = Some(rust_resettable_enter_fn::<T>);
}
if <T as ResettablePhasesImpl>::HOLD.is_some() {
self.phases.hold = Some(rust_resettable_hold_fn::<T>);
self.0.phases.hold = Some(rust_resettable_hold_fn::<T>);
}
if <T as ResettablePhasesImpl>::EXIT.is_some() {
self.phases.exit = Some(rust_resettable_exit_fn::<T>);
self.0.phases.exit = Some(rust_resettable_exit_fn::<T>);
}
}
}
impl DeviceClass {
/// Fill in the virtual methods of `DeviceClass` based on the definitions in
/// the `DeviceImpl` trait.
pub fn class_init<T: DeviceImpl>(&mut self) {
pub trait DeviceClassExt {
fn class_init<T: DeviceImpl>(&mut self);
}
impl DeviceClassExt for DeviceClass {
fn class_init<T: DeviceImpl>(&mut self) {
if <T as DeviceImpl>::REALIZE.is_some() {
self.realize = Some(rust_realize_fn::<T>);
}

View File

@@ -142,7 +142,7 @@ fn test_cast() {
let obj_ref: &Object = p_ref.upcast();
assert_eq!(addr_of!(*obj_ref), p_ptr.cast());
let sbd_ref: Option<&SysBusDevice> = obj_ref.dynamic_cast();
let sbd_ref: Option<&DummyChildState> = obj_ref.dynamic_cast();
assert!(sbd_ref.is_none());
let dev_ref: Option<&DeviceState> = obj_ref.downcast();
@@ -150,7 +150,7 @@ fn test_cast() {
// SAFETY: the cast is wrong, but the value is only used for comparison
unsafe {
let sbd_ref: &SysBusDevice = obj_ref.unsafe_cast();
let sbd_ref: &DummyChildState = obj_ref.unsafe_cast();
assert_eq!(addr_of!(*sbd_ref), p_ptr.cast());
}
}

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

@@ -725,7 +725,6 @@ impl HPETState {
self.irqs[0].lower();
self.irqs[RTC_ISA_IRQ].lower();
} else if deactivating_bit(old_val, new_val, HPET_CFG_LEG_RT_SHIFT) {
// TODO: Add irq binding: qemu_irq_lower(s->irqs[0])
self.irqs[0].lower();
self.pit_enabled.set(true);
self.irqs[RTC_ISA_IRQ].set(self.rtc_irq_level.get() != 0);

View File

@@ -35,15 +35,16 @@ genrs = []
subdir('qemu-macros')
subdir('common')
subdir('bindings')
subdir('bits')
subdir('util')
subdir('bql')
subdir('migration')
subdir('qom')
subdir('system')
subdir('chardev')
subdir('hw/core')
subdir('system')
subdir('tests')
subdir('trace')
subdir('hw')

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

@@ -4,6 +4,7 @@ pub use crate::qom::InterfaceType;
pub use crate::qom::IsA;
pub use crate::qom::Object;
pub use crate::qom::ObjectCast;
pub use crate::qom::ObjectClassExt;
pub use crate::qom::ObjectClassMethods;
pub use crate::qom::ObjectDeref;
pub use crate::qom::ObjectImpl;

View File

@@ -729,10 +729,14 @@ unsafe extern "C" fn rust_unparent_fn<T: ObjectImpl>(dev: *mut bindings::Object)
T::UNPARENT.unwrap()(unsafe { state.as_ref() });
}
impl ObjectClass {
pub trait ObjectClassExt {
fn class_init<T: ObjectImpl>(&mut self);
}
impl ObjectClassExt for ObjectClass {
/// Fill in the virtual methods of `ObjectClass` based on the definitions in
/// the `ObjectImpl` trait.
pub fn class_init<T: ObjectImpl>(&mut self) {
fn class_init<T: ObjectImpl>(&mut self) {
if <T as ObjectImpl>::UNPARENT.is_some() {
self.unparent = Some(rust_unparent_fn::<T>);
}

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,10 @@ rust-version.workspace = true
[dependencies]
common = { path = "../common" }
system-sys = { path = "../bindings/system-sys" }
bql = { path = "../bql" }
hwcore = { path = "../hw/core" }
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}
),
link_with: [_bql_rs, _migration_rs, _qom_rs, _util_rs],
dependencies: [glib_sys_rs, common_rs, qemu_macros],
'src/lib.rs',
link_with: [_bql_rs, _hwcore_rs, _migration_rs, _qom_rs, _util_rs],
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::*;
@@ -9,3 +9,6 @@ pub use memory::*;
// for prelude-like modules
#[rustfmt::skip]
pub mod prelude;
mod sysbus;
pub use sysbus::*;

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

@@ -6,3 +6,8 @@ pub use crate::memory::MemoryRegion;
pub use crate::memory::MemoryRegionOps;
pub use crate::memory::MemoryRegionOpsBuilder;
pub use crate::memory::MemTxAttrs;
pub use crate::sysbus::SysBusDevice;
pub use crate::sysbus::SysBusDeviceClassExt;
pub use crate::sysbus::SysBusDeviceImpl;
pub use crate::sysbus::SysBusDeviceMethods;

View File

@@ -6,22 +6,18 @@
use std::ffi::CStr;
pub use bindings::SysBusDeviceClass;
use common::Opaque;
use hwcore::{prelude::*, IRQState};
use qom::prelude::*;
use system::MemoryRegion;
pub use system_sys::SysBusDeviceClass;
use util::{Error, Result};
use crate::{
bindings,
irq::{IRQState, InterruptSource},
qdev::{DeviceImpl, DeviceState},
};
use crate::MemoryRegion;
/// 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 +25,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);
@@ -37,10 +33,14 @@ qom_isa!(SysBusDevice: DeviceState, Object);
// TODO: add virtual methods
pub trait SysBusDeviceImpl: DeviceImpl + IsA<SysBusDevice> {}
impl SysBusDeviceClass {
pub trait SysBusDeviceClassExt {
fn class_init<T: SysBusDeviceImpl>(&mut self);
}
impl SysBusDeviceClassExt for SysBusDeviceClass {
/// Fill in the virtual methods of `SysBusDeviceClass` based on the
/// definitions in the `SysBusDeviceImpl` trait.
pub fn class_init<T: SysBusDeviceImpl>(self: &mut SysBusDeviceClass) {
fn class_init<T: SysBusDeviceImpl>(&mut self) {
self.parent_class.class_init::<T>();
}
}
@@ -58,7 +58,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());
}
}
@@ -69,7 +69,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());
}
}
@@ -78,7 +78,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
@@ -92,7 +92,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);
}
}
@@ -104,7 +104,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());
}
}
@@ -112,7 +112,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,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

@@ -3,6 +3,7 @@
//! This crate provides macros that aid in using QEMU's tracepoint
//! functionality.
#[cfg(not(windows))]
#[doc(hidden)]
/// Re-exported item to avoid adding libc as a dependency everywhere.
pub use libc::{syslog, LOG_INFO};

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"

View File

@@ -628,7 +628,7 @@ static void decode_0F7E(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
static const X86OpEntry opcodes_0F7E[4] = {
X86_OP_ENTRY3(MOVD_from, E,y, None,None, P,y, vex5 mmx),
X86_OP_ENTRY3(MOVD_from, E,y, None,None, V,y, vex5),
X86_OP_ENTRY3(MOVQ, V,x, None,None, W,q, vex5), /* wrong dest Vy on SDM! */
X86_OP_ENTRY3(MOVQ, V,dq,None,None, W,q, vex5), /* wrong dest Vq on SDM! */
{},
};
*entry = *decode_by_prefix(s, opcodes_0F7E);
@@ -693,7 +693,7 @@ static void decode_0FD6(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
{
static const X86OpEntry movq[4] = {
{},
X86_OP_ENTRY3(MOVQ, W,x, None, None, V,q, vex5),
X86_OP_ENTRY3(MOVQ, W,dq, None, None, V,q, vex5),
X86_OP_ENTRY3(MOVq_dq, V,dq, None, None, N,q),
X86_OP_ENTRY3(MOVq_dq, P,q, None, None, U,q),
};
@@ -977,8 +977,8 @@ static const X86OpEntry opcodes_0F3A[256] = {
[0x21] = X86_OP_GROUP0(VINSERTPS),
[0x22] = X86_OP_ENTRY4(PINSR, V,dq, H,dq, E,y, vex5 cpuid(SSE41) p_66),
[0x40] = X86_OP_ENTRY4(VDDPS, V,x, H,x, W,x, vex2 cpuid(SSE41) p_66),
[0x41] = X86_OP_ENTRY4(VDDPD, V,dq, H,dq, W,dq, vex2 cpuid(SSE41) p_66),
[0x40] = X86_OP_ENTRY4(VDPPS, V,x, H,x, W,x, vex2 cpuid(SSE41) p_66),
[0x41] = X86_OP_ENTRY4(VDPPD, V,dq, H,dq, W,dq, vex2 cpuid(SSE41) p_66),
[0x42] = X86_OP_ENTRY4(VMPSADBW, V,x, H,x, W,x, vex2 cpuid(SSE41) avx2_256 p_66),
[0x44] = X86_OP_ENTRY4(PCLMULQDQ, V,dq, H,dq, W,dq, vex4 cpuid(PCLMULQDQ) p_66),
[0x46] = X86_OP_ENTRY4(VPERM2x128, V,qq, H,qq, W,qq, vex6 chk(W0) cpuid(AVX2) p_66),
@@ -1102,7 +1102,7 @@ static void decode_0F12(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
};
static const X86OpEntry opcodes_0F12_reg[4] = {
X86_OP_ENTRY3(VMOVHLPS, V,dq, H,dq, U,dq, vex7),
X86_OP_ENTRY3(VMOVLPx, W,x, H,x, U,q, vex5), /* MOVLPD */
X86_OP_ENTRY3(VMOVLPx, W,dq, H,dq, U,q, vex5), /* MOVLPD */
X86_OP_ENTRY3(VMOVSLDUP, V,x, None,None, U,x, vex4 cpuid(SSE3)),
X86_OP_ENTRY3(VMOVDDUP, V,x, None,None, U,x, vex5 cpuid(SSE3)),
};
@@ -1465,7 +1465,7 @@ static const X86OpEntry opcodes_0F[256] = {
[0x6b] = X86_OP_ENTRY3(PACKSSDW, V,x, H,x, W,x, vex4 mmx avx2_256 p_00_66),
[0x6c] = X86_OP_ENTRY3(PUNPCKLQDQ, V,x, H,x, W,x, vex4 p_66 avx2_256),
[0x6d] = X86_OP_ENTRY3(PUNPCKHQDQ, V,x, H,x, W,x, vex4 p_66 avx2_256),
[0x6e] = X86_OP_ENTRY3(MOVD_to, V,x, None,None, E,y, vex5 mmx p_00_66), /* wrong dest Vy on SDM! */
[0x6e] = X86_OP_ENTRY3(MOVD_to, V,dq,None,None, E,y, vex5 mmx p_00_66), /* wrong dest Vy on SDM! */
[0x6f] = X86_OP_GROUP0(0F6F),
[0x78] = X86_OP_GROUP0(0F78),
@@ -2007,42 +2007,42 @@ static void decode_root(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
*entry = opcodes_root[*b];
}
/* Decompose an address. */
static AddressParts decode_modrm_address(CPUX86State *env, DisasContext *s,
int modrm, bool is_vsib)
/* Decode the MODRM and SIB bytes into a register or memory operand. */
static void decode_modrm(DisasContext *s, CPUX86State *env,
X86DecodedInsn *decode, X86DecodedOp *op)
{
int def_seg, base, index, scale, mod, rm;
target_long disp;
bool havesib;
def_seg = R_DS;
index = -1;
scale = 0;
disp = 0;
mod = (modrm >> 6) & 3;
rm = modrm & 7;
base = rm | REX_B(s);
int modrm = get_modrm(s, env);
int mod = (modrm >> 6) & 3;
int rm = modrm & 7;
bool is_vsib = decode->e.vex_class == 12;
int sib = -1;
if (mod == 3) {
/* Normally filtered out earlier, but including this path
simplifies multi-byte nop, as well as bndcl, bndcu, bndcn. */
goto done;
op->n = rm;
if (op->unit != X86_OP_MMX) {
op->n |= REX_B(s);
}
return;
}
/* Decompose an address. */
int def_seg = R_DS;
int base = rm | REX_B(s);
int index = -1;
int scale = 0;
target_ulong disp = 0;
switch (s->aflag) {
case MO_64:
case MO_32:
havesib = 0;
if (rm == 4) {
int code = x86_ldub_code(env, s);
scale = (code >> 6) & 3;
index = ((code >> 3) & 7) | REX_X(s);
sib = x86_ldub_code(env, s);
scale = (sib >> 6) & 3;
index = ((sib >> 3) & 7) | REX_X(s);
if (index == 4 && !is_vsib) {
index = -1; /* no index */
}
base = (code & 7) | REX_B(s);
havesib = 1;
base = (sib & 7) | REX_B(s);
}
switch (mod) {
@@ -2050,7 +2050,7 @@ static AddressParts decode_modrm_address(CPUX86State *env, DisasContext *s,
if ((base & 7) == 5) {
base = -1;
disp = (int32_t)x86_ldl_code(env, s);
if (CODE64(s) && !havesib) {
if (CODE64(s) && sib == -1) {
base = -2;
disp += s->pc + s->rip_offset;
}
@@ -2127,26 +2127,9 @@ static AddressParts decode_modrm_address(CPUX86State *env, DisasContext *s,
g_assert_not_reached();
}
done:
return (AddressParts){ def_seg, base, index, scale, disp };
}
static int decode_modrm(DisasContext *s, CPUX86State *env,
X86DecodedInsn *decode, X86DecodedOp *op)
{
int modrm = get_modrm(s, env);
if ((modrm >> 6) == 3) {
op->n = (modrm & 7);
if (op->unit != X86_OP_MMX) {
op->n |= REX_B(s);
}
} else {
op->has_ea = true;
op->n = -1;
decode->mem = decode_modrm_address(env, s, get_modrm(s, env),
decode->e.vex_class == 12);
}
return modrm;
op->has_ea = true;
op->n = -1;
decode->mem = (AddressParts){ def_seg, base, index, scale, disp };
}
static bool decode_op_size(DisasContext *s, X86OpEntry *e, X86OpSize size, MemOp *ot)

View File

@@ -788,9 +788,9 @@ static void gen_##uname(DisasContext *s, X86DecodedInsn *decode)
BINARY_IMM_SSE(VBLENDPD, blendpd)
BINARY_IMM_SSE(VBLENDPS, blendps)
BINARY_IMM_SSE(VPBLENDW, pblendw)
BINARY_IMM_SSE(VDDPS, dpps)
BINARY_IMM_SSE(VDPPS, dpps)
#define gen_helper_dppd_ymm NULL
BINARY_IMM_SSE(VDDPD, dppd)
BINARY_IMM_SSE(VDPPD, dppd)
BINARY_IMM_SSE(VMPSADBW, mpsadbw)
BINARY_IMM_SSE(PCLMULQDQ, pclmulqdq)
@@ -1236,8 +1236,8 @@ static void gen_ADCOX(DisasContext *s, X86DecodedInsn *decode, int cc_op)
}
switch (ot) {
#ifdef TARGET_X86_64
case MO_32:
#ifdef TARGET_X86_64
/* If TL is 64-bit just do everything in 64-bit arithmetic. */
tcg_gen_ext32u_tl(s->T0, s->T0);
tcg_gen_ext32u_tl(s->T1, s->T1);
@@ -1245,12 +1245,16 @@ static void gen_ADCOX(DisasContext *s, X86DecodedInsn *decode, int cc_op)
tcg_gen_add_i64(s->T0, s->T0, carry_in);
tcg_gen_shri_i64(*carry_out, s->T0, 32);
break;
case MO_64:
#endif
default:
zero = tcg_constant_tl(0);
tcg_gen_add2_tl(s->T0, *carry_out, s->T0, zero, carry_in, zero);
tcg_gen_add2_tl(s->T0, *carry_out, s->T0, *carry_out, s->T1, zero);
break;
default:
g_assert_not_reached();
}
}
@@ -1991,7 +1995,6 @@ static void gen_DIV(DisasContext *s, X86DecodedInsn *decode)
case MO_16:
gen_helper_divw_AX(tcg_env, s->T0);
break;
default:
case MO_32:
gen_helper_divl_EAX(tcg_env, s->T0);
break;
@@ -2000,6 +2003,8 @@ static void gen_DIV(DisasContext *s, X86DecodedInsn *decode)
gen_helper_divq_EAX(tcg_env, s->T0);
break;
#endif
default:
g_assert_not_reached();
}
}
@@ -2065,7 +2070,6 @@ static void gen_IDIV(DisasContext *s, X86DecodedInsn *decode)
case MO_16:
gen_helper_idivw_AX(tcg_env, s->T0);
break;
default:
case MO_32:
gen_helper_idivl_EAX(tcg_env, s->T0);
break;
@@ -2074,6 +2078,8 @@ static void gen_IDIV(DisasContext *s, X86DecodedInsn *decode)
gen_helper_idivq_EAX(tcg_env, s->T0);
break;
#endif
default:
g_assert_not_reached();
}
}
@@ -2876,7 +2882,7 @@ static inline void gen_pextr(DisasContext *s, X86DecodedInsn *decode, MemOp ot)
tcg_gen_ld_tl(s->T0, tcg_env, vector_elem_offset(&decode->op[1], ot, val));
break;
default:
abort();
g_assert_not_reached();
}
}
@@ -2923,7 +2929,7 @@ static inline void gen_pinsr(DisasContext *s, X86DecodedInsn *decode, MemOp ot)
tcg_gen_st_tl(s->T1, tcg_env, vector_elem_offset(&decode->op[0], ot, val));
break;
default:
abort();
g_assert_not_reached();
}
}

View File

@@ -374,30 +374,6 @@ static void gen_update_cc_op(DisasContext *s)
}
}
#ifdef TARGET_X86_64
#define NB_OP_SIZES 4
#else /* !TARGET_X86_64 */
#define NB_OP_SIZES 3
#endif /* !TARGET_X86_64 */
#if HOST_BIG_ENDIAN
#define REG_B_OFFSET (sizeof(target_ulong) - 1)
#define REG_H_OFFSET (sizeof(target_ulong) - 2)
#define REG_W_OFFSET (sizeof(target_ulong) - 2)
#define REG_L_OFFSET (sizeof(target_ulong) - 4)
#define REG_LH_OFFSET (sizeof(target_ulong) - 8)
#else
#define REG_B_OFFSET 0
#define REG_H_OFFSET 1
#define REG_W_OFFSET 0
#define REG_L_OFFSET 0
#define REG_LH_OFFSET 4
#endif
/* In instruction encodings for byte register accesses the
* register number usually indicates "low 8 bits of register N";
* however there are some special cases where N 4..7 indicates
@@ -454,17 +430,15 @@ static TCGv gen_op_deposit_reg_v(DisasContext *s, MemOp ot, int reg, TCGv dest,
tcg_gen_deposit_tl(dest, cpu_regs[reg], t0, 0, 16);
break;
case MO_32:
/* For x86_64, this sets the higher half of register to zero.
For i386, this is equivalent to a mov. */
#ifdef TARGET_X86_64
dest = dest ? dest : cpu_regs[reg];
tcg_gen_ext32u_tl(dest, t0);
break;
#ifdef TARGET_X86_64
case MO_64:
#endif
dest = dest ? dest : cpu_regs[reg];
tcg_gen_mov_tl(dest, t0);
break;
#endif
default:
g_assert_not_reached();
}
@@ -1609,8 +1583,8 @@ static TCGv gen_shiftd_rm_T1(DisasContext *s, MemOp ot,
tcg_gen_shri_i64(s->T0, s->T0, 32);
}
break;
case MO_64:
#endif
default:
hishift = tcg_temp_new();
tcg_gen_subi_tl(tmp, count, 1);
if (is_right) {
@@ -1639,6 +1613,9 @@ static TCGv gen_shiftd_rm_T1(DisasContext *s, MemOp ot,
tcg_constant_tl(0), s->T1);
tcg_gen_or_tl(s->T0, s->T0, s->T1);
break;
default:
g_assert_not_reached();
}
return cc_src;