* first commit for Rust support
* add CI job using Fedora + Rust nightly * fix detection of ATOMIC128 on x86_64 * fix compilation with Sphinx 8.1.0 -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmcJEKUUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroOSZQf+LlvZm9npHR6lZ9DEruhu/uf0c1gO 9+dBJiKQ1OWopSQOqEgOsLL0J123Ls4V8O3tzZwIDuuRofCB2+wKswad6CHoydJx 4p9rRXv6MLlnTqqGxemm/dPZqJ7+6L0poHoDKW+s7AgfVDshhj1RSbQfs8Ujh41F f1sdi3DzopVWtK4CE+8/UeLy5Cxlixke9SKhYQrFHrdsANARP81gxQjczKApMc1z v9qkrLtkM06VUyuvbPps7CHSHDpzx9mXcmkkPgLqLX9MfbCztzi44aVSaS9HYk5G y54dSKdY7VJEuGhG916G+GMDJyow4nhT9Gk6tWtk63TQN5nExVsoZMOmdw== =PFGL -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * first commit for Rust support * add CI job using Fedora + Rust nightly * fix detection of ATOMIC128 on x86_64 * fix compilation with Sphinx 8.1.0 # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmcJEKUUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroOSZQf+LlvZm9npHR6lZ9DEruhu/uf0c1gO # 9+dBJiKQ1OWopSQOqEgOsLL0J123Ls4V8O3tzZwIDuuRofCB2+wKswad6CHoydJx # 4p9rRXv6MLlnTqqGxemm/dPZqJ7+6L0poHoDKW+s7AgfVDshhj1RSbQfs8Ujh41F # f1sdi3DzopVWtK4CE+8/UeLy5Cxlixke9SKhYQrFHrdsANARP81gxQjczKApMc1z # v9qkrLtkM06VUyuvbPps7CHSHDpzx9mXcmkkPgLqLX9MfbCztzi44aVSaS9HYk5G # y54dSKdY7VJEuGhG916G+GMDJyow4nhT9Gk6tWtk63TQN5nExVsoZMOmdw== # =PFGL # -----END PGP SIGNATURE----- # gpg: Signature made Fri 11 Oct 2024 12:48:53 BST # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # 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: docs: use consistent markup for footnotes docs: avoid footnotes consisting of just URLs docs: fix invalid footnote syntax gitlab-ci: add Rust-enabled CI job dockerfiles: add a Dockerfile using a nightly Rust toolchain meson: ensure -mcx16 is passed when detecting ATOMIC128 meson: define qemu_isa_flags meson: fix machine option for x86_version rust: add PL011 device model rust: add utility procedural macro crate scripts/archive-source: find directory name for subprojects rust: add crate to expose bindings and interfaces meson.build: add HAVE_GLIB_WITH_ALIGNED_ALLOC flag .gitattributes: add Rust diff and merge attributes rust: add bindgen step as a meson dependency configure, meson: detect Rust toolchain build-sys: Add rust feature option Require meson version 1.5.0 Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b38d263bca
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -2,3 +2,6 @@
|
||||
*.h.inc diff=c
|
||||
*.m diff=objc
|
||||
*.py diff=python
|
||||
*.rs diff=rust
|
||||
*.rs.inc diff=rust
|
||||
Cargo.lock diff=toml merge=binary
|
||||
|
@ -120,6 +120,19 @@ build-system-fedora:
|
||||
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
|
||||
build-system-fedora-rust-nightly:
|
||||
extends:
|
||||
- .native_build_job_template
|
||||
- .native_build_artifact_template
|
||||
needs:
|
||||
job: amd64-fedora-rust-nightly-container
|
||||
variables:
|
||||
IMAGE: fedora-rust-nightly
|
||||
CONFIGURE_ARGS: --disable-docs --enable-rust
|
||||
TARGETS: aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
allow_failure: true
|
||||
|
||||
check-system-fedora:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
|
@ -27,3 +27,9 @@ python-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: python
|
||||
|
||||
amd64-fedora-rust-nightly-container:
|
||||
extends: .container_job_template
|
||||
variables:
|
||||
NAME: fedora-rust-nightly
|
||||
allow_failure: true
|
||||
|
1
Kconfig
1
Kconfig
@ -4,3 +4,4 @@ source accel/Kconfig
|
||||
source target/Kconfig
|
||||
source hw/Kconfig
|
||||
source semihosting/Kconfig
|
||||
source rust/Kconfig
|
||||
|
@ -52,3 +52,6 @@ config VFIO_USER_SERVER_ALLOWED
|
||||
|
||||
config HV_BALLOON_POSSIBLE
|
||||
bool
|
||||
|
||||
config HAVE_RUST
|
||||
bool
|
||||
|
21
MAINTAINERS
21
MAINTAINERS
@ -1134,6 +1134,11 @@ F: include/hw/*/microbit*.h
|
||||
F: tests/qtest/microbit-test.c
|
||||
F: docs/system/arm/nrf.rst
|
||||
|
||||
ARM PL011 Rust device
|
||||
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
S: Maintained
|
||||
F: rust/hw/char/pl011/
|
||||
|
||||
AVR Machines
|
||||
-------------
|
||||
|
||||
@ -3286,6 +3291,13 @@ F: hw/core/register.c
|
||||
F: include/hw/register.h
|
||||
F: include/hw/registerfields.h
|
||||
|
||||
Rust
|
||||
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
S: Maintained
|
||||
F: rust/qemu-api
|
||||
F: rust/qemu-api-macros
|
||||
F: rust/rustfmt.toml
|
||||
|
||||
SLIRP
|
||||
M: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||
S: Maintained
|
||||
@ -4183,6 +4195,15 @@ F: docs/sphinx/
|
||||
F: docs/_templates/
|
||||
F: docs/devel/docs.rst
|
||||
|
||||
Rust build system integration
|
||||
M: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
S: Maintained
|
||||
F: scripts/rust/
|
||||
F: rust/.gitignore
|
||||
F: rust/Kconfig
|
||||
F: rust/meson.build
|
||||
F: rust/wrapper.h
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
Performance Tools and Tests
|
||||
|
166
configure
vendored
166
configure
vendored
@ -207,6 +207,8 @@ for opt do
|
||||
;;
|
||||
--objcc=*) objcc="$optarg"
|
||||
;;
|
||||
--rustc=*) RUSTC="$optarg"
|
||||
;;
|
||||
--cpu=*) cpu="$optarg"
|
||||
;;
|
||||
--extra-cflags=*)
|
||||
@ -252,6 +254,8 @@ python=
|
||||
download="enabled"
|
||||
skip_meson=no
|
||||
use_containers="yes"
|
||||
rust="disabled"
|
||||
rust_target_triple=""
|
||||
gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb")
|
||||
gdb_arches=""
|
||||
|
||||
@ -310,6 +314,7 @@ objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
||||
ld="${LD-${cross_prefix}ld}"
|
||||
ranlib="${RANLIB-${cross_prefix}ranlib}"
|
||||
nm="${NM-${cross_prefix}nm}"
|
||||
readelf="${READELF-${cross_prefix}readelf}"
|
||||
strip="${STRIP-${cross_prefix}strip}"
|
||||
widl="${WIDL-${cross_prefix}widl}"
|
||||
windres="${WINDRES-${cross_prefix}windres}"
|
||||
@ -317,6 +322,8 @@ windmc="${WINDMC-${cross_prefix}windmc}"
|
||||
pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
|
||||
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
|
||||
|
||||
rustc="${RUSTC-rustc}"
|
||||
|
||||
check_define() {
|
||||
cat > $TMPC <<EOF
|
||||
#if !defined($1)
|
||||
@ -425,6 +432,7 @@ fi
|
||||
# Please keep it sorted and synchronized with meson.build's host_arch.
|
||||
host_arch=
|
||||
linux_arch=
|
||||
raw_cpu=$cpu
|
||||
case "$cpu" in
|
||||
aarch64)
|
||||
host_arch=aarch64
|
||||
@ -658,6 +666,8 @@ for opt do
|
||||
;;
|
||||
--objcc=*)
|
||||
;;
|
||||
--rustc=*)
|
||||
;;
|
||||
--make=*)
|
||||
;;
|
||||
--install=*)
|
||||
@ -777,8 +787,14 @@ for opt do
|
||||
;;
|
||||
--container-engine=*) container_engine="$optarg"
|
||||
;;
|
||||
--rust-target-triple=*) rust_target_triple="$optarg"
|
||||
;;
|
||||
--gdb=*) gdb_bin="$optarg"
|
||||
;;
|
||||
--enable-rust) rust=enabled
|
||||
;;
|
||||
--disable-rust) rust=disabled
|
||||
;;
|
||||
# everything else has the same name in configure and meson
|
||||
--*) meson_option_parse "$opt" "$optarg"
|
||||
;;
|
||||
@ -881,6 +897,7 @@ Advanced options (experts only):
|
||||
at build time [$host_cc]
|
||||
--cxx=CXX use C++ compiler CXX [$cxx]
|
||||
--objcc=OBJCC use Objective-C compiler OBJCC [$objcc]
|
||||
--rustc=RUSTC use Rust compiler RUSTC [$rustc]
|
||||
--extra-cflags=CFLAGS append extra C compiler flags CFLAGS
|
||||
--extra-cxxflags=CXXFLAGS append extra C++ compiler flags CXXFLAGS
|
||||
--extra-objcflags=OBJCFLAGS append extra Objective C compiler flags OBJCFLAGS
|
||||
@ -891,6 +908,7 @@ Advanced options (experts only):
|
||||
--python=PYTHON use specified python [$python]
|
||||
--ninja=NINJA use specified ninja [$ninja]
|
||||
--static enable static build [$static]
|
||||
--rust-target-triple=TRIPLE compilation target for Rust code [autodetect]
|
||||
--without-default-features default all --enable-* options to "disabled"
|
||||
--without-default-devices do not include any device that is not needed to
|
||||
start the emulator (only use if you are including
|
||||
@ -1166,6 +1184,132 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# detect rust triple
|
||||
|
||||
if test "$rust" != disabled && has "$rustc" && $rustc -vV > "${TMPDIR1}/${TMPB}.out"; then
|
||||
rust_host_triple=$(sed -n 's/^host: //p' "${TMPDIR1}/${TMPB}.out")
|
||||
else
|
||||
if test "$rust" = enabled; then
|
||||
error_exit "could not execute rustc binary \"$rustc\""
|
||||
fi
|
||||
rust=disabled
|
||||
fi
|
||||
if test "$rust" != disabled && test -z "$rust_target_triple"; then
|
||||
# arch and os generally matches between meson and rust
|
||||
rust_arch=$host_arch
|
||||
rust_os=$host_os
|
||||
rust_machine=unknown
|
||||
rust_osvariant=
|
||||
|
||||
# tweak rust_os if needed; also, machine and variant depend on the OS
|
||||
android=no
|
||||
case "$host_os" in
|
||||
darwin)
|
||||
# e.g. aarch64-apple-darwin
|
||||
rust_machine=apple
|
||||
;;
|
||||
|
||||
linux)
|
||||
# detect android/glibc/musl
|
||||
if check_define __ANDROID__; then
|
||||
rust_osvariant=android
|
||||
android=yes
|
||||
else
|
||||
cat > $TMPC << EOF
|
||||
#define _GNU_SOURCE
|
||||
#include <features.h>
|
||||
#ifndef __USE_GNU
|
||||
error using musl
|
||||
#endif
|
||||
EOF
|
||||
if compile_object; then
|
||||
rust_osvariant=gnu
|
||||
else
|
||||
rust_osvariant=musl
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$host_arch" in
|
||||
arm)
|
||||
# e.g. arm-unknown-linux-gnueabi, arm-unknown-linux-gnueabihf
|
||||
write_c_skeleton
|
||||
compile_object
|
||||
if $READELF -A $TMPO | grep Tag_API_VFP_args: > /dev/null; then
|
||||
rust_osvariant=${rust_osvariant}eabihf
|
||||
else
|
||||
rust_osvariant=${rust_osvariant}eabi
|
||||
fi
|
||||
;;
|
||||
|
||||
mips64)
|
||||
# e.g. mips64-unknown-linux-gnuabi64
|
||||
rust_osvariant=${rust_osvariant}abi64
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
netbsd)
|
||||
# e.g. arm-unknown-netbsd-eabihf
|
||||
test "$host_arch" = arm && rust_osvariant=eabihf
|
||||
;;
|
||||
|
||||
sunos)
|
||||
rust_machine=pc
|
||||
rust_os=solaris
|
||||
;;
|
||||
|
||||
windows)
|
||||
# e.g. aarch64-pc-windows-gnullvm, x86_64-pc-windows-gnu (MSVC not supported)
|
||||
rust_machine=pc
|
||||
if test "$host_arch" = aarch64; then
|
||||
rust_osvariant=gnullvm
|
||||
else
|
||||
rust_osvariant=gnu
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# now tweak the architecture part, possibly based on pre-canonicalization --cpu
|
||||
case "$host_arch" in
|
||||
arm)
|
||||
# preserve ISA version (armv7 etc.) from $raw_cpu if passed via --cpu
|
||||
rust_arch=$raw_cpu
|
||||
test "$rust_arch" = arm && test "$rust_os" != linux && rust_arch=armv7
|
||||
;;
|
||||
|
||||
mips|mips64)
|
||||
# preserve ISA version (mipsisa64r6 etc.) and include endianness
|
||||
rust_arch=${raw_cpu%el}
|
||||
test "$bigendian" = no && rust_arch=${rust_arch}el
|
||||
;;
|
||||
|
||||
riscv32|riscv64)
|
||||
# e.g. riscv64gc-unknown-linux-gnu, but riscv64-linux-android
|
||||
test "$android" = no && rust_arch=${rust_arch}gc
|
||||
;;
|
||||
|
||||
sparc64)
|
||||
if test "$rust_os" = solaris; then
|
||||
rust_arch=sparcv9
|
||||
rust_machine=sun
|
||||
fi
|
||||
;;
|
||||
|
||||
x86_64)
|
||||
# e.g. x86_64-unknown-linux-gnux32
|
||||
test "$raw_cpu" = x32 && rust_osvariant=${rust_osvariant}x32
|
||||
;;
|
||||
esac
|
||||
|
||||
if test "$android" = yes; then
|
||||
# e.g. aarch64-linux-android
|
||||
rust_target_triple=$rust_arch-$rust_os-$rust_osvariant
|
||||
else
|
||||
rust_target_triple=$rust_arch-$rust_machine-$rust_os${rust_osvariant:+-$rust_osvariant}
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# functions to probe cross compilers
|
||||
|
||||
@ -1628,6 +1772,9 @@ if test "$container" != no; then
|
||||
echo "RUNC=$runc" >> $config_host_mak
|
||||
fi
|
||||
echo "SUBDIRS=$subdirs" >> $config_host_mak
|
||||
if test "$rust" != disabled; then
|
||||
echo "RUST_TARGET_TRIPLE=$rust_target_triple" >> $config_host_mak
|
||||
fi
|
||||
echo "PYTHON=$python" >> $config_host_mak
|
||||
echo "MKVENV_ENSUREGROUP=$mkvenv ensuregroup $mkvenv_online_flag" >> $config_host_mak
|
||||
echo "GENISOIMAGE=$genisoimage" >> $config_host_mak
|
||||
@ -1764,12 +1911,20 @@ if test "$skip_meson" = no; then
|
||||
echo "c = [$(meson_quote $cc $CPU_CFLAGS)]" >> $cross
|
||||
test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross
|
||||
test -n "$objcc" && echo "objc = [$(meson_quote $objcc $CPU_CFLAGS)]" >> $cross
|
||||
if test "$rust" != disabled; then
|
||||
if test "$rust_host_triple" != "$rust_target_triple"; then
|
||||
echo "rust = [$(meson_quote $rustc --target "$rust_target_triple")]" >> $cross
|
||||
else
|
||||
echo "rust = [$(meson_quote $rustc)]" >> $cross
|
||||
fi
|
||||
fi
|
||||
echo "ar = [$(meson_quote $ar)]" >> $cross
|
||||
echo "dlltool = [$(meson_quote $dlltool)]" >> $cross
|
||||
echo "nm = [$(meson_quote $nm)]" >> $cross
|
||||
echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross
|
||||
echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross
|
||||
echo "ranlib = [$(meson_quote $ranlib)]" >> $cross
|
||||
echo "readelf = [$(meson_quote $readelf)]" >> $cross
|
||||
if has $sdl2_config; then
|
||||
echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross
|
||||
fi
|
||||
@ -1799,6 +1954,9 @@ if test "$skip_meson" = no; then
|
||||
echo "# Automatically generated by configure - do not modify" > $native
|
||||
echo "[binaries]" >> $native
|
||||
echo "c = [$(meson_quote $host_cc)]" >> $native
|
||||
if test "$rust" != disabled; then
|
||||
echo "rust = [$(meson_quote $rustc)]" >> $cross
|
||||
fi
|
||||
mv $native config-meson.native
|
||||
meson_option_add --native-file
|
||||
meson_option_add config-meson.native
|
||||
@ -1817,6 +1975,7 @@ if test "$skip_meson" = no; then
|
||||
test "$pie" = no && meson_option_add -Db_pie=false
|
||||
|
||||
# QEMU options
|
||||
test "$rust" != "auto" && meson_option_add "-Drust=$rust"
|
||||
test "$cfi" != false && meson_option_add "-Dcfi=$cfi" "-Db_lto=$cfi"
|
||||
test "$docs" != auto && meson_option_add "-Ddocs=$docs"
|
||||
test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE"
|
||||
@ -1901,3 +2060,10 @@ echo ' "$@"' >>config.status
|
||||
chmod +x config.status
|
||||
|
||||
rm -r "$TMPDIR1"
|
||||
|
||||
if test "$rust" != disabled; then
|
||||
echo '\nINFO: Rust bindings generation with `bindgen` might fail in some cases where'
|
||||
echo 'the detected `libclang` does not match the expected `clang` version/target. In'
|
||||
echo 'this case you must pass the path to `clang` and `libclang` to your build'
|
||||
echo 'command invocation using the environment variables CLANG_PATH and LIBCLANG_PATH'
|
||||
fi
|
||||
|
@ -204,7 +204,7 @@ They come in six kinds:
|
||||
before the second with respect to the other components of the system.
|
||||
Therefore, unlike ``smp_rmb()`` or ``qatomic_load_acquire()``,
|
||||
``smp_read_barrier_depends()`` can be just a compiler barrier on
|
||||
weakly-ordered architectures such as Arm or PPC[#]_.
|
||||
weakly-ordered architectures such as Arm or PPC\ [#alpha]_.
|
||||
|
||||
Note that the first load really has to have a _data_ dependency and not
|
||||
a control dependency. If the address for the second load is dependent
|
||||
@ -212,7 +212,7 @@ They come in six kinds:
|
||||
than actually loading the address itself, then it's a _control_
|
||||
dependency and a full read barrier or better is required.
|
||||
|
||||
.. [#] The DEC Alpha is an exception, because ``smp_read_barrier_depends()``
|
||||
.. [#alpha] The DEC Alpha is an exception, because ``smp_read_barrier_depends()``
|
||||
needs a processor barrier. On strongly-ordered architectures such
|
||||
as x86 or s390, ``smp_rmb()`` and ``qatomic_load_acquire()`` can
|
||||
also be compiler barriers only.
|
||||
@ -295,7 +295,7 @@ Acquire/release pairing and the *synchronizes-with* relation
|
||||
------------------------------------------------------------
|
||||
|
||||
Atomic operations other than ``qatomic_set()`` and ``qatomic_read()`` have
|
||||
either *acquire* or *release* semantics [#rmw]_. This has two effects:
|
||||
either *acquire* or *release* semantics\ [#rmw]_. This has two effects:
|
||||
|
||||
.. [#rmw] Read-modify-write operations can have both---acquire applies to the
|
||||
read part, and release to the write.
|
||||
|
@ -145,13 +145,13 @@ was installed in the ``site-packages`` directory of another interpreter,
|
||||
or with the wrong ``pip`` program.
|
||||
|
||||
If a package is available for the chosen interpreter, ``configure``
|
||||
prepares a small script that invokes it from the venv itself[#distlib]_.
|
||||
prepares a small script that invokes it from the venv itself\ [#distlib]_.
|
||||
If not, ``configure`` can also optionally install dependencies in the
|
||||
virtual environment with ``pip``, either from wheels in ``python/wheels``
|
||||
or by downloading the package with PyPI. Downloading can be disabled with
|
||||
``--disable-download``; and anyway, it only happens when a ``configure``
|
||||
option (currently, only ``--enable-docs``) is explicitly enabled but
|
||||
the dependencies are not present[#pip]_.
|
||||
the dependencies are not present\ [#pip]_.
|
||||
|
||||
.. [#distlib] The scripts are created based on the package's metadata,
|
||||
specifically the ``console_script`` entry points. This is the
|
||||
@ -333,7 +333,7 @@ into each emulator:
|
||||
|
||||
``default-configs/targets/*.mak``
|
||||
These files mostly define symbols that appear in the ``*-config-target.h``
|
||||
file for each emulator [#cfgtarget]_. However, the ``TARGET_ARCH``
|
||||
file for each emulator\ [#cfgtarget]_. However, the ``TARGET_ARCH``
|
||||
and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and
|
||||
``target/`` subdirectories that are compiled into each target.
|
||||
|
||||
|
@ -95,7 +95,7 @@ guest CPU state in case of a guest CPU exception. This is passed
|
||||
to ``cpu_restore_state()``. Therefore the value should either be 0,
|
||||
to indicate that the guest CPU state is already synchronized, or
|
||||
the result of ``GETPC()`` from the top level ``HELPER(foo)``
|
||||
function, which is a return address into the generated code [#gpc]_.
|
||||
function, which is a return address into the generated code\ [#gpc]_.
|
||||
|
||||
.. [#gpc] Note that ``GETPC()`` should be used with great care: calling
|
||||
it in other functions that are *not* the top level
|
||||
|
@ -99,9 +99,9 @@ members of the QEMU community, you should make arrangements to attend
|
||||
a `KeySigningParty <https://wiki.qemu.org/KeySigningParty>`__ (for
|
||||
example at KVM Forum) or make alternative arrangements to have your
|
||||
key signed by an attendee. Key signing requires meeting another
|
||||
community member **in person** [#]_ so please make appropriate
|
||||
community member **in person**\ [#2020]_ so please make appropriate
|
||||
arrangements.
|
||||
|
||||
.. [#] In recent pandemic times we have had to exercise some
|
||||
.. [#2020] In recent pandemic times we have had to exercise some
|
||||
flexibility here. Maintainers still need to sign their pull
|
||||
requests though.
|
||||
|
@ -44,7 +44,7 @@ Use-cases
|
||||
|
||||
The mapped-ram feature was designed for use cases where the migration
|
||||
stream will be directed to a file in the filesystem and not
|
||||
immediately restored on the destination VM [#]_. These could be
|
||||
immediately restored on the destination VM\ [#alternatives]_. These could be
|
||||
thought of as snapshots. We can further categorize them into live and
|
||||
non-live.
|
||||
|
||||
@ -70,7 +70,7 @@ mapped-ram in this scenario is portability since background-snapshot
|
||||
depends on async dirty tracking (KVM_GET_DIRTY_LOG) which is not
|
||||
supported outside of Linux.
|
||||
|
||||
.. [#] While this same effect could be obtained with the usage of
|
||||
.. [#alternatives] While this same effect could be obtained with the usage of
|
||||
snapshots or the ``file:`` migration alone, mapped-ram provides
|
||||
a performance increase for VMs with larger RAM sizes (10s to
|
||||
100s of GiBs), specially if the VM has been stopped beforehand.
|
||||
|
@ -30,15 +30,20 @@ OS modules are generally written using low level languages such as C and
|
||||
low level assembly machine language. Writing test routines in a low level
|
||||
language makes things more cumbersome. These and other reasons makes using
|
||||
bios-bits very attractive for testing bioses. More details on the inspiration
|
||||
for developing biosbits and its real life uses can be found in [#a]_ and [#b]_.
|
||||
for developing biosbits and its real life uses were presented `at Plumbers
|
||||
in 2011 <Plumbers_>`__ and `at Linux.conf.au in 2012 <Linux.conf.au_>`__.
|
||||
|
||||
For QEMU, we maintain a fork of bios bits in gitlab along with all the
|
||||
dependent submodules `here <https://gitlab.com/qemu-project/biosbits-bits>`__.
|
||||
This fork contains numerous fixes, a newer acpica and changes specific to
|
||||
running these functional QEMU tests using bits. The author of this document
|
||||
is the sole maintainer of the QEMU fork of bios bits repository. For more
|
||||
information, please see author's `FOSDEM talk on this bios-bits based test
|
||||
framework <https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/>`__.
|
||||
For QEMU, we maintain a fork of bios bits in `gitlab`_, along with all
|
||||
the dependent submodules. This fork contains numerous fixes, a newer
|
||||
acpica and changes specific to running these functional QEMU tests using
|
||||
bits. The author of this document is the current maintainer of the QEMU
|
||||
fork of bios bits repository. For more information, please see `the
|
||||
author's FOSDEM presentation <FOSDEM_>`__ on this bios-bits based test framework.
|
||||
|
||||
.. _Plumbers: https://blog.linuxplumbersconf.org/2011/ocw/system/presentations/867/original/bits.pdf
|
||||
.. _Linux.conf.au: https://www.youtube.com/watch?v=36QIepyUuhg
|
||||
.. _gitlab: https://gitlab.com/qemu-project/biosbits-bits
|
||||
.. _FOSDEM: https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/
|
||||
|
||||
*********************************
|
||||
Description of the test framework
|
||||
@ -148,8 +153,3 @@ Under ``tests/functional/`` as the root we have:
|
||||
|
||||
Author: Ani Sinha <anisinha@redhat.com>
|
||||
|
||||
References:
|
||||
-----------
|
||||
.. [#a] https://blog.linuxplumbersconf.org/2011/ocw/system/presentations/867/original/bits.pdf
|
||||
.. [#b] https://www.youtube.com/watch?v=36QIepyUuhg
|
||||
.. [#c] https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/
|
||||
|
@ -54,11 +54,11 @@ Data Register
|
||||
-------------
|
||||
|
||||
* Read/Write (writes ignored as of QEMU v2.4, but see the DMA interface)
|
||||
* Location: platform dependent (IOport [#]_ or MMIO)
|
||||
* Location: platform dependent (IOport\ [#placement]_ or MMIO)
|
||||
* Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO)
|
||||
* Endianness: string-preserving
|
||||
|
||||
.. [#]
|
||||
.. [#placement]
|
||||
On platforms where the data register is exposed as an IOport, its
|
||||
port number will always be one greater than the port number of the
|
||||
selector register. In other words, the two ports overlap, and can not
|
||||
|
@ -9,11 +9,12 @@ The consumption is reported via MSRs (model specific registers) like
|
||||
MSR_PKG_ENERGY_STATUS for the CPU package power domain. These MSRs are 64 bits
|
||||
registers that represent the accumulated energy consumption in micro Joules.
|
||||
|
||||
Thanks to the MSR Filtering patch [#a]_ not all MSRs are handled by KVM. Some
|
||||
of them can now be handled by the userspace (QEMU). It uses a mechanism called
|
||||
"MSR filtering" where a list of MSRs is given at init time of a VM to KVM so
|
||||
that a callback is put in place. The design of this patch uses only this
|
||||
mechanism for handling the MSRs between guest/host.
|
||||
Thanks to KVM's `MSR filtering <msr-filter-patch_>`__ functionality,
|
||||
not all MSRs are handled by KVM. Some of them can now be handled by the
|
||||
userspace (QEMU); a list of MSRs is given at VM creation time to KVM, and
|
||||
a userspace exit occurs when they are accessed.
|
||||
|
||||
.. _msr-filter-patch: https://patchwork.kernel.org/project/kvm/patch/20200916202951.23760-7-graf@amazon.com/
|
||||
|
||||
At the moment the following MSRs are involved:
|
||||
|
||||
@ -92,9 +93,12 @@ found by the sysconf system call. A typical value of clock ticks per second is
|
||||
package has 4 cores, 400 ticks maximum can be scheduled on all the cores
|
||||
of the package for a period of 1 second.
|
||||
|
||||
The /proc/[pid]/stat [#b]_ is a sysfs file that can give the executed time of a
|
||||
process with the [pid] as the process ID. It gives the amount of ticks the
|
||||
process has been scheduled in userspace (utime) and kernel space (stime).
|
||||
`/proc/[pid]/stat <stat_>`__ is a procfs file that can give the executed
|
||||
time of a process with the [pid] as the process ID. It gives the amount
|
||||
of ticks the process has been scheduled in userspace (utime) and kernel
|
||||
space (stime).
|
||||
|
||||
.. _stat: https://man7.org/linux/man-pages/man5/proc.5.html
|
||||
|
||||
By reading those metrics for a thread, one can calculate the ratio of time the
|
||||
package has spent executing the thread.
|
||||
@ -148,8 +152,3 @@ Current Limitations
|
||||
- Only the Package Power-Plane (MSR_PKG_ENERGY_STATUS) is reported at the
|
||||
moment.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
.. [#a] https://patchwork.kernel.org/project/kvm/patch/20200916202951.23760-7-graf@amazon.com/
|
||||
.. [#b] https://man7.org/linux/man-pages/man5/proc.5.html
|
||||
|
@ -20,7 +20,8 @@ config ARM_VIRT
|
||||
select PCI_EXPRESS
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
select PFLASH_CFI01
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL031 # RTC
|
||||
select PL061 # GPIO
|
||||
select GPIO_PWR
|
||||
@ -73,7 +74,8 @@ config HIGHBANK
|
||||
select AHCI
|
||||
select ARM_TIMER # sp804
|
||||
select ARM_V7M
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL022 # SPI
|
||||
select PL031 # RTC
|
||||
select PL061 # GPIO
|
||||
@ -86,7 +88,8 @@ config INTEGRATOR
|
||||
depends on TCG && ARM
|
||||
select ARM_TIMER
|
||||
select INTEGRATOR_DEBUG
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL031 # RTC
|
||||
select PL041 # audio
|
||||
select PL050 # keyboard/mouse
|
||||
@ -104,7 +107,8 @@ config MUSCA
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select ARMSSE
|
||||
select PL011
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL031
|
||||
select SPLIT_IRQ
|
||||
select UNIMP
|
||||
@ -169,7 +173,8 @@ config REALVIEW
|
||||
select WM8750 # audio codec
|
||||
select LSI_SCSI_PCI
|
||||
select PCI
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL031 # RTC
|
||||
select PL041 # audio codec
|
||||
select PL050 # keyboard/mouse
|
||||
@ -194,7 +199,8 @@ config SBSA_REF
|
||||
select PCI_EXPRESS
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
select PFLASH_CFI01
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL031 # RTC
|
||||
select PL061 # GPIO
|
||||
select USB_XHCI_SYSBUS
|
||||
@ -218,7 +224,8 @@ config STELLARIS
|
||||
select ARM_V7M
|
||||
select CMSDK_APB_WATCHDOG
|
||||
select I2C
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL022 # SPI
|
||||
select PL061 # GPIO
|
||||
select SSD0303 # OLED display
|
||||
@ -278,7 +285,8 @@ config VEXPRESS
|
||||
select ARM_TIMER # sp804
|
||||
select LAN9118
|
||||
select PFLASH_CFI01
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select PL041 # audio codec
|
||||
select PL181 # display
|
||||
select REALVIEW
|
||||
@ -362,7 +370,8 @@ config RASPI
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select FRAMEBUFFER
|
||||
select PL011 # UART
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select SDHCI
|
||||
select USB_DWC2
|
||||
select BCM2835_SPI
|
||||
@ -437,7 +446,8 @@ config XLNX_VERSAL
|
||||
select ARM_GIC
|
||||
select CPU_CLUSTER
|
||||
select DEVICE_TREE
|
||||
select PL011
|
||||
select PL011 if !HAVE_RUST # UART
|
||||
select X_PL011_RUST if HAVE_RUST # UART
|
||||
select CADENCE
|
||||
select VIRTIO_MMIO
|
||||
select UNIMP
|
||||
|
158
meson.build
158
meson.build
@ -1,4 +1,4 @@
|
||||
project('qemu', ['c'], meson_version: '>=1.1.0',
|
||||
project('qemu', ['c'], meson_version: '>=1.5.0',
|
||||
default_options: ['warning_level=1', 'c_std=gnu11', 'cpp_std=gnu++11', 'b_colorout=auto',
|
||||
'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'],
|
||||
version: files('VERSION'))
|
||||
@ -70,6 +70,19 @@ if host_os == 'darwin' and \
|
||||
all_languages += ['objc']
|
||||
objc = meson.get_compiler('objc')
|
||||
endif
|
||||
have_rust = false
|
||||
if not get_option('rust').disabled() and add_languages('rust', required: get_option('rust'), native: false)
|
||||
rustc = meson.get_compiler('rust')
|
||||
have_rust = true
|
||||
if rustc.version().version_compare('<1.80.0')
|
||||
if get_option('rust').enabled()
|
||||
error('rustc version ' + rustc.version() + ' is unsupported: Please upgrade to at least 1.80.0')
|
||||
else
|
||||
warning('rustc version ' + rustc.version() + ' is unsupported: Disabling Rust compilation. Please upgrade to at least 1.80.0 to use Rust.')
|
||||
have_rust = false
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
dtrace = not_found
|
||||
stap = not_found
|
||||
@ -322,6 +335,10 @@ elif host_os == 'windows'
|
||||
endif
|
||||
endif
|
||||
|
||||
# Choose instruction set (currently x86-only)
|
||||
|
||||
qemu_isa_flags = []
|
||||
|
||||
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
|
||||
# use i686 as default anyway, but for those that don't, an explicit
|
||||
# specification is necessary
|
||||
@ -338,7 +355,7 @@ if host_arch == 'i386' and not cc.links('''
|
||||
sfaa(&val);
|
||||
return val;
|
||||
}''')
|
||||
qemu_common_flags = ['-march=i486'] + qemu_common_flags
|
||||
qemu_isa_flags += ['-march=i486']
|
||||
endif
|
||||
|
||||
# Pick x86-64 baseline version
|
||||
@ -354,29 +371,31 @@ if host_arch in ['i386', 'x86_64']
|
||||
else
|
||||
# present on basically all processors but technically not part of
|
||||
# x86-64-v1, so only include -mneeded for x86-64 version 2 and above
|
||||
qemu_common_flags = ['-mcx16'] + qemu_common_flags
|
||||
qemu_isa_flags += ['-mcx16']
|
||||
endif
|
||||
endif
|
||||
if get_option('x86_version') >= '2'
|
||||
qemu_common_flags = ['-mpopcnt'] + qemu_common_flags
|
||||
qemu_common_flags = cc.get_supported_arguments('-mneeded') + qemu_common_flags
|
||||
qemu_isa_flags += ['-mpopcnt']
|
||||
qemu_isa_flags += cc.get_supported_arguments('-mneeded')
|
||||
endif
|
||||
if get_option('x86_version') >= '3'
|
||||
qemu_common_flags = ['-mmovbe', '-mabm', '-mbmi1', '-mbmi2', '-mfma', '-mf16c'] + qemu_common_flags
|
||||
qemu_isa_flags += ['-mmovbe', '-mabm', '-mbmi', '-mbmi2', '-mfma', '-mf16c']
|
||||
endif
|
||||
|
||||
# add required vector instruction set (each level implies those below)
|
||||
if get_option('x86_version') == '1'
|
||||
qemu_common_flags = ['-msse2'] + qemu_common_flags
|
||||
qemu_isa_flags += ['-msse2']
|
||||
elif get_option('x86_version') == '2'
|
||||
qemu_common_flags = ['-msse4.2'] + qemu_common_flags
|
||||
qemu_isa_flags += ['-msse4.2']
|
||||
elif get_option('x86_version') == '3'
|
||||
qemu_common_flags = ['-mavx2'] + qemu_common_flags
|
||||
qemu_isa_flags += ['-mavx2']
|
||||
elif get_option('x86_version') == '4'
|
||||
qemu_common_flags = ['-mavx512f', '-mavx512bw', '-mavx512cd', '-mavx512dq', '-mavx512vl'] + qemu_common_flags
|
||||
qemu_isa_flags += ['-mavx512f', '-mavx512bw', '-mavx512cd', '-mavx512dq', '-mavx512vl']
|
||||
endif
|
||||
endif
|
||||
|
||||
qemu_common_flags = qemu_isa_flags + qemu_common_flags
|
||||
|
||||
if get_option('prefer_static')
|
||||
qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static'
|
||||
endif
|
||||
@ -935,7 +954,9 @@ have_xen_pci_passthrough = get_option('xen_pci_passthrough') \
|
||||
################
|
||||
|
||||
# When bumping glib minimum version, please check also whether to increase
|
||||
# the _WIN32_WINNT setting in osdep.h according to the value from glib
|
||||
# the _WIN32_WINNT setting in osdep.h according to the value from glib.
|
||||
# You should also check if any of the glib.version() checks
|
||||
# below can also be removed.
|
||||
glib_req_ver = '>=2.66.0'
|
||||
glib_pc = dependency('glib-2.0', version: glib_req_ver, required: true,
|
||||
method: 'pkg-config')
|
||||
@ -985,6 +1006,9 @@ glib = declare_dependency(dependencies: [glib_pc, gmodule],
|
||||
# TODO: remove this check and the corresponding workaround (qtree) when
|
||||
# the minimum supported glib is >= 2.75.3
|
||||
glib_has_gslice = glib.version().version_compare('<2.75.3')
|
||||
# Check whether glib has the aligned_alloc family of functions.
|
||||
# <https://docs.gtk.org/glib/func.aligned_alloc.html>
|
||||
glib_has_aligned_alloc = glib.version().version_compare('>=2.72.0')
|
||||
|
||||
# override glib dep to include the above refinements
|
||||
meson.override_dependency('glib-2.0', glib)
|
||||
@ -2158,6 +2182,7 @@ endif
|
||||
|
||||
config_host_data = configuration_data()
|
||||
|
||||
config_host_data.set('CONFIG_HAVE_RUST', have_rust)
|
||||
audio_drivers_selected = []
|
||||
if have_system
|
||||
audio_drivers_available = {
|
||||
@ -2516,6 +2541,7 @@ config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
|
||||
config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
|
||||
config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
|
||||
config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice)
|
||||
config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc)
|
||||
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
|
||||
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
|
||||
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
|
||||
@ -2806,7 +2832,7 @@ config_host_data.set('CONFIG_ATOMIC64', cc.links('''
|
||||
__atomic_exchange_n(&x, y, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_add(&x, y, __ATOMIC_RELAXED);
|
||||
return 0;
|
||||
}'''))
|
||||
}''', args: qemu_isa_flags))
|
||||
|
||||
has_int128_type = cc.compiles('''
|
||||
__int128_t a;
|
||||
@ -2840,7 +2866,7 @@ if has_int128_type
|
||||
__atomic_compare_exchange_n(&p[4], &p[5], p[6], 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
|
||||
return 0;
|
||||
}'''
|
||||
has_atomic128 = cc.links(atomic_test_128)
|
||||
has_atomic128 = cc.links(atomic_test_128, args: qemu_isa_flags)
|
||||
|
||||
config_host_data.set('CONFIG_ATOMIC128', has_atomic128)
|
||||
|
||||
@ -2849,7 +2875,8 @@ if has_int128_type
|
||||
# without optimization enabled. Try again with optimizations locally
|
||||
# enabled for the function. See
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107389
|
||||
has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128)
|
||||
has_atomic128_opt = cc.links('__attribute__((optimize("O1")))' + atomic_test_128,
|
||||
args: qemu_isa_flags)
|
||||
config_host_data.set('CONFIG_ATOMIC128_OPT', has_atomic128_opt)
|
||||
|
||||
if not has_atomic128_opt
|
||||
@ -2860,7 +2887,7 @@ if has_int128_type
|
||||
__sync_val_compare_and_swap_16(&x, y, x);
|
||||
return 0;
|
||||
}
|
||||
'''))
|
||||
''', args: qemu_isa_flags))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -3097,7 +3124,8 @@ host_kconfig = \
|
||||
(host_os == 'linux' ? ['CONFIG_LINUX=y'] : []) + \
|
||||
(multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \
|
||||
(vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_ALLOWED=y'] : []) + \
|
||||
(hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : [])
|
||||
(hv_balloon ? ['CONFIG_HV_BALLOON_POSSIBLE=y'] : []) + \
|
||||
(have_rust ? ['CONFIG_HAVE_RUST=y'] : [])
|
||||
|
||||
ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ]
|
||||
|
||||
@ -3491,6 +3519,7 @@ qom_ss = ss.source_set()
|
||||
system_ss = ss.source_set()
|
||||
specific_fuzz_ss = ss.source_set()
|
||||
specific_ss = ss.source_set()
|
||||
rust_devices_ss = ss.source_set()
|
||||
stub_ss = ss.source_set()
|
||||
trace_ss = ss.source_set()
|
||||
user_ss = ss.source_set()
|
||||
@ -3877,6 +3906,74 @@ common_all = static_library('common',
|
||||
implicit_include_directories: false,
|
||||
dependencies: common_ss.all_dependencies())
|
||||
|
||||
if have_rust and have_system
|
||||
rustc_args = run_command(
|
||||
find_program('scripts/rust/rustc_args.py'),
|
||||
'--config-headers', meson.project_build_root() / 'config-host.h',
|
||||
capture : true,
|
||||
check: true).stdout().strip().split()
|
||||
rustc_args += ['-D', 'unsafe_op_in_unsafe_fn']
|
||||
bindgen_args = [
|
||||
'--disable-header-comment',
|
||||
'--raw-line', '// @generated',
|
||||
'--ctypes-prefix', 'core::ffi',
|
||||
'--formatter', 'rustfmt',
|
||||
'--generate-block',
|
||||
'--generate-cstr',
|
||||
'--impl-debug',
|
||||
'--merge-extern-blocks',
|
||||
'--no-doc-comments',
|
||||
'--use-core',
|
||||
'--with-derive-default',
|
||||
'--no-size_t-is-usize',
|
||||
'--no-layout-tests',
|
||||
'--no-prepend-enum-name',
|
||||
'--allowlist-file', meson.project_source_root() + '/include/.*',
|
||||
'--allowlist-file', meson.project_source_root() + '/.*',
|
||||
'--allowlist-file', meson.project_build_root() + '/.*'
|
||||
]
|
||||
c_enums = [
|
||||
'DeviceCategory',
|
||||
'GpioPolarity',
|
||||
'MachineInitPhase',
|
||||
'MemoryDeviceInfoKind',
|
||||
'MigrationPolicy',
|
||||
'MigrationPriority',
|
||||
'QEMUChrEvent',
|
||||
'QEMUClockType',
|
||||
'device_endian',
|
||||
'module_init_type',
|
||||
]
|
||||
foreach enum : c_enums
|
||||
bindgen_args += ['--rustified-enum', enum]
|
||||
endforeach
|
||||
c_bitfields = [
|
||||
'ClockEvent',
|
||||
'VMStateFlags',
|
||||
]
|
||||
foreach enum : c_bitfields
|
||||
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
|
||||
bindings_rs = import('rust').bindgen(
|
||||
input: 'rust/wrapper.h',
|
||||
dependencies: common_ss.all_dependencies(),
|
||||
output: 'bindings.rs',
|
||||
include_directories: include_directories('.', 'include'),
|
||||
bindgen_version: ['>=0.69.4'],
|
||||
args: bindgen_args,
|
||||
)
|
||||
subdir('rust')
|
||||
endif
|
||||
|
||||
|
||||
feature_to_c = find_program('scripts/feature_to_c.py')
|
||||
|
||||
if host_os == 'darwin'
|
||||
@ -3970,6 +4067,29 @@ foreach target : target_dirs
|
||||
arch_srcs += target_specific.sources()
|
||||
arch_deps += target_specific.dependencies()
|
||||
|
||||
if have_rust and have_system
|
||||
target_rust = rust_devices_ss.apply(config_target, strict: false)
|
||||
crates = []
|
||||
foreach dep : target_rust.dependencies()
|
||||
crates += dep.get_variable('crate')
|
||||
endforeach
|
||||
if crates.length() > 0
|
||||
rlib_rs = custom_target('rust_' + target.underscorify() + '.rs',
|
||||
output: 'rust_' + target.underscorify() + '.rs',
|
||||
command: [find_program('scripts/rust/rust_root_crate.sh')] + crates,
|
||||
capture: true,
|
||||
build_by_default: true,
|
||||
build_always_stale: true)
|
||||
rlib = static_library('rust_' + target.underscorify(),
|
||||
rlib_rs,
|
||||
dependencies: target_rust.dependencies(),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_args: rustc_args,
|
||||
rust_abi: 'c')
|
||||
arch_deps += declare_dependency(link_whole: [rlib])
|
||||
endif
|
||||
endif
|
||||
|
||||
# allow using headers from the dependencies but do not include the sources,
|
||||
# because this emulator only needs those in "objects". For external
|
||||
# dependencies, the full dependency is included below in the executable.
|
||||
@ -4308,6 +4428,12 @@ if 'objc' in all_languages
|
||||
else
|
||||
summary_info += {'Objective-C compiler': false}
|
||||
endif
|
||||
summary_info += {'Rust support': have_rust}
|
||||
if have_rust
|
||||
summary_info += {'rustc version': rustc.version()}
|
||||
summary_info += {'rustc': ' '.join(rustc.cmd_array())}
|
||||
summary_info += {'Rust target': config_host['RUST_TARGET_TRIPLE']}
|
||||
endif
|
||||
option_cflags = (get_option('debug') ? ['-g'] : [])
|
||||
if get_option('optimization') != 'plain'
|
||||
option_cflags += ['-O' + get_option('optimization')]
|
||||
|
@ -373,3 +373,6 @@ option('hexagon_idef_parser', type : 'boolean', value : true,
|
||||
|
||||
option('x86_version', type : 'combo', choices : ['0', '1', '2', '3', '4'], value: '1',
|
||||
description: 'tweak required x86_64 architecture version beyond compiler default')
|
||||
|
||||
option('rust', type: 'feature', value: 'auto',
|
||||
description: 'Rust support')
|
||||
|
@ -41,8 +41,8 @@ def main() -> int:
|
||||
parser.parse_args()
|
||||
|
||||
packages = {
|
||||
"meson==1.2.3":
|
||||
"4533a43c34548edd1f63a276a42690fce15bde9409bcf20c4b8fa3d7e4d7cac1",
|
||||
"meson==1.5.0":
|
||||
"52b34f4903b882df52ad0d533146d4b992c018ea77399f825579737672ae7b20",
|
||||
}
|
||||
|
||||
vendor_dir = Path(__file__, "..", "..", "wheels").resolve()
|
||||
|
Binary file not shown.
BIN
python/wheels/meson-1.5.0-py3-none-any.whl
Normal file
BIN
python/wheels/meson-1.5.0-py3-none-any.whl
Normal file
Binary file not shown.
@ -19,7 +19,7 @@
|
||||
|
||||
[meson]
|
||||
# The install key should match the version in python/wheels/
|
||||
meson = { accepted = ">=1.1.0", installed = "1.2.3", canary = "meson" }
|
||||
meson = { accepted = ">=1.5.0", installed = "1.5.0", canary = "meson" }
|
||||
pycotap = { accepted = ">=1.1.0", installed = "1.3.1" }
|
||||
|
||||
[docs]
|
||||
|
3
rust/.gitignore
vendored
Normal file
3
rust/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# Ignore any cargo development build artifacts; for qemu-wide builds, all build
|
||||
# artifacts will go to the meson build directory.
|
||||
target
|
1
rust/Kconfig
Normal file
1
rust/Kconfig
Normal file
@ -0,0 +1 @@
|
||||
source hw/Kconfig
|
2
rust/hw/Kconfig
Normal file
2
rust/hw/Kconfig
Normal file
@ -0,0 +1,2 @@
|
||||
# devices Kconfig
|
||||
source char/Kconfig
|
3
rust/hw/char/Kconfig
Normal file
3
rust/hw/char/Kconfig
Normal file
@ -0,0 +1,3 @@
|
||||
config X_PL011_RUST
|
||||
bool
|
||||
default y if HAVE_RUST
|
1
rust/hw/char/meson.build
Normal file
1
rust/hw/char/meson.build
Normal file
@ -0,0 +1 @@
|
||||
subdir('pl011')
|
2
rust/hw/char/pl011/.gitignore
vendored
Normal file
2
rust/hw/char/pl011/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Ignore generated bindings file overrides.
|
||||
src/bindings.rs.inc
|
134
rust/hw/char/pl011/Cargo.lock
generated
Normal file
134
rust/hw/char/pl011/Cargo.lock
generated
Normal file
@ -0,0 +1,134 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary-int"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d"
|
||||
|
||||
[[package]]
|
||||
name = "bilge"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57"
|
||||
dependencies = [
|
||||
"arbitrary-int",
|
||||
"bilge-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bilge-impl"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pl011"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bilge",
|
||||
"bilge-impl",
|
||||
"qemu_api",
|
||||
"qemu_api_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qemu_api"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "qemu_api_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
26
rust/hw/char/pl011/Cargo.toml
Normal file
26
rust/hw/char/pl011/Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "pl011"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
|
||||
license = "GPL-2.0-or-later"
|
||||
readme = "README.md"
|
||||
homepage = "https://www.qemu.org"
|
||||
description = "pl011 device model for QEMU"
|
||||
repository = "https://gitlab.com/epilys/rust-for-qemu"
|
||||
resolver = "2"
|
||||
publish = false
|
||||
keywords = []
|
||||
categories = []
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
bilge = { version = "0.2.0" }
|
||||
bilge-impl = { version = "0.2.0" }
|
||||
qemu_api = { path = "../../../qemu-api" }
|
||||
qemu_api_macros = { path = "../../../qemu-api-macros" }
|
||||
|
||||
# Do not include in any global workspace
|
||||
[workspace]
|
31
rust/hw/char/pl011/README.md
Normal file
31
rust/hw/char/pl011/README.md
Normal file
@ -0,0 +1,31 @@
|
||||
# PL011 QEMU Device Model
|
||||
|
||||
This library implements a device model for the PrimeCell® UART (PL011)
|
||||
device in QEMU.
|
||||
|
||||
## Build static lib
|
||||
|
||||
Host build target must be explicitly specified:
|
||||
|
||||
```sh
|
||||
cargo build --target x86_64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
Replace host target triplet if necessary.
|
||||
|
||||
## Generate Rust documentation
|
||||
|
||||
To generate docs for this crate, including private items:
|
||||
|
||||
```sh
|
||||
cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
|
||||
```
|
||||
|
||||
To include direct dependencies like `bilge` (bitmaps for register types):
|
||||
|
||||
```sh
|
||||
cargo tree --depth 1 -e normal --prefix none \
|
||||
| cut -d' ' -f1 \
|
||||
| xargs printf -- '-p %s\n' \
|
||||
| xargs cargo doc --no-deps --document-private-items --target x86_64-unknown-linux-gnu
|
||||
```
|
26
rust/hw/char/pl011/meson.build
Normal file
26
rust/hw/char/pl011/meson.build
Normal file
@ -0,0 +1,26 @@
|
||||
subproject('bilge-0.2-rs', required: true)
|
||||
subproject('bilge-impl-0.2-rs', required: true)
|
||||
|
||||
bilge_dep = dependency('bilge-0.2-rs')
|
||||
bilge_impl_dep = dependency('bilge-impl-0.2-rs')
|
||||
|
||||
_libpl011_rs = static_library(
|
||||
'pl011',
|
||||
files('src/lib.rs'),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
dependencies: [
|
||||
bilge_dep,
|
||||
bilge_impl_dep,
|
||||
qemu_api,
|
||||
qemu_api_macros,
|
||||
],
|
||||
)
|
||||
|
||||
rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency(
|
||||
link_whole: [_libpl011_rs],
|
||||
# Putting proc macro crates in `dependencies` is necessary for Meson to find
|
||||
# them when compiling the root per-target static rust lib.
|
||||
dependencies: [bilge_impl_dep, qemu_api_macros],
|
||||
variables: {'crate': 'pl011'},
|
||||
)])
|
599
rust/hw/char/pl011/src/device.rs
Normal file
599
rust/hw/char/pl011/src/device.rs
Normal file
@ -0,0 +1,599 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use core::{
|
||||
ffi::{c_int, c_uchar, c_uint, c_void, CStr},
|
||||
ptr::{addr_of, addr_of_mut, NonNull},
|
||||
};
|
||||
|
||||
use qemu_api::{
|
||||
bindings::{self, *},
|
||||
definitions::ObjectImpl,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
memory_ops::PL011_OPS,
|
||||
registers::{self, Interrupt},
|
||||
RegisterOffset,
|
||||
};
|
||||
|
||||
static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1];
|
||||
|
||||
const DATA_BREAK: u32 = 1 << 10;
|
||||
|
||||
/// QEMU sourced constant.
|
||||
pub const PL011_FIFO_DEPTH: usize = 16_usize;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, qemu_api_macros::Object)]
|
||||
/// PL011 Device Model in QEMU
|
||||
pub struct PL011State {
|
||||
pub parent_obj: SysBusDevice,
|
||||
pub iomem: MemoryRegion,
|
||||
#[doc(alias = "fr")]
|
||||
pub flags: registers::Flags,
|
||||
#[doc(alias = "lcr")]
|
||||
pub line_control: registers::LineControl,
|
||||
#[doc(alias = "rsr")]
|
||||
pub receive_status_error_clear: registers::ReceiveStatusErrorClear,
|
||||
#[doc(alias = "cr")]
|
||||
pub control: registers::Control,
|
||||
pub dmacr: u32,
|
||||
pub int_enabled: u32,
|
||||
pub int_level: u32,
|
||||
pub read_fifo: [u32; PL011_FIFO_DEPTH],
|
||||
pub ilpr: u32,
|
||||
pub ibrd: u32,
|
||||
pub fbrd: u32,
|
||||
pub ifl: u32,
|
||||
pub read_pos: usize,
|
||||
pub read_count: usize,
|
||||
pub read_trigger: usize,
|
||||
#[doc(alias = "chr")]
|
||||
pub char_backend: CharBackend,
|
||||
/// QEMU interrupts
|
||||
///
|
||||
/// ```text
|
||||
/// * sysbus MMIO region 0: device registers
|
||||
/// * sysbus IRQ 0: `UARTINTR` (combined interrupt line)
|
||||
/// * sysbus IRQ 1: `UARTRXINTR` (receive FIFO interrupt line)
|
||||
/// * sysbus IRQ 2: `UARTTXINTR` (transmit FIFO interrupt line)
|
||||
/// * sysbus IRQ 3: `UARTRTINTR` (receive timeout interrupt line)
|
||||
/// * sysbus IRQ 4: `UARTMSINTR` (momem status interrupt line)
|
||||
/// * sysbus IRQ 5: `UARTEINTR` (error interrupt line)
|
||||
/// ```
|
||||
#[doc(alias = "irq")]
|
||||
pub interrupts: [qemu_irq; 6usize],
|
||||
#[doc(alias = "clk")]
|
||||
pub clock: NonNull<Clock>,
|
||||
#[doc(alias = "migrate_clk")]
|
||||
pub migrate_clock: bool,
|
||||
}
|
||||
|
||||
impl ObjectImpl for PL011State {
|
||||
type Class = PL011Class;
|
||||
const TYPE_INFO: qemu_api::bindings::TypeInfo = qemu_api::type_info! { Self };
|
||||
const TYPE_NAME: &'static CStr = crate::TYPE_PL011;
|
||||
const PARENT_TYPE_NAME: Option<&'static CStr> = Some(TYPE_SYS_BUS_DEVICE);
|
||||
const ABSTRACT: bool = false;
|
||||
const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = Some(pl011_init);
|
||||
const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
|
||||
const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)> = None;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PL011Class {
|
||||
_inner: [u8; 0],
|
||||
}
|
||||
|
||||
impl qemu_api::definitions::Class for PL011Class {
|
||||
const CLASS_INIT: Option<
|
||||
unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
|
||||
> = Some(crate::device_class::pl011_class_init);
|
||||
const CLASS_BASE_INIT: Option<
|
||||
unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut core::ffi::c_void),
|
||||
> = None;
|
||||
}
|
||||
|
||||
#[used]
|
||||
pub static CLK_NAME: &CStr = c"clk";
|
||||
|
||||
impl PL011State {
|
||||
/// Initializes a pre-allocated, unitialized instance of `PL011State`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `self` must point to a correctly sized and aligned location for the
|
||||
/// `PL011State` type. It must not be called more than once on the same
|
||||
/// location/instance. All its fields are expected to hold unitialized
|
||||
/// values with the sole exception of `parent_obj`.
|
||||
pub unsafe fn init(&mut self) {
|
||||
let dev = addr_of_mut!(*self).cast::<DeviceState>();
|
||||
// SAFETY:
|
||||
//
|
||||
// self and self.iomem are guaranteed to be valid at this point since callers
|
||||
// must make sure the `self` reference is valid.
|
||||
unsafe {
|
||||
memory_region_init_io(
|
||||
addr_of_mut!(self.iomem),
|
||||
addr_of_mut!(*self).cast::<Object>(),
|
||||
&PL011_OPS,
|
||||
addr_of_mut!(*self).cast::<c_void>(),
|
||||
Self::TYPE_INFO.name,
|
||||
0x1000,
|
||||
);
|
||||
let sbd = addr_of_mut!(*self).cast::<SysBusDevice>();
|
||||
sysbus_init_mmio(sbd, addr_of_mut!(self.iomem));
|
||||
for irq in self.interrupts.iter_mut() {
|
||||
sysbus_init_irq(sbd, irq);
|
||||
}
|
||||
}
|
||||
// SAFETY:
|
||||
//
|
||||
// self.clock is not initialized at this point; but since `NonNull<_>` is Copy,
|
||||
// we can overwrite the undefined value without side effects. This is
|
||||
// safe since all PL011State instances are created by QOM code which
|
||||
// calls this function to initialize the fields; therefore no code is
|
||||
// able to access an invalid self.clock value.
|
||||
unsafe {
|
||||
self.clock = NonNull::new(qdev_init_clock_in(
|
||||
dev,
|
||||
CLK_NAME.as_ptr(),
|
||||
None, /* pl011_clock_update */
|
||||
addr_of_mut!(*self).cast::<c_void>(),
|
||||
ClockEvent::ClockUpdate.0,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(
|
||||
&mut self,
|
||||
offset: hwaddr,
|
||||
_size: core::ffi::c_uint,
|
||||
) -> std::ops::ControlFlow<u64, u64> {
|
||||
use RegisterOffset::*;
|
||||
|
||||
std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) {
|
||||
Err(v) if (0x3f8..0x400).contains(&v) => {
|
||||
u64::from(PL011_ID_ARM[((offset - 0xfe0) >> 2) as usize])
|
||||
}
|
||||
Err(_) => {
|
||||
// qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset);
|
||||
0
|
||||
}
|
||||
Ok(DR) => {
|
||||
// s->flags &= ~PL011_FLAG_RXFF;
|
||||
self.flags.set_receive_fifo_full(false);
|
||||
let c = self.read_fifo[self.read_pos];
|
||||
if self.read_count > 0 {
|
||||
self.read_count -= 1;
|
||||
self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
|
||||
}
|
||||
if self.read_count == 0 {
|
||||
// self.flags |= PL011_FLAG_RXFE;
|
||||
self.flags.set_receive_fifo_empty(true);
|
||||
}
|
||||
if self.read_count + 1 == self.read_trigger {
|
||||
//self.int_level &= ~ INT_RX;
|
||||
self.int_level &= !registers::INT_RX;
|
||||
}
|
||||
// Update error bits.
|
||||
self.receive_status_error_clear = c.to_be_bytes()[3].into();
|
||||
self.update();
|
||||
// Must call qemu_chr_fe_accept_input, so return Continue:
|
||||
return std::ops::ControlFlow::Continue(c.into());
|
||||
}
|
||||
Ok(RSR) => u8::from(self.receive_status_error_clear).into(),
|
||||
Ok(FR) => u16::from(self.flags).into(),
|
||||
Ok(FBRD) => self.fbrd.into(),
|
||||
Ok(ILPR) => self.ilpr.into(),
|
||||
Ok(IBRD) => self.ibrd.into(),
|
||||
Ok(LCR_H) => u16::from(self.line_control).into(),
|
||||
Ok(CR) => {
|
||||
// We exercise our self-control.
|
||||
u16::from(self.control).into()
|
||||
}
|
||||
Ok(FLS) => self.ifl.into(),
|
||||
Ok(IMSC) => self.int_enabled.into(),
|
||||
Ok(RIS) => self.int_level.into(),
|
||||
Ok(MIS) => u64::from(self.int_level & self.int_enabled),
|
||||
Ok(ICR) => {
|
||||
// "The UARTICR Register is the interrupt clear register and is write-only"
|
||||
// Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
|
||||
0
|
||||
}
|
||||
Ok(DMACR) => self.dmacr.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write(&mut self, offset: hwaddr, value: u64) {
|
||||
// eprintln!("write offset {offset} value {value}");
|
||||
use RegisterOffset::*;
|
||||
let value: u32 = value as u32;
|
||||
match RegisterOffset::try_from(offset) {
|
||||
Err(_bad_offset) => {
|
||||
eprintln!("write bad offset {offset} value {value}");
|
||||
}
|
||||
Ok(DR) => {
|
||||
// ??? Check if transmitter is enabled.
|
||||
let ch: u8 = value as u8;
|
||||
// XXX this blocks entire thread. Rewrite to use
|
||||
// qemu_chr_fe_write and background I/O callbacks
|
||||
|
||||
// SAFETY: self.char_backend is a valid CharBackend instance after it's been
|
||||
// initialized in realize().
|
||||
unsafe {
|
||||
qemu_chr_fe_write_all(addr_of_mut!(self.char_backend), &ch, 1);
|
||||
}
|
||||
self.loopback_tx(value);
|
||||
self.int_level |= registers::INT_TX;
|
||||
self.update();
|
||||
}
|
||||
Ok(RSR) => {
|
||||
self.receive_status_error_clear = 0.into();
|
||||
}
|
||||
Ok(FR) => {
|
||||
// flag writes are ignored
|
||||
}
|
||||
Ok(ILPR) => {
|
||||
self.ilpr = value;
|
||||
}
|
||||
Ok(IBRD) => {
|
||||
self.ibrd = value;
|
||||
}
|
||||
Ok(FBRD) => {
|
||||
self.fbrd = value;
|
||||
}
|
||||
Ok(LCR_H) => {
|
||||
let value = value as u16;
|
||||
let new_val: registers::LineControl = value.into();
|
||||
// Reset the FIFO state on FIFO enable or disable
|
||||
if bool::from(self.line_control.fifos_enabled())
|
||||
^ bool::from(new_val.fifos_enabled())
|
||||
{
|
||||
self.reset_fifo();
|
||||
}
|
||||
if self.line_control.send_break() ^ new_val.send_break() {
|
||||
let mut break_enable: c_int = new_val.send_break().into();
|
||||
// SAFETY: self.char_backend is a valid CharBackend instance after it's been
|
||||
// initialized in realize().
|
||||
unsafe {
|
||||
qemu_chr_fe_ioctl(
|
||||
addr_of_mut!(self.char_backend),
|
||||
CHR_IOCTL_SERIAL_SET_BREAK as i32,
|
||||
addr_of_mut!(break_enable).cast::<c_void>(),
|
||||
);
|
||||
}
|
||||
self.loopback_break(break_enable > 0);
|
||||
}
|
||||
self.line_control = new_val;
|
||||
self.set_read_trigger();
|
||||
}
|
||||
Ok(CR) => {
|
||||
// ??? Need to implement the enable bit.
|
||||
let value = value as u16;
|
||||
self.control = value.into();
|
||||
self.loopback_mdmctrl();
|
||||
}
|
||||
Ok(FLS) => {
|
||||
self.ifl = value;
|
||||
self.set_read_trigger();
|
||||
}
|
||||
Ok(IMSC) => {
|
||||
self.int_enabled = value;
|
||||
self.update();
|
||||
}
|
||||
Ok(RIS) => {}
|
||||
Ok(MIS) => {}
|
||||
Ok(ICR) => {
|
||||
self.int_level &= !value;
|
||||
self.update();
|
||||
}
|
||||
Ok(DMACR) => {
|
||||
self.dmacr = value;
|
||||
if value & 3 > 0 {
|
||||
// qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
|
||||
eprintln!("pl011: DMA not implemented");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn loopback_tx(&mut self, value: u32) {
|
||||
if !self.loopback_enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Caveat:
|
||||
//
|
||||
// In real hardware, TX loopback happens at the serial-bit level
|
||||
// and then reassembled by the RX logics back into bytes and placed
|
||||
// into the RX fifo. That is, loopback happens after TX fifo.
|
||||
//
|
||||
// Because the real hardware TX fifo is time-drained at the frame
|
||||
// rate governed by the configured serial format, some loopback
|
||||
// bytes in TX fifo may still be able to get into the RX fifo
|
||||
// that could be full at times while being drained at software
|
||||
// pace.
|
||||
//
|
||||
// In such scenario, the RX draining pace is the major factor
|
||||
// deciding which loopback bytes get into the RX fifo, unless
|
||||
// hardware flow-control is enabled.
|
||||
//
|
||||
// For simplicity, the above described is not emulated.
|
||||
self.put_fifo(value);
|
||||
}
|
||||
|
||||
fn loopback_mdmctrl(&mut self) {
|
||||
if !self.loopback_enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loopback software-driven modem control outputs to modem status inputs:
|
||||
* FR.RI <= CR.Out2
|
||||
* FR.DCD <= CR.Out1
|
||||
* FR.CTS <= CR.RTS
|
||||
* FR.DSR <= CR.DTR
|
||||
*
|
||||
* The loopback happens immediately even if this call is triggered
|
||||
* by setting only CR.LBE.
|
||||
*
|
||||
* CTS/RTS updates due to enabled hardware flow controls are not
|
||||
* dealt with here.
|
||||
*/
|
||||
|
||||
//fr = s->flags & ~(PL011_FLAG_RI | PL011_FLAG_DCD |
|
||||
// PL011_FLAG_DSR | PL011_FLAG_CTS);
|
||||
//fr |= (cr & CR_OUT2) ? PL011_FLAG_RI : 0;
|
||||
//fr |= (cr & CR_OUT1) ? PL011_FLAG_DCD : 0;
|
||||
//fr |= (cr & CR_RTS) ? PL011_FLAG_CTS : 0;
|
||||
//fr |= (cr & CR_DTR) ? PL011_FLAG_DSR : 0;
|
||||
//
|
||||
self.flags.set_ring_indicator(self.control.out_2());
|
||||
self.flags.set_data_carrier_detect(self.control.out_1());
|
||||
self.flags.set_clear_to_send(self.control.request_to_send());
|
||||
self.flags
|
||||
.set_data_set_ready(self.control.data_transmit_ready());
|
||||
|
||||
// Change interrupts based on updated FR
|
||||
let mut il = self.int_level;
|
||||
|
||||
il &= !Interrupt::MS;
|
||||
//il |= (fr & PL011_FLAG_DSR) ? INT_DSR : 0;
|
||||
//il |= (fr & PL011_FLAG_DCD) ? INT_DCD : 0;
|
||||
//il |= (fr & PL011_FLAG_CTS) ? INT_CTS : 0;
|
||||
//il |= (fr & PL011_FLAG_RI) ? INT_RI : 0;
|
||||
|
||||
if self.flags.data_set_ready() {
|
||||
il |= Interrupt::DSR as u32;
|
||||
}
|
||||
if self.flags.data_carrier_detect() {
|
||||
il |= Interrupt::DCD as u32;
|
||||
}
|
||||
if self.flags.clear_to_send() {
|
||||
il |= Interrupt::CTS as u32;
|
||||
}
|
||||
if self.flags.ring_indicator() {
|
||||
il |= Interrupt::RI as u32;
|
||||
}
|
||||
self.int_level = il;
|
||||
self.update();
|
||||
}
|
||||
|
||||
fn loopback_break(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.loopback_tx(DATA_BREAK);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_read_trigger(&mut self) {
|
||||
self.read_trigger = 1;
|
||||
}
|
||||
|
||||
pub fn realize(&mut self) {
|
||||
// SAFETY: self.char_backend has the correct size and alignment for a
|
||||
// CharBackend object, and its callbacks are of the correct types.
|
||||
unsafe {
|
||||
qemu_chr_fe_set_handlers(
|
||||
addr_of_mut!(self.char_backend),
|
||||
Some(pl011_can_receive),
|
||||
Some(pl011_receive),
|
||||
Some(pl011_event),
|
||||
None,
|
||||
addr_of_mut!(*self).cast::<c_void>(),
|
||||
core::ptr::null_mut(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.line_control.reset();
|
||||
self.receive_status_error_clear.reset();
|
||||
self.dmacr = 0;
|
||||
self.int_enabled = 0;
|
||||
self.int_level = 0;
|
||||
self.ilpr = 0;
|
||||
self.ibrd = 0;
|
||||
self.fbrd = 0;
|
||||
self.read_trigger = 1;
|
||||
self.ifl = 0x12;
|
||||
self.control.reset();
|
||||
self.flags = 0.into();
|
||||
self.reset_fifo();
|
||||
}
|
||||
|
||||
pub fn reset_fifo(&mut self) {
|
||||
self.read_count = 0;
|
||||
self.read_pos = 0;
|
||||
|
||||
/* Reset FIFO flags */
|
||||
self.flags.reset();
|
||||
}
|
||||
|
||||
pub fn can_receive(&self) -> bool {
|
||||
// trace_pl011_can_receive(s->lcr, s->read_count, r);
|
||||
self.read_count < self.fifo_depth()
|
||||
}
|
||||
|
||||
pub fn event(&mut self, event: QEMUChrEvent) {
|
||||
if event == bindings::QEMUChrEvent::CHR_EVENT_BREAK && !self.fifo_enabled() {
|
||||
self.put_fifo(DATA_BREAK);
|
||||
self.receive_status_error_clear.set_break_error(true);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fifo_enabled(&self) -> bool {
|
||||
matches!(self.line_control.fifos_enabled(), registers::Mode::FIFO)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn loopback_enabled(&self) -> bool {
|
||||
self.control.enable_loopback()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fifo_depth(&self) -> usize {
|
||||
// Note: FIFO depth is expected to be power-of-2
|
||||
if self.fifo_enabled() {
|
||||
return PL011_FIFO_DEPTH;
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
pub fn put_fifo(&mut self, value: c_uint) {
|
||||
let depth = self.fifo_depth();
|
||||
assert!(depth > 0);
|
||||
let slot = (self.read_pos + self.read_count) & (depth - 1);
|
||||
self.read_fifo[slot] = value;
|
||||
self.read_count += 1;
|
||||
// s->flags &= ~PL011_FLAG_RXFE;
|
||||
self.flags.set_receive_fifo_empty(false);
|
||||
if self.read_count == depth {
|
||||
//s->flags |= PL011_FLAG_RXFF;
|
||||
self.flags.set_receive_fifo_full(true);
|
||||
}
|
||||
|
||||
if self.read_count == self.read_trigger {
|
||||
self.int_level |= registers::INT_RX;
|
||||
self.update();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&self) {
|
||||
let flags = self.int_level & self.int_enabled;
|
||||
for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
|
||||
// SAFETY: self.interrupts have been initialized in init().
|
||||
unsafe { qemu_set_irq(*irq, i32::from(flags & i != 0)) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Which bits in the interrupt status matter for each outbound IRQ line ?
|
||||
pub const IRQMASK: [u32; 6] = [
|
||||
/* combined IRQ */
|
||||
Interrupt::E
|
||||
| Interrupt::MS
|
||||
| Interrupt::RT as u32
|
||||
| Interrupt::TX as u32
|
||||
| Interrupt::RX as u32,
|
||||
Interrupt::RX as u32,
|
||||
Interrupt::TX as u32,
|
||||
Interrupt::RT as u32,
|
||||
Interrupt::MS,
|
||||
Interrupt::E,
|
||||
];
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// We expect the FFI user of this function to pass a valid pointer, that has
|
||||
/// the same size as [`PL011State`]. We also expect the device is
|
||||
/// readable/writeable from one thread at any time.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pl011_can_receive(opaque: *mut c_void) -> c_int {
|
||||
unsafe {
|
||||
debug_assert!(!opaque.is_null());
|
||||
let state = NonNull::new_unchecked(opaque.cast::<PL011State>());
|
||||
state.as_ref().can_receive().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// We expect the FFI user of this function to pass a valid pointer, that has
|
||||
/// the same size as [`PL011State`]. We also expect the device is
|
||||
/// readable/writeable from one thread at any time.
|
||||
///
|
||||
/// The buffer and size arguments must also be valid.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pl011_receive(
|
||||
opaque: *mut core::ffi::c_void,
|
||||
buf: *const u8,
|
||||
size: core::ffi::c_int,
|
||||
) {
|
||||
unsafe {
|
||||
debug_assert!(!opaque.is_null());
|
||||
let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
|
||||
if state.as_ref().loopback_enabled() {
|
||||
return;
|
||||
}
|
||||
if size > 0 {
|
||||
debug_assert!(!buf.is_null());
|
||||
state.as_mut().put_fifo(c_uint::from(buf.read_volatile()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// We expect the FFI user of this function to pass a valid pointer, that has
|
||||
/// the same size as [`PL011State`]. We also expect the device is
|
||||
/// readable/writeable from one thread at any time.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pl011_event(opaque: *mut core::ffi::c_void, event: QEMUChrEvent) {
|
||||
unsafe {
|
||||
debug_assert!(!opaque.is_null());
|
||||
let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
|
||||
state.as_mut().event(event)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// We expect the FFI user of this function to pass a valid pointer for `chr`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pl011_create(
|
||||
addr: u64,
|
||||
irq: qemu_irq,
|
||||
chr: *mut Chardev,
|
||||
) -> *mut DeviceState {
|
||||
unsafe {
|
||||
let dev: *mut DeviceState = qdev_new(PL011State::TYPE_INFO.name);
|
||||
let sysbus: *mut SysBusDevice = dev.cast::<SysBusDevice>();
|
||||
|
||||
qdev_prop_set_chr(dev, bindings::TYPE_CHARDEV.as_ptr(), chr);
|
||||
sysbus_realize_and_unref(sysbus, addr_of!(error_fatal) as *mut *mut Error);
|
||||
sysbus_mmio_map(sysbus, 0, addr);
|
||||
sysbus_connect_irq(sysbus, 0, irq);
|
||||
dev
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// We expect the FFI user of this function to pass a valid pointer, that has
|
||||
/// the same size as [`PL011State`]. We also expect the device is
|
||||
/// readable/writeable from one thread at any time.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pl011_init(obj: *mut Object) {
|
||||
unsafe {
|
||||
debug_assert!(!obj.is_null());
|
||||
let mut state = NonNull::new_unchecked(obj.cast::<PL011State>());
|
||||
state.as_mut().init();
|
||||
}
|
||||
}
|
70
rust/hw/char/pl011/src/device_class.rs
Normal file
70
rust/hw/char/pl011/src/device_class.rs
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use qemu_api::{bindings::*, definitions::ObjectImpl};
|
||||
|
||||
use crate::device::PL011State;
|
||||
|
||||
#[used]
|
||||
pub static VMSTATE_PL011: VMStateDescription = VMStateDescription {
|
||||
name: PL011State::TYPE_INFO.name,
|
||||
unmigratable: true,
|
||||
..unsafe { ::core::mem::MaybeUninit::<VMStateDescription>::zeroed().assume_init() }
|
||||
};
|
||||
|
||||
qemu_api::declare_properties! {
|
||||
PL011_PROPERTIES,
|
||||
qemu_api::define_property!(
|
||||
c"chardev",
|
||||
PL011State,
|
||||
char_backend,
|
||||
unsafe { &qdev_prop_chr },
|
||||
CharBackend
|
||||
),
|
||||
qemu_api::define_property!(
|
||||
c"migrate-clk",
|
||||
PL011State,
|
||||
migrate_clock,
|
||||
unsafe { &qdev_prop_bool },
|
||||
bool
|
||||
),
|
||||
}
|
||||
|
||||
qemu_api::device_class_init! {
|
||||
pl011_class_init,
|
||||
props => PL011_PROPERTIES,
|
||||
realize_fn => Some(pl011_realize),
|
||||
legacy_reset_fn => Some(pl011_reset),
|
||||
vmsd => VMSTATE_PL011,
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// We expect the FFI user of this function to pass a valid pointer, that has
|
||||
/// the same size as [`PL011State`]. We also expect the device is
|
||||
/// readable/writeable from one thread at any time.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pl011_realize(dev: *mut DeviceState, _errp: *mut *mut Error) {
|
||||
unsafe {
|
||||
assert!(!dev.is_null());
|
||||
let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
|
||||
state.as_mut().realize();
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// We expect the FFI user of this function to pass a valid pointer, that has
|
||||
/// the same size as [`PL011State`]. We also expect the device is
|
||||
/// readable/writeable from one thread at any time.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pl011_reset(dev: *mut DeviceState) {
|
||||
unsafe {
|
||||
assert!(!dev.is_null());
|
||||
let mut state = NonNull::new_unchecked(dev.cast::<PL011State>());
|
||||
state.as_mut().reset();
|
||||
}
|
||||
}
|
586
rust/hw/char/pl011/src/lib.rs
Normal file
586
rust/hw/char/pl011/src/lib.rs
Normal file
@ -0,0 +1,586 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
//
|
||||
// PL011 QEMU Device Model
|
||||
//
|
||||
// This library implements a device model for the PrimeCell® UART (PL011)
|
||||
// device in QEMU.
|
||||
//
|
||||
#![doc = include_str!("../README.md")]
|
||||
//! # Library crate
|
||||
//!
|
||||
//! See [`PL011State`](crate::device::PL011State) for the device model type and
|
||||
//! the [`registers`] module for register types.
|
||||
|
||||
#![deny(
|
||||
rustdoc::broken_intra_doc_links,
|
||||
rustdoc::redundant_explicit_links,
|
||||
clippy::correctness,
|
||||
clippy::suspicious,
|
||||
clippy::complexity,
|
||||
clippy::perf,
|
||||
clippy::cargo,
|
||||
clippy::nursery,
|
||||
clippy::style,
|
||||
// restriction group
|
||||
clippy::dbg_macro,
|
||||
clippy::as_underscore,
|
||||
clippy::assertions_on_result_states,
|
||||
// pedantic group
|
||||
clippy::doc_markdown,
|
||||
clippy::borrow_as_ptr,
|
||||
clippy::cast_lossless,
|
||||
clippy::option_if_let_else,
|
||||
clippy::missing_const_for_fn,
|
||||
clippy::cognitive_complexity,
|
||||
clippy::missing_safety_doc,
|
||||
)]
|
||||
|
||||
extern crate bilge;
|
||||
extern crate bilge_impl;
|
||||
extern crate qemu_api;
|
||||
|
||||
pub mod device;
|
||||
pub mod device_class;
|
||||
pub mod memory_ops;
|
||||
|
||||
pub const TYPE_PL011: &::core::ffi::CStr = c"pl011";
|
||||
|
||||
/// Offset of each register from the base memory address of the device.
|
||||
///
|
||||
/// # Source
|
||||
/// ARM DDI 0183G, Table 3-1 p.3-3
|
||||
#[doc(alias = "offset")]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u64)]
|
||||
#[derive(Debug)]
|
||||
pub enum RegisterOffset {
|
||||
/// Data Register
|
||||
///
|
||||
/// A write to this register initiates the actual data transmission
|
||||
#[doc(alias = "UARTDR")]
|
||||
DR = 0x000,
|
||||
/// Receive Status Register or Error Clear Register
|
||||
#[doc(alias = "UARTRSR")]
|
||||
#[doc(alias = "UARTECR")]
|
||||
RSR = 0x004,
|
||||
/// Flag Register
|
||||
///
|
||||
/// A read of this register shows if transmission is complete
|
||||
#[doc(alias = "UARTFR")]
|
||||
FR = 0x018,
|
||||
/// Fractional Baud Rate Register
|
||||
///
|
||||
/// responsible for baud rate speed
|
||||
#[doc(alias = "UARTFBRD")]
|
||||
FBRD = 0x028,
|
||||
/// `IrDA` Low-Power Counter Register
|
||||
#[doc(alias = "UARTILPR")]
|
||||
ILPR = 0x020,
|
||||
/// Integer Baud Rate Register
|
||||
///
|
||||
/// Responsible for baud rate speed
|
||||
#[doc(alias = "UARTIBRD")]
|
||||
IBRD = 0x024,
|
||||
/// line control register (data frame format)
|
||||
#[doc(alias = "UARTLCR_H")]
|
||||
LCR_H = 0x02C,
|
||||
/// Toggle UART, transmission or reception
|
||||
#[doc(alias = "UARTCR")]
|
||||
CR = 0x030,
|
||||
/// Interrupt FIFO Level Select Register
|
||||
#[doc(alias = "UARTIFLS")]
|
||||
FLS = 0x034,
|
||||
/// Interrupt Mask Set/Clear Register
|
||||
#[doc(alias = "UARTIMSC")]
|
||||
IMSC = 0x038,
|
||||
/// Raw Interrupt Status Register
|
||||
#[doc(alias = "UARTRIS")]
|
||||
RIS = 0x03C,
|
||||
/// Masked Interrupt Status Register
|
||||
#[doc(alias = "UARTMIS")]
|
||||
MIS = 0x040,
|
||||
/// Interrupt Clear Register
|
||||
#[doc(alias = "UARTICR")]
|
||||
ICR = 0x044,
|
||||
/// DMA control Register
|
||||
#[doc(alias = "UARTDMACR")]
|
||||
DMACR = 0x048,
|
||||
///// Reserved, offsets `0x04C` to `0x07C`.
|
||||
//Reserved = 0x04C,
|
||||
}
|
||||
|
||||
impl core::convert::TryFrom<u64> for RegisterOffset {
|
||||
type Error = u64;
|
||||
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
macro_rules! case {
|
||||
($($discriminant:ident),*$(,)*) => {
|
||||
/* check that matching on all macro arguments compiles, which means we are not
|
||||
* missing any enum value; if the type definition ever changes this will stop
|
||||
* compiling.
|
||||
*/
|
||||
const fn _assert_exhaustive(val: RegisterOffset) {
|
||||
match val {
|
||||
$(RegisterOffset::$discriminant => (),)*
|
||||
}
|
||||
}
|
||||
|
||||
match value {
|
||||
$(x if x == Self::$discriminant as u64 => Ok(Self::$discriminant),)*
|
||||
_ => Err(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
case! { DR, RSR, FR, FBRD, ILPR, IBRD, LCR_H, CR, FLS, IMSC, RIS, MIS, ICR, DMACR }
|
||||
}
|
||||
}
|
||||
|
||||
pub mod registers {
|
||||
//! Device registers exposed as typed structs which are backed by arbitrary
|
||||
//! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
|
||||
//!
|
||||
//! All PL011 registers are essentially 32-bit wide, but are typed here as
|
||||
//! bitmaps with only the necessary width. That is, if a struct bitmap
|
||||
//! in this module is for example 16 bits long, it should be conceived
|
||||
//! as a 32-bit register where the unmentioned higher bits are always
|
||||
//! unused thus treated as zero when read or written.
|
||||
use bilge::prelude::*;
|
||||
|
||||
// TODO: FIFO Mode has different semantics
|
||||
/// Data Register, `UARTDR`
|
||||
///
|
||||
/// The `UARTDR` register is the data register.
|
||||
///
|
||||
/// For words to be transmitted:
|
||||
///
|
||||
/// - if the FIFOs are enabled, data written to this location is pushed onto
|
||||
/// the transmit
|
||||
/// FIFO
|
||||
/// - if the FIFOs are not enabled, data is stored in the transmitter
|
||||
/// holding register (the
|
||||
/// bottom word of the transmit FIFO).
|
||||
///
|
||||
/// The write operation initiates transmission from the UART. The data is
|
||||
/// prefixed with a start bit, appended with the appropriate parity bit
|
||||
/// (if parity is enabled), and a stop bit. The resultant word is then
|
||||
/// transmitted.
|
||||
///
|
||||
/// For received words:
|
||||
///
|
||||
/// - if the FIFOs are enabled, the data byte and the 4-bit status (break,
|
||||
/// frame, parity,
|
||||
/// and overrun) is pushed onto the 12-bit wide receive FIFO
|
||||
/// - if the FIFOs are not enabled, the data byte and status are stored in
|
||||
/// the receiving
|
||||
/// holding register (the bottom word of the receive FIFO).
|
||||
///
|
||||
/// The received data byte is read by performing reads from the `UARTDR`
|
||||
/// register along with the corresponding status information. The status
|
||||
/// information can also be read by a read of the `UARTRSR/UARTECR`
|
||||
/// register.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// You must disable the UART before any of the control registers are
|
||||
/// reprogrammed. When the UART is disabled in the middle of
|
||||
/// transmission or reception, it completes the current character before
|
||||
/// stopping.
|
||||
///
|
||||
/// # Source
|
||||
/// ARM DDI 0183G 3.3.1 Data Register, UARTDR
|
||||
#[bitsize(16)]
|
||||
#[derive(Clone, Copy, DebugBits, FromBits)]
|
||||
#[doc(alias = "UARTDR")]
|
||||
pub struct Data {
|
||||
_reserved: u4,
|
||||
pub data: u8,
|
||||
pub framing_error: bool,
|
||||
pub parity_error: bool,
|
||||
pub break_error: bool,
|
||||
pub overrun_error: bool,
|
||||
}
|
||||
|
||||
// TODO: FIFO Mode has different semantics
|
||||
/// Receive Status Register / Error Clear Register, `UARTRSR/UARTECR`
|
||||
///
|
||||
/// The UARTRSR/UARTECR register is the receive status register/error clear
|
||||
/// register. Receive status can also be read from the `UARTRSR`
|
||||
/// register. If the status is read from this register, then the status
|
||||
/// information for break, framing and parity corresponds to the
|
||||
/// data character read from the [Data register](Data), `UARTDR` prior to
|
||||
/// reading the UARTRSR register. The status information for overrun is
|
||||
/// set immediately when an overrun condition occurs.
|
||||
///
|
||||
///
|
||||
/// # Note
|
||||
/// The received data character must be read first from the [Data
|
||||
/// Register](Data), `UARTDR` before reading the error status associated
|
||||
/// with that data character from the `UARTRSR` register. This read
|
||||
/// sequence cannot be reversed, because the `UARTRSR` register is
|
||||
/// updated only when a read occurs from the `UARTDR` register. However,
|
||||
/// the status information can also be obtained by reading the `UARTDR`
|
||||
/// register
|
||||
///
|
||||
/// # Source
|
||||
/// ARM DDI 0183G 3.3.2 Receive Status Register/Error Clear Register,
|
||||
/// UARTRSR/UARTECR
|
||||
#[bitsize(8)]
|
||||
#[derive(Clone, Copy, DebugBits, FromBits)]
|
||||
pub struct ReceiveStatusErrorClear {
|
||||
pub framing_error: bool,
|
||||
pub parity_error: bool,
|
||||
pub break_error: bool,
|
||||
pub overrun_error: bool,
|
||||
_reserved_unpredictable: u4,
|
||||
}
|
||||
|
||||
impl ReceiveStatusErrorClear {
|
||||
pub fn reset(&mut self) {
|
||||
// All the bits are cleared to 0 on reset.
|
||||
*self = 0.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ReceiveStatusErrorClear {
|
||||
fn default() -> Self {
|
||||
0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[bitsize(16)]
|
||||
#[derive(Clone, Copy, DebugBits, FromBits)]
|
||||
/// Flag Register, `UARTFR`
|
||||
#[doc(alias = "UARTFR")]
|
||||
pub struct Flags {
|
||||
/// CTS Clear to send. This bit is the complement of the UART clear to
|
||||
/// send, `nUARTCTS`, modem status input. That is, the bit is 1
|
||||
/// when `nUARTCTS` is LOW.
|
||||
pub clear_to_send: bool,
|
||||
/// DSR Data set ready. This bit is the complement of the UART data set
|
||||
/// ready, `nUARTDSR`, modem status input. That is, the bit is 1 when
|
||||
/// `nUARTDSR` is LOW.
|
||||
pub data_set_ready: bool,
|
||||
/// DCD Data carrier detect. This bit is the complement of the UART data
|
||||
/// carrier detect, `nUARTDCD`, modem status input. That is, the bit is
|
||||
/// 1 when `nUARTDCD` is LOW.
|
||||
pub data_carrier_detect: bool,
|
||||
/// BUSY UART busy. If this bit is set to 1, the UART is busy
|
||||
/// transmitting data. This bit remains set until the complete
|
||||
/// byte, including all the stop bits, has been sent from the
|
||||
/// shift register. This bit is set as soon as the transmit FIFO
|
||||
/// becomes non-empty, regardless of whether the UART is enabled
|
||||
/// or not.
|
||||
pub busy: bool,
|
||||
/// RXFE Receive FIFO empty. The meaning of this bit depends on the
|
||||
/// state of the FEN bit in the UARTLCR_H register. If the FIFO
|
||||
/// is disabled, this bit is set when the receive holding
|
||||
/// register is empty. If the FIFO is enabled, the RXFE bit is
|
||||
/// set when the receive FIFO is empty.
|
||||
pub receive_fifo_empty: bool,
|
||||
/// TXFF Transmit FIFO full. The meaning of this bit depends on the
|
||||
/// state of the FEN bit in the UARTLCR_H register. If the FIFO
|
||||
/// is disabled, this bit is set when the transmit holding
|
||||
/// register is full. If the FIFO is enabled, the TXFF bit is
|
||||
/// set when the transmit FIFO is full.
|
||||
pub transmit_fifo_full: bool,
|
||||
/// RXFF Receive FIFO full. The meaning of this bit depends on the state
|
||||
/// of the FEN bit in the UARTLCR_H register. If the FIFO is
|
||||
/// disabled, this bit is set when the receive holding register
|
||||
/// is full. If the FIFO is enabled, the RXFF bit is set when
|
||||
/// the receive FIFO is full.
|
||||
pub receive_fifo_full: bool,
|
||||
/// Transmit FIFO empty. The meaning of this bit depends on the state of
|
||||
/// the FEN bit in the [Line Control register](LineControl),
|
||||
/// `UARTLCR_H`. If the FIFO is disabled, this bit is set when the
|
||||
/// transmit holding register is empty. If the FIFO is enabled,
|
||||
/// the TXFE bit is set when the transmit FIFO is empty. This
|
||||
/// bit does not indicate if there is data in the transmit shift
|
||||
/// register.
|
||||
pub transmit_fifo_empty: bool,
|
||||
/// `RI`, is `true` when `nUARTRI` is `LOW`.
|
||||
pub ring_indicator: bool,
|
||||
_reserved_zero_no_modify: u7,
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
pub fn reset(&mut self) {
|
||||
// After reset TXFF, RXFF, and BUSY are 0, and TXFE and RXFE are 1
|
||||
self.set_receive_fifo_full(false);
|
||||
self.set_transmit_fifo_full(false);
|
||||
self.set_busy(false);
|
||||
self.set_receive_fifo_empty(true);
|
||||
self.set_transmit_fifo_empty(true);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Flags {
|
||||
fn default() -> Self {
|
||||
let mut ret: Self = 0.into();
|
||||
ret.reset();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[bitsize(16)]
|
||||
#[derive(Clone, Copy, DebugBits, FromBits)]
|
||||
/// Line Control Register, `UARTLCR_H`
|
||||
#[doc(alias = "UARTLCR_H")]
|
||||
pub struct LineControl {
|
||||
/// 15:8 - Reserved, do not modify, read as zero.
|
||||
_reserved_zero_no_modify: u8,
|
||||
/// 7 SPS Stick parity select.
|
||||
/// 0 = stick parity is disabled
|
||||
/// 1 = either:
|
||||
/// • if the EPS bit is 0 then the parity bit is transmitted and checked
|
||||
/// as a 1 • if the EPS bit is 1 then the parity bit is
|
||||
/// transmitted and checked as a 0. This bit has no effect when
|
||||
/// the PEN bit disables parity checking and generation. See Table 3-11
|
||||
/// on page 3-14 for the parity truth table.
|
||||
pub sticky_parity: bool,
|
||||
/// WLEN Word length. These bits indicate the number of data bits
|
||||
/// transmitted or received in a frame as follows: b11 = 8 bits
|
||||
/// b10 = 7 bits
|
||||
/// b01 = 6 bits
|
||||
/// b00 = 5 bits.
|
||||
pub word_length: WordLength,
|
||||
/// FEN Enable FIFOs:
|
||||
/// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
|
||||
/// 1-byte-deep holding registers 1 = transmit and receive FIFO
|
||||
/// buffers are enabled (FIFO mode).
|
||||
pub fifos_enabled: Mode,
|
||||
/// 3 STP2 Two stop bits select. If this bit is set to 1, two stop bits
|
||||
/// are transmitted at the end of the frame. The receive
|
||||
/// logic does not check for two stop bits being received.
|
||||
pub two_stops_bits: bool,
|
||||
/// EPS Even parity select. Controls the type of parity the UART uses
|
||||
/// during transmission and reception:
|
||||
/// - 0 = odd parity. The UART generates or checks for an odd number of
|
||||
/// 1s in the data and parity bits.
|
||||
/// - 1 = even parity. The UART generates or checks for an even number
|
||||
/// of 1s in the data and parity bits.
|
||||
/// This bit has no effect when the `PEN` bit disables parity checking
|
||||
/// and generation. See Table 3-11 on page 3-14 for the parity
|
||||
/// truth table.
|
||||
pub parity: Parity,
|
||||
/// 1 PEN Parity enable:
|
||||
///
|
||||
/// - 0 = parity is disabled and no parity bit added to the data frame
|
||||
/// - 1 = parity checking and generation is enabled.
|
||||
///
|
||||
/// See Table 3-11 on page 3-14 for the parity truth table.
|
||||
pub parity_enabled: bool,
|
||||
/// BRK Send break.
|
||||
///
|
||||
/// If this bit is set to `1`, a low-level is continually output on the
|
||||
/// `UARTTXD` output, after completing transmission of the
|
||||
/// current character. For the proper execution of the break command,
|
||||
/// the software must set this bit for at least two complete
|
||||
/// frames. For normal use, this bit must be cleared to `0`.
|
||||
pub send_break: bool,
|
||||
}
|
||||
|
||||
impl LineControl {
|
||||
pub fn reset(&mut self) {
|
||||
// All the bits are cleared to 0 when reset.
|
||||
*self = 0.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LineControl {
|
||||
fn default() -> Self {
|
||||
0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[bitsize(1)]
|
||||
#[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
|
||||
/// `EPS` "Even parity select", field of [Line Control
|
||||
/// register](LineControl).
|
||||
pub enum Parity {
|
||||
/// - 0 = odd parity. The UART generates or checks for an odd number of
|
||||
/// 1s in the data and parity bits.
|
||||
Odd = 0,
|
||||
/// - 1 = even parity. The UART generates or checks for an even number
|
||||
/// of 1s in the data and parity bits.
|
||||
Even = 1,
|
||||
}
|
||||
|
||||
#[bitsize(1)]
|
||||
#[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
|
||||
/// `FEN` "Enable FIFOs" or Device mode, field of [Line Control
|
||||
/// register](LineControl).
|
||||
pub enum Mode {
|
||||
/// 0 = FIFOs are disabled (character mode) that is, the FIFOs become
|
||||
/// 1-byte-deep holding registers
|
||||
Character = 0,
|
||||
/// 1 = transmit and receive FIFO buffers are enabled (FIFO mode).
|
||||
FIFO = 1,
|
||||
}
|
||||
|
||||
impl From<Mode> for bool {
|
||||
fn from(val: Mode) -> Self {
|
||||
matches!(val, Mode::FIFO)
|
||||
}
|
||||
}
|
||||
|
||||
#[bitsize(2)]
|
||||
#[derive(Clone, Copy, Debug, Eq, FromBits, PartialEq)]
|
||||
/// `WLEN` Word length, field of [Line Control register](LineControl).
|
||||
///
|
||||
/// These bits indicate the number of data bits transmitted or received in a
|
||||
/// frame as follows:
|
||||
pub enum WordLength {
|
||||
/// b11 = 8 bits
|
||||
_8Bits = 0b11,
|
||||
/// b10 = 7 bits
|
||||
_7Bits = 0b10,
|
||||
/// b01 = 6 bits
|
||||
_6Bits = 0b01,
|
||||
/// b00 = 5 bits.
|
||||
_5Bits = 0b00,
|
||||
}
|
||||
|
||||
/// Control Register, `UARTCR`
|
||||
///
|
||||
/// The `UARTCR` register is the control register. All the bits are cleared
|
||||
/// to `0` on reset except for bits `9` and `8` that are set to `1`.
|
||||
///
|
||||
/// # Source
|
||||
/// ARM DDI 0183G, 3.3.8 Control Register, `UARTCR`, Table 3-12
|
||||
#[bitsize(16)]
|
||||
#[doc(alias = "UARTCR")]
|
||||
#[derive(Clone, Copy, DebugBits, FromBits)]
|
||||
pub struct Control {
|
||||
/// `UARTEN` UART enable: 0 = UART is disabled. If the UART is disabled
|
||||
/// in the middle of transmission or reception, it completes the current
|
||||
/// character before stopping. 1 = the UART is enabled. Data
|
||||
/// transmission and reception occurs for either UART signals or SIR
|
||||
/// signals depending on the setting of the SIREN bit.
|
||||
pub enable_uart: bool,
|
||||
/// `SIREN` `SIR` enable: 0 = IrDA SIR ENDEC is disabled. `nSIROUT`
|
||||
/// remains LOW (no light pulse generated), and signal transitions on
|
||||
/// SIRIN have no effect. 1 = IrDA SIR ENDEC is enabled. Data is
|
||||
/// transmitted and received on nSIROUT and SIRIN. UARTTXD remains HIGH,
|
||||
/// in the marking state. Signal transitions on UARTRXD or modem status
|
||||
/// inputs have no effect. This bit has no effect if the UARTEN bit
|
||||
/// disables the UART.
|
||||
pub enable_sir: bool,
|
||||
/// `SIRLP` SIR low-power IrDA mode. This bit selects the IrDA encoding
|
||||
/// mode. If this bit is cleared to 0, low-level bits are transmitted as
|
||||
/// an active high pulse with a width of 3/ 16th of the bit period. If
|
||||
/// this bit is set to 1, low-level bits are transmitted with a pulse
|
||||
/// width that is 3 times the period of the IrLPBaud16 input signal,
|
||||
/// regardless of the selected bit rate. Setting this bit uses less
|
||||
/// power, but might reduce transmission distances.
|
||||
pub sir_lowpower_irda_mode: u1,
|
||||
/// Reserved, do not modify, read as zero.
|
||||
_reserved_zero_no_modify: u4,
|
||||
/// `LBE` Loopback enable. If this bit is set to 1 and the SIREN bit is
|
||||
/// set to 1 and the SIRTEST bit in the Test Control register, UARTTCR
|
||||
/// on page 4-5 is set to 1, then the nSIROUT path is inverted, and fed
|
||||
/// through to the SIRIN path. The SIRTEST bit in the test register must
|
||||
/// be set to 1 to override the normal half-duplex SIR operation. This
|
||||
/// must be the requirement for accessing the test registers during
|
||||
/// normal operation, and SIRTEST must be cleared to 0 when loopback
|
||||
/// testing is finished. This feature reduces the amount of external
|
||||
/// coupling required during system test. If this bit is set to 1, and
|
||||
/// the SIRTEST bit is set to 0, the UARTTXD path is fed through to the
|
||||
/// UARTRXD path. In either SIR mode or UART mode, when this bit is set,
|
||||
/// the modem outputs are also fed through to the modem inputs. This bit
|
||||
/// is cleared to 0 on reset, to disable loopback.
|
||||
pub enable_loopback: bool,
|
||||
/// `TXE` Transmit enable. If this bit is set to 1, the transmit section
|
||||
/// of the UART is enabled. Data transmission occurs for either UART
|
||||
/// signals, or SIR signals depending on the setting of the SIREN bit.
|
||||
/// When the UART is disabled in the middle of transmission, it
|
||||
/// completes the current character before stopping.
|
||||
pub enable_transmit: bool,
|
||||
/// `RXE` Receive enable. If this bit is set to 1, the receive section
|
||||
/// of the UART is enabled. Data reception occurs for either UART
|
||||
/// signals or SIR signals depending on the setting of the SIREN bit.
|
||||
/// When the UART is disabled in the middle of reception, it completes
|
||||
/// the current character before stopping.
|
||||
pub enable_receive: bool,
|
||||
/// `DTR` Data transmit ready. This bit is the complement of the UART
|
||||
/// data transmit ready, `nUARTDTR`, modem status output. That is, when
|
||||
/// the bit is programmed to a 1 then `nUARTDTR` is LOW.
|
||||
pub data_transmit_ready: bool,
|
||||
/// `RTS` Request to send. This bit is the complement of the UART
|
||||
/// request to send, `nUARTRTS`, modem status output. That is, when the
|
||||
/// bit is programmed to a 1 then `nUARTRTS` is LOW.
|
||||
pub request_to_send: bool,
|
||||
/// `Out1` This bit is the complement of the UART Out1 (`nUARTOut1`)
|
||||
/// modem status output. That is, when the bit is programmed to a 1 the
|
||||
/// output is 0. For DTE this can be used as Data Carrier Detect (DCD).
|
||||
pub out_1: bool,
|
||||
/// `Out2` This bit is the complement of the UART Out2 (`nUARTOut2`)
|
||||
/// modem status output. That is, when the bit is programmed to a 1, the
|
||||
/// output is 0. For DTE this can be used as Ring Indicator (RI).
|
||||
pub out_2: bool,
|
||||
/// `RTSEn` RTS hardware flow control enable. If this bit is set to 1,
|
||||
/// RTS hardware flow control is enabled. Data is only requested when
|
||||
/// there is space in the receive FIFO for it to be received.
|
||||
pub rts_hardware_flow_control_enable: bool,
|
||||
/// `CTSEn` CTS hardware flow control enable. If this bit is set to 1,
|
||||
/// CTS hardware flow control is enabled. Data is only transmitted when
|
||||
/// the `nUARTCTS` signal is asserted.
|
||||
pub cts_hardware_flow_control_enable: bool,
|
||||
}
|
||||
|
||||
impl Control {
|
||||
pub fn reset(&mut self) {
|
||||
*self = 0.into();
|
||||
self.set_enable_receive(true);
|
||||
self.set_enable_transmit(true);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Control {
|
||||
fn default() -> Self {
|
||||
let mut ret: Self = 0.into();
|
||||
ret.reset();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC
|
||||
pub const INT_OE: u32 = 1 << 10;
|
||||
pub const INT_BE: u32 = 1 << 9;
|
||||
pub const INT_PE: u32 = 1 << 8;
|
||||
pub const INT_FE: u32 = 1 << 7;
|
||||
pub const INT_RT: u32 = 1 << 6;
|
||||
pub const INT_TX: u32 = 1 << 5;
|
||||
pub const INT_RX: u32 = 1 << 4;
|
||||
pub const INT_DSR: u32 = 1 << 3;
|
||||
pub const INT_DCD: u32 = 1 << 2;
|
||||
pub const INT_CTS: u32 = 1 << 1;
|
||||
pub const INT_RI: u32 = 1 << 0;
|
||||
pub const INT_E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
|
||||
pub const INT_MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum Interrupt {
|
||||
OE = 1 << 10,
|
||||
BE = 1 << 9,
|
||||
PE = 1 << 8,
|
||||
FE = 1 << 7,
|
||||
RT = 1 << 6,
|
||||
TX = 1 << 5,
|
||||
RX = 1 << 4,
|
||||
DSR = 1 << 3,
|
||||
DCD = 1 << 2,
|
||||
CTS = 1 << 1,
|
||||
RI = 1 << 0,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub const E: u32 = INT_OE | INT_BE | INT_PE | INT_FE;
|
||||
pub const MS: u32 = INT_RI | INT_DSR | INT_DCD | INT_CTS;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: You must disable the UART before any of the control registers are
|
||||
// reprogrammed. When the UART is disabled in the middle of transmission or
|
||||
// reception, it completes the current character before stopping
|
59
rust/hw/char/pl011/src/memory_ops.rs
Normal file
59
rust/hw/char/pl011/src/memory_ops.rs
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use core::{mem::MaybeUninit, ptr::NonNull};
|
||||
|
||||
use qemu_api::bindings::*;
|
||||
|
||||
use crate::device::PL011State;
|
||||
|
||||
pub static PL011_OPS: MemoryRegionOps = MemoryRegionOps {
|
||||
read: Some(pl011_read),
|
||||
write: Some(pl011_write),
|
||||
read_with_attrs: None,
|
||||
write_with_attrs: None,
|
||||
endianness: device_endian::DEVICE_NATIVE_ENDIAN,
|
||||
valid: unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_1>::zeroed().assume_init() },
|
||||
impl_: MemoryRegionOps__bindgen_ty_2 {
|
||||
min_access_size: 4,
|
||||
max_access_size: 4,
|
||||
..unsafe { MaybeUninit::<MemoryRegionOps__bindgen_ty_2>::zeroed().assume_init() }
|
||||
},
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pl011_read(
|
||||
opaque: *mut core::ffi::c_void,
|
||||
addr: hwaddr,
|
||||
size: core::ffi::c_uint,
|
||||
) -> u64 {
|
||||
assert!(!opaque.is_null());
|
||||
let mut state = unsafe { NonNull::new_unchecked(opaque.cast::<PL011State>()) };
|
||||
let val = unsafe { state.as_mut().read(addr, size) };
|
||||
match val {
|
||||
std::ops::ControlFlow::Break(val) => val,
|
||||
std::ops::ControlFlow::Continue(val) => {
|
||||
// SAFETY: self.char_backend is a valid CharBackend instance after it's been
|
||||
// initialized in realize().
|
||||
let cb_ptr = unsafe { core::ptr::addr_of_mut!(state.as_mut().char_backend) };
|
||||
unsafe { qemu_chr_fe_accept_input(cb_ptr) };
|
||||
|
||||
val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn pl011_write(
|
||||
opaque: *mut core::ffi::c_void,
|
||||
addr: hwaddr,
|
||||
data: u64,
|
||||
_size: core::ffi::c_uint,
|
||||
) {
|
||||
unsafe {
|
||||
assert!(!opaque.is_null());
|
||||
let mut state = NonNull::new_unchecked(opaque.cast::<PL011State>());
|
||||
state.as_mut().write(addr, data)
|
||||
}
|
||||
}
|
1
rust/hw/meson.build
Normal file
1
rust/hw/meson.build
Normal file
@ -0,0 +1 @@
|
||||
subdir('char')
|
4
rust/meson.build
Normal file
4
rust/meson.build
Normal file
@ -0,0 +1,4 @@
|
||||
subdir('qemu-api-macros')
|
||||
subdir('qemu-api')
|
||||
|
||||
subdir('hw')
|
47
rust/qemu-api-macros/Cargo.lock
generated
Normal file
47
rust/qemu-api-macros/Cargo.lock
generated
Normal file
@ -0,0 +1,47 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qemu_api_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
25
rust/qemu-api-macros/Cargo.toml
Normal file
25
rust/qemu-api-macros/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "qemu_api_macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
|
||||
license = "GPL-2.0-or-later"
|
||||
readme = "README.md"
|
||||
homepage = "https://www.qemu.org"
|
||||
description = "Rust bindings for QEMU - Utility macros"
|
||||
repository = "https://gitlab.com/qemu-project/qemu/"
|
||||
resolver = "2"
|
||||
publish = false
|
||||
keywords = []
|
||||
categories = []
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1"
|
||||
quote = "1"
|
||||
syn = "2"
|
||||
|
||||
# Do not include in any global workspace
|
||||
[workspace]
|
1
rust/qemu-api-macros/README.md
Normal file
1
rust/qemu-api-macros/README.md
Normal file
@ -0,0 +1 @@
|
||||
# `qemu-api-macros` - Utility macros for defining QEMU devices
|
25
rust/qemu-api-macros/meson.build
Normal file
25
rust/qemu-api-macros/meson.build
Normal file
@ -0,0 +1,25 @@
|
||||
add_languages('rust', required: true, native: true)
|
||||
|
||||
quote_dep = dependency('quote-1-rs', native: true)
|
||||
syn_dep = dependency('syn-2-rs', native: true)
|
||||
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
|
||||
|
||||
_qemu_api_macros_rs = import('rust').proc_macro(
|
||||
'qemu_api_macros',
|
||||
files('src/lib.rs'),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_args: [
|
||||
'--cfg', 'use_fallback',
|
||||
'--cfg', 'feature="syn-error"',
|
||||
'--cfg', 'feature="proc-macro"',
|
||||
],
|
||||
dependencies: [
|
||||
proc_macro2_dep,
|
||||
quote_dep,
|
||||
syn_dep,
|
||||
],
|
||||
)
|
||||
|
||||
qemu_api_macros = declare_dependency(
|
||||
link_with: _qemu_api_macros_rs,
|
||||
)
|
43
rust/qemu-api-macros/src/lib.rs
Normal file
43
rust/qemu-api-macros/src/lib.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
#[proc_macro_derive(Object)]
|
||||
pub fn derive_object(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
let name = input.ident;
|
||||
let module_static = format_ident!("__{}_LOAD_MODULE", name);
|
||||
|
||||
let expanded = quote! {
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[used]
|
||||
#[cfg_attr(target_os = "linux", link_section = ".ctors")]
|
||||
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
|
||||
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
|
||||
pub static #module_static: extern "C" fn() = {
|
||||
extern "C" fn __register() {
|
||||
unsafe {
|
||||
::qemu_api::bindings::type_register_static(&<#name as ::qemu_api::definitions::ObjectImpl>::TYPE_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn __load() {
|
||||
unsafe {
|
||||
::qemu_api::bindings::register_module_init(
|
||||
Some(__register),
|
||||
::qemu_api::bindings::module_init_type::MODULE_INIT_QOM
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
__load
|
||||
};
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
2
rust/qemu-api/.gitignore
vendored
Normal file
2
rust/qemu-api/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Ignore generated bindings file overrides.
|
||||
src/bindings.rs
|
7
rust/qemu-api/Cargo.lock
generated
Normal file
7
rust/qemu-api/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "qemu_api"
|
||||
version = "0.1.0"
|
26
rust/qemu-api/Cargo.toml
Normal file
26
rust/qemu-api/Cargo.toml
Normal file
@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "qemu_api"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Manos Pitsidianakis <manos.pitsidianakis@linaro.org>"]
|
||||
license = "GPL-2.0-or-later"
|
||||
readme = "README.md"
|
||||
homepage = "https://www.qemu.org"
|
||||
description = "Rust bindings for QEMU"
|
||||
repository = "https://gitlab.com/qemu-project/qemu/"
|
||||
resolver = "2"
|
||||
publish = false
|
||||
keywords = []
|
||||
categories = []
|
||||
|
||||
[dependencies]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
allocator = []
|
||||
|
||||
# Do not include in any global workspace
|
||||
[workspace]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)'] }
|
17
rust/qemu-api/README.md
Normal file
17
rust/qemu-api/README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# QEMU bindings and API wrappers
|
||||
|
||||
This library exports helper Rust types, Rust macros and C FFI bindings for internal QEMU APIs.
|
||||
|
||||
The C bindings can be generated with `bindgen`, using this build target:
|
||||
|
||||
```console
|
||||
$ ninja bindings.rs
|
||||
```
|
||||
|
||||
## Generate Rust documentation
|
||||
|
||||
To generate docs for this crate, including private items:
|
||||
|
||||
```sh
|
||||
cargo doc --no-deps --document-private-items
|
||||
```
|
14
rust/qemu-api/build.rs
Normal file
14
rust/qemu-api/build.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
if !Path::new("src/bindings.rs").exists() {
|
||||
panic!(
|
||||
"No generated C bindings found! Either build them manually with bindgen or with meson \
|
||||
(`ninja bindings.rs`) and copy them to src/bindings.rs, or build through meson."
|
||||
);
|
||||
}
|
||||
}
|
24
rust/qemu-api/meson.build
Normal file
24
rust/qemu-api/meson.build
Normal file
@ -0,0 +1,24 @@
|
||||
_qemu_api_rs = static_library(
|
||||
'qemu_api',
|
||||
structured_sources(
|
||||
[
|
||||
'src/lib.rs',
|
||||
'src/definitions.rs',
|
||||
'src/device_class.rs',
|
||||
],
|
||||
{'.' : bindings_rs},
|
||||
),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: rustc_args + [
|
||||
'--cfg', 'MESON',
|
||||
# '--cfg', 'feature="allocator"',
|
||||
],
|
||||
dependencies: [
|
||||
qemu_api_macros,
|
||||
],
|
||||
)
|
||||
|
||||
qemu_api = declare_dependency(
|
||||
link_with: _qemu_api_rs,
|
||||
)
|
97
rust/qemu-api/src/definitions.rs
Normal file
97
rust/qemu-api/src/definitions.rs
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
//! Definitions required by QEMU when registering a device.
|
||||
|
||||
use ::core::ffi::{c_void, CStr};
|
||||
|
||||
use crate::bindings::{Object, ObjectClass, TypeInfo};
|
||||
|
||||
/// Trait a type must implement to be registered with QEMU.
|
||||
pub trait ObjectImpl {
|
||||
type Class;
|
||||
const TYPE_INFO: TypeInfo;
|
||||
const TYPE_NAME: &'static CStr;
|
||||
const PARENT_TYPE_NAME: Option<&'static CStr>;
|
||||
const ABSTRACT: bool;
|
||||
const INSTANCE_INIT: Option<unsafe extern "C" fn(obj: *mut Object)>;
|
||||
const INSTANCE_POST_INIT: Option<unsafe extern "C" fn(obj: *mut Object)>;
|
||||
const INSTANCE_FINALIZE: Option<unsafe extern "C" fn(obj: *mut Object)>;
|
||||
}
|
||||
|
||||
pub trait Class {
|
||||
const CLASS_INIT: Option<unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void)>;
|
||||
const CLASS_BASE_INIT: Option<
|
||||
unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void),
|
||||
>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! module_init {
|
||||
($func:expr, $type:expr) => {
|
||||
#[used]
|
||||
#[cfg_attr(target_os = "linux", link_section = ".ctors")]
|
||||
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
|
||||
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
|
||||
pub static LOAD_MODULE: extern "C" fn() = {
|
||||
extern "C" fn __load() {
|
||||
unsafe {
|
||||
$crate::bindings::register_module_init(Some($func), $type);
|
||||
}
|
||||
}
|
||||
|
||||
__load
|
||||
};
|
||||
};
|
||||
(qom: $func:ident => $body:block) => {
|
||||
// NOTE: To have custom identifiers for the ctor func we need to either supply
|
||||
// them directly as a macro argument or create them with a proc macro.
|
||||
#[used]
|
||||
#[cfg_attr(target_os = "linux", link_section = ".ctors")]
|
||||
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
|
||||
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
|
||||
pub static LOAD_MODULE: extern "C" fn() = {
|
||||
extern "C" fn __load() {
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn $func() {
|
||||
$body
|
||||
}
|
||||
|
||||
unsafe {
|
||||
$crate::bindings::register_module_init(
|
||||
Some($func),
|
||||
$crate::bindings::module_init_type::MODULE_INIT_QOM,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
__load
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! type_info {
|
||||
($t:ty) => {
|
||||
$crate::bindings::TypeInfo {
|
||||
name: <$t as $crate::definitions::ObjectImpl>::TYPE_NAME.as_ptr(),
|
||||
parent: if let Some(pname) = <$t as $crate::definitions::ObjectImpl>::PARENT_TYPE_NAME {
|
||||
pname.as_ptr()
|
||||
} else {
|
||||
::core::ptr::null_mut()
|
||||
},
|
||||
instance_size: ::core::mem::size_of::<$t>() as $crate::bindings::size_t,
|
||||
instance_align: ::core::mem::align_of::<$t>() as $crate::bindings::size_t,
|
||||
instance_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_INIT,
|
||||
instance_post_init: <$t as $crate::definitions::ObjectImpl>::INSTANCE_POST_INIT,
|
||||
instance_finalize: <$t as $crate::definitions::ObjectImpl>::INSTANCE_FINALIZE,
|
||||
abstract_: <$t as $crate::definitions::ObjectImpl>::ABSTRACT,
|
||||
class_size: ::core::mem::size_of::<<$t as $crate::definitions::ObjectImpl>::Class>() as $crate::bindings::size_t,
|
||||
class_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_INIT,
|
||||
class_base_init: <<$t as $crate::definitions::ObjectImpl>::Class as $crate::definitions::Class>::CLASS_BASE_INIT,
|
||||
class_data: ::core::ptr::null_mut(),
|
||||
interfaces: ::core::ptr::null_mut(),
|
||||
};
|
||||
}
|
||||
}
|
128
rust/qemu-api/src/device_class.rs
Normal file
128
rust/qemu-api/src/device_class.rs
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::bindings::Property;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! device_class_init {
|
||||
($func:ident, props => $props:ident, realize_fn => $realize_fn:expr, legacy_reset_fn => $legacy_reset_fn:expr, vmsd => $vmsd:ident$(,)*) => {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn $func(
|
||||
klass: *mut $crate::bindings::ObjectClass,
|
||||
_: *mut ::core::ffi::c_void,
|
||||
) {
|
||||
let mut dc =
|
||||
::core::ptr::NonNull::new(klass.cast::<$crate::bindings::DeviceClass>()).unwrap();
|
||||
dc.as_mut().realize = $realize_fn;
|
||||
dc.as_mut().vmsd = &$vmsd;
|
||||
$crate::bindings::device_class_set_legacy_reset(dc.as_mut(), $legacy_reset_fn);
|
||||
$crate::bindings::device_class_set_props(dc.as_mut(), $props.as_mut_ptr());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! define_property {
|
||||
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr, default = $defval:expr$(,)*) => {
|
||||
$crate::bindings::Property {
|
||||
name: {
|
||||
#[used]
|
||||
static _TEMP: &::core::ffi::CStr = $name;
|
||||
_TEMP.as_ptr()
|
||||
},
|
||||
info: $prop,
|
||||
offset: ::core::mem::offset_of!($state, $field)
|
||||
.try_into()
|
||||
.expect("Could not fit offset value to type"),
|
||||
bitnr: 0,
|
||||
bitmask: 0,
|
||||
set_default: true,
|
||||
defval: $crate::bindings::Property__bindgen_ty_1 { u: $defval.into() },
|
||||
arrayoffset: 0,
|
||||
arrayinfo: ::core::ptr::null(),
|
||||
arrayfieldsize: 0,
|
||||
link_type: ::core::ptr::null(),
|
||||
}
|
||||
};
|
||||
($name:expr, $state:ty, $field:expr, $prop:expr, $type:expr$(,)*) => {
|
||||
$crate::bindings::Property {
|
||||
name: {
|
||||
#[used]
|
||||
static _TEMP: &::core::ffi::CStr = $name;
|
||||
_TEMP.as_ptr()
|
||||
},
|
||||
info: $prop,
|
||||
offset: ::core::mem::offset_of!($state, $field)
|
||||
.try_into()
|
||||
.expect("Could not fit offset value to type"),
|
||||
bitnr: 0,
|
||||
bitmask: 0,
|
||||
set_default: false,
|
||||
defval: $crate::bindings::Property__bindgen_ty_1 { i: 0 },
|
||||
arrayoffset: 0,
|
||||
arrayinfo: ::core::ptr::null(),
|
||||
arrayfieldsize: 0,
|
||||
link_type: ::core::ptr::null(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Properties<const N: usize>(pub OnceLock<[Property; N]>, pub fn() -> [Property; N]);
|
||||
|
||||
impl<const N: usize> Properties<N> {
|
||||
pub fn as_mut_ptr(&mut self) -> *mut Property {
|
||||
_ = self.0.get_or_init(self.1);
|
||||
self.0.get_mut().unwrap().as_mut_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! declare_properties {
|
||||
($ident:ident, $($prop:expr),*$(,)*) => {
|
||||
|
||||
const fn _calc_prop_len() -> usize {
|
||||
let mut len = 1;
|
||||
$({
|
||||
_ = stringify!($prop);
|
||||
len += 1;
|
||||
})*
|
||||
len
|
||||
}
|
||||
const PROP_LEN: usize = _calc_prop_len();
|
||||
|
||||
fn _make_properties() -> [$crate::bindings::Property; PROP_LEN] {
|
||||
[
|
||||
$($prop),*,
|
||||
unsafe { ::core::mem::MaybeUninit::<$crate::bindings::Property>::zeroed().assume_init() },
|
||||
]
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub static mut $ident: $crate::device_class::Properties<PROP_LEN> = $crate::device_class::Properties(::std::sync::OnceLock::new(), _make_properties);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! vm_state_description {
|
||||
($(#[$outer:meta])*
|
||||
$name:ident,
|
||||
$(name: $vname:expr,)*
|
||||
$(unmigratable: $um_val:expr,)*
|
||||
) => {
|
||||
#[used]
|
||||
$(#[$outer])*
|
||||
pub static $name: $crate::bindings::VMStateDescription = $crate::bindings::VMStateDescription {
|
||||
$(name: {
|
||||
#[used]
|
||||
static VMSTATE_NAME: &::core::ffi::CStr = $vname;
|
||||
$vname.as_ptr()
|
||||
},)*
|
||||
unmigratable: true,
|
||||
..unsafe { ::core::mem::MaybeUninit::<$crate::bindings::VMStateDescription>::zeroed().assume_init() }
|
||||
};
|
||||
}
|
||||
}
|
166
rust/qemu-api/src/lib.rs
Normal file
166
rust/qemu-api/src/lib.rs
Normal file
@ -0,0 +1,166 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#![cfg_attr(not(MESON), doc = include_str!("../README.md"))]
|
||||
|
||||
#[allow(
|
||||
dead_code,
|
||||
improper_ctypes_definitions,
|
||||
improper_ctypes,
|
||||
non_camel_case_types,
|
||||
non_snake_case,
|
||||
non_upper_case_globals,
|
||||
unsafe_op_in_unsafe_fn,
|
||||
clippy::missing_const_for_fn,
|
||||
clippy::too_many_arguments,
|
||||
clippy::approx_constant,
|
||||
clippy::use_self,
|
||||
clippy::useless_transmute,
|
||||
clippy::missing_safety_doc,
|
||||
)]
|
||||
#[rustfmt::skip]
|
||||
pub mod bindings;
|
||||
|
||||
unsafe impl Send for bindings::Property {}
|
||||
unsafe impl Sync for bindings::Property {}
|
||||
unsafe impl Sync for bindings::TypeInfo {}
|
||||
unsafe impl Sync for bindings::VMStateDescription {}
|
||||
|
||||
pub mod definitions;
|
||||
pub mod device_class;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
#[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
|
||||
extern "C" {
|
||||
fn g_aligned_alloc0(
|
||||
n_blocks: bindings::gsize,
|
||||
n_block_bytes: bindings::gsize,
|
||||
alignment: bindings::gsize,
|
||||
) -> bindings::gpointer;
|
||||
fn g_aligned_free(mem: bindings::gpointer);
|
||||
}
|
||||
|
||||
#[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
|
||||
extern "C" {
|
||||
fn qemu_memalign(alignment: usize, size: usize) -> *mut ::core::ffi::c_void;
|
||||
fn qemu_vfree(ptr: *mut ::core::ffi::c_void);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn g_malloc0(n_bytes: bindings::gsize) -> bindings::gpointer;
|
||||
fn g_free(mem: bindings::gpointer);
|
||||
}
|
||||
|
||||
/// An allocator that uses the same allocator as QEMU in C.
|
||||
///
|
||||
/// It is enabled by default with the `allocator` feature.
|
||||
///
|
||||
/// To set it up manually as a global allocator in your crate:
|
||||
///
|
||||
/// ```ignore
|
||||
/// use qemu_api::QemuAllocator;
|
||||
///
|
||||
/// #[global_allocator]
|
||||
/// static GLOBAL: QemuAllocator = QemuAllocator::new();
|
||||
/// ```
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct QemuAllocator {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
|
||||
#[cfg_attr(all(feature = "allocator", not(test)), global_allocator)]
|
||||
pub static GLOBAL: QemuAllocator = QemuAllocator::new();
|
||||
|
||||
impl QemuAllocator {
|
||||
// From the glibc documentation, on GNU systems, malloc guarantees 16-byte
|
||||
// alignment on 64-bit systems and 8-byte alignment on 32-bit systems. See
|
||||
// https://www.gnu.org/software/libc/manual/html_node/Malloc-Examples.html.
|
||||
// This alignment guarantee also applies to Windows and Android. On Darwin
|
||||
// and OpenBSD, the alignment is 16 bytes on both 64-bit and 32-bit systems.
|
||||
#[cfg(all(
|
||||
target_pointer_width = "32",
|
||||
not(any(target_os = "macos", target_os = "openbsd"))
|
||||
))]
|
||||
pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(8);
|
||||
#[cfg(all(
|
||||
target_pointer_width = "64",
|
||||
not(any(target_os = "macos", target_os = "openbsd"))
|
||||
))]
|
||||
pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16);
|
||||
#[cfg(all(
|
||||
any(target_pointer_width = "32", target_pointer_width = "64"),
|
||||
any(target_os = "macos", target_os = "openbsd")
|
||||
))]
|
||||
pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = Some(16);
|
||||
#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))]
|
||||
pub const DEFAULT_ALIGNMENT_BYTES: Option<usize> = None;
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self { _unused: [] }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuAllocator {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity check.
|
||||
const _: [(); 8] = [(); ::core::mem::size_of::<*mut ::core::ffi::c_void>()];
|
||||
|
||||
unsafe impl GlobalAlloc for QemuAllocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0))
|
||||
{
|
||||
// SAFETY: g_malloc0() is safe to call.
|
||||
unsafe { g_malloc0(layout.size().try_into().unwrap()).cast::<u8>() }
|
||||
} else {
|
||||
#[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
|
||||
{
|
||||
// SAFETY: g_aligned_alloc0() is safe to call.
|
||||
unsafe {
|
||||
g_aligned_alloc0(
|
||||
layout.size().try_into().unwrap(),
|
||||
1,
|
||||
layout.align().try_into().unwrap(),
|
||||
)
|
||||
.cast::<u8>()
|
||||
}
|
||||
}
|
||||
#[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
|
||||
{
|
||||
// SAFETY: qemu_memalign() is safe to call.
|
||||
unsafe { qemu_memalign(layout.align(), layout.size()).cast::<u8>() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
if matches!(Self::DEFAULT_ALIGNMENT_BYTES, Some(default) if default.checked_rem(layout.align()) == Some(0))
|
||||
{
|
||||
// SAFETY: `ptr` must have been allocated by Self::alloc thus a valid
|
||||
// glib-allocated pointer, so `g_free`ing is safe.
|
||||
unsafe { g_free(ptr.cast::<_>()) }
|
||||
} else {
|
||||
#[cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)]
|
||||
{
|
||||
// SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned
|
||||
// glib-allocated pointer, so `g_aligned_free`ing is safe.
|
||||
unsafe { g_aligned_free(ptr.cast::<_>()) }
|
||||
}
|
||||
#[cfg(not(HAVE_GLIB_WITH_ALIGNED_ALLOC))]
|
||||
{
|
||||
// SAFETY: `ptr` must have been allocated by Self::alloc thus a valid aligned
|
||||
// glib-allocated pointer, so `qemu_vfree`ing is safe.
|
||||
unsafe { qemu_vfree(ptr.cast::<_>()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
49
rust/qemu-api/src/tests.rs
Normal file
49
rust/qemu-api/src/tests.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2024, Linaro Limited
|
||||
// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
use crate::{
|
||||
bindings::*, declare_properties, define_property, device_class_init, vm_state_description,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_device_decl_macros() {
|
||||
// Test that macros can compile.
|
||||
vm_state_description! {
|
||||
VMSTATE,
|
||||
name: c"name",
|
||||
unmigratable: true,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct DummyState {
|
||||
pub char_backend: CharBackend,
|
||||
pub migrate_clock: bool,
|
||||
}
|
||||
|
||||
declare_properties! {
|
||||
DUMMY_PROPERTIES,
|
||||
define_property!(
|
||||
c"chardev",
|
||||
DummyState,
|
||||
char_backend,
|
||||
unsafe { &qdev_prop_chr },
|
||||
CharBackend
|
||||
),
|
||||
define_property!(
|
||||
c"migrate-clk",
|
||||
DummyState,
|
||||
migrate_clock,
|
||||
unsafe { &qdev_prop_bool },
|
||||
bool
|
||||
),
|
||||
}
|
||||
|
||||
device_class_init! {
|
||||
dummy_class_init,
|
||||
props => DUMMY_PROPERTIES,
|
||||
realize_fn => None,
|
||||
reset_fn => None,
|
||||
vmsd => VMSTATE,
|
||||
}
|
||||
}
|
7
rust/rustfmt.toml
Normal file
7
rust/rustfmt.toml
Normal file
@ -0,0 +1,7 @@
|
||||
edition = "2021"
|
||||
format_generated_files = false
|
||||
format_code_in_doc_comments = true
|
||||
format_strings = true
|
||||
imports_granularity = "Crate"
|
||||
group_imports = "StdExternalCrate"
|
||||
wrap_comments = true
|
47
rust/wrapper.h
Normal file
47
rust/wrapper.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu-io.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/memory.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "hw/clock.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "hw/irq.h"
|
||||
#include "qapi/error.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "chardev/char-serial.h"
|
@ -26,7 +26,11 @@ sub_file="${sub_tdir}/submodule.tar"
|
||||
# independent of what the developer currently has initialized
|
||||
# in their checkout, because the build environment is completely
|
||||
# different to the host OS.
|
||||
subprojects="keycodemapdb libvfio-user berkeley-softfloat-3 berkeley-testfloat-3"
|
||||
subprojects="keycodemapdb libvfio-user berkeley-softfloat-3
|
||||
berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
|
||||
bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
|
||||
proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
|
||||
syn-2-rs unicode-ident-1-rs"
|
||||
sub_deinit=""
|
||||
|
||||
function cleanup() {
|
||||
@ -48,13 +52,34 @@ function tree_ish() {
|
||||
echo "$retval"
|
||||
}
|
||||
|
||||
function subproject_dir() {
|
||||
if test ! -f "subprojects/$1.wrap"; then
|
||||
error "scripts/archive-source.sh should only process wrap subprojects"
|
||||
fi
|
||||
|
||||
# Print the directory key of the wrap file, defaulting to the
|
||||
# subproject name. The wrap file is in ini format and should
|
||||
# have a single section only. There should be only one section
|
||||
# named "[wrap-*]", which helps keeping the script simple.
|
||||
local dir
|
||||
dir=$(sed -n \
|
||||
-e '/^\[wrap-[a-z][a-z]*\]$/,/^\[/{' \
|
||||
-e '/^directory *= */!b' \
|
||||
-e 's///p' \
|
||||
-e 'q' \
|
||||
-e '}' \
|
||||
"subprojects/$1.wrap")
|
||||
|
||||
echo "${dir:-$1}"
|
||||
}
|
||||
|
||||
git archive --format tar "$(tree_ish)" > "$tar_file"
|
||||
test $? -ne 0 && error "failed to archive qemu"
|
||||
|
||||
for sp in $subprojects; do
|
||||
meson subprojects download $sp
|
||||
test $? -ne 0 && error "failed to download subproject $sp"
|
||||
tar --append --file "$tar_file" --exclude=.git subprojects/$sp
|
||||
tar --append --file "$tar_file" --exclude=.git subprojects/"$(subproject_dir $sp)"
|
||||
test $? -ne 0 && error "failed to append subproject $sp to $tar_file"
|
||||
done
|
||||
exit 0
|
||||
|
@ -17,7 +17,11 @@ if [ $# -ne 2 ]; then
|
||||
fi
|
||||
|
||||
# Only include wraps that are invoked with subproject()
|
||||
SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3 berkeley-testfloat-3"
|
||||
SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3
|
||||
berkeley-testfloat-3 arbitrary-int-1-rs bilge-0.2-rs
|
||||
bilge-impl-0.2-rs either-1-rs itertools-0.11-rs proc-macro2-1-rs
|
||||
proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
|
||||
syn-2-rs unicode-ident-1-rs"
|
||||
|
||||
src="$1"
|
||||
version="$2"
|
||||
|
@ -172,6 +172,7 @@ meson_options_help() {
|
||||
printf "%s\n" ' rbd Ceph block device driver'
|
||||
printf "%s\n" ' rdma Enable RDMA-based migration'
|
||||
printf "%s\n" ' replication replication support'
|
||||
printf "%s\n" ' rust Rust support'
|
||||
printf "%s\n" ' rutabaga-gfx rutabaga_gfx support'
|
||||
printf "%s\n" ' sdl SDL user interface'
|
||||
printf "%s\n" ' sdl-image SDL Image support for icons'
|
||||
@ -456,6 +457,8 @@ _meson_option_parse() {
|
||||
--disable-replication) printf "%s" -Dreplication=disabled ;;
|
||||
--enable-rng-none) printf "%s" -Drng_none=true ;;
|
||||
--disable-rng-none) printf "%s" -Drng_none=false ;;
|
||||
--enable-rust) printf "%s" -Drust=enabled ;;
|
||||
--disable-rust) printf "%s" -Drust=disabled ;;
|
||||
--enable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=enabled ;;
|
||||
--disable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=disabled ;;
|
||||
--enable-safe-stack) printf "%s" -Dsafe_stack=true ;;
|
||||
|
13
scripts/rust/rust_root_crate.sh
Executable file
13
scripts/rust/rust_root_crate.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
cat <<EOF
|
||||
// @generated
|
||||
// This file is autogenerated by scripts/rust_root_crate.sh
|
||||
|
||||
EOF
|
||||
|
||||
for crate in $*; do
|
||||
echo "extern crate $crate;"
|
||||
done
|
84
scripts/rust/rustc_args.py
Normal file
84
scripts/rust/rustc_args.py
Normal file
@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Generate rustc arguments for meson rust builds.
|
||||
|
||||
This program generates --cfg compile flags for the configuration headers passed
|
||||
as arguments.
|
||||
|
||||
Copyright (c) 2024 Linaro Ltd.
|
||||
|
||||
Authors:
|
||||
Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
from typing import List
|
||||
|
||||
|
||||
def generate_cfg_flags(header: str) -> List[str]:
|
||||
"""Converts defines from config[..].h headers to rustc --cfg flags."""
|
||||
|
||||
def cfg_name(name: str) -> str:
|
||||
"""Filter function for C #defines"""
|
||||
if (
|
||||
name.startswith("CONFIG_")
|
||||
or name.startswith("TARGET_")
|
||||
or name.startswith("HAVE_")
|
||||
):
|
||||
return name
|
||||
return ""
|
||||
|
||||
with open(header, encoding="utf-8") as cfg:
|
||||
config = [l.split()[1:] for l in cfg if l.startswith("#define")]
|
||||
|
||||
cfg_list = []
|
||||
for cfg in config:
|
||||
name = cfg_name(cfg[0])
|
||||
if not name:
|
||||
continue
|
||||
if len(cfg) >= 2 and cfg[1] != "1":
|
||||
continue
|
||||
cfg_list.append("--cfg")
|
||||
cfg_list.append(name)
|
||||
return cfg_list
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# pylint: disable=missing-function-docstring
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-v", "--verbose", action="store_true")
|
||||
parser.add_argument(
|
||||
"--config-headers",
|
||||
metavar="CONFIG_HEADER",
|
||||
action="append",
|
||||
dest="config_headers",
|
||||
help="paths to any configuration C headers (*.h files), if any",
|
||||
required=False,
|
||||
default=[],
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if args.verbose:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.debug("args: %s", args)
|
||||
for header in args.config_headers:
|
||||
for tok in generate_cfg_flags(header):
|
||||
print(tok)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
11
subprojects/.gitignore
vendored
11
subprojects/.gitignore
vendored
@ -6,3 +6,14 @@
|
||||
/keycodemapdb
|
||||
/libvfio-user
|
||||
/slirp
|
||||
/arbitrary-int-1.2.7
|
||||
/bilge-0.2.0
|
||||
/bilge-impl-0.2.0
|
||||
/either-1.12.0
|
||||
/itertools-0.11.0
|
||||
/proc-macro-error-1.0.4
|
||||
/proc-macro-error-attr-1.0.4
|
||||
/proc-macro2-1.0.84
|
||||
/quote-1.0.36
|
||||
/syn-2.0.66
|
||||
/unicode-ident-1.0.12
|
||||
|
7
subprojects/arbitrary-int-1-rs.wrap
Normal file
7
subprojects/arbitrary-int-1-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = arbitrary-int-1.2.7
|
||||
source_url = https://crates.io/api/v1/crates/arbitrary-int/1.2.7/download
|
||||
source_filename = arbitrary-int-1.2.7.tar.gz
|
||||
source_hash = c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d
|
||||
#method = cargo
|
||||
patch_directory = arbitrary-int-1-rs
|
7
subprojects/bilge-0.2-rs.wrap
Normal file
7
subprojects/bilge-0.2-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = bilge-0.2.0
|
||||
source_url = https://crates.io/api/v1/crates/bilge/0.2.0/download
|
||||
source_filename = bilge-0.2.0.tar.gz
|
||||
source_hash = dc707ed8ebf81de5cd6c7f48f54b4c8621760926cdf35a57000747c512e67b57
|
||||
#method = cargo
|
||||
patch_directory = bilge-0.2-rs
|
7
subprojects/bilge-impl-0.2-rs.wrap
Normal file
7
subprojects/bilge-impl-0.2-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = bilge-impl-0.2.0
|
||||
source_url = https://crates.io/api/v1/crates/bilge-impl/0.2.0/download
|
||||
source_filename = bilge-impl-0.2.0.tar.gz
|
||||
source_hash = feb11e002038ad243af39c2068c8a72bcf147acf05025dcdb916fcc000adb2d8
|
||||
#method = cargo
|
||||
patch_directory = bilge-impl-0.2-rs
|
7
subprojects/either-1-rs.wrap
Normal file
7
subprojects/either-1-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = either-1.12.0
|
||||
source_url = https://crates.io/api/v1/crates/either/1.12.0/download
|
||||
source_filename = either-1.12.0.tar.gz
|
||||
source_hash = 3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b
|
||||
#method = cargo
|
||||
patch_directory = either-1-rs
|
7
subprojects/itertools-0.11-rs.wrap
Normal file
7
subprojects/itertools-0.11-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = itertools-0.11.0
|
||||
source_url = https://crates.io/api/v1/crates/itertools/0.11.0/download
|
||||
source_filename = itertools-0.11.0.tar.gz
|
||||
source_hash = b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57
|
||||
#method = cargo
|
||||
patch_directory = itertools-0.11-rs
|
19
subprojects/packagefiles/arbitrary-int-1-rs/meson.build
Normal file
19
subprojects/packagefiles/arbitrary-int-1-rs/meson.build
Normal file
@ -0,0 +1,19 @@
|
||||
project('arbitrary-int-1-rs', 'rust',
|
||||
version: '1.2.7',
|
||||
license: 'MIT',
|
||||
default_options: [])
|
||||
|
||||
_arbitrary_int_rs = static_library(
|
||||
'arbitrary_int',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
dependencies: [],
|
||||
)
|
||||
|
||||
arbitrary_int_dep = declare_dependency(
|
||||
link_with: _arbitrary_int_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('arbitrary-int-1-rs', arbitrary_int_dep)
|
29
subprojects/packagefiles/bilge-0.2-rs/meson.build
Normal file
29
subprojects/packagefiles/bilge-0.2-rs/meson.build
Normal file
@ -0,0 +1,29 @@
|
||||
project(
|
||||
'bilge-0.2-rs',
|
||||
'rust',
|
||||
version : '0.2.0',
|
||||
license : 'MIT or Apache-2.0',
|
||||
)
|
||||
|
||||
subproject('arbitrary-int-1-rs', required: true)
|
||||
subproject('bilge-impl-0.2-rs', required: true)
|
||||
|
||||
arbitrary_int_dep = dependency('arbitrary-int-1-rs')
|
||||
bilge_impl_dep = dependency('bilge-impl-0.2-rs')
|
||||
|
||||
lib = static_library(
|
||||
'bilge',
|
||||
'src/lib.rs',
|
||||
override_options : ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi : 'rust',
|
||||
dependencies: [
|
||||
arbitrary_int_dep,
|
||||
bilge_impl_dep,
|
||||
],
|
||||
)
|
||||
|
||||
bilge_dep = declare_dependency(
|
||||
link_with : [lib],
|
||||
)
|
||||
|
||||
meson.override_dependency('bilge-0.2-rs', bilge_dep)
|
45
subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
Normal file
45
subprojects/packagefiles/bilge-impl-0.2-rs/meson.build
Normal file
@ -0,0 +1,45 @@
|
||||
project('bilge-impl-0.2-rs', 'rust',
|
||||
version: '0.2.0',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
subproject('itertools-0.11-rs', required: true)
|
||||
subproject('proc-macro-error-attr-1-rs', required: true)
|
||||
subproject('proc-macro-error-1-rs', required: true)
|
||||
subproject('quote-1-rs', required: true)
|
||||
subproject('syn-2-rs', required: true)
|
||||
subproject('proc-macro2-1-rs', required: true)
|
||||
|
||||
itertools_dep = dependency('itertools-0.11-rs', native: true)
|
||||
proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
|
||||
proc_macro_error_dep = dependency('proc-macro-error-1-rs', native: true)
|
||||
quote_dep = dependency('quote-1-rs', native: true)
|
||||
syn_dep = dependency('syn-2-rs', native: true)
|
||||
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
|
||||
|
||||
rust = import('rust')
|
||||
|
||||
_bilge_impl_rs = rust.proc_macro(
|
||||
'bilge_impl',
|
||||
files('src/lib.rs'),
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_args: [
|
||||
'--cfg', 'use_fallback',
|
||||
'--cfg', 'feature="syn-error"',
|
||||
'--cfg', 'feature="proc-macro"',
|
||||
],
|
||||
dependencies: [
|
||||
itertools_dep,
|
||||
proc_macro_error_attr_dep,
|
||||
proc_macro_error_dep,
|
||||
quote_dep,
|
||||
syn_dep,
|
||||
proc_macro2_dep,
|
||||
],
|
||||
)
|
||||
|
||||
bilge_impl_dep = declare_dependency(
|
||||
link_with: _bilge_impl_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('bilge-impl-0.2-rs', bilge_impl_dep)
|
24
subprojects/packagefiles/either-1-rs/meson.build
Normal file
24
subprojects/packagefiles/either-1-rs/meson.build
Normal file
@ -0,0 +1,24 @@
|
||||
project('either-1-rs', 'rust',
|
||||
version: '1.12.0',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
_either_rs = static_library(
|
||||
'either',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2018', 'build.rust_std=2018'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: [
|
||||
'--cfg', 'feature="use_std"',
|
||||
'--cfg', 'feature="use_alloc"',
|
||||
],
|
||||
dependencies: [],
|
||||
native: true,
|
||||
)
|
||||
|
||||
either_dep = declare_dependency(
|
||||
link_with: _either_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('either-1-rs', either_dep, native: true)
|
30
subprojects/packagefiles/itertools-0.11-rs/meson.build
Normal file
30
subprojects/packagefiles/itertools-0.11-rs/meson.build
Normal file
@ -0,0 +1,30 @@
|
||||
project('itertools-0.11-rs', 'rust',
|
||||
version: '0.11.0',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
subproject('either-1-rs', required: true)
|
||||
|
||||
either_dep = dependency('either-1-rs', native: true)
|
||||
|
||||
_itertools_rs = static_library(
|
||||
'itertools',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2018', 'build.rust_std=2018'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: [
|
||||
'--cfg', 'feature="use_std"',
|
||||
'--cfg', 'feature="use_alloc"',
|
||||
],
|
||||
dependencies: [
|
||||
either_dep,
|
||||
],
|
||||
native: true,
|
||||
)
|
||||
|
||||
itertools_dep = declare_dependency(
|
||||
link_with: _itertools_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('itertools-0.11-rs', itertools_dep, native: true)
|
40
subprojects/packagefiles/proc-macro-error-1-rs/meson.build
Normal file
40
subprojects/packagefiles/proc-macro-error-1-rs/meson.build
Normal file
@ -0,0 +1,40 @@
|
||||
project('proc-macro-error-1-rs', 'rust',
|
||||
version: '1.0.4',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
subproject('proc-macro-error-attr-1-rs', required: true)
|
||||
subproject('quote-1-rs', required: true)
|
||||
subproject('syn-2-rs', required: true)
|
||||
subproject('proc-macro2-1-rs', required: true)
|
||||
|
||||
proc_macro_error_attr_dep = dependency('proc-macro-error-attr-1-rs', native: true)
|
||||
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
|
||||
quote_dep = dependency('quote-1-rs', native: true)
|
||||
syn_dep = dependency('syn-2-rs', native: true)
|
||||
|
||||
_proc_macro_error_rs = static_library(
|
||||
'proc_macro_error',
|
||||
files('src/lib.rs'),
|
||||
override_options: ['rust_std=2018', 'build.rust_std=2018'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: [
|
||||
'--cfg', 'use_fallback',
|
||||
'--cfg', 'feature="syn-error"',
|
||||
'--cfg', 'feature="proc-macro"',
|
||||
'-A', 'non_fmt_panics'
|
||||
],
|
||||
dependencies: [
|
||||
proc_macro_error_attr_dep,
|
||||
proc_macro2_dep,
|
||||
quote_dep,
|
||||
syn_dep,
|
||||
],
|
||||
native: true,
|
||||
)
|
||||
|
||||
proc_macro_error_dep = declare_dependency(
|
||||
link_with: _proc_macro_error_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('proc-macro-error-1-rs', proc_macro_error_dep, native: true)
|
@ -0,0 +1,32 @@
|
||||
project('proc-macro-error-attr-1-rs', 'rust',
|
||||
version: '1.12.0',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
subproject('proc-macro2-1-rs', required: true)
|
||||
subproject('quote-1-rs', required: true)
|
||||
|
||||
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
|
||||
quote_dep = dependency('quote-1-rs', native: true)
|
||||
|
||||
rust = import('rust')
|
||||
_proc_macro_error_attr_rs = rust.proc_macro(
|
||||
'proc_macro_error_attr',
|
||||
files('src/lib.rs'),
|
||||
override_options: ['rust_std=2018', 'build.rust_std=2018'],
|
||||
rust_args: [
|
||||
'--cfg', 'use_fallback',
|
||||
'--cfg', 'feature="syn-error"',
|
||||
'--cfg', 'feature="proc-macro"'
|
||||
],
|
||||
dependencies: [
|
||||
proc_macro2_dep,
|
||||
quote_dep,
|
||||
],
|
||||
)
|
||||
|
||||
proc_macro_error_attr_dep = declare_dependency(
|
||||
link_with: _proc_macro_error_attr_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('proc-macro-error-attr-1-rs', proc_macro_error_attr_dep, native: true)
|
31
subprojects/packagefiles/proc-macro2-1-rs/meson.build
Normal file
31
subprojects/packagefiles/proc-macro2-1-rs/meson.build
Normal file
@ -0,0 +1,31 @@
|
||||
project('proc-macro2-1-rs', 'rust',
|
||||
version: '1.0.84',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
subproject('unicode-ident-1-rs', required: true)
|
||||
|
||||
unicode_ident_dep = dependency('unicode-ident-1-rs', native: true)
|
||||
|
||||
_proc_macro2_rs = static_library(
|
||||
'proc_macro2',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: [
|
||||
'--cfg', 'feature="proc-macro"',
|
||||
'--cfg', 'span_locations',
|
||||
'--cfg', 'wrap_proc_macro',
|
||||
],
|
||||
dependencies: [
|
||||
unicode_ident_dep,
|
||||
],
|
||||
native: true,
|
||||
)
|
||||
|
||||
proc_macro2_dep = declare_dependency(
|
||||
link_with: _proc_macro2_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('proc-macro2-1-rs', proc_macro2_dep, native: true)
|
29
subprojects/packagefiles/quote-1-rs/meson.build
Normal file
29
subprojects/packagefiles/quote-1-rs/meson.build
Normal file
@ -0,0 +1,29 @@
|
||||
project('quote-1-rs', 'rust',
|
||||
version: '1.12.0',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
subproject('proc-macro2-1-rs', required: true)
|
||||
|
||||
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
|
||||
|
||||
_quote_rs = static_library(
|
||||
'quote',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: [
|
||||
'--cfg', 'feature="proc-macro"',
|
||||
],
|
||||
dependencies: [
|
||||
proc_macro2_dep,
|
||||
],
|
||||
native: true,
|
||||
)
|
||||
|
||||
quote_dep = declare_dependency(
|
||||
link_with: _quote_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('quote-1-rs', quote_dep, native: true)
|
40
subprojects/packagefiles/syn-2-rs/meson.build
Normal file
40
subprojects/packagefiles/syn-2-rs/meson.build
Normal file
@ -0,0 +1,40 @@
|
||||
project('syn-2-rs', 'rust',
|
||||
version: '2.0.66',
|
||||
license: 'MIT OR Apache-2.0',
|
||||
default_options: [])
|
||||
|
||||
subproject('proc-macro2-1-rs', required: true)
|
||||
subproject('quote-1-rs', required: true)
|
||||
subproject('unicode-ident-1-rs', required: true)
|
||||
|
||||
proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
|
||||
quote_dep = dependency('quote-1-rs', native: true)
|
||||
unicode_ident_dep = dependency('unicode-ident-1-rs', native: true)
|
||||
|
||||
_syn_rs = static_library(
|
||||
'syn',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
rust_args: [
|
||||
'--cfg', 'feature="full"',
|
||||
'--cfg', 'feature="derive"',
|
||||
'--cfg', 'feature="parsing"',
|
||||
'--cfg', 'feature="printing"',
|
||||
'--cfg', 'feature="clone-impls"',
|
||||
'--cfg', 'feature="proc-macro"',
|
||||
],
|
||||
dependencies: [
|
||||
quote_dep,
|
||||
proc_macro2_dep,
|
||||
unicode_ident_dep,
|
||||
],
|
||||
native: true,
|
||||
)
|
||||
|
||||
syn_dep = declare_dependency(
|
||||
link_with: _syn_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('syn-2-rs', syn_dep, native: true)
|
20
subprojects/packagefiles/unicode-ident-1-rs/meson.build
Normal file
20
subprojects/packagefiles/unicode-ident-1-rs/meson.build
Normal file
@ -0,0 +1,20 @@
|
||||
project('unicode-ident-1-rs', 'rust',
|
||||
version: '1.0.12',
|
||||
license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016',
|
||||
default_options: [])
|
||||
|
||||
_unicode_ident_rs = static_library(
|
||||
'unicode_ident',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
dependencies: [],
|
||||
native: true,
|
||||
)
|
||||
|
||||
unicode_ident_dep = declare_dependency(
|
||||
link_with: _unicode_ident_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true)
|
7
subprojects/proc-macro-error-1-rs.wrap
Normal file
7
subprojects/proc-macro-error-1-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = proc-macro-error-1.0.4
|
||||
source_url = https://crates.io/api/v1/crates/proc-macro-error/1.0.4/download
|
||||
source_filename = proc-macro-error-1.0.4.tar.gz
|
||||
source_hash = da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c
|
||||
#method = cargo
|
||||
patch_directory = proc-macro-error-1-rs
|
7
subprojects/proc-macro-error-attr-1-rs.wrap
Normal file
7
subprojects/proc-macro-error-attr-1-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = proc-macro-error-attr-1.0.4
|
||||
source_url = https://crates.io/api/v1/crates/proc-macro-error-attr/1.0.4/download
|
||||
source_filename = proc-macro-error-attr-1.0.4.tar.gz
|
||||
source_hash = a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869
|
||||
#method = cargo
|
||||
patch_directory = proc-macro-error-attr-1-rs
|
7
subprojects/proc-macro2-1-rs.wrap
Normal file
7
subprojects/proc-macro2-1-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = proc-macro2-1.0.84
|
||||
source_url = https://crates.io/api/v1/crates/proc-macro2/1.0.84/download
|
||||
source_filename = proc-macro2-1.0.84.0.tar.gz
|
||||
source_hash = ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6
|
||||
#method = cargo
|
||||
patch_directory = proc-macro2-1-rs
|
7
subprojects/quote-1-rs.wrap
Normal file
7
subprojects/quote-1-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = quote-1.0.36
|
||||
source_url = https://crates.io/api/v1/crates/quote/1.0.36/download
|
||||
source_filename = quote-1.0.36.0.tar.gz
|
||||
source_hash = 0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7
|
||||
#method = cargo
|
||||
patch_directory = quote-1-rs
|
7
subprojects/syn-2-rs.wrap
Normal file
7
subprojects/syn-2-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = syn-2.0.66
|
||||
source_url = https://crates.io/api/v1/crates/syn/2.0.66/download
|
||||
source_filename = syn-2.0.66.0.tar.gz
|
||||
source_hash = c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5
|
||||
#method = cargo
|
||||
patch_directory = syn-2-rs
|
7
subprojects/unicode-ident-1-rs.wrap
Normal file
7
subprojects/unicode-ident-1-rs.wrap
Normal file
@ -0,0 +1,7 @@
|
||||
[wrap-file]
|
||||
directory = unicode-ident-1.0.12
|
||||
source_url = https://crates.io/api/v1/crates/unicode-ident/1.0.12/download
|
||||
source_filename = unicode-ident-1.0.12.tar.gz
|
||||
source_hash = 3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b
|
||||
#method = cargo
|
||||
patch_directory = unicode-ident-1-rs
|
20
subprojects/unicode-ident-1-rs/meson.build
Normal file
20
subprojects/unicode-ident-1-rs/meson.build
Normal file
@ -0,0 +1,20 @@
|
||||
project('unicode-ident-1-rs', 'rust',
|
||||
version: '1.0.12',
|
||||
license: '(MIT OR Apache-2.0) AND Unicode-DFS-2016',
|
||||
default_options: [])
|
||||
|
||||
_unicode_ident_rs = static_library(
|
||||
'unicode_ident',
|
||||
files('src/lib.rs'),
|
||||
gnu_symbol_visibility: 'hidden',
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
rust_abi: 'rust',
|
||||
dependencies: [],
|
||||
native: true,
|
||||
)
|
||||
|
||||
unicode_ident_dep = declare_dependency(
|
||||
link_with: _unicode_ident_rs,
|
||||
)
|
||||
|
||||
meson.override_dependency('unicode-ident-1-rs', unicode_ident_dep, native: true)
|
173
tests/docker/dockerfiles/fedora-rust-nightly.docker
Normal file
173
tests/docker/dockerfiles/fedora-rust-nightly.docker
Normal file
@ -0,0 +1,173 @@
|
||||
# THIS FILE WAS AUTO-GENERATED
|
||||
#
|
||||
# $ lcitool dockerfile --layers all fedora-40 qemu
|
||||
#
|
||||
# https://gitlab.com/libvirt/libvirt-ci
|
||||
|
||||
FROM registry.fedoraproject.org/fedora:40
|
||||
|
||||
RUN dnf install -y nosync && \
|
||||
printf '#!/bin/sh\n\
|
||||
if test -d /usr/lib64\n\
|
||||
then\n\
|
||||
export LD_PRELOAD=/usr/lib64/nosync/nosync.so\n\
|
||||
else\n\
|
||||
export LD_PRELOAD=/usr/lib/nosync/nosync.so\n\
|
||||
fi\n\
|
||||
exec "$@"\n' > /usr/bin/nosync && \
|
||||
chmod +x /usr/bin/nosync && \
|
||||
nosync dnf update -y && \
|
||||
nosync dnf install -y \
|
||||
SDL2-devel \
|
||||
SDL2_image-devel \
|
||||
alsa-lib-devel \
|
||||
bash \
|
||||
bc \
|
||||
bison \
|
||||
brlapi-devel \
|
||||
bzip2 \
|
||||
bzip2-devel \
|
||||
ca-certificates \
|
||||
capstone-devel \
|
||||
ccache \
|
||||
clang \
|
||||
ctags \
|
||||
cyrus-sasl-devel \
|
||||
daxctl-devel \
|
||||
dbus-daemon \
|
||||
device-mapper-multipath-devel \
|
||||
diffutils \
|
||||
findutils \
|
||||
flex \
|
||||
fuse3-devel \
|
||||
gcc \
|
||||
gcovr \
|
||||
gettext \
|
||||
git \
|
||||
glib2-devel \
|
||||
glib2-static \
|
||||
glibc-langpack-en \
|
||||
glibc-static \
|
||||
glusterfs-api-devel \
|
||||
gnutls-devel \
|
||||
gtk-vnc2-devel \
|
||||
gtk3-devel \
|
||||
hostname \
|
||||
jemalloc-devel \
|
||||
json-c-devel \
|
||||
libaio-devel \
|
||||
libasan \
|
||||
libattr-devel \
|
||||
libbpf-devel \
|
||||
libcacard-devel \
|
||||
libcap-ng-devel \
|
||||
libcmocka-devel \
|
||||
libcurl-devel \
|
||||
libdrm-devel \
|
||||
libepoxy-devel \
|
||||
libfdt-devel \
|
||||
libffi-devel \
|
||||
libgcrypt-devel \
|
||||
libiscsi-devel \
|
||||
libjpeg-devel \
|
||||
libnfs-devel \
|
||||
libpmem-devel \
|
||||
libpng-devel \
|
||||
librbd-devel \
|
||||
libseccomp-devel \
|
||||
libselinux-devel \
|
||||
libslirp-devel \
|
||||
libssh-devel \
|
||||
libtasn1-devel \
|
||||
libubsan \
|
||||
liburing-devel \
|
||||
libusbx-devel \
|
||||
libxdp-devel \
|
||||
libzstd-devel \
|
||||
llvm \
|
||||
lttng-ust-devel \
|
||||
lzo-devel \
|
||||
make \
|
||||
mesa-libgbm-devel \
|
||||
meson \
|
||||
mtools \
|
||||
ncurses-devel \
|
||||
nettle-devel \
|
||||
ninja-build \
|
||||
nmap-ncat \
|
||||
numactl-devel \
|
||||
openssh-clients \
|
||||
pam-devel \
|
||||
pcre-static \
|
||||
pipewire-devel \
|
||||
pixman-devel \
|
||||
pkgconfig \
|
||||
pulseaudio-libs-devel \
|
||||
python3 \
|
||||
python3-PyYAML \
|
||||
python3-numpy \
|
||||
python3-opencv \
|
||||
python3-pillow \
|
||||
python3-pip \
|
||||
python3-sphinx \
|
||||
python3-sphinx_rtd_theme \
|
||||
python3-zombie-imp \
|
||||
rdma-core-devel \
|
||||
sed \
|
||||
snappy-devel \
|
||||
socat \
|
||||
sparse \
|
||||
spice-protocol \
|
||||
spice-server-devel \
|
||||
swtpm \
|
||||
systemd-devel \
|
||||
systemtap-sdt-devel \
|
||||
tar \
|
||||
tesseract \
|
||||
tesseract-langpack-eng \
|
||||
usbredir-devel \
|
||||
util-linux \
|
||||
virglrenderer-devel \
|
||||
vte291-devel \
|
||||
which \
|
||||
xen-devel \
|
||||
xorriso \
|
||||
zlib-devel \
|
||||
zlib-static \
|
||||
zstd && \
|
||||
nosync dnf autoremove -y && \
|
||||
nosync dnf clean all -y && \
|
||||
rm -f /usr/lib*/python3*/EXTERNALLY-MANAGED && \
|
||||
rpm -qa | sort > /packages.txt && \
|
||||
mkdir -p /usr/libexec/ccache-wrappers && \
|
||||
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/cc && \
|
||||
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/clang && \
|
||||
ln -s /usr/bin/ccache /usr/libexec/ccache-wrappers/gcc
|
||||
|
||||
ENV CCACHE_WRAPPERSDIR "/usr/libexec/ccache-wrappers"
|
||||
ENV LANG "en_US.UTF-8"
|
||||
ENV MAKE "/usr/bin/make"
|
||||
ENV NINJA "/usr/bin/ninja"
|
||||
ENV PYTHON "/usr/bin/python3"
|
||||
RUN dnf install -y wget
|
||||
ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
|
||||
ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc
|
||||
RUN set -eux && \
|
||||
rustArch='x86_64-unknown-linux-gnu' && \
|
||||
rustupSha256='6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d' && \
|
||||
url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" && \
|
||||
wget "$url" && \
|
||||
echo "${rustupSha256} *rustup-init" | sha256sum -c - && \
|
||||
chmod +x rustup-init && \
|
||||
./rustup-init -y --no-modify-path --profile default --default-toolchain nightly --default-host ${rustArch} && \
|
||||
chmod -R a+w $RUSTUP_HOME $CARGO_HOME && \
|
||||
/usr/local/cargo/bin/rustup --version && \
|
||||
/usr/local/cargo/bin/rustup run nightly rustc --version && \
|
||||
test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"
|
||||
ENV PATH=$CARGO_HOME/bin:$PATH
|
||||
RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli
|
||||
# As a final step configure the user (if env is defined)
|
||||
ARG USER
|
||||
ARG UID
|
||||
RUN if [ "${USER}" ]; then \
|
||||
id ${USER} 2>/dev/null || useradd -u ${UID} -U ${USER}; fi
|
@ -127,7 +127,7 @@ RUN zypper update -y && \
|
||||
|
||||
RUN /usr/bin/pip3.11 install \
|
||||
PyYAML \
|
||||
meson==0.63.2 \
|
||||
meson==1.5.0 \
|
||||
pillow \
|
||||
sphinx \
|
||||
sphinx-rtd-theme
|
||||
|
@ -89,7 +89,7 @@ mappings:
|
||||
pypi_mappings:
|
||||
# Request more recent version
|
||||
meson:
|
||||
default: meson==0.63.2
|
||||
default: meson==1.5.0
|
||||
|
||||
# Drop packages that need devel headers
|
||||
python3-numpy:
|
||||
|
@ -116,6 +116,26 @@ debian12_extras = [
|
||||
"ENV QEMU_CONFIGURE_OPTS --enable-netmap\n"
|
||||
]
|
||||
|
||||
# Based on the hub.docker.com/library/rust Dockerfiles
|
||||
fedora_rustup_nightly_extras = [
|
||||
"RUN dnf install -y wget\n",
|
||||
"ENV RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo\n",
|
||||
"ENV RUSTC=/usr/local/rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc\n",
|
||||
"RUN set -eux && \\\n",
|
||||
" rustArch='x86_64-unknown-linux-gnu' && \\\n",
|
||||
" rustupSha256='6aeece6993e902708983b209d04c0d1dbb14ebb405ddb87def578d41f920f56d' && \\\n",
|
||||
' url="https://static.rust-lang.org/rustup/archive/1.27.1/${rustArch}/rustup-init" && \\\n',
|
||||
' wget "$url" && \\\n',
|
||||
' echo "${rustupSha256} *rustup-init" | sha256sum -c - && \\\n',
|
||||
" chmod +x rustup-init && \\\n",
|
||||
" ./rustup-init -y --no-modify-path --profile default --default-toolchain nightly --default-host ${rustArch} && \\\n",
|
||||
" chmod -R a+w $RUSTUP_HOME $CARGO_HOME && \\\n",
|
||||
" /usr/local/cargo/bin/rustup --version && \\\n",
|
||||
" /usr/local/cargo/bin/rustup run nightly rustc --version && \\\n",
|
||||
' test "$RUSTC" = "$(/usr/local/cargo/bin/rustup +nightly which rustc)"\n',
|
||||
'ENV PATH=$CARGO_HOME/bin:$PATH\n',
|
||||
'RUN /usr/local/cargo/bin/rustup run nightly cargo install bindgen-cli\n',
|
||||
]
|
||||
|
||||
def cross_build(prefix, targets):
|
||||
conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix)
|
||||
@ -139,6 +159,12 @@ try:
|
||||
generate_dockerfile("opensuse-leap", "opensuse-leap-15")
|
||||
generate_dockerfile("ubuntu2204", "ubuntu-2204")
|
||||
|
||||
#
|
||||
# Non-fatal Rust-enabled build
|
||||
#
|
||||
generate_dockerfile("fedora-rust-nightly", "fedora-40",
|
||||
trailer="".join(fedora_rustup_nightly_extras))
|
||||
|
||||
#
|
||||
# Cross compiling builds
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user