* 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
|
*.h.inc diff=c
|
||||||
*.m diff=objc
|
*.m diff=objc
|
||||||
*.py diff=python
|
*.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
|
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
|
||||||
MAKE_CHECK_ARGS: check-build
|
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:
|
check-system-fedora:
|
||||||
extends: .native_test_job_template
|
extends: .native_test_job_template
|
||||||
needs:
|
needs:
|
||||||
|
@ -27,3 +27,9 @@ python-container:
|
|||||||
extends: .container_job_template
|
extends: .container_job_template
|
||||||
variables:
|
variables:
|
||||||
NAME: python
|
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 target/Kconfig
|
||||||
source hw/Kconfig
|
source hw/Kconfig
|
||||||
source semihosting/Kconfig
|
source semihosting/Kconfig
|
||||||
|
source rust/Kconfig
|
||||||
|
@ -52,3 +52,6 @@ config VFIO_USER_SERVER_ALLOWED
|
|||||||
|
|
||||||
config HV_BALLOON_POSSIBLE
|
config HV_BALLOON_POSSIBLE
|
||||||
bool
|
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: tests/qtest/microbit-test.c
|
||||||
F: docs/system/arm/nrf.rst
|
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
|
AVR Machines
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@ -3286,6 +3291,13 @@ F: hw/core/register.c
|
|||||||
F: include/hw/register.h
|
F: include/hw/register.h
|
||||||
F: include/hw/registerfields.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
|
SLIRP
|
||||||
M: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
M: Samuel Thibault <samuel.thibault@ens-lyon.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@ -4183,6 +4195,15 @@ F: docs/sphinx/
|
|||||||
F: docs/_templates/
|
F: docs/_templates/
|
||||||
F: docs/devel/docs.rst
|
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
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
Performance Tools and Tests
|
Performance Tools and Tests
|
||||||
|
170
configure
vendored
170
configure
vendored
@ -207,6 +207,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--objcc=*) objcc="$optarg"
|
--objcc=*) objcc="$optarg"
|
||||||
;;
|
;;
|
||||||
|
--rustc=*) RUSTC="$optarg"
|
||||||
|
;;
|
||||||
--cpu=*) cpu="$optarg"
|
--cpu=*) cpu="$optarg"
|
||||||
;;
|
;;
|
||||||
--extra-cflags=*)
|
--extra-cflags=*)
|
||||||
@ -252,6 +254,8 @@ python=
|
|||||||
download="enabled"
|
download="enabled"
|
||||||
skip_meson=no
|
skip_meson=no
|
||||||
use_containers="yes"
|
use_containers="yes"
|
||||||
|
rust="disabled"
|
||||||
|
rust_target_triple=""
|
||||||
gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb")
|
gdb_bin=$(command -v "gdb-multiarch" || command -v "gdb")
|
||||||
gdb_arches=""
|
gdb_arches=""
|
||||||
|
|
||||||
@ -310,6 +314,7 @@ objcopy="${OBJCOPY-${cross_prefix}objcopy}"
|
|||||||
ld="${LD-${cross_prefix}ld}"
|
ld="${LD-${cross_prefix}ld}"
|
||||||
ranlib="${RANLIB-${cross_prefix}ranlib}"
|
ranlib="${RANLIB-${cross_prefix}ranlib}"
|
||||||
nm="${NM-${cross_prefix}nm}"
|
nm="${NM-${cross_prefix}nm}"
|
||||||
|
readelf="${READELF-${cross_prefix}readelf}"
|
||||||
strip="${STRIP-${cross_prefix}strip}"
|
strip="${STRIP-${cross_prefix}strip}"
|
||||||
widl="${WIDL-${cross_prefix}widl}"
|
widl="${WIDL-${cross_prefix}widl}"
|
||||||
windres="${WINDRES-${cross_prefix}windres}"
|
windres="${WINDRES-${cross_prefix}windres}"
|
||||||
@ -317,6 +322,8 @@ windmc="${WINDMC-${cross_prefix}windmc}"
|
|||||||
pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
|
pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
|
||||||
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
|
sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
|
||||||
|
|
||||||
|
rustc="${RUSTC-rustc}"
|
||||||
|
|
||||||
check_define() {
|
check_define() {
|
||||||
cat > $TMPC <<EOF
|
cat > $TMPC <<EOF
|
||||||
#if !defined($1)
|
#if !defined($1)
|
||||||
@ -425,6 +432,7 @@ fi
|
|||||||
# Please keep it sorted and synchronized with meson.build's host_arch.
|
# Please keep it sorted and synchronized with meson.build's host_arch.
|
||||||
host_arch=
|
host_arch=
|
||||||
linux_arch=
|
linux_arch=
|
||||||
|
raw_cpu=$cpu
|
||||||
case "$cpu" in
|
case "$cpu" in
|
||||||
aarch64)
|
aarch64)
|
||||||
host_arch=aarch64
|
host_arch=aarch64
|
||||||
@ -658,6 +666,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--objcc=*)
|
--objcc=*)
|
||||||
;;
|
;;
|
||||||
|
--rustc=*)
|
||||||
|
;;
|
||||||
--make=*)
|
--make=*)
|
||||||
;;
|
;;
|
||||||
--install=*)
|
--install=*)
|
||||||
@ -777,8 +787,14 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--container-engine=*) container_engine="$optarg"
|
--container-engine=*) container_engine="$optarg"
|
||||||
;;
|
;;
|
||||||
|
--rust-target-triple=*) rust_target_triple="$optarg"
|
||||||
|
;;
|
||||||
--gdb=*) gdb_bin="$optarg"
|
--gdb=*) gdb_bin="$optarg"
|
||||||
;;
|
;;
|
||||||
|
--enable-rust) rust=enabled
|
||||||
|
;;
|
||||||
|
--disable-rust) rust=disabled
|
||||||
|
;;
|
||||||
# everything else has the same name in configure and meson
|
# everything else has the same name in configure and meson
|
||||||
--*) meson_option_parse "$opt" "$optarg"
|
--*) meson_option_parse "$opt" "$optarg"
|
||||||
;;
|
;;
|
||||||
@ -881,6 +897,7 @@ Advanced options (experts only):
|
|||||||
at build time [$host_cc]
|
at build time [$host_cc]
|
||||||
--cxx=CXX use C++ compiler CXX [$cxx]
|
--cxx=CXX use C++ compiler CXX [$cxx]
|
||||||
--objcc=OBJCC use Objective-C compiler OBJCC [$objcc]
|
--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-cflags=CFLAGS append extra C compiler flags CFLAGS
|
||||||
--extra-cxxflags=CXXFLAGS append extra C++ compiler flags CXXFLAGS
|
--extra-cxxflags=CXXFLAGS append extra C++ compiler flags CXXFLAGS
|
||||||
--extra-objcflags=OBJCFLAGS append extra Objective C compiler flags OBJCFLAGS
|
--extra-objcflags=OBJCFLAGS append extra Objective C compiler flags OBJCFLAGS
|
||||||
@ -891,8 +908,9 @@ Advanced options (experts only):
|
|||||||
--python=PYTHON use specified python [$python]
|
--python=PYTHON use specified python [$python]
|
||||||
--ninja=NINJA use specified ninja [$ninja]
|
--ninja=NINJA use specified ninja [$ninja]
|
||||||
--static enable static build [$static]
|
--static enable static build [$static]
|
||||||
--without-default-features default all --enable-* options to "disabled"
|
--rust-target-triple=TRIPLE compilation target for Rust code [autodetect]
|
||||||
--without-default-devices do not include any device that is not needed to
|
--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
|
start the emulator (only use if you are including
|
||||||
desired devices in configs/devices/)
|
desired devices in configs/devices/)
|
||||||
--with-devices-ARCH=NAME override default configs/devices
|
--with-devices-ARCH=NAME override default configs/devices
|
||||||
@ -1166,6 +1184,132 @@ EOF
|
|||||||
fi
|
fi
|
||||||
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
|
# functions to probe cross compilers
|
||||||
|
|
||||||
@ -1628,6 +1772,9 @@ if test "$container" != no; then
|
|||||||
echo "RUNC=$runc" >> $config_host_mak
|
echo "RUNC=$runc" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
echo "SUBDIRS=$subdirs" >> $config_host_mak
|
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 "PYTHON=$python" >> $config_host_mak
|
||||||
echo "MKVENV_ENSUREGROUP=$mkvenv ensuregroup $mkvenv_online_flag" >> $config_host_mak
|
echo "MKVENV_ENSUREGROUP=$mkvenv ensuregroup $mkvenv_online_flag" >> $config_host_mak
|
||||||
echo "GENISOIMAGE=$genisoimage" >> $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
|
echo "c = [$(meson_quote $cc $CPU_CFLAGS)]" >> $cross
|
||||||
test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $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
|
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 "ar = [$(meson_quote $ar)]" >> $cross
|
||||||
echo "dlltool = [$(meson_quote $dlltool)]" >> $cross
|
echo "dlltool = [$(meson_quote $dlltool)]" >> $cross
|
||||||
echo "nm = [$(meson_quote $nm)]" >> $cross
|
echo "nm = [$(meson_quote $nm)]" >> $cross
|
||||||
echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross
|
echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross
|
||||||
echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross
|
echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross
|
||||||
echo "ranlib = [$(meson_quote $ranlib)]" >> $cross
|
echo "ranlib = [$(meson_quote $ranlib)]" >> $cross
|
||||||
|
echo "readelf = [$(meson_quote $readelf)]" >> $cross
|
||||||
if has $sdl2_config; then
|
if has $sdl2_config; then
|
||||||
echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross
|
echo "sdl2-config = [$(meson_quote $sdl2_config)]" >> $cross
|
||||||
fi
|
fi
|
||||||
@ -1799,6 +1954,9 @@ if test "$skip_meson" = no; then
|
|||||||
echo "# Automatically generated by configure - do not modify" > $native
|
echo "# Automatically generated by configure - do not modify" > $native
|
||||||
echo "[binaries]" >> $native
|
echo "[binaries]" >> $native
|
||||||
echo "c = [$(meson_quote $host_cc)]" >> $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
|
mv $native config-meson.native
|
||||||
meson_option_add --native-file
|
meson_option_add --native-file
|
||||||
meson_option_add config-meson.native
|
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
|
test "$pie" = no && meson_option_add -Db_pie=false
|
||||||
|
|
||||||
# QEMU options
|
# QEMU options
|
||||||
|
test "$rust" != "auto" && meson_option_add "-Drust=$rust"
|
||||||
test "$cfi" != false && meson_option_add "-Dcfi=$cfi" "-Db_lto=$cfi"
|
test "$cfi" != false && meson_option_add "-Dcfi=$cfi" "-Db_lto=$cfi"
|
||||||
test "$docs" != auto && meson_option_add "-Ddocs=$docs"
|
test "$docs" != auto && meson_option_add "-Ddocs=$docs"
|
||||||
test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE"
|
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
|
chmod +x config.status
|
||||||
|
|
||||||
rm -r "$TMPDIR1"
|
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.
|
before the second with respect to the other components of the system.
|
||||||
Therefore, unlike ``smp_rmb()`` or ``qatomic_load_acquire()``,
|
Therefore, unlike ``smp_rmb()`` or ``qatomic_load_acquire()``,
|
||||||
``smp_read_barrier_depends()`` can be just a compiler barrier on
|
``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
|
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
|
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_
|
than actually loading the address itself, then it's a _control_
|
||||||
dependency and a full read barrier or better is required.
|
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
|
needs a processor barrier. On strongly-ordered architectures such
|
||||||
as x86 or s390, ``smp_rmb()`` and ``qatomic_load_acquire()`` can
|
as x86 or s390, ``smp_rmb()`` and ``qatomic_load_acquire()`` can
|
||||||
also be compiler barriers only.
|
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
|
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
|
.. [#rmw] Read-modify-write operations can have both---acquire applies to the
|
||||||
read part, and release to the write.
|
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.
|
or with the wrong ``pip`` program.
|
||||||
|
|
||||||
If a package is available for the chosen interpreter, ``configure``
|
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
|
If not, ``configure`` can also optionally install dependencies in the
|
||||||
virtual environment with ``pip``, either from wheels in ``python/wheels``
|
virtual environment with ``pip``, either from wheels in ``python/wheels``
|
||||||
or by downloading the package with PyPI. Downloading can be disabled with
|
or by downloading the package with PyPI. Downloading can be disabled with
|
||||||
``--disable-download``; and anyway, it only happens when a ``configure``
|
``--disable-download``; and anyway, it only happens when a ``configure``
|
||||||
option (currently, only ``--enable-docs``) is explicitly enabled but
|
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,
|
.. [#distlib] The scripts are created based on the package's metadata,
|
||||||
specifically the ``console_script`` entry points. This is the
|
specifically the ``console_script`` entry points. This is the
|
||||||
@ -333,7 +333,7 @@ into each emulator:
|
|||||||
|
|
||||||
``default-configs/targets/*.mak``
|
``default-configs/targets/*.mak``
|
||||||
These files mostly define symbols that appear in the ``*-config-target.h``
|
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
|
and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and
|
||||||
``target/`` subdirectories that are compiled into each target.
|
``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 ``cpu_restore_state()``. Therefore the value should either be 0,
|
||||||
to indicate that the guest CPU state is already synchronized, or
|
to indicate that the guest CPU state is already synchronized, or
|
||||||
the result of ``GETPC()`` from the top level ``HELPER(foo)``
|
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
|
.. [#gpc] Note that ``GETPC()`` should be used with great care: calling
|
||||||
it in other functions that are *not* the top level
|
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
|
a `KeySigningParty <https://wiki.qemu.org/KeySigningParty>`__ (for
|
||||||
example at KVM Forum) or make alternative arrangements to have your
|
example at KVM Forum) or make alternative arrangements to have your
|
||||||
key signed by an attendee. Key signing requires meeting another
|
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.
|
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
|
flexibility here. Maintainers still need to sign their pull
|
||||||
requests though.
|
requests though.
|
||||||
|
@ -44,7 +44,7 @@ Use-cases
|
|||||||
|
|
||||||
The mapped-ram feature was designed for use cases where the migration
|
The mapped-ram feature was designed for use cases where the migration
|
||||||
stream will be directed to a file in the filesystem and not
|
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
|
thought of as snapshots. We can further categorize them into live and
|
||||||
non-live.
|
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
|
depends on async dirty tracking (KVM_GET_DIRTY_LOG) which is not
|
||||||
supported outside of Linux.
|
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
|
snapshots or the ``file:`` migration alone, mapped-ram provides
|
||||||
a performance increase for VMs with larger RAM sizes (10s to
|
a performance increase for VMs with larger RAM sizes (10s to
|
||||||
100s of GiBs), specially if the VM has been stopped beforehand.
|
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
|
low level assembly machine language. Writing test routines in a low level
|
||||||
language makes things more cumbersome. These and other reasons makes using
|
language makes things more cumbersome. These and other reasons makes using
|
||||||
bios-bits very attractive for testing bioses. More details on the inspiration
|
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
|
For QEMU, we maintain a fork of bios bits in `gitlab`_, along with all
|
||||||
dependent submodules `here <https://gitlab.com/qemu-project/biosbits-bits>`__.
|
the dependent submodules. This fork contains numerous fixes, a newer
|
||||||
This fork contains numerous fixes, a newer acpica and changes specific to
|
acpica and changes specific to running these functional QEMU tests using
|
||||||
running these functional QEMU tests using bits. The author of this document
|
bits. The author of this document is the current maintainer of the QEMU
|
||||||
is the sole maintainer of the QEMU fork of bios bits repository. For more
|
fork of bios bits repository. For more information, please see `the
|
||||||
information, please see author's `FOSDEM talk on this bios-bits based test
|
author's FOSDEM presentation <FOSDEM_>`__ on this bios-bits based test framework.
|
||||||
framework <https://fosdem.org/2024/schedule/event/fosdem-2024-2262-exercising-qemu-generated-acpi-smbios-tables-using-biosbits-from-within-a-guest-vm-/>`__.
|
|
||||||
|
.. _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
|
Description of the test framework
|
||||||
@ -148,8 +153,3 @@ Under ``tests/functional/`` as the root we have:
|
|||||||
|
|
||||||
Author: Ani Sinha <anisinha@redhat.com>
|
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)
|
* 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)
|
* Width: 8-bit (if IOport), 8/16/32/64-bit (if MMIO)
|
||||||
* Endianness: string-preserving
|
* Endianness: string-preserving
|
||||||
|
|
||||||
.. [#]
|
.. [#placement]
|
||||||
On platforms where the data register is exposed as an IOport, its
|
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
|
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
|
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
|
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.
|
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
|
Thanks to KVM's `MSR filtering <msr-filter-patch_>`__ functionality,
|
||||||
of them can now be handled by the userspace (QEMU). It uses a mechanism called
|
not all MSRs are handled by KVM. Some of them can now be handled by the
|
||||||
"MSR filtering" where a list of MSRs is given at init time of a VM to KVM so
|
userspace (QEMU); a list of MSRs is given at VM creation time to KVM, and
|
||||||
that a callback is put in place. The design of this patch uses only this
|
a userspace exit occurs when they are accessed.
|
||||||
mechanism for handling the MSRs between guest/host.
|
|
||||||
|
.. _msr-filter-patch: https://patchwork.kernel.org/project/kvm/patch/20200916202951.23760-7-graf@amazon.com/
|
||||||
|
|
||||||
At the moment the following MSRs are involved:
|
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
|
package has 4 cores, 400 ticks maximum can be scheduled on all the cores
|
||||||
of the package for a period of 1 second.
|
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
|
`/proc/[pid]/stat <stat_>`__ is a procfs file that can give the executed
|
||||||
process with the [pid] as the process ID. It gives the amount of ticks the
|
time of a process with the [pid] as the process ID. It gives the amount
|
||||||
process has been scheduled in userspace (utime) and kernel space (stime).
|
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
|
By reading those metrics for a thread, one can calculate the ratio of time the
|
||||||
package has spent executing the thread.
|
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
|
- Only the Package Power-Plane (MSR_PKG_ENERGY_STATUS) is reported at the
|
||||||
moment.
|
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
|
||||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||||
select PFLASH_CFI01
|
select PFLASH_CFI01
|
||||||
select PL011 # UART
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select PL031 # RTC
|
select PL031 # RTC
|
||||||
select PL061 # GPIO
|
select PL061 # GPIO
|
||||||
select GPIO_PWR
|
select GPIO_PWR
|
||||||
@ -73,7 +74,8 @@ config HIGHBANK
|
|||||||
select AHCI
|
select AHCI
|
||||||
select ARM_TIMER # sp804
|
select ARM_TIMER # sp804
|
||||||
select ARM_V7M
|
select ARM_V7M
|
||||||
select PL011 # UART
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select PL022 # SPI
|
select PL022 # SPI
|
||||||
select PL031 # RTC
|
select PL031 # RTC
|
||||||
select PL061 # GPIO
|
select PL061 # GPIO
|
||||||
@ -86,7 +88,8 @@ config INTEGRATOR
|
|||||||
depends on TCG && ARM
|
depends on TCG && ARM
|
||||||
select ARM_TIMER
|
select ARM_TIMER
|
||||||
select INTEGRATOR_DEBUG
|
select INTEGRATOR_DEBUG
|
||||||
select PL011 # UART
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select PL031 # RTC
|
select PL031 # RTC
|
||||||
select PL041 # audio
|
select PL041 # audio
|
||||||
select PL050 # keyboard/mouse
|
select PL050 # keyboard/mouse
|
||||||
@ -104,7 +107,8 @@ config MUSCA
|
|||||||
default y
|
default y
|
||||||
depends on TCG && ARM
|
depends on TCG && ARM
|
||||||
select ARMSSE
|
select ARMSSE
|
||||||
select PL011
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select PL031
|
select PL031
|
||||||
select SPLIT_IRQ
|
select SPLIT_IRQ
|
||||||
select UNIMP
|
select UNIMP
|
||||||
@ -169,7 +173,8 @@ config REALVIEW
|
|||||||
select WM8750 # audio codec
|
select WM8750 # audio codec
|
||||||
select LSI_SCSI_PCI
|
select LSI_SCSI_PCI
|
||||||
select PCI
|
select PCI
|
||||||
select PL011 # UART
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select PL031 # RTC
|
select PL031 # RTC
|
||||||
select PL041 # audio codec
|
select PL041 # audio codec
|
||||||
select PL050 # keyboard/mouse
|
select PL050 # keyboard/mouse
|
||||||
@ -194,7 +199,8 @@ config SBSA_REF
|
|||||||
select PCI_EXPRESS
|
select PCI_EXPRESS
|
||||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||||
select PFLASH_CFI01
|
select PFLASH_CFI01
|
||||||
select PL011 # UART
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select PL031 # RTC
|
select PL031 # RTC
|
||||||
select PL061 # GPIO
|
select PL061 # GPIO
|
||||||
select USB_XHCI_SYSBUS
|
select USB_XHCI_SYSBUS
|
||||||
@ -218,7 +224,8 @@ config STELLARIS
|
|||||||
select ARM_V7M
|
select ARM_V7M
|
||||||
select CMSDK_APB_WATCHDOG
|
select CMSDK_APB_WATCHDOG
|
||||||
select I2C
|
select I2C
|
||||||
select PL011 # UART
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select PL022 # SPI
|
select PL022 # SPI
|
||||||
select PL061 # GPIO
|
select PL061 # GPIO
|
||||||
select SSD0303 # OLED display
|
select SSD0303 # OLED display
|
||||||
@ -278,7 +285,8 @@ config VEXPRESS
|
|||||||
select ARM_TIMER # sp804
|
select ARM_TIMER # sp804
|
||||||
select LAN9118
|
select LAN9118
|
||||||
select PFLASH_CFI01
|
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 PL041 # audio codec
|
||||||
select PL181 # display
|
select PL181 # display
|
||||||
select REALVIEW
|
select REALVIEW
|
||||||
@ -362,7 +370,8 @@ config RASPI
|
|||||||
default y
|
default y
|
||||||
depends on TCG && ARM
|
depends on TCG && ARM
|
||||||
select FRAMEBUFFER
|
select FRAMEBUFFER
|
||||||
select PL011 # UART
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select SDHCI
|
select SDHCI
|
||||||
select USB_DWC2
|
select USB_DWC2
|
||||||
select BCM2835_SPI
|
select BCM2835_SPI
|
||||||
@ -437,7 +446,8 @@ config XLNX_VERSAL
|
|||||||
select ARM_GIC
|
select ARM_GIC
|
||||||
select CPU_CLUSTER
|
select CPU_CLUSTER
|
||||||
select DEVICE_TREE
|
select DEVICE_TREE
|
||||||
select PL011
|
select PL011 if !HAVE_RUST # UART
|
||||||
|
select X_PL011_RUST if HAVE_RUST # UART
|
||||||
select CADENCE
|
select CADENCE
|
||||||
select VIRTIO_MMIO
|
select VIRTIO_MMIO
|
||||||
select UNIMP
|
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',
|
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'],
|
'b_staticpic=false', 'stdsplit=false', 'optimization=2', 'b_pie=true'],
|
||||||
version: files('VERSION'))
|
version: files('VERSION'))
|
||||||
@ -70,6 +70,19 @@ if host_os == 'darwin' and \
|
|||||||
all_languages += ['objc']
|
all_languages += ['objc']
|
||||||
objc = meson.get_compiler('objc')
|
objc = meson.get_compiler('objc')
|
||||||
endif
|
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
|
dtrace = not_found
|
||||||
stap = not_found
|
stap = not_found
|
||||||
@ -322,6 +335,10 @@ elif host_os == 'windows'
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Choose instruction set (currently x86-only)
|
||||||
|
|
||||||
|
qemu_isa_flags = []
|
||||||
|
|
||||||
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
|
# __sync_fetch_and_and requires at least -march=i486. Many toolchains
|
||||||
# use i686 as default anyway, but for those that don't, an explicit
|
# use i686 as default anyway, but for those that don't, an explicit
|
||||||
# specification is necessary
|
# specification is necessary
|
||||||
@ -338,7 +355,7 @@ if host_arch == 'i386' and not cc.links('''
|
|||||||
sfaa(&val);
|
sfaa(&val);
|
||||||
return val;
|
return val;
|
||||||
}''')
|
}''')
|
||||||
qemu_common_flags = ['-march=i486'] + qemu_common_flags
|
qemu_isa_flags += ['-march=i486']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Pick x86-64 baseline version
|
# Pick x86-64 baseline version
|
||||||
@ -354,29 +371,31 @@ if host_arch in ['i386', 'x86_64']
|
|||||||
else
|
else
|
||||||
# present on basically all processors but technically not part of
|
# present on basically all processors but technically not part of
|
||||||
# x86-64-v1, so only include -mneeded for x86-64 version 2 and above
|
# 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
|
||||||
endif
|
endif
|
||||||
if get_option('x86_version') >= '2'
|
if get_option('x86_version') >= '2'
|
||||||
qemu_common_flags = ['-mpopcnt'] + qemu_common_flags
|
qemu_isa_flags += ['-mpopcnt']
|
||||||
qemu_common_flags = cc.get_supported_arguments('-mneeded') + qemu_common_flags
|
qemu_isa_flags += cc.get_supported_arguments('-mneeded')
|
||||||
endif
|
endif
|
||||||
if get_option('x86_version') >= '3'
|
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
|
endif
|
||||||
|
|
||||||
# add required vector instruction set (each level implies those below)
|
# add required vector instruction set (each level implies those below)
|
||||||
if get_option('x86_version') == '1'
|
if get_option('x86_version') == '1'
|
||||||
qemu_common_flags = ['-msse2'] + qemu_common_flags
|
qemu_isa_flags += ['-msse2']
|
||||||
elif get_option('x86_version') == '2'
|
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'
|
elif get_option('x86_version') == '3'
|
||||||
qemu_common_flags = ['-mavx2'] + qemu_common_flags
|
qemu_isa_flags += ['-mavx2']
|
||||||
elif get_option('x86_version') == '4'
|
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
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
qemu_common_flags = qemu_isa_flags + qemu_common_flags
|
||||||
|
|
||||||
if get_option('prefer_static')
|
if get_option('prefer_static')
|
||||||
qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static'
|
qemu_ldflags += get_option('b_pie') ? '-static-pie' : '-static'
|
||||||
endif
|
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
|
# 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_req_ver = '>=2.66.0'
|
||||||
glib_pc = dependency('glib-2.0', version: glib_req_ver, required: true,
|
glib_pc = dependency('glib-2.0', version: glib_req_ver, required: true,
|
||||||
method: 'pkg-config')
|
method: 'pkg-config')
|
||||||
@ -985,6 +1006,9 @@ glib = declare_dependency(dependencies: [glib_pc, gmodule],
|
|||||||
# TODO: remove this check and the corresponding workaround (qtree) when
|
# TODO: remove this check and the corresponding workaround (qtree) when
|
||||||
# the minimum supported glib is >= 2.75.3
|
# the minimum supported glib is >= 2.75.3
|
||||||
glib_has_gslice = glib.version().version_compare('<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
|
# override glib dep to include the above refinements
|
||||||
meson.override_dependency('glib-2.0', glib)
|
meson.override_dependency('glib-2.0', glib)
|
||||||
@ -2158,6 +2182,7 @@ endif
|
|||||||
|
|
||||||
config_host_data = configuration_data()
|
config_host_data = configuration_data()
|
||||||
|
|
||||||
|
config_host_data.set('CONFIG_HAVE_RUST', have_rust)
|
||||||
audio_drivers_selected = []
|
audio_drivers_selected = []
|
||||||
if have_system
|
if have_system
|
||||||
audio_drivers_available = {
|
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_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
|
||||||
config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
|
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_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_OPENPTY', cc.has_function('openpty', dependencies: util))
|
||||||
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
|
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>'))
|
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_exchange_n(&x, y, __ATOMIC_RELAXED);
|
||||||
__atomic_fetch_add(&x, y, __ATOMIC_RELAXED);
|
__atomic_fetch_add(&x, y, __ATOMIC_RELAXED);
|
||||||
return 0;
|
return 0;
|
||||||
}'''))
|
}''', args: qemu_isa_flags))
|
||||||
|
|
||||||
has_int128_type = cc.compiles('''
|
has_int128_type = cc.compiles('''
|
||||||
__int128_t a;
|
__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);
|
__atomic_compare_exchange_n(&p[4], &p[5], p[6], 0, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
|
||||||
return 0;
|
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)
|
config_host_data.set('CONFIG_ATOMIC128', has_atomic128)
|
||||||
|
|
||||||
@ -2849,7 +2875,8 @@ if has_int128_type
|
|||||||
# without optimization enabled. Try again with optimizations locally
|
# without optimization enabled. Try again with optimizations locally
|
||||||
# enabled for the function. See
|
# enabled for the function. See
|
||||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107389
|
# 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)
|
config_host_data.set('CONFIG_ATOMIC128_OPT', has_atomic128_opt)
|
||||||
|
|
||||||
if not 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);
|
__sync_val_compare_and_swap_16(&x, y, x);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
'''))
|
''', args: qemu_isa_flags))
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@ -3097,7 +3124,8 @@ host_kconfig = \
|
|||||||
(host_os == 'linux' ? ['CONFIG_LINUX=y'] : []) + \
|
(host_os == 'linux' ? ['CONFIG_LINUX=y'] : []) + \
|
||||||
(multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \
|
(multiprocess_allowed ? ['CONFIG_MULTIPROCESS_ALLOWED=y'] : []) + \
|
||||||
(vfio_user_server_allowed ? ['CONFIG_VFIO_USER_SERVER_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' ]
|
ignored = [ 'TARGET_XML_FILES', 'TARGET_ABI_DIR', 'TARGET_ARCH' ]
|
||||||
|
|
||||||
@ -3491,6 +3519,7 @@ qom_ss = ss.source_set()
|
|||||||
system_ss = ss.source_set()
|
system_ss = ss.source_set()
|
||||||
specific_fuzz_ss = ss.source_set()
|
specific_fuzz_ss = ss.source_set()
|
||||||
specific_ss = ss.source_set()
|
specific_ss = ss.source_set()
|
||||||
|
rust_devices_ss = ss.source_set()
|
||||||
stub_ss = ss.source_set()
|
stub_ss = ss.source_set()
|
||||||
trace_ss = ss.source_set()
|
trace_ss = ss.source_set()
|
||||||
user_ss = ss.source_set()
|
user_ss = ss.source_set()
|
||||||
@ -3877,6 +3906,74 @@ common_all = static_library('common',
|
|||||||
implicit_include_directories: false,
|
implicit_include_directories: false,
|
||||||
dependencies: common_ss.all_dependencies())
|
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')
|
feature_to_c = find_program('scripts/feature_to_c.py')
|
||||||
|
|
||||||
if host_os == 'darwin'
|
if host_os == 'darwin'
|
||||||
@ -3970,6 +4067,29 @@ foreach target : target_dirs
|
|||||||
arch_srcs += target_specific.sources()
|
arch_srcs += target_specific.sources()
|
||||||
arch_deps += target_specific.dependencies()
|
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,
|
# allow using headers from the dependencies but do not include the sources,
|
||||||
# because this emulator only needs those in "objects". For external
|
# because this emulator only needs those in "objects". For external
|
||||||
# dependencies, the full dependency is included below in the executable.
|
# dependencies, the full dependency is included below in the executable.
|
||||||
@ -4308,6 +4428,12 @@ if 'objc' in all_languages
|
|||||||
else
|
else
|
||||||
summary_info += {'Objective-C compiler': false}
|
summary_info += {'Objective-C compiler': false}
|
||||||
endif
|
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'] : [])
|
option_cflags = (get_option('debug') ? ['-g'] : [])
|
||||||
if get_option('optimization') != 'plain'
|
if get_option('optimization') != 'plain'
|
||||||
option_cflags += ['-O' + get_option('optimization')]
|
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',
|
option('x86_version', type : 'combo', choices : ['0', '1', '2', '3', '4'], value: '1',
|
||||||
description: 'tweak required x86_64 architecture version beyond compiler default')
|
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()
|
parser.parse_args()
|
||||||
|
|
||||||
packages = {
|
packages = {
|
||||||
"meson==1.2.3":
|
"meson==1.5.0":
|
||||||
"4533a43c34548edd1f63a276a42690fce15bde9409bcf20c4b8fa3d7e4d7cac1",
|
"52b34f4903b882df52ad0d533146d4b992c018ea77399f825579737672ae7b20",
|
||||||
}
|
}
|
||||||
|
|
||||||
vendor_dir = Path(__file__, "..", "..", "wheels").resolve()
|
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]
|
[meson]
|
||||||
# The install key should match the version in python/wheels/
|
# 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" }
|
pycotap = { accepted = ">=1.1.0", installed = "1.3.1" }
|
||||||
|
|
||||||
[docs]
|
[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
|
# independent of what the developer currently has initialized
|
||||||
# in their checkout, because the build environment is completely
|
# in their checkout, because the build environment is completely
|
||||||
# different to the host OS.
|
# 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=""
|
sub_deinit=""
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
@ -48,13 +52,34 @@ function tree_ish() {
|
|||||||
echo "$retval"
|
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"
|
git archive --format tar "$(tree_ish)" > "$tar_file"
|
||||||
test $? -ne 0 && error "failed to archive qemu"
|
test $? -ne 0 && error "failed to archive qemu"
|
||||||
|
|
||||||
for sp in $subprojects; do
|
for sp in $subprojects; do
|
||||||
meson subprojects download $sp
|
meson subprojects download $sp
|
||||||
test $? -ne 0 && error "failed to download subproject $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"
|
test $? -ne 0 && error "failed to append subproject $sp to $tar_file"
|
||||||
done
|
done
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -17,7 +17,11 @@ if [ $# -ne 2 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Only include wraps that are invoked with subproject()
|
# 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"
|
src="$1"
|
||||||
version="$2"
|
version="$2"
|
||||||
|
@ -172,6 +172,7 @@ meson_options_help() {
|
|||||||
printf "%s\n" ' rbd Ceph block device driver'
|
printf "%s\n" ' rbd Ceph block device driver'
|
||||||
printf "%s\n" ' rdma Enable RDMA-based migration'
|
printf "%s\n" ' rdma Enable RDMA-based migration'
|
||||||
printf "%s\n" ' replication replication support'
|
printf "%s\n" ' replication replication support'
|
||||||
|
printf "%s\n" ' rust Rust support'
|
||||||
printf "%s\n" ' rutabaga-gfx rutabaga_gfx support'
|
printf "%s\n" ' rutabaga-gfx rutabaga_gfx support'
|
||||||
printf "%s\n" ' sdl SDL user interface'
|
printf "%s\n" ' sdl SDL user interface'
|
||||||
printf "%s\n" ' sdl-image SDL Image support for icons'
|
printf "%s\n" ' sdl-image SDL Image support for icons'
|
||||||
@ -456,6 +457,8 @@ _meson_option_parse() {
|
|||||||
--disable-replication) printf "%s" -Dreplication=disabled ;;
|
--disable-replication) printf "%s" -Dreplication=disabled ;;
|
||||||
--enable-rng-none) printf "%s" -Drng_none=true ;;
|
--enable-rng-none) printf "%s" -Drng_none=true ;;
|
||||||
--disable-rng-none) printf "%s" -Drng_none=false ;;
|
--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 ;;
|
--enable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=enabled ;;
|
||||||
--disable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=disabled ;;
|
--disable-rutabaga-gfx) printf "%s" -Drutabaga_gfx=disabled ;;
|
||||||
--enable-safe-stack) printf "%s" -Dsafe_stack=true ;;
|
--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
|
/keycodemapdb
|
||||||
/libvfio-user
|
/libvfio-user
|
||||||
/slirp
|
/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 \
|
RUN /usr/bin/pip3.11 install \
|
||||||
PyYAML \
|
PyYAML \
|
||||||
meson==0.63.2 \
|
meson==1.5.0 \
|
||||||
pillow \
|
pillow \
|
||||||
sphinx \
|
sphinx \
|
||||||
sphinx-rtd-theme
|
sphinx-rtd-theme
|
||||||
|
@ -89,7 +89,7 @@ mappings:
|
|||||||
pypi_mappings:
|
pypi_mappings:
|
||||||
# Request more recent version
|
# Request more recent version
|
||||||
meson:
|
meson:
|
||||||
default: meson==0.63.2
|
default: meson==1.5.0
|
||||||
|
|
||||||
# Drop packages that need devel headers
|
# Drop packages that need devel headers
|
||||||
python3-numpy:
|
python3-numpy:
|
||||||
|
@ -116,6 +116,26 @@ debian12_extras = [
|
|||||||
"ENV QEMU_CONFIGURE_OPTS --enable-netmap\n"
|
"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):
|
def cross_build(prefix, targets):
|
||||||
conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix)
|
conf = "ENV QEMU_CONFIGURE_OPTS --cross-prefix=%s\n" % (prefix)
|
||||||
@ -139,6 +159,12 @@ try:
|
|||||||
generate_dockerfile("opensuse-leap", "opensuse-leap-15")
|
generate_dockerfile("opensuse-leap", "opensuse-leap-15")
|
||||||
generate_dockerfile("ubuntu2204", "ubuntu-2204")
|
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
|
# Cross compiling builds
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user