diff --git a/.gitignore b/.gitignore index e2a4c2f4a0..1b2bbe92dc 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,4 @@ packages/ sources/x86_64-unknown-redox/ sources/*.tar.gz Packages/*.pkgar +.slim/deepwork/ diff --git a/build-live.log b/build-live.log index 3b39b0697a..62ac7b8ebe 100644 --- a/build-live.log +++ b/build-live.log @@ -21,11 +21,11 @@ Tag: build/x86_64/redbear-full/redbear.tag ✅ Custom recipe symlinks ready (188 linked, 5 skipped) ==> Validating local source forks... -✅ local/sources/base: 177 commits +✅ local/sources/base: 184 commits ✅ local/sources/bootloader: 9 commits ✅ local/sources/installer: 328 commits -✅ local/sources/relibc: 1594 commits -✅ local/sources/kernel: 2782 commits +✅ local/sources/relibc: 37 commits +✅ local/sources/kernel: 2783 commits ✅ Local source forks validated ==> Validating Red Bear configs... @@ -51,9 +51,9 @@ Tag: build/x86_64/redbear-full/redbear.tag export PATH="/mnt/data/Builds/RedBear-OS/prefix/x86_64-unknown-redox/sysroot//bin:$PATH" && \ export COOKBOOK_HOST_SYSROOT="/mnt/data/Builds/RedBear-OS/prefix/x86_64-unknown-redox/sysroot/" && \ ./target/release/repo cook "--filesystem=config/redbear-full.toml" --with-package-deps +WARN: binary store missing repo/x86_64-unknown-redox/base.pkgar — will rebuild DEBUG: dependency blake3 hashes unchanged (content-based cache) -DEBUG: updating 'recipes/core/base/target/x86_64-unknown-redox/stage' -DEBUG: updating 'recipes/core/base/target/x86_64-unknown-redox/sysroot' +DEBUG: using cached sysroot + export PATH=/mnt/data/Builds/RedBear-OS/bin:/home/kellito/.redoxer/x86_64-unknown-redox/toolchain/bin:/mnt/data/Builds/RedBear-OS/prefix/x86_64-unknown-redox/sysroot//bin:/home/kellito/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/android-sdk/cmdline-tools/latest/bin:/opt/android-sdk/platform-tools:/opt/android-sdk/tools:/opt/android-sdk/tools/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/usr/lib/rustup/bin + PATH=/mnt/data/Builds/RedBear-OS/bin:/home/kellito/.redoxer/x86_64-unknown-redox/toolchain/bin:/mnt/data/Builds/RedBear-OS/prefix/x86_64-unknown-redox/sysroot//bin:/home/kellito/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/opt/android-sdk/cmdline-tools/latest/bin:/opt/android-sdk/platform-tools:/opt/android-sdk/tools:/opt/android-sdk/tools/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/usr/lib/rustup/bin + '[' '!' -z '' ']' @@ -110,8 +110,8 @@ mkdir: создан каталог '/mnt/data/Builds/RedBear-OS/recipes/core/bas mkdir: создан каталог '/mnt/data/Builds/RedBear-OS/recipes/core/base/target/x86_64-unknown-redox/stage.tmp/usr/bin' + for package in audiod ipcd ptyd dhcpd + /mnt/data/Builds/RedBear-OS/target/release/cookbook_redbear_redoxer build --manifest-path /mnt/data/Builds/RedBear-OS/local/sources/base/audiod/Cargo.toml --target x86_64-unknown-redox --release -warning: /mnt/data/Builds/RedBear-OS/local/sources/base/netstack/Cargo.toml: `default-features` is ignored for log, since `default-features` was not specified for `workspace.dependencies.log`, this could become a hard error in the future warning: /mnt/data/Builds/RedBear-OS/local/sources/base/drivers/hwd/Cargo.toml: `default-features` is ignored for libredox, since `default-features` was true for `workspace.dependencies.libredox`, this could become a hard error in the future +warning: /mnt/data/Builds/RedBear-OS/local/sources/base/netstack/Cargo.toml: `default-features` is ignored for log, since `default-features` was not specified for `workspace.dependencies.log`, this could become a hard error in the future warning: `extern` block uses type `[u8]`, which is not FFI-safe --> /mnt/data/Builds/RedBear-OS/local/sources/libredox/src/lib.rs:314:77 | @@ -136,7 +136,7 @@ help: first cast to a pointer `as *const ()` | ++++++++++++ warning: `audiod` (bin "audiod") generated 1 warning (run `cargo fix --bin "audiod" -p audiod` to apply 1 suggestion) - Finished `release` profile [optimized] target(s) in 0.26s + Finished `release` profile [optimized] target(s) in 0.21s + cp -v target/x86_64-unknown-redox/release/audiod /mnt/data/Builds/RedBear-OS/recipes/core/base/target/x86_64-unknown-redox/stage.tmp/usr/bin/audiod 'target/x86_64-unknown-redox/release/audiod' -> '/mnt/data/Builds/RedBear-OS/recipes/core/base/target/x86_64-unknown-redox/stage.tmp/usr/bin/audiod' + for package in audiod ipcd ptyd dhcpd @@ -154,7 +154,7 @@ warning: `extern` block uses type `[u8]`, which is not FFI-safe = note: `#[warn(improper_ctypes)]` on by default warning: `libredox` (lib) generated 1 warning - Finished `release` profile [optimized] target(s) in 0.09s + Finished `release` profile [optimized] target(s) in 0.10s + cp -v target/x86_64-unknown-redox/release/ipcd /mnt/data/Builds/RedBear-OS/recipes/core/base/target/x86_64-unknown-redox/stage.tmp/usr/bin/ipcd 'target/x86_64-unknown-redox/release/ipcd' -> '/mnt/data/Builds/RedBear-OS/recipes/core/base/target/x86_64-unknown-redox/stage.tmp/usr/bin/ipcd' + for package in audiod ipcd ptyd dhcpd @@ -222,7 +222,7 @@ warning: constant `OPT_PARAM_REQUEST` is never used | ^^^^^^^^^^^^^^^^^ warning: `dhcpd` (bin "dhcpd") generated 6 warnings (run `cargo fix --bin "dhcpd" -p dhcpd` to apply 2 suggestions) - Finished `release` profile [optimized] target(s) in 0.07s + Finished `release` profile [optimized] target(s) in 0.08s + cp -v target/x86_64-unknown-redox/release/dhcpd /mnt/data/Builds/RedBear-OS/recipes/core/base/target/x86_64-unknown-redox/stage.tmp/usr/bin/dhcpd 'target/x86_64-unknown-redox/release/dhcpd' -> '/mnt/data/Builds/RedBear-OS/recipes/core/base/target/x86_64-unknown-redox/stage.tmp/usr/bin/dhcpd' + /mnt/data/Builds/RedBear-OS/target/release/cookbook_redbear_redoxer build --manifest-path /mnt/data/Builds/RedBear-OS/local/sources/base/netstack/Cargo.toml --target x86_64-unknown-redox --release @@ -485,9 +485,9 @@ note: multiple earlier patterns match some of the same values | ^ collectively making this unreachable warning: unused variable: `e` - --> netstack/src/scheme/netcfg/mod.rs:741:59 + --> netstack/src/scheme/netcfg/mod.rs:764:59 | -741 | ... dev.set_qdisc(&kind).map_err(|e| { +764 | ... dev.set_qdisc(&kind).map_err(|e| { | ^ help: if this is intentional, prefix it with an underscore: `_e` warning: unused variable: `e` @@ -1242,3 +1242,33 @@ mkdir: создан каталог '/mnt/data/Builds/RedBear-OS/recipes/core/bas + EXISTING_BINS+=("${bin}") + for bin in "${BINS[@]}" + grep -Rqs '^name = "amd-mp2-i2cd"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "dw-acpi-i2cd"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "e1000d"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "ihdad"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "ihdgd"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "i2c-hidd"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "intel-thc-hidd"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "intel-lpss-i2cd"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "ixgbed"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "pcid"$' /mnt/data/Builds/RedBear-OS/local/sources/base ++ EXISTING_BINS+=("${bin}") ++ for bin in "${BINS[@]}" ++ grep -Rqs '^name = "pcid-spawner"$' /mnt/data/Builds/RedBear-OS/local/sources/base diff --git a/config/redbear-full.toml b/config/redbear-full.toml index 2a93a6ccb3..1e08b23b44 100644 --- a/config/redbear-full.toml +++ b/config/redbear-full.toml @@ -187,11 +187,12 @@ kglobalacceld = {} # (host tool Qt6::qmlprofiler is intentionally not built — see qtdeclarative recipe). kwin = {} -# Plasma packages — still commented out; need kirigami (QML) + plasma-workspace to build -# before they can be enabled. See local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md. -# plasma-framework = {} -# plasma-workspace = {} -# plasma-desktop = {} +# Plasma packages — QML/Quick re-enabled in kf6-kdeclarative and kf6-kcmutils. +# These should now build against the target Qt6::Qml + Qt6::Quick from qtdeclarative. +# See local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md for the full desktop path. +plasma-framework = {} +plasma-workspace = {} +plasma-desktop = {} redbear-authd = {} redbear-session-launch = {} diff --git a/local/patches/build-system/002-cookbook-fixes.patch b/local/patches/build-system/002-cookbook-fixes.patch index ff661d7f51..eb827c2ee1 100644 --- a/local/patches/build-system/002-cookbook-fixes.patch +++ b/local/patches/build-system/002-cookbook-fixes.patch @@ -1056,12 +1056,12 @@ index 2305cdaa9..129a53580 100644 + | "redbear-quirks" + // Red Bear branding + | "redbear-release" -+ // Red Bear library stubs and custom libs -+ | "libepoxy-stub" -+ | "libdisplay-info-stub" -+ | "lcms2-stub" -+ | "libxcvt-stub" -+ | "libudev-stub" ++ // Red Bear custom libs ++ | "libepoxy" ++ | "libdisplay-info" ++ | "lcms2" ++ | "libxcvt" ++ | "libudev" + | "zbus" + | "libqrencode" + // Red Bear Wayland diff --git a/local/patches/build-system/005-qtbase-toolchain-elf-header.patch b/local/patches/build-system/005-qtbase-toolchain-elf-header.patch index 5e605d7205..5d5ac0c10e 100644 --- a/local/patches/build-system/005-qtbase-toolchain-elf-header.patch +++ b/local/patches/build-system/005-qtbase-toolchain-elf-header.patch @@ -276,28 +276,20 @@ index 000000000..8fe0e4637 +' "${COOKBOOK_SOURCE}/src/corelib/CMakeLists.txt" > "${COOKBOOK_SOURCE}/src/corelib/CMakeLists.txt.tmp" +mv "${COOKBOOK_SOURCE}/src/corelib/CMakeLists.txt.tmp" "${COOKBOOK_SOURCE}/src/corelib/CMakeLists.txt" + -+# Disable QtNetwork — relibc now provides a minimal resolv.h and bounded interface view, -+# but broader networking/runtime compatibility (for example `in6_pktinfo`, richer interface -+# semantics, and full downstream validation) is still incomplete. -+sed -i 's/^ add_subdirectory(network)/ # add_subdirectory(network) # disabled for Redox/' \ -+ "${COOKBOOK_SOURCE}/src/CMakeLists.txt" -+# Disable TUIO touch plugin — depends on QtNetwork which is disabled -+sed -i 's/^ add_subdirectory(tuiotouch)/ # add_subdirectory(tuiotouch) # disabled for Redox (needs Network)/' \ -+ "${COOKBOOK_SOURCE}/src/plugins/generic/CMakeLists.txt" -+# Disable Wayland shm-emulation-server on Redox. -+# Clean rebuilds still do not expose QSharedMemory::lock/unlock strongly enough for this path, -+# so keep the bounded software compositor path honest until QtCore runtime support is proven. -+HWI_CMAKE="${COOKBOOK_SOURCE}/src/plugins/platforms/wayland/plugins/hardwareintegration/CMakeLists.txt" -+awk 'index($0, "if(QT_FEATURE_wayland_shm_emulation_server_buffer)") { -+ print "if(FALSE AND QT_FEATURE_wayland_shm_emulation_server_buffer) # disabled for Redox (QSharedMemory locking still not runtime-proven on clean rebuilds)"; -+ next -+ } { print }' "${HWI_CMAKE}" > "${HWI_CMAKE}.tmp" -+mv "${HWI_CMAKE}.tmp" "${HWI_CMAKE}" ++# QtNetwork and TUIO touch — enabled by qtbase recipe (P2-enable-network-and-tuiotouch.patch). ++# The recipe.toml handles uncommenting these subdirectories; no build-time sed override needed. ++# QtNetwork builds on Redox with relibc resolv.h. ++echo "QtNetwork enabled by qtbase recipe — P2-enable-network-and-tuiotouch.patch" ++# Wayland shm-emulation-server — QSharedMemory shm_open/shm_unlink now live in relibc. ++# The `FALSE AND` gate is removed; the feature probe will determine real availability. ++echo "Wayland shm-emulation-server: relibc QSharedMemory now live — removing FALSE gate" + + + -+# Redox relibc now exports sem_open/sem_close/sem_unlink, but the target toolchain's -+# builtin semaphore.h can still hide those declarations during C++ feature probes. -+# Inject a small Redox-only declaration shim both into the POSIX semaphore compile test -+# and the Qt runtime backend source so configure can detect the path honestly. ++# Redox relibc now exports sem_open/sem_close/sem_unlink with full POSIX signatures. ++# The C++ extern "C" declaration shim below may no longer be necessary — the toolchain's ++# semaphore.h should provide these via the relibc header sync (see elf.h sync above). ++# TODO: verify Qt configure detects sem_open without this shim, then remove. +python - <<'PY' +import os +from pathlib import Path @@ -410,50 +402,10 @@ index 000000000..8fe0e4637 +PY +fi + -+# forkfd still needs waitid idtype constants on Redox. Provide source-level fallbacks near the -+# waitid consumer instead of relying on toolchain/env defines that clean builds may drop. -+FORKFD_C="${COOKBOOK_SOURCE}/src/3rdparty/forkfd/forkfd.c" -+if ! grep -q 'REDOX_DISABLE_HAVE_WAITID' "${FORKFD_C}" 2>/dev/null; then -+ awk 'index($0, "#if !defined(WEXITED) || !defined(WNOWAIT)") { -+ print; -+ print "#ifdef __redox__"; -+ print "#define REDOX_DISABLE_HAVE_WAITID 1"; -+ print "#undef HAVE_WAITID"; -+ print "#endif"; -+ next -+ } { print }' "${FORKFD_C}" > "${FORKFD_C}.tmp" -+ mv "${FORKFD_C}.tmp" "${FORKFD_C}" -+fi -+if ! grep -q 'REDOX_FORCE_WAITPID_FALLBACK' "${FORKFD_C}" 2>/dev/null; then -+ awk 'index($0, "#if defined(__APPLE__)") { -+ print "#ifdef __redox__"; -+ print "#define REDOX_FORCE_WAITPID_FALLBACK 1"; -+ print "#undef HAVE_WAITID"; -+ print "#endif"; -+ print; -+ next -+ } { print }' "${FORKFD_C}" > "${FORKFD_C}.tmp" -+ mv "${FORKFD_C}.tmp" "${FORKFD_C}" -+fi -+if ! grep -q 'REDOX_WAITID_IDTYPE_SHIMS' "${FORKFD_C}" 2>/dev/null; then -+ awk '/#include / { -+ print; -+ print "#ifdef __redox__"; -+ print "#define REDOX_WAITID_IDTYPE_SHIMS 1"; -+ print "#ifndef P_ALL"; -+ print "#define P_ALL 0"; -+ print "#endif"; -+ print "#ifndef P_PID"; -+ print "#define P_PID 1"; -+ print "#endif"; -+ print "#ifndef P_PGID"; -+ print "#define P_PGID 2"; -+ print "#endif"; -+ print "#endif"; -+ next -+ } { print }' "${FORKFD_C}" > "${FORKFD_C}.tmp" -+ mv "${FORKFD_C}.tmp" "${FORKFD_C}" -+fi ++# waitid is now fully implemented in relibc (src/header/sys_wait/mod.rs). ++# No forkfd source mutations needed — HAVE_WAITID is available. ++echo "waitid: relibc implementation complete — no forkfd mutations needed" + +# qprocess_unix.cpp needs sys/ioctl.h (for FIONREAD) but doesn't include it +QP="${COOKBOOK_SOURCE}/src/corelib/io/qprocess_unix.cpp" +if ! grep -q 'sys/ioctl.h' "${QP}" 2>/dev/null; then @@ -461,20 +413,8 @@ index 000000000..8fe0e4637 + "${QP}" > "${QP}.tmp" + mv "${QP}.tmp" "${QP}" +fi -+if ! grep -q 'REDOX_VFORK_SHIM' "${QP}" 2>/dev/null; then -+ awk '/#include / { -+ print; -+ print "#ifdef __redox__"; -+ print "#define REDOX_VFORK_SHIM 1"; -+ print "#ifndef vfork"; -+ print "#define vfork fork"; -+ print "#endif"; -+ print "#endif"; -+ next -+ } { print }' "${QP}" > "${QP}.tmp" -+ mv "${QP}.tmp" "${QP}" -+fi -+ +# vfork is now provided by relibc (header/unistd/mod.rs delegates to fork). +# The REDOX_VFORK_SHIM shim is no longer needed. +# On Redox, keep Qt plugin metadata at the architectural baseline. +# The x86 plugin arch-requirement path produces feature-level warnings at runtime +# and can cause otherwise-present plugins to be rejected before load. diff --git a/local/patches/kf6-kcmutils/01-initial-migration.patch b/local/patches/kf6-kcmutils/01-initial-migration.patch index 67eb73d217..91993c7a7d 100644 --- a/local/patches/kf6-kcmutils/01-initial-migration.patch +++ b/local/patches/kf6-kcmutils/01-initial-migration.patch @@ -17,15 +17,15 @@ add_subdirectory(core) -add_subdirectory(qml) -add_subdirectory(quick) -+#add_subdirectory(qml) -+#add_subdirectory(quick) +add_subdirectory(qml) +add_subdirectory(quick) ########### kcmutils ############### set(kcmutils_LIB_SRCS kcmoduleloader.cpp kcmoduleloader.h -- kcmoduleqml.cpp -- kcmoduleqml_p.h + kcmoduleqml.cpp + kcmoduleqml_p.h kcmultidialog.cpp kcmultidialog.h kcmultidialog_p.h @@ -33,12 +33,12 @@ Qt6::Widgets KF6::CoreAddons # KPluginMetaData KF6::ConfigWidgets # KPageDialog -- KF6KCMUtilsQuick # QML KCM class + KF6KCMUtilsQuick # QML KCM class PRIVATE kcmutils_proxy_model -- Qt6::Qml -- Qt6::Quick -- Qt6::QuickWidgets + Qt6::Qml + Qt6::Quick + Qt6::QuickWidgets KF6::GuiAddons # KIconUtils KF6::I18n KF6::ItemViews # KWidgetItemDelegate @@ -46,8 +46,7 @@ DESTINATION "${KDE_INSTALL_LOGGINGCATEGORIESDIR}" ) --add_subdirectory(kcmshell) -+#add_subdirectory(kcmshell) +add_subdirectory(kcmshell) --- ./CMakeLists.txt +++ ./CMakeLists.txt @@ -23,7 +23,7 @@ @@ -55,7 +54,7 @@ include(ECMMarkNonGuiExecutable) include(KDEGitCommitHooks) -include(ECMQmlModule) -+#include(ECMQmlModule) +include(ECMQmlModule) include(ECMFindQmlModule) include(ECMGenerateQDoc) @@ -63,8 +62,7 @@ PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF6KCMUtilsConfigVersion.cmake" SOVERSION 6) --find_package(KF6KIO ${KF_DEP_VERSION} REQUIRED) -+#find_package(KF6KIO ${KF_DEP_VERSION} REQUIRED) +find_package(KF6KIO ${KF_DEP_VERSION} REQUIRED) find_package(KF6ItemViews ${KF_DEP_VERSION} REQUIRED) find_package(KF6ConfigWidgets ${KF_DEP_VERSION} REQUIRED) find_package(KF6CoreAddons ${KF_DEP_VERSION} REQUIRED) diff --git a/local/patches/kf6-kdeclarative/01-initial-migration.patch b/local/patches/kf6-kdeclarative/01-initial-migration.patch index 6f832baaa2..d4090e936f 100644 --- a/local/patches/kf6-kdeclarative/01-initial-migration.patch +++ b/local/patches/kf6-kdeclarative/01-initial-migration.patch @@ -13,7 +13,7 @@ +++ ./src/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(qmlcontrols) -+#add_subdirectory(qmlcontrols) ++add_subdirectory(qmlcontrols) add_subdirectory(calendarevents) --- ./CMakeLists.txt +++ ./CMakeLists.txt @@ -22,30 +22,30 @@ include(ECMSetupVersion) include(ECMGenerateHeaders) -include(ECMQmlModule) -+#include(ECMQmlModule) ++include(ECMQmlModule) include(CMakePackageConfigHelpers) include(ECMGenerateQDoc) - + -find_package(Qt6 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Qml Quick Gui) -+find_package(Qt6 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Gui) ++find_package(Qt6 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Qml Quick Gui) find_package(KF6I18n ${KF_DEP_VERSION} REQUIRED) find_package(KF6Config ${KF_DEP_VERSION} REQUIRED) find_package(KF6GuiAddons ${KF_DEP_VERSION} REQUIRED) - - + + if(NOT WIN32 AND NOT APPLE AND NOT ANDROID AND NOT HAIKU) - find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED) -+# find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED) ++ find_package(KF6GlobalAccel ${KF_DEP_VERSION} REQUIRED) set(HAVE_KGLOBALACCEL TRUE) else() set(HAVE_KGLOBALACCEL FALSE) @@ -63,7 +63,7 @@ KF 6.23.0 ) - + -ki18n_install(po) -+#ki18n_install(po) - ++#ki18n_install(po) # TODO: enable when cross-compile ECM translation toolchain is wired + add_subdirectory(src) if (BUILD_TESTING) diff --git a/local/patches/kwin/02-kf6svg-target.patch b/local/patches/kwin/02-kf6svg-target.patch new file mode 100644 index 0000000000..aeeb3c265e --- /dev/null +++ b/local/patches/kwin/02-kf6svg-target.patch @@ -0,0 +1,15 @@ +diff --git a/local/recipes/kde/kwin/source/CMakeLists.txt b/local/recipes/kde/kwin/source/CMakeLists.txt +index 326ea13df7..67ea327610 100644 +--- a/local/recipes/kde/kwin/source/CMakeLists.txt ++++ b/local/recipes/kde/kwin/source/CMakeLists.txt +@@ -46,6 +46,10 @@ include(ECMGenerateQmlTypes) + include(ECMDeprecationSettings) + include(ECMGenerateQDoc) + ++if(NOT TARGET KF6::Svg) ++ find_package(KF6Svg REQUIRED) ++endif() ++ + option(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON) + option(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON) + option(KWIN_BUILD_NOTIFICATIONS "Enable building of KWin with knotifications support" ON) diff --git a/local/recipes/core/ext4d/source/Cargo.toml b/local/recipes/core/ext4d/source/Cargo.toml index b12ad93c42..2b41765d94 100644 --- a/local/recipes/core/ext4d/source/Cargo.toml +++ b/local/recipes/core/ext4d/source/Cargo.toml @@ -13,15 +13,15 @@ license = "MIT" [workspace.dependencies] rsext4 = "0.3" -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +libredox = { path = "../../../../../local/sources/libredox" } redox-path = "0.3.0" log = "0.4" env_logger = "0.11" libc = "0.2" [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/core/ext4d/source/ext4-blockdev/Cargo.toml b/local/recipes/core/ext4d/source/ext4-blockdev/Cargo.toml index fc825d81b6..1b106019bf 100644 --- a/local/recipes/core/ext4d/source/ext4-blockdev/Cargo.toml +++ b/local/recipes/core/ext4d/source/ext4-blockdev/Cargo.toml @@ -7,8 +7,8 @@ license.workspace = true [dependencies] rsext4.workspace = true -redox_syscall = { path = "../../../../../../recipes/core/base/syscall", workspace = true, optional = true } -libredox = { path = "../../../../../../recipes/core/base/libredox", workspace = true, optional = true } +redox_syscall = { path = "../../../../../../local/sources/syscall", workspace = true, optional = true } +libredox = { path = "../../../../../../local/sources/libredox", workspace = true, optional = true } log.workspace = true [features] diff --git a/local/recipes/core/ext4d/source/ext4d/Cargo.toml b/local/recipes/core/ext4d/source/ext4d/Cargo.toml index cd01761484..2212c92e24 100644 --- a/local/recipes/core/ext4d/source/ext4d/Cargo.toml +++ b/local/recipes/core/ext4d/source/ext4d/Cargo.toml @@ -14,7 +14,7 @@ ext4-blockdev = { path = "../ext4-blockdev" } rsext4.workspace = true redox_syscall.workspace = true redox-scheme.workspace = true -libredox = { path = "../../../../../../recipes/core/base/libredox", workspace = true, optional = true } +libredox = { path = "../../../../../../local/sources/libredox", workspace = true, optional = true } redox-path = { workspace = true, optional = true } log.workspace = true env_logger = { workspace = true, optional = true } diff --git a/local/recipes/core/fatd/source/Cargo.toml b/local/recipes/core/fatd/source/Cargo.toml index 5349fc1db8..651551a794 100644 --- a/local/recipes/core/fatd/source/Cargo.toml +++ b/local/recipes/core/fatd/source/Cargo.toml @@ -16,15 +16,15 @@ license = "MIT" [workspace.dependencies] fatfs = "0.3.6" fscommon = "0.1.1" -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +libredox = { path = "../../../../../local/sources/libredox" } redox-path = "0.3.0" log = "0.4" env_logger = "0.11" libc = "0.2" [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/core/fatd/source/fatd/Cargo.toml b/local/recipes/core/fatd/source/fatd/Cargo.toml index 54e0214aab..d1f68a28d7 100644 --- a/local/recipes/core/fatd/source/fatd/Cargo.toml +++ b/local/recipes/core/fatd/source/fatd/Cargo.toml @@ -15,7 +15,7 @@ fatfs.workspace = true fscommon.workspace = true redox_syscall.workspace = true redox-scheme.workspace = true -libredox = { path = "../../../../../../recipes/core/base/libredox", workspace = true, optional = true } +libredox = { path = "../../../../../../local/sources/libredox", workspace = true, optional = true } redox-path = { workspace = true, optional = true } log.workspace = true env_logger = { workspace = true, optional = true } diff --git a/local/recipes/drivers/ehcid/Cargo.toml b/local/recipes/drivers/ehcid/Cargo.toml index f44cee4944..0767dd7a56 100644 --- a/local/recipes/drivers/ehcid/Cargo.toml +++ b/local/recipes/drivers/ehcid/Cargo.toml @@ -10,5 +10,5 @@ path = "src/main.rs" [dependencies] usb-core = { path = "../../usb-core/source" } -redox_syscall = { path = "../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../local/sources/syscall" } log = "0.4" diff --git a/local/recipes/drivers/ehcid/source/Cargo.toml b/local/recipes/drivers/ehcid/source/Cargo.toml index bcacabbc09..2f3ef71d97 100644 --- a/local/recipes/drivers/ehcid/source/Cargo.toml +++ b/local/recipes/drivers/ehcid/source/Cargo.toml @@ -10,16 +10,16 @@ path = "src/main.rs" [dependencies] usb-core = { path = "../../usb-core/source" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } redox-driver-sys = { path = "../../redox-driver-sys/source" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { package = "redox_syscall", path = "../../../../../recipes/core/base/syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { package = "redox_syscall", path = "../../../../../local/sources/syscall", features = ["std"] } [target.'cfg(target_os = "redox")'.dependencies] redox-driver-sys = { path = "../../redox-driver-sys/source", features = ["redox"] } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } diff --git a/local/recipes/drivers/linux-kpi/recipe.toml b/local/recipes/drivers/linux-kpi/recipe.toml index 10e581aa7e..35cfb908ca 100644 --- a/local/recipes/drivers/linux-kpi/recipe.toml +++ b/local/recipes/drivers/linux-kpi/recipe.toml @@ -1,6 +1,9 @@ # linux-kpi build-ordering marker. Downstream driver builds compile the crate via Cargo path deps. # The cookbook cargo template cannot install a library-only crate cleanly here, so keep this as a -# custom no-op recipe until the cookbook grows first-class Rust library packaging. +# custom recipe until the cookbook grows first-class Rust library packaging. +# +# We install the C compatibility headers into the sysroot so that meson/cmake recipes +# (libdrm, mesa, etc.) can find them at . [source] path = "source" @@ -10,6 +13,9 @@ dependencies = [ "redox-driver-sys", ] script = """ -echo "linux-kpi: build-ordering marker — actual crate is compiled by downstream Cargo builds" -mkdir -p "${COOKBOOK_STAGE}/usr" +DYNAMIC_INIT + +echo "linux-kpi: installing C compatibility headers into sysroot" +mkdir -p "${COOKBOOK_STAGE}/usr/include/linux-kpi" +cp -R "${COOKBOOK_SOURCE}/src/c_headers/." "${COOKBOOK_STAGE}/usr/include/linux-kpi/" """ diff --git a/local/recipes/drivers/linux-kpi/source/Cargo.toml b/local/recipes/drivers/linux-kpi/source/Cargo.toml index 14a0a1e403..4ac2cf1e92 100644 --- a/local/recipes/drivers/linux-kpi/source/Cargo.toml +++ b/local/recipes/drivers/linux-kpi/source/Cargo.toml @@ -6,8 +6,8 @@ description = "Linux Kernel API compatibility layer for Redox OS (LinuxKPI-style license = "MIT" [dependencies] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall", features = ["std"] } +libredox = { path = "../../../../../local/sources/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall", features = ["std"] } log = "0.4" thiserror = "2" lazy_static = "1.4" @@ -17,5 +17,5 @@ redox-driver-sys = { path = "../../redox-driver-sys/source" } crate-type = ["rlib", "staticlib"] [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/drm_fourcc.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/drm_fourcc.h new file mode 100644 index 0000000000..3a4d4dc635 --- /dev/null +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/drm_fourcc.h @@ -0,0 +1,1788 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2011 Intel Corporation + */ + +#ifndef DRM_FOURCC_H +#define DRM_FOURCC_H + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * DOC: overview + * + * In the DRM subsystem, framebuffer pixel formats are described using the + * fourcc codes defined in `include/uapi/drm/drm_fourcc.h`. In addition to the + * fourcc code, a Format Modifier may optionally be provided, in order to + * further describe the buffer's format - for example tiling or compression. + * + * Format Modifiers + * ---------------- + * + * Format modifiers are used in conjunction with a fourcc code, forming a + * unique fourcc:modifier pair. This format:modifier pair must fully define the + * format and data layout of the buffer, and should be the only way to describe + * that particular buffer. + * + * Having multiple fourcc:modifier pairs which describe the same layout should + * be avoided, as such aliases run the risk of different drivers exposing + * different names for the same data format, forcing userspace to understand + * that they are aliases. + * + * Format modifiers may change any property of the buffer, including the number + * of planes and/or the required allocation size. Format modifiers are + * vendor-namespaced, and as such the relationship between a fourcc code and a + * modifier is specific to the modifier being used. For example, some modifiers + * may preserve meaning - such as number of planes - from the fourcc code, + * whereas others may not. + * + * Modifiers must uniquely encode buffer layout. In other words, a buffer must + * match only a single modifier. A modifier must not be a subset of layouts of + * another modifier. For instance, it's incorrect to encode pitch alignment in + * a modifier: a buffer may match a 64-pixel aligned modifier and a 32-pixel + * aligned modifier. That said, modifiers can have implicit minimal + * requirements. + * + * For modifiers where the combination of fourcc code and modifier can alias, + * a canonical pair needs to be defined and used by all drivers. Preferred + * combinations are also encouraged where all combinations might lead to + * confusion and unnecessarily reduced interoperability. An example for the + * latter is AFBC, where the ABGR layouts are preferred over ARGB layouts. + * + * There are two kinds of modifier users: + * + * - Kernel and user-space drivers: for drivers it's important that modifiers + * don't alias, otherwise two drivers might support the same format but use + * different aliases, preventing them from sharing buffers in an efficient + * format. + * - Higher-level programs interfacing with KMS/GBM/EGL/Vulkan/etc: these users + * see modifiers as opaque tokens they can check for equality and intersect. + * These users mustn't need to know to reason about the modifier value + * (i.e. they are not expected to extract information out of the modifier). + * + * Vendors should document their modifier usage in as much detail as + * possible, to ensure maximum compatibility across devices, drivers and + * applications. + * + * The authoritative list of format modifier codes is found in + * `include/uapi/drm/drm_fourcc.h` + * + * Open Source User Waiver + * ----------------------- + * + * Because this is the authoritative source for pixel formats and modifiers + * referenced by GL, Vulkan extensions and other standards and hence used both + * by open source and closed source driver stacks, the usual requirement for an + * upstream in-kernel or open source userspace user does not apply. + * + * To ensure, as much as feasible, compatibility across stacks and avoid + * confusion with incompatible enumerations stakeholders for all relevant driver + * stacks should approve additions. + */ + +#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ + ((__u32)(c) << 16) | ((__u32)(d) << 24)) + +#define DRM_FORMAT_BIG_ENDIAN (1U<<31) /* format is big endian instead of little endian */ + +/* Reserve 0 for the invalid format specifier */ +#define DRM_FORMAT_INVALID 0 + +/* color index */ +#define DRM_FORMAT_C1 fourcc_code('C', '1', ' ', ' ') /* [7:0] C0:C1:C2:C3:C4:C5:C6:C7 1:1:1:1:1:1:1:1 eight pixels/byte */ +#define DRM_FORMAT_C2 fourcc_code('C', '2', ' ', ' ') /* [7:0] C0:C1:C2:C3 2:2:2:2 four pixels/byte */ +#define DRM_FORMAT_C4 fourcc_code('C', '4', ' ', ' ') /* [7:0] C0:C1 4:4 two pixels/byte */ +#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ + +/* 1 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D1 fourcc_code('D', '1', ' ', ' ') /* [7:0] D0:D1:D2:D3:D4:D5:D6:D7 1:1:1:1:1:1:1:1 eight pixels/byte */ + +/* 2 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D2 fourcc_code('D', '2', ' ', ' ') /* [7:0] D0:D1:D2:D3 2:2:2:2 four pixels/byte */ + +/* 4 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D4 fourcc_code('D', '4', ' ', ' ') /* [7:0] D0:D1 4:4 two pixels/byte */ + +/* 8 bpp Darkness (inverse relationship between channel value and brightness) */ +#define DRM_FORMAT_D8 fourcc_code('D', '8', ' ', ' ') /* [7:0] D */ + +/* 1 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R1 fourcc_code('R', '1', ' ', ' ') /* [7:0] R0:R1:R2:R3:R4:R5:R6:R7 1:1:1:1:1:1:1:1 eight pixels/byte */ + +/* 2 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R2 fourcc_code('R', '2', ' ', ' ') /* [7:0] R0:R1:R2:R3 2:2:2:2 four pixels/byte */ + +/* 4 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R4 fourcc_code('R', '4', ' ', ' ') /* [7:0] R0:R1 4:4 two pixels/byte */ + +/* 8 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ + +/* 10 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R10 fourcc_code('R', '1', '0', ' ') /* [15:0] x:R 6:10 little endian */ + +/* 12 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R12 fourcc_code('R', '1', '2', ' ') /* [15:0] x:R 4:12 little endian */ + +/* 16 bpp Red (direct relationship between channel value and brightness) */ +#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */ + +/* 16 bpp RG */ +#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */ +#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */ + +/* 32 bpp RG */ +#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */ +#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */ + +/* 8 bpp RGB */ +#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */ +#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */ + +/* 16 bpp RGB */ +#define DRM_FORMAT_XRGB4444 fourcc_code('X', 'R', '1', '2') /* [15:0] x:R:G:B 4:4:4:4 little endian */ +#define DRM_FORMAT_XBGR4444 fourcc_code('X', 'B', '1', '2') /* [15:0] x:B:G:R 4:4:4:4 little endian */ +#define DRM_FORMAT_RGBX4444 fourcc_code('R', 'X', '1', '2') /* [15:0] R:G:B:x 4:4:4:4 little endian */ +#define DRM_FORMAT_BGRX4444 fourcc_code('B', 'X', '1', '2') /* [15:0] B:G:R:x 4:4:4:4 little endian */ + +#define DRM_FORMAT_ARGB4444 fourcc_code('A', 'R', '1', '2') /* [15:0] A:R:G:B 4:4:4:4 little endian */ +#define DRM_FORMAT_ABGR4444 fourcc_code('A', 'B', '1', '2') /* [15:0] A:B:G:R 4:4:4:4 little endian */ +#define DRM_FORMAT_RGBA4444 fourcc_code('R', 'A', '1', '2') /* [15:0] R:G:B:A 4:4:4:4 little endian */ +#define DRM_FORMAT_BGRA4444 fourcc_code('B', 'A', '1', '2') /* [15:0] B:G:R:A 4:4:4:4 little endian */ + +#define DRM_FORMAT_XRGB1555 fourcc_code('X', 'R', '1', '5') /* [15:0] x:R:G:B 1:5:5:5 little endian */ +#define DRM_FORMAT_XBGR1555 fourcc_code('X', 'B', '1', '5') /* [15:0] x:B:G:R 1:5:5:5 little endian */ +#define DRM_FORMAT_RGBX5551 fourcc_code('R', 'X', '1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */ +#define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */ + +#define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */ +#define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */ +#define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */ +#define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */ + +#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */ +#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */ + +/* 24 bpp RGB */ +#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */ +#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */ + +/* 32 bpp RGB */ +#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */ +#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */ +#define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */ +#define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */ + +#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */ +#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */ +#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */ +#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */ + +#define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */ +#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */ +#define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */ +#define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */ + +#define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */ +#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */ +#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ +#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ + +/* 48 bpp RGB */ +#define DRM_FORMAT_RGB161616 fourcc_code('R', 'G', '4', '8') /* [47:0] R:G:B 16:16:16 little endian */ +#define DRM_FORMAT_BGR161616 fourcc_code('B', 'G', '4', '8') /* [47:0] B:G:R 16:16:16 little endian */ + +/* 64 bpp RGB */ +#define DRM_FORMAT_XRGB16161616 fourcc_code('X', 'R', '4', '8') /* [63:0] x:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_XBGR16161616 fourcc_code('X', 'B', '4', '8') /* [63:0] x:B:G:R 16:16:16:16 little endian */ + +#define DRM_FORMAT_ARGB16161616 fourcc_code('A', 'R', '4', '8') /* [63:0] A:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_ABGR16161616 fourcc_code('A', 'B', '4', '8') /* [63:0] A:B:G:R 16:16:16:16 little endian */ + +/* + * Half-Floating point - 16b/component + * IEEE 754-2008 binary16 half-precision float + * [15:0] sign:exponent:mantissa 1:5:10 + */ +#define DRM_FORMAT_XRGB16161616F fourcc_code('X', 'R', '4', 'H') /* [63:0] x:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_XBGR16161616F fourcc_code('X', 'B', '4', 'H') /* [63:0] x:B:G:R 16:16:16:16 little endian */ + +#define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ + +#define DRM_FORMAT_R16F fourcc_code('R', ' ', ' ', 'H') /* [15:0] R 16 little endian */ +#define DRM_FORMAT_GR1616F fourcc_code('G', 'R', ' ', 'H') /* [31:0] G:R 16:16 little endian */ +#define DRM_FORMAT_BGR161616F fourcc_code('B', 'G', 'R', 'H') /* [47:0] B:G:R 16:16:16 little endian */ + +/* + * Floating point - 32b/component + * IEEE 754-2008 binary32 float + * [31:0] sign:exponent:mantissa 1:8:23 + */ +#define DRM_FORMAT_R32F fourcc_code('R', ' ', ' ', 'F') /* [31:0] R 32 little endian */ +#define DRM_FORMAT_GR3232F fourcc_code('G', 'R', ' ', 'F') /* [63:0] G:R 32:32 little endian */ +#define DRM_FORMAT_BGR323232F fourcc_code('B', 'G', 'R', 'F') /* [95:0] B:G:R 32:32:32 little endian */ +#define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') /* [127:0] A:B:G:R 32:32:32:32 little endian */ + +/* + * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits + * of unused padding per component: + */ +#define DRM_FORMAT_AXBXGXRX106106106106 fourcc_code('A', 'B', '1', '0') /* [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian */ + +/* packed YCbCr */ +#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ +#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ +#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ +#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ + +#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_AVUY8888 fourcc_code('A', 'V', 'U', 'Y') /* [31:0] A:Cr:Cb:Y 8:8:8:8 little endian */ +#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_XVUY8888 fourcc_code('X', 'V', 'U', 'Y') /* [31:0] X:Cr:Cb:Y 8:8:8:8 little endian */ +#define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */ +#define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */ +#define DRM_FORMAT_XVUY2101010 fourcc_code('X', 'Y', '3', '0') /* [31:0] x:Cr:Cb:Y 2:10:10:10 little endian */ + +/* + * packed Y2xx indicate for each component, xx valid data occupy msb + * 16-xx padding occupy lsb + */ +#define DRM_FORMAT_Y210 fourcc_code('Y', '2', '1', '0') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels */ +#define DRM_FORMAT_Y212 fourcc_code('Y', '2', '1', '2') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels */ +#define DRM_FORMAT_Y216 fourcc_code('Y', '2', '1', '6') /* [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels */ + +/* + * packed Y4xx indicate for each component, xx valid data occupy msb + * 16-xx padding occupy lsb except Y410 + */ +#define DRM_FORMAT_Y410 fourcc_code('Y', '4', '1', '0') /* [31:0] A:Cr:Y:Cb 2:10:10:10 little endian */ +#define DRM_FORMAT_Y412 fourcc_code('Y', '4', '1', '2') /* [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ +#define DRM_FORMAT_Y416 fourcc_code('Y', '4', '1', '6') /* [63:0] A:Cr:Y:Cb 16:16:16:16 little endian */ + +#define DRM_FORMAT_XVYU2101010 fourcc_code('X', 'V', '3', '0') /* [31:0] X:Cr:Y:Cb 2:10:10:10 little endian */ +#define DRM_FORMAT_XVYU12_16161616 fourcc_code('X', 'V', '3', '6') /* [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ +#define DRM_FORMAT_XVYU16161616 fourcc_code('X', 'V', '4', '8') /* [63:0] X:Cr:Y:Cb 16:16:16:16 little endian */ + +/* + * packed YCbCr420 2x2 tiled formats + * first 64 bits will contain Y,Cb,Cr components for a 2x2 tile + */ +/* [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ +#define DRM_FORMAT_Y0L0 fourcc_code('Y', '0', 'L', '0') +/* [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ +#define DRM_FORMAT_X0L0 fourcc_code('X', '0', 'L', '0') + +/* [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ +#define DRM_FORMAT_Y0L2 fourcc_code('Y', '0', 'L', '2') +/* [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ +#define DRM_FORMAT_X0L2 fourcc_code('X', '0', 'L', '2') + +/* + * 1-plane YUV 4:2:0 + * In these formats, the component ordering is specified (Y, followed by U + * then V), but the exact Linear layout is undefined. + * These formats can only be used with a non-Linear modifier. + */ +#define DRM_FORMAT_YUV420_8BIT fourcc_code('Y', 'U', '0', '8') +#define DRM_FORMAT_YUV420_10BIT fourcc_code('Y', 'U', '1', '0') + +/* + * 2 plane RGB + A + * index 0 = RGB plane, same format as the corresponding non _A8 format has + * index 1 = A plane, [7:0] A + */ +#define DRM_FORMAT_XRGB8888_A8 fourcc_code('X', 'R', 'A', '8') +#define DRM_FORMAT_XBGR8888_A8 fourcc_code('X', 'B', 'A', '8') +#define DRM_FORMAT_RGBX8888_A8 fourcc_code('R', 'X', 'A', '8') +#define DRM_FORMAT_BGRX8888_A8 fourcc_code('B', 'X', 'A', '8') +#define DRM_FORMAT_RGB888_A8 fourcc_code('R', '8', 'A', '8') +#define DRM_FORMAT_BGR888_A8 fourcc_code('B', '8', 'A', '8') +#define DRM_FORMAT_RGB565_A8 fourcc_code('R', '5', 'A', '8') +#define DRM_FORMAT_BGR565_A8 fourcc_code('B', '5', 'A', '8') + +/* + * 2 plane YCbCr + * index 0 = Y plane, [7:0] Y + * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian + * or + * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian + */ +#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */ +#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ +#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ +/* + * 2 plane YCbCr + * index 0 = Y plane, [39:0] Y3:Y2:Y1:Y0 little endian + * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian + */ +#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV20 fourcc_code('N', 'V', '2', '0') /* 2x1 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV30 fourcc_code('N', 'V', '3', '0') /* non-subsampled Cr:Cb plane */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [10:6] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian + */ +#define DRM_FORMAT_P210 fourcc_code('P', '2', '1', '0') /* 2x1 subsampled Cr:Cb plane, 10 bit per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [10:6] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian + */ +#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [12:4] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [12:4:12:4] little endian + */ +#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cr:Cb plane 12 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y little endian + * index 1 = Cr:Cb plane, [31:0] Cr:Cb [16:16] little endian + */ +#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ + +/* 2 plane YCbCr420. + * 3 10 bit components and 2 padding bits packed into 4 bytes. + * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian + * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian + */ +#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */ + +/* + * 2 plane YCbCr422. + * 3 10 bit components and 2 padding bits packed into 4 bytes. + * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian + * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian + */ +#define DRM_FORMAT_P230 fourcc_code('P', '2', '3', '0') /* 2x1 subsampled Cr:Cb plane 10 bits per channel packed */ + +/* 3 plane non-subsampled (444) YCbCr + * 16 bits per component, but only 10 bits are used and 6 bits are padded + * index 0: Y plane, [15:0] Y:x [10:6] little endian + * index 1: Cb plane, [15:0] Cb:x [10:6] little endian + * index 2: Cr plane, [15:0] Cr:x [10:6] little endian + */ +#define DRM_FORMAT_Q410 fourcc_code('Q', '4', '1', '0') + +/* 3 plane non-subsampled (444) YCrCb + * 16 bits per component, but only 10 bits are used and 6 bits are padded + * index 0: Y plane, [15:0] Y:x [10:6] little endian + * index 1: Cr plane, [15:0] Cr:x [10:6] little endian + * index 2: Cb plane, [15:0] Cb:x [10:6] little endian + */ +#define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') + +/* + * 3 plane non-subsampled (444) YCbCr LSB aligned + * 10 bpc, 30 bits per sample image data in a single contiguous buffer. + * index 0: Y plane, [31:0] x:Y2:Y1:Y0 [2:10:10:10] little endian + * index 1: Cb plane, [31:0] x:Cb2:Cb1:Cb0 [2:10:10:10] little endian + * index 2: Cr plane, [31:0] x:Cr2:Cr1:Cr0 [2:10:10:10] little endian + */ +#define DRM_FORMAT_T430 fourcc_code('T', '4', '3', '0') + +/* + * 3 plane YCbCr LSB aligned + * In order to use these formats in a similar fashion to MSB aligned ones + * implementation can multiply the values by 2^6=64. For that reason the padding + * must only contain zeros. + * index 0 = Y plane, [15:0] z:Y [6:10] little endian + * index 1 = Cb plane, [15:0] z:Cb [6:10] little endian + * index 2 = Cr plane, [15:0] z:Cr [6:10] little endian + */ +#define DRM_FORMAT_S010 fourcc_code('S', '0', '1', '0') /* 2x2 subsampled Cb (1) and Cr (2) planes 10 bits per channel */ +#define DRM_FORMAT_S210 fourcc_code('S', '2', '1', '0') /* 2x1 subsampled Cb (1) and Cr (2) planes 10 bits per channel */ +#define DRM_FORMAT_S410 fourcc_code('S', '4', '1', '0') /* non-subsampled Cb (1) and Cr (2) planes 10 bits per channel */ + +/* + * 3 plane YCbCr LSB aligned + * In order to use these formats in a similar fashion to MSB aligned ones + * implementation can multiply the values by 2^4=16. For that reason the padding + * must only contain zeros. + * index 0 = Y plane, [15:0] z:Y [4:12] little endian + * index 1 = Cb plane, [15:0] z:Cb [4:12] little endian + * index 2 = Cr plane, [15:0] z:Cr [4:12] little endian + */ +#define DRM_FORMAT_S012 fourcc_code('S', '0', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes 12 bits per channel */ +#define DRM_FORMAT_S212 fourcc_code('S', '2', '1', '2') /* 2x1 subsampled Cb (1) and Cr (2) planes 12 bits per channel */ +#define DRM_FORMAT_S412 fourcc_code('S', '4', '1', '2') /* non-subsampled Cb (1) and Cr (2) planes 12 bits per channel */ + +/* + * 3 plane YCbCr + * index 0 = Y plane, [15:0] Y little endian + * index 1 = Cb plane, [15:0] Cb little endian + * index 2 = Cr plane, [15:0] Cr little endian + */ +#define DRM_FORMAT_S016 fourcc_code('S', '0', '1', '6') /* 2x2 subsampled Cb (1) and Cr (2) planes 16 bits per channel */ +#define DRM_FORMAT_S216 fourcc_code('S', '2', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes 16 bits per channel */ +#define DRM_FORMAT_S416 fourcc_code('S', '4', '1', '6') /* non-subsampled Cb (1) and Cr (2) planes 16 bits per channel */ + +/* + * 3 plane YCbCr + * index 0: Y plane, [7:0] Y + * index 1: Cb plane, [7:0] Cb + * index 2: Cr plane, [7:0] Cr + * or + * index 1: Cr plane, [7:0] Cr + * index 2: Cb plane, [7:0] Cb + */ +#define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ + +/* + * Y-only (greyscale) formats + * + * The Y-only formats are handled similarly to the YCbCr formats in the display + * pipeline, with the Cb and Cr implicitly neutral (0.0 in nominal values). This + * also means that COLOR_RANGE property applies to the Y-only formats. + */ + +#define DRM_FORMAT_Y8 fourcc_code('G', 'R', 'E', 'Y') /* 8-bit Y-only */ +#define DRM_FORMAT_XYYY2101010 fourcc_code('Y', 'P', 'A', '4') /* [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian */ + +/* + * Format Modifiers: + * + * Format modifiers describe, typically, a re-ordering or modification + * of the data in a plane of an FB. This can be used to express tiled/ + * swizzled formats, or compression, or a combination of the two. + * + * The upper 8 bits of the format modifier are a vendor-id as assigned + * below. The lower 56 bits are assigned as vendor sees fit. + */ + +/* Vendor Ids: */ +#define DRM_FORMAT_MOD_VENDOR_NONE 0 +#define DRM_FORMAT_MOD_VENDOR_INTEL 0x01 +#define DRM_FORMAT_MOD_VENDOR_AMD 0x02 +#define DRM_FORMAT_MOD_VENDOR_NVIDIA 0x03 +#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04 +#define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 +#define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 +#define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 +#define DRM_FORMAT_MOD_VENDOR_ARM 0x08 +#define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 +#define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a +#define DRM_FORMAT_MOD_VENDOR_MTK 0x0b +#define DRM_FORMAT_MOD_VENDOR_APPLE 0x0c + +/* add more to the end as needed */ + +#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) + +#define fourcc_mod_get_vendor(modifier) \ + (((modifier) >> 56) & 0xff) + +#define fourcc_mod_is_vendor(modifier, vendor) \ + (fourcc_mod_get_vendor(modifier) == DRM_FORMAT_MOD_VENDOR_## vendor) + +#define fourcc_mod_code(vendor, val) \ + ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL)) + +/* + * Format Modifier tokens: + * + * When adding a new token please document the layout with a code comment, + * similar to the fourcc codes above. drm_fourcc.h is considered the + * authoritative source for all of these. + * + * Generic modifier names: + * + * DRM_FORMAT_MOD_GENERIC_* definitions are used to provide vendor-neutral names + * for layouts which are common across multiple vendors. To preserve + * compatibility, in cases where a vendor-specific definition already exists and + * a generic name for it is desired, the common name is a purely symbolic alias + * and must use the same numerical value as the original definition. + * + * Note that generic names should only be used for modifiers which describe + * generic layouts (such as pixel re-ordering), which may have + * independently-developed support across multiple vendors. + * + * In future cases where a generic layout is identified before merging with a + * vendor-specific modifier, a new 'GENERIC' vendor or modifier using vendor + * 'NONE' could be considered. This should only be for obvious, exceptional + * cases to avoid polluting the 'GENERIC' namespace with modifiers which only + * apply to a single vendor. + * + * Generic names should not be used for cases where multiple hardware vendors + * have implementations of the same standardised compression scheme (such as + * AFBC). In those cases, all implementations should use the same format + * modifier(s), reflecting the vendor of the standard. + */ + +#define DRM_FORMAT_MOD_GENERIC_16_16_TILE DRM_FORMAT_MOD_SAMSUNG_16_16_TILE + +/* + * Invalid Modifier + * + * This modifier can be used as a sentinel to terminate the format modifiers + * list, or to initialize a variable with an invalid modifier. It might also be + * used to report an error back to userspace for certain APIs. + */ +#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED) + +/* + * Linear Layout + * + * Just plain linear layout. Note that this is different from no specifying any + * modifier (e.g. not setting DRM_MODE_FB_MODIFIERS in the DRM_ADDFB2 ioctl), + * which tells the driver to also take driver-internal information into account + * and so might actually result in a tiled framebuffer. + */ +#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0) + +/* + * Deprecated: use DRM_FORMAT_MOD_LINEAR instead + * + * The "none" format modifier doesn't actually mean that the modifier is + * implicit, instead it means that the layout is linear. Whether modifiers are + * used is out-of-band information carried in an API-specific way (e.g. in a + * flag for drm_mode_fb_cmd2). + */ +#define DRM_FORMAT_MOD_NONE 0 + +/* Intel framebuffer modifiers */ + +/* + * Intel X-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out row-major, with + * a platform-dependent stride. On top of that the memory can apply + * platform-depending swizzling of some higher address bits into bit6. + * + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. + */ +#define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1) + +/* + * Intel Y-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes) + * chunks column-major, with a platform-dependent height. On top of that the + * memory can apply platform-depending swizzling of some higher address bits + * into bit6. + * + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. + */ +#define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) + +/* + * Intel Yf-tiling layout + * + * This is a tiled layout using 4Kb tiles in row-major layout. + * Within the tile pixels are laid out in 16 256 byte units / sub-tiles which + * are arranged in four groups (two wide, two high) with column-major layout. + * Each group therefore consists out of four 256 byte units, which are also laid + * out as 2x2 column-major. + * 256 byte units are made out of four 64 byte blocks of pixels, producing + * either a square block or a 2:1 unit. + * 64 byte blocks of pixels contain four pixel rows of 16 bytes, where the width + * in pixel depends on the pixel depth. + */ +#define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3) + +/* + * Intel color control surface (CCS) for render compression + * + * The framebuffer format must be one of the 8:8:8:8 RGB formats. + * The main surface will be plane index 0 and must be Y/Yf-tiled, + * the CCS will be plane index 1. + * + * Each CCS tile matches a 1024x512 pixel area of the main surface. + * To match certain aspects of the 3D hardware the CCS is + * considered to be made up of normal 128Bx32 Y tiles, Thus + * the CCS pitch must be specified in multiples of 128 bytes. + * + * In reality the CCS tile appears to be a 64Bx64 Y tile, composed + * of QWORD (8 bytes) chunks instead of OWORD (16 bytes) chunks. + * But that fact is not relevant unless the memory is accessed + * directly. + */ +#define I915_FORMAT_MOD_Y_TILED_CCS fourcc_mod_code(INTEL, 4) +#define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5) + +/* + * Intel color control surfaces (CCS) for Gen-12 render compression. + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS fourcc_mod_code(INTEL, 6) + +/* + * Intel color control surfaces (CCS) for Gen-12 media compression + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. For semi-planar formats like NV12, CCS planes follow the + * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces, + * planes 2 and 3 for the respective CCS. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS fourcc_mod_code(INTEL, 7) + +/* + * Intel Color Control Surface with Clear Color (CCS) for Gen-12 render + * compression. + * + * The main surface is Y-tiled and is at plane index 0 whereas CCS is linear + * and at index 1. The clear color is stored at index 2, and the pitch should + * be 64 bytes aligned. The clear color structure is 256 bits. The first 128 bits + * represents Raw Clear Color Red, Green, Blue and Alpha color each represented + * by 32 bits. The raw clear color is consumed by the 3d engine and generates + * the converted clear color of size 64 bits. The first 32 bits store the Lower + * Converted Clear Color value and the next 32 bits store the Higher Converted + * Clear Color value when applicable. The Converted Clear Color values are + * consumed by the DE. The last 64 bits are used to store Color Discard Enable + * and Depth Clear Value Valid which are ignored by the DE. A CCS cache line + * corresponds to an area of 4x1 tiles in the main surface. The main surface + * pitch is required to be a multiple of 4 tile widths. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC fourcc_mod_code(INTEL, 8) + +/* + * Intel Tile 4 layout + * + * This is a tiled layout using 4KB tiles in a row-major layout. It has the same + * shape as Tile Y at two granularities: 4KB (128B x 32) and 64B (16B x 4). It + * only differs from Tile Y at the 256B granularity in between. At this + * granularity, Tile Y has a shape of 16B x 32 rows, but this tiling has a shape + * of 64B x 8 rows. + */ +#define I915_FORMAT_MOD_4_TILED fourcc_mod_code(INTEL, 9) + +/* + * Intel color control surfaces (CCS) for DG2 render compression. + * + * The main surface is Tile 4 and at plane index 0. The CCS data is stored + * outside of the GEM object in a reserved memory area dedicated for the + * storage of the CCS data for all RC/RC_CC/MC compressible GEM objects. The + * main surface pitch is required to be a multiple of four Tile 4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_RC_CCS fourcc_mod_code(INTEL, 10) + +/* + * Intel color control surfaces (CCS) for DG2 media compression. + * + * The main surface is Tile 4 and at plane index 0. For semi-planar formats + * like NV12, the Y and UV planes are Tile 4 and are located at plane indices + * 0 and 1, respectively. The CCS for all planes are stored outside of the + * GEM object in a reserved memory area dedicated for the storage of the + * CCS data for all RC/RC_CC/MC compressible GEM objects. The main surface + * pitch is required to be a multiple of four Tile 4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_MC_CCS fourcc_mod_code(INTEL, 11) + +/* + * Intel Color Control Surface with Clear Color (CCS) for DG2 render compression. + * + * The main surface is Tile 4 and at plane index 0. The CCS data is stored + * outside of the GEM object in a reserved memory area dedicated for the + * storage of the CCS data for all RC/RC_CC/MC compressible GEM objects. The + * main surface pitch is required to be a multiple of four Tile 4 widths. The + * clear color is stored at plane index 1 and the pitch should be 64 bytes + * aligned. The format of the 256 bits of clear color data matches the one used + * for the I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC modifier, see its description + * for details. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC fourcc_mod_code(INTEL, 12) + +/* + * Intel Color Control Surfaces (CCS) for display ver. 14 render compression. + * + * The main surface is tile4 and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * tile4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_MTL_RC_CCS fourcc_mod_code(INTEL, 13) + +/* + * Intel Color Control Surfaces (CCS) for display ver. 14 media compression + * + * The main surface is tile4 and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * tile4 widths. For semi-planar formats like NV12, CCS planes follow the + * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces, + * planes 2 and 3 for the respective CCS. + */ +#define I915_FORMAT_MOD_4_TILED_MTL_MC_CCS fourcc_mod_code(INTEL, 14) + +/* + * Intel Color Control Surface with Clear Color (CCS) for display ver. 14 render + * compression. + * + * The main surface is tile4 and is at plane index 0 whereas CCS is linear + * and at index 1. The clear color is stored at index 2, and the pitch should + * be ignored. The clear color structure is 256 bits. The first 128 bits + * represents Raw Clear Color Red, Green, Blue and Alpha color each represented + * by 32 bits. The raw clear color is consumed by the 3d engine and generates + * the converted clear color of size 64 bits. The first 32 bits store the Lower + * Converted Clear Color value and the next 32 bits store the Higher Converted + * Clear Color value when applicable. The Converted Clear Color values are + * consumed by the DE. The last 64 bits are used to store Color Discard Enable + * and Depth Clear Value Valid which are ignored by the DE. A CCS cache line + * corresponds to an area of 4x1 tiles in the main surface. The main surface + * pitch is required to be a multiple of 4 tile widths. + */ +#define I915_FORMAT_MOD_4_TILED_MTL_RC_CCS_CC fourcc_mod_code(INTEL, 15) + +/* + * Intel Color Control Surfaces (CCS) for graphics ver. 20 unified compression + * on integrated graphics + * + * The main surface is Tile 4 and at plane index 0. For semi-planar formats + * like NV12, the Y and UV planes are Tile 4 and are located at plane indices + * 0 and 1, respectively. The CCS for all planes are stored outside of the + * GEM object in a reserved memory area dedicated for the storage of the + * CCS data for all compressible GEM objects. + */ +#define I915_FORMAT_MOD_4_TILED_LNL_CCS fourcc_mod_code(INTEL, 16) + +/* + * Intel Color Control Surfaces (CCS) for graphics ver. 20 unified compression + * on discrete graphics + * + * The main surface is Tile 4 and at plane index 0. For semi-planar formats + * like NV12, the Y and UV planes are Tile 4 and are located at plane indices + * 0 and 1, respectively. The CCS for all planes are stored outside of the + * GEM object in a reserved memory area dedicated for the storage of the + * CCS data for all compressible GEM objects. The GEM object must be stored in + * contiguous memory with a size aligned to 64KB + */ +#define I915_FORMAT_MOD_4_TILED_BMG_CCS fourcc_mod_code(INTEL, 17) + +/* + * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks + * + * Macroblocks are laid in a Z-shape, and each pixel data is following the + * standard NV12 style. + * As for NV12, an image is the result of two frame buffers: one for Y, + * one for the interleaved Cb/Cr components (1/2 the height of the Y buffer). + * Alignment requirements are (for each buffer): + * - multiple of 128 pixels for the width + * - multiple of 32 pixels for the height + * + * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html + */ +#define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1) + +/* + * Tiled, 16 (pixels) x 16 (lines) - sized macroblocks + * + * This is a simple tiled layout using tiles of 16x16 pixels in a row-major + * layout. For YCbCr formats Cb/Cr components are taken in such a way that + * they correspond to their 16x16 luma block. + */ +#define DRM_FORMAT_MOD_SAMSUNG_16_16_TILE fourcc_mod_code(SAMSUNG, 2) + +/* + * Qualcomm Compressed Format + * + * Refers to a compressed variant of the base format that is compressed. + * Implementation may be platform and base-format specific. + * + * Each macrotile consists of m x n (mostly 4 x 4) tiles. + * Pixel data pitch/stride is aligned with macrotile width. + * Pixel data height is aligned with macrotile height. + * Entire pixel data buffer is aligned with 4k(bytes). + */ +#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) + +/* + * Qualcomm Tiled Format + * + * Similar to DRM_FORMAT_MOD_QCOM_COMPRESSED but not compressed. + * Implementation may be platform and base-format specific. + * + * Each macrotile consists of m x n (mostly 4 x 4) tiles. + * Pixel data pitch/stride is aligned with macrotile width. + * Pixel data height is aligned with macrotile height. + * Entire pixel data buffer is aligned with 4k(bytes). + */ +#define DRM_FORMAT_MOD_QCOM_TILED3 fourcc_mod_code(QCOM, 3) + +/* + * Qualcomm Alternate Tiled Format + * + * Alternate tiled format typically only used within GMEM. + * Implementation may be platform and base-format specific. + */ +#define DRM_FORMAT_MOD_QCOM_TILED2 fourcc_mod_code(QCOM, 2) + + +/* Vivante framebuffer modifiers */ + +/* + * Vivante 4x4 tiling layout + * + * This is a simple tiled layout using tiles of 4x4 pixels in a row-major + * layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_TILED fourcc_mod_code(VIVANTE, 1) + +/* + * Vivante 64x64 super-tiling layout + * + * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile + * contains 8x4 groups of 2x4 tiles of 4x4 pixels (like above) each, all in row- + * major layout. + * + * For more information: see + * https://github.com/etnaviv/etna_viv/blob/master/doc/hardware.md#texture-tiling + */ +#define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED fourcc_mod_code(VIVANTE, 2) + +/* + * Vivante 4x4 tiling layout for dual-pipe + * + * Same as the 4x4 tiling layout, except every second 4x4 pixel tile starts at a + * different base address. Offsets from the base addresses are therefore halved + * compared to the non-split tiled layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED fourcc_mod_code(VIVANTE, 3) + +/* + * Vivante 64x64 super-tiling layout for dual-pipe + * + * Same as the 64x64 super-tiling layout, except every second 4x4 pixel tile + * starts at a different base address. Offsets from the base addresses are + * therefore halved compared to the non-split super-tiled layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) + +/* + * Vivante TS (tile-status) buffer modifiers. They can be combined with all of + * the color buffer tiling modifiers defined above. When TS is present it's a + * separate buffer containing the clear/compression status of each tile. The + * modifiers are defined as VIVANTE_MOD_TS_c_s, where c is the color buffer + * tile size in bytes covered by one entry in the status buffer and s is the + * number of status bits per entry. + * We reserve the top 8 bits of the Vivante modifier space for tile status + * clear/compression modifiers, as future cores might add some more TS layout + * variations. + */ +#define VIVANTE_MOD_TS_64_4 (1ULL << 48) +#define VIVANTE_MOD_TS_64_2 (2ULL << 48) +#define VIVANTE_MOD_TS_128_4 (3ULL << 48) +#define VIVANTE_MOD_TS_256_4 (4ULL << 48) +#define VIVANTE_MOD_TS_MASK (0xfULL << 48) + +/* + * Vivante compression modifiers. Those depend on a TS modifier being present + * as the TS bits get reinterpreted as compression tags instead of simple + * clear markers when compression is enabled. + */ +#define VIVANTE_MOD_COMP_DEC400 (1ULL << 52) +#define VIVANTE_MOD_COMP_MASK (0xfULL << 52) + +/* Masking out the extension bits will yield the base modifier. */ +#define VIVANTE_MOD_EXT_MASK (VIVANTE_MOD_TS_MASK | \ + VIVANTE_MOD_COMP_MASK) + +/* NVIDIA frame buffer modifiers */ + +/* + * Tegra Tiled Layout, used by Tegra 2, 3 and 4. + * + * Pixels are arranged in simple tiles of 16 x 16 bytes. + */ +#define DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED fourcc_mod_code(NVIDIA, 1) + +/* + * Generalized Block Linear layout, used by desktop GPUs starting with NV50/G80, + * and Tegra GPUs starting with Tegra K1. + * + * Pixels are arranged in Groups of Bytes (GOBs). GOB size and layout varies + * based on the architecture generation. GOBs themselves are then arranged in + * 3D blocks, with the block dimensions (in terms of GOBs) always being a power + * of two, and hence expressible as their log2 equivalent (E.g., "2" represents + * a block depth or height of "4"). + * + * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format + * in full detail. + * + * Macro + * Bits Param Description + * ---- ----- ----------------------------------------------------------------- + * + * 3:0 h log2(height) of each block, in GOBs. Placed here for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 4:4 - Must be 1, to indicate block-linear layout. Necessary for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 8:5 - Reserved (To support 3D-surfaces with variable log2(depth) block + * size). Must be zero. + * + * Note there is no log2(width) parameter. Some portions of the + * hardware support a block width of two gobs, but it is impractical + * to use due to lack of support elsewhere, and has no known + * benefits. + * + * 11:9 - Reserved (To support 2D-array textures with variable array stride + * in blocks, specified via log2(tile width in blocks)). Must be + * zero. + * + * 19:12 k Page Kind. This value directly maps to a field in the page + * tables of all GPUs >= NV50. It affects the exact layout of bits + * in memory and can be derived from the tuple + * + * (format, GPU model, compression type, samples per pixel) + * + * Where compression type is defined below. If GPU model were + * implied by the format modifier, format, or memory buffer, page + * kind would not need to be included in the modifier itself, but + * since the modifier should define the layout of the associated + * memory buffer independent from any device or other context, it + * must be included here. + * + * 21:20 g GOB Height and Page Kind Generation. The height of a GOB changed + * starting with Fermi GPUs. Additionally, the mapping between page + * kind and bit layout has changed at various points. + * + * 0 = Gob Height 8, Fermi - Volta, Tegra K1+ Page Kind mapping + * 1 = Gob Height 4, G80 - GT2XX Page Kind mapping + * 2 = Gob Height 8, Turing+ Page Kind mapping + * 3 = Reserved for future use. + * + * 22:22 s Sector layout. There is a further bit remapping step that occurs + * 26:27 at an even lower level than the page kind and block linear + * swizzles. This causes the bit arrangement of surfaces in memory + * to differ subtly, and prevents direct sharing of surfaces between + * GPUs with different layouts. + * + * 0 = Tegra K1 - Tegra Parker/TX2 Layout + * 1 = Pre-GB20x, GB20x 32+ bpp, GB10, Tegra Xavier-Orin Layout + * 2 = GB20x(Blackwell 2)+ 8 bpp surface layout + * 3 = GB20x(Blackwell 2)+ 16 bpp surface layout + * 4 = Reserved for future use. + * 5 = Reserved for future use. + * 6 = Reserved for future use. + * 7 = Reserved for future use. + * + * 25:23 c Lossless Framebuffer Compression type. + * + * 0 = none + * 1 = ROP/3D, layout 1, exact compression format implied by Page + * Kind field + * 2 = ROP/3D, layout 2, exact compression format implied by Page + * Kind field + * 3 = CDE horizontal + * 4 = CDE vertical + * 5 = Reserved for future use + * 6 = Reserved for future use + * 7 = Reserved for future use + * + * 55:28 - Reserved for future use. Must be zero. + */ +#define DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(c, s, g, k, h) \ + fourcc_mod_code(NVIDIA, (0x10 | \ + ((h) & 0xf) | \ + (((k) & 0xff) << 12) | \ + (((g) & 0x3) << 20) | \ + (((s) & 0x1) << 22) | \ + (((s) & 0x6) << 25) | \ + (((c) & 0x7) << 23))) + +/* To grandfather in prior block linear format modifiers to the above layout, + * the page kind "0", which corresponds to "pitch/linear" and hence is unusable + * with block-linear layouts, is remapped within drivers to the value 0xfe, + * which corresponds to the "generic" kind used for simple single-sample + * uncompressed color formats on Fermi - Volta GPUs. + */ +static inline __u64 +drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) +{ + if (!(modifier & 0x10) || (modifier & (0xff << 12))) + return modifier; + else + return modifier | (0xfe << 12); +} + +/* + * 16Bx2 Block Linear layout, used by Tegra K1 and later + * + * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked + * vertically by a power of 2 (1 to 32 GOBs) to form a block. + * + * Within a GOB, data is ordered as 16B x 2 lines sectors laid in Z-shape. + * + * Parameter 'v' is the log2 encoding of the number of GOBs stacked vertically. + * Valid values are: + * + * 0 == ONE_GOB + * 1 == TWO_GOBS + * 2 == FOUR_GOBS + * 3 == EIGHT_GOBS + * 4 == SIXTEEN_GOBS + * 5 == THIRTYTWO_GOBS + * + * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format + * in full detail. + */ +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(v) \ + DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0, (v)) + +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) + +/* + * Some Broadcom modifiers take parameters, for example the number of + * vertical lines in the image. Reserve the lower 32 bits for modifier + * type, and the next 24 bits for parameters. Top 8 bits are the + * vendor code. + */ +#define __fourcc_mod_broadcom_param_shift 8 +#define __fourcc_mod_broadcom_param_bits 48 +#define fourcc_mod_broadcom_code(val, params) \ + fourcc_mod_code(BROADCOM, ((((__u64)params) << __fourcc_mod_broadcom_param_shift) | val)) +#define fourcc_mod_broadcom_param(m) \ + ((int)(((m) >> __fourcc_mod_broadcom_param_shift) & \ + ((1ULL << __fourcc_mod_broadcom_param_bits) - 1))) +#define fourcc_mod_broadcom_mod(m) \ + ((m) & ~(((1ULL << __fourcc_mod_broadcom_param_bits) - 1) << \ + __fourcc_mod_broadcom_param_shift)) + +/* + * Broadcom VC4 "T" format + * + * This is the primary layout that the V3D GPU can texture from (it + * can't do linear). The T format has: + * + * - 64b utiles of pixels in a raster-order grid according to cpp. It's 4x4 + * pixels at 32 bit depth. + * + * - 1k subtiles made of a 4x4 raster-order grid of 64b utiles (so usually + * 16x16 pixels). + * + * - 4k tiles made of a 2x2 grid of 1k subtiles (so usually 32x32 pixels). On + * even 4k tile rows, they're arranged as (BL, TL, TR, BR), and on odd rows + * they're (TR, BR, BL, TL), where bottom left is start of memory. + * + * - an image made of 4k tiles in rows either left-to-right (even rows of 4k + * tiles) or right-to-left (odd rows of 4k tiles). + */ +#define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED fourcc_mod_code(BROADCOM, 1) + +/* + * Broadcom SAND format + * + * This is the native format that the H.264 codec block uses. For VC4 + * HVS, it is only valid for H.264 (NV12/21) and RGBA modes. + * + * The image can be considered to be split into columns, and the + * columns are placed consecutively into memory. The width of those + * columns can be either 32, 64, 128, or 256 pixels, but in practice + * only 128 pixel columns are used. + * + * The pitch between the start of each column is set to optimally + * switch between SDRAM banks. This is passed as the number of lines + * of column width in the modifier (we can't use the stride value due + * to various core checks that look at it , so you should set the + * stride to width*cpp). + * + * Note that the column height for this format modifier is the same + * for all of the planes, assuming that each column contains both Y + * and UV. Some SAND-using hardware stores UV in a separate tiled + * image from Y to reduce the column height, which is not supported + * with these modifiers. + * + * The DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT modifier is also + * supported for DRM_FORMAT_P030 where the columns remain as 128 bytes + * wide, but as this is a 10 bpp format that translates to 96 pixels. + */ + +#define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(2, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(3, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(4, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(5, v) + +#define DRM_FORMAT_MOD_BROADCOM_SAND32 \ + DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND64 \ + DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND128 \ + DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND256 \ + DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0) + +/* Broadcom UIF format + * + * This is the common format for the current Broadcom multimedia + * blocks, including V3D 3.x and newer, newer video codecs, and + * displays. + * + * The image consists of utiles (64b blocks), UIF blocks (2x2 utiles), + * and macroblocks (4x4 UIF blocks). Those 4x4 UIF block groups are + * stored in columns, with padding between the columns to ensure that + * moving from one column to the next doesn't hit the same SDRAM page + * bank. + * + * To calculate the padding, it is assumed that each hardware block + * and the software driving it knows the platform's SDRAM page size, + * number of banks, and XOR address, and that it's identical between + * all blocks using the format. This tiling modifier will use XOR as + * necessary to reduce the padding. If a hardware block can't do XOR, + * the assumption is that a no-XOR tiling modifier will be created. + */ +#define DRM_FORMAT_MOD_BROADCOM_UIF fourcc_mod_code(BROADCOM, 6) + +/* + * Arm Framebuffer Compression (AFBC) modifiers + * + * AFBC is a proprietary lossless image compression protocol and format. + * It provides fine-grained random access and minimizes the amount of data + * transferred between IP blocks. + * + * AFBC has several features which may be supported and/or used, which are + * represented using bits in the modifier. Not all combinations are valid, + * and different devices or use-cases may support different combinations. + * + * Further information on the use of AFBC modifiers can be found in + * Documentation/gpu/afbc.rst + */ + +/* + * The top 4 bits (out of the 56 bits allotted for specifying vendor specific + * modifiers) denote the category for modifiers. Currently we have three + * categories of modifiers ie AFBC, MISC and AFRC. We can have a maximum of + * sixteen different categories. + */ +#define DRM_FORMAT_MOD_ARM_CODE(__type, __val) \ + fourcc_mod_code(ARM, ((__u64)(__type) << 52) | ((__val) & 0x000fffffffffffffULL)) + +#define DRM_FORMAT_MOD_ARM_TYPE_AFBC 0x00 +#define DRM_FORMAT_MOD_ARM_TYPE_MISC 0x01 + +#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFBC, __afbc_mode) + +/* + * AFBC superblock size + * + * Indicates the superblock size(s) used for the AFBC buffer. The buffer + * size (in pixels) must be aligned to a multiple of the superblock size. + * Four lowest significant bits(LSBs) are reserved for block size. + * + * Where one superblock size is specified, it applies to all planes of the + * buffer (e.g. 16x16, 32x8). When multiple superblock sizes are specified, + * the first applies to the Luma plane and the second applies to the Chroma + * plane(s). e.g. (32x8_64x4 means 32x8 Luma, with 64x4 Chroma). + * Multiple superblock sizes are only valid for multi-plane YCbCr formats. + */ +#define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf +#define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 (3ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 (4ULL) + +/* + * AFBC lossless colorspace transform + * + * Indicates that the buffer makes use of the AFBC lossless colorspace + * transform. + */ +#define AFBC_FORMAT_MOD_YTR (1ULL << 4) + +/* + * AFBC block-split + * + * Indicates that the payload of each superblock is split. The second + * half of the payload is positioned at a predefined offset from the start + * of the superblock payload. + */ +#define AFBC_FORMAT_MOD_SPLIT (1ULL << 5) + +/* + * AFBC sparse layout + * + * This flag indicates that the payload of each superblock must be stored at a + * predefined position relative to the other superblocks in the same AFBC + * buffer. This order is the same order used by the header buffer. In this mode + * each superblock is given the same amount of space as an uncompressed + * superblock of the particular format would require, rounding up to the next + * multiple of 128 bytes in size. + */ +#define AFBC_FORMAT_MOD_SPARSE (1ULL << 6) + +/* + * AFBC copy-block restrict + * + * Buffers with this flag must obey the copy-block restriction. The restriction + * is such that there are no copy-blocks referring across the border of 8x8 + * blocks. For the subsampled data the 8x8 limitation is also subsampled. + */ +#define AFBC_FORMAT_MOD_CBR (1ULL << 7) + +/* + * AFBC tiled layout + * + * The tiled layout groups superblocks in 8x8 or 4x4 tiles, where all + * superblocks inside a tile are stored together in memory. 8x8 tiles are used + * for pixel formats up to and including 32 bpp while 4x4 tiles are used for + * larger bpp formats. The order between the tiles is scan line. + * When the tiled layout is used, the buffer size (in pixels) must be aligned + * to the tile size. + */ +#define AFBC_FORMAT_MOD_TILED (1ULL << 8) + +/* + * AFBC solid color blocks + * + * Indicates that the buffer makes use of solid-color blocks, whereby bandwidth + * can be reduced if a whole superblock is a single color. + */ +#define AFBC_FORMAT_MOD_SC (1ULL << 9) + +/* + * AFBC double-buffer + * + * Indicates that the buffer is allocated in a layout safe for front-buffer + * rendering. + */ +#define AFBC_FORMAT_MOD_DB (1ULL << 10) + +/* + * AFBC buffer content hints + * + * Indicates that the buffer includes per-superblock content hints. + */ +#define AFBC_FORMAT_MOD_BCH (1ULL << 11) + +/* AFBC uncompressed storage mode + * + * Indicates that the buffer is using AFBC uncompressed storage mode. + * In this mode all superblock payloads in the buffer use the uncompressed + * storage mode, which is usually only used for data which cannot be compressed. + * The buffer layout is the same as for AFBC buffers without USM set, this only + * affects the storage mode of the individual superblocks. Note that even a + * buffer without USM set may use uncompressed storage mode for some or all + * superblocks, USM just guarantees it for all. + */ +#define AFBC_FORMAT_MOD_USM (1ULL << 12) + +/* + * Arm Fixed-Rate Compression (AFRC) modifiers + * + * AFRC is a proprietary fixed rate image compression protocol and format, + * designed to provide guaranteed bandwidth and memory footprint + * reductions in graphics and media use-cases. + * + * AFRC buffers consist of one or more planes, with the same components + * and meaning as an uncompressed buffer using the same pixel format. + * + * Within each plane, the pixel/luma/chroma values are grouped into + * "coding unit" blocks which are individually compressed to a + * fixed size (in bytes). All coding units within a given plane of a buffer + * store the same number of values, and have the same compressed size. + * + * The coding unit size is configurable, allowing different rates of compression. + * + * The start of each AFRC buffer plane must be aligned to an alignment granule which + * depends on the coding unit size. + * + * Coding Unit Size Plane Alignment + * ---------------- --------------- + * 16 bytes 1024 bytes + * 24 bytes 512 bytes + * 32 bytes 2048 bytes + * + * Coding units are grouped into paging tiles. AFRC buffer dimensions must be aligned + * to a multiple of the paging tile dimensions. + * The dimensions of each paging tile depend on whether the buffer is optimised for + * scanline (SCAN layout) or rotated (ROT layout) access. + * + * Layout Paging Tile Width Paging Tile Height + * ------ ----------------- ------------------ + * SCAN 16 coding units 4 coding units + * ROT 8 coding units 8 coding units + * + * The dimensions of each coding unit depend on the number of components + * in the compressed plane and whether the buffer is optimised for + * scanline (SCAN layout) or rotated (ROT layout) access. + * + * Number of Components in Plane Layout Coding Unit Width Coding Unit Height + * ----------------------------- --------- ----------------- ------------------ + * 1 SCAN 16 samples 4 samples + * Example: 16x4 luma samples in a 'Y' plane + * 16x4 chroma 'V' values, in the 'V' plane of a fully-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 1 ROT 8 samples 8 samples + * Example: 8x8 luma samples in a 'Y' plane + * 8x8 chroma 'V' values, in the 'V' plane of a fully-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 2 DONT CARE 8 samples 4 samples + * Example: 8x4 chroma pairs in the 'UV' plane of a semi-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 3 DONT CARE 4 samples 4 samples + * Example: 4x4 pixels in an RGB buffer without alpha + * ----------------------------- --------- ----------------- ------------------ + * 4 DONT CARE 4 samples 4 samples + * Example: 4x4 pixels in an RGB buffer with alpha + */ + +#define DRM_FORMAT_MOD_ARM_TYPE_AFRC 0x02 + +#define DRM_FORMAT_MOD_ARM_AFRC(__afrc_mode) \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFRC, __afrc_mode) + +/* + * AFRC coding unit size modifier. + * + * Indicates the number of bytes used to store each compressed coding unit for + * one or more planes in an AFRC encoded buffer. The coding unit size for chrominance + * is the same for both Cb and Cr, which may be stored in separate planes. + * + * AFRC_FORMAT_MOD_CU_SIZE_P0 indicates the number of bytes used to store + * each compressed coding unit in the first plane of the buffer. For RGBA buffers + * this is the only plane, while for semi-planar and fully-planar YUV buffers, + * this corresponds to the luma plane. + * + * AFRC_FORMAT_MOD_CU_SIZE_P12 indicates the number of bytes used to store + * each compressed coding unit in the second and third planes in the buffer. + * For semi-planar and fully-planar YUV buffers, this corresponds to the chroma plane(s). + * + * For single-plane buffers, AFRC_FORMAT_MOD_CU_SIZE_P0 must be specified + * and AFRC_FORMAT_MOD_CU_SIZE_P12 must be zero. + * For semi-planar and fully-planar buffers, both AFRC_FORMAT_MOD_CU_SIZE_P0 and + * AFRC_FORMAT_MOD_CU_SIZE_P12 must be specified. + */ +#define AFRC_FORMAT_MOD_CU_SIZE_MASK 0xf +#define AFRC_FORMAT_MOD_CU_SIZE_16 (1ULL) +#define AFRC_FORMAT_MOD_CU_SIZE_24 (2ULL) +#define AFRC_FORMAT_MOD_CU_SIZE_32 (3ULL) + +#define AFRC_FORMAT_MOD_CU_SIZE_P0(__afrc_cu_size) (__afrc_cu_size) +#define AFRC_FORMAT_MOD_CU_SIZE_P12(__afrc_cu_size) ((__afrc_cu_size) << 4) + +/* + * AFRC scanline memory layout. + * + * Indicates if the buffer uses the scanline-optimised layout + * for an AFRC encoded buffer, otherwise, it uses the rotation-optimised layout. + * The memory layout is the same for all planes. + */ +#define AFRC_FORMAT_MOD_LAYOUT_SCAN (1ULL << 8) + +/* + * Arm 16x16 Block U-Interleaved modifier + * + * This is used by Arm Mali Utgard and Midgard GPUs. It divides the image + * into 16x16 pixel blocks. Blocks are stored linearly in order, but pixels + * in the block are reordered. + */ +#define DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_MISC, 1ULL) + +/* + * ARM 64k interleaved modifier + * + * This is used by ARM Mali v10+ GPUs. With this modifier, the plane is divided + * into 64k byte 1:1 or 2:1 -sided tiles. The 64k tiles are laid out linearly. + * Each 64k tile is divided into blocks of 16x16 texel blocks, which are + * themselves laid out linearly within a 64k tile. Then within each 16x16 + * block, texel blocks are laid out according to U order, similar to + * 16X16_BLOCK_U_INTERLEAVED. + * + * Note that unlike 16X16_BLOCK_U_INTERLEAVED, the layout does not change + * depending on whether a format is compressed or not. + */ +#define DRM_FORMAT_MOD_ARM_INTERLEAVED_64K \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_MISC, 2ULL) + +/* + * Allwinner tiled modifier + * + * This tiling mode is implemented by the VPU found on all Allwinner platforms, + * codenamed sunxi. It is associated with a YUV format that uses either 2 or 3 + * planes. + * + * With this tiling, the luminance samples are disposed in tiles representing + * 32x32 pixels and the chrominance samples in tiles representing 32x64 pixels. + * The pixel order in each tile is linear and the tiles are disposed linearly, + * both in row-major order. + */ +#define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) + +/* + * Amlogic Video Framebuffer Compression modifiers + * + * Amlogic uses a proprietary lossless image compression protocol and format + * for their hardware video codec accelerators, either video decoders or + * video input encoders. + * + * It considerably reduces memory bandwidth while writing and reading + * frames in memory. + * + * The underlying storage is considered to be 3 components, 8bit or 10-bit + * per component YCbCr 420, single plane : + * - DRM_FORMAT_YUV420_8BIT + * - DRM_FORMAT_YUV420_10BIT + * + * The first 8 bits of the mode defines the layout, then the following 8 bits + * defines the options changing the layout. + * + * Not all combinations are valid, and different SoCs may support different + * combinations of layout and options. + */ +#define __fourcc_mod_amlogic_layout_mask 0xff +#define __fourcc_mod_amlogic_options_shift 8 +#define __fourcc_mod_amlogic_options_mask 0xff + +#define DRM_FORMAT_MOD_AMLOGIC_FBC(__layout, __options) \ + fourcc_mod_code(AMLOGIC, \ + ((__layout) & __fourcc_mod_amlogic_layout_mask) | \ + (((__options) & __fourcc_mod_amlogic_options_mask) \ + << __fourcc_mod_amlogic_options_shift)) + +/* Amlogic FBC Layouts */ + +/* + * Amlogic FBC Basic Layout + * + * The basic layout is composed of: + * - a body content organized in 64x32 superblocks with 4096 bytes per + * superblock in default mode. + * - a 32 bytes per 128x64 header block + * + * This layout is transferrable between Amlogic SoCs supporting this modifier. + */ +#define AMLOGIC_FBC_LAYOUT_BASIC (1ULL) + +/* + * Amlogic FBC Scatter Memory layout + * + * Indicates the header contains IOMMU references to the compressed + * frames content to optimize memory access and layout. + * + * In this mode, only the header memory address is needed, thus the + * content memory organization is tied to the current producer + * execution and cannot be saved/dumped neither transferrable between + * Amlogic SoCs supporting this modifier. + * + * Due to the nature of the layout, these buffers are not expected to + * be accessible by the user-space clients, but only accessible by the + * hardware producers and consumers. + * + * The user-space clients should expect a failure while trying to mmap + * the DMA-BUF handle returned by the producer. + */ +#define AMLOGIC_FBC_LAYOUT_SCATTER (2ULL) + +/* Amlogic FBC Layout Options Bit Mask */ + +/* + * Amlogic FBC Memory Saving mode + * + * Indicates the storage is packed when pixel size is multiple of word + * boundaries, i.e. 8bit should be stored in this mode to save allocation + * memory. + * + * This mode reduces body layout to 3072 bytes per 64x32 superblock with + * the basic layout and 3200 bytes per 64x32 superblock combined with + * the scatter layout. + */ +#define AMLOGIC_FBC_OPTION_MEM_SAVING (1ULL << 0) + +/* MediaTek modifiers + * Bits Parameter Notes + * ----- ------------------------ --------------------------------------------- + * 7: 0 TILE LAYOUT Values are MTK_FMT_MOD_TILE_* + * 15: 8 COMPRESSION Values are MTK_FMT_MOD_COMPRESS_* + * 23:16 10 BIT LAYOUT Values are MTK_FMT_MOD_10BIT_LAYOUT_* + * + */ + +#define DRM_FORMAT_MOD_MTK(__flags) fourcc_mod_code(MTK, __flags) + +/* + * MediaTek Tiled Modifier + * The lowest 8 bits of the modifier is used to specify the tiling + * layout. Only the 16L_32S tiling is used for now, but we define an + * "untiled" version and leave room for future expansion. + */ +#define MTK_FMT_MOD_TILE_MASK 0xf +#define MTK_FMT_MOD_TILE_NONE 0x0 +#define MTK_FMT_MOD_TILE_16L32S 0x1 + +/* + * Bits 8-15 specify compression options + */ +#define MTK_FMT_MOD_COMPRESS_MASK (0xf << 8) +#define MTK_FMT_MOD_COMPRESS_NONE (0x0 << 8) +#define MTK_FMT_MOD_COMPRESS_V1 (0x1 << 8) + +/* + * Bits 16-23 specify how the bits of 10 bit formats are + * stored out in memory + */ +#define MTK_FMT_MOD_10BIT_LAYOUT_MASK (0xf << 16) +#define MTK_FMT_MOD_10BIT_LAYOUT_PACKED (0x0 << 16) +#define MTK_FMT_MOD_10BIT_LAYOUT_LSBTILED (0x1 << 16) +#define MTK_FMT_MOD_10BIT_LAYOUT_LSBRASTER (0x2 << 16) + +/* alias for the most common tiling format */ +#define DRM_FORMAT_MOD_MTK_16L_32S_TILE DRM_FORMAT_MOD_MTK(MTK_FMT_MOD_TILE_16L32S) + +/* + * Apple GPU-tiled layouts. + * + * Apple GPUs support nonlinear tilings with optional lossless compression. + * + * GPU-tiled images are divided into 16KiB tiles: + * + * Bytes per pixel Tile size + * --------------- --------- + * 1 128x128 + * 2 128x64 + * 4 64x64 + * 8 64x32 + * 16 32x32 + * + * Tiles are raster-order. Pixels within a tile are interleaved (Morton order). + * + * Compressed images pad the body to 128-bytes and are immediately followed by a + * metadata section. The metadata section rounds the image dimensions to + * powers-of-two and contains 8 bytes for each 16x16 compression subtile. + * Subtiles are interleaved (Morton order). + * + * All images are 128-byte aligned. + * + * These layouts fundamentally do not have meaningful strides. No matter how we + * specify strides for these layouts, userspace unaware of Apple image layouts + * will be unable to use correctly the specified stride for any purpose. + * Userspace aware of the image layouts do not use strides. The most "correct" + * convention would be setting the image stride to 0. Unfortunately, some + * software assumes the stride is at least (width * bytes per pixel). We + * therefore require that stride equals (width * bytes per pixel). Since the + * stride is arbitrary here, we pick the simplest convention. + * + * Although containing two sections, compressed image layouts are treated in + * software as a single plane. This is modelled after AFBC, a similar + * scheme. Attempting to separate the sections to be "explicit" in DRM would + * only generate more confusion, as software does not treat the image this way. + * + * For detailed information on the hardware image layouts, see + * https://docs.mesa3d.org/drivers/asahi.html#image-layouts + */ +#define DRM_FORMAT_MOD_APPLE_GPU_TILED fourcc_mod_code(APPLE, 1) +#define DRM_FORMAT_MOD_APPLE_GPU_TILED_COMPRESSED fourcc_mod_code(APPLE, 2) + +/* + * AMD modifiers + * + * Memory layout: + * + * without DCC: + * - main surface + * + * with DCC & without DCC_RETILE: + * - main surface in plane 0 + * - DCC surface in plane 1 (RB-aligned, pipe-aligned if DCC_PIPE_ALIGN is set) + * + * with DCC & DCC_RETILE: + * - main surface in plane 0 + * - displayable DCC surface in plane 1 (not RB-aligned & not pipe-aligned) + * - pipe-aligned DCC surface in plane 2 (RB-aligned & pipe-aligned) + * + * For multi-plane formats the above surfaces get merged into one plane for + * each format plane, based on the required alignment only. + * + * Bits Parameter Notes + * ----- ------------------------ --------------------------------------------- + * + * 7:0 TILE_VERSION Values are AMD_FMT_MOD_TILE_VER_* + * 12:8 TILE Values are AMD_FMT_MOD_TILE__* + * 13 DCC + * 14 DCC_RETILE + * 15 DCC_PIPE_ALIGN + * 16 DCC_INDEPENDENT_64B + * 17 DCC_INDEPENDENT_128B + * 19:18 DCC_MAX_COMPRESSED_BLOCK Values are AMD_FMT_MOD_DCC_BLOCK_* + * 20 DCC_CONSTANT_ENCODE + * 23:21 PIPE_XOR_BITS Only for some chips + * 26:24 BANK_XOR_BITS Only for some chips + * 29:27 PACKERS Only for some chips + * 32:30 RB Only for some chips + * 35:33 PIPE Only for some chips + * 55:36 - Reserved for future use, must be zero + */ +#define AMD_FMT_MOD fourcc_mod_code(AMD, 0) + +#define IS_AMD_FMT_MOD(val) (((val) >> 56) == DRM_FORMAT_MOD_VENDOR_AMD) + +/* Reserve 0 for GFX8 and older */ +#define AMD_FMT_MOD_TILE_VER_GFX9 1 +#define AMD_FMT_MOD_TILE_VER_GFX10 2 +#define AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS 3 +#define AMD_FMT_MOD_TILE_VER_GFX11 4 +#define AMD_FMT_MOD_TILE_VER_GFX12 5 + +/* + * 64K_S is the same for GFX9/GFX10/GFX10_RBPLUS and hence has GFX9 as canonical + * version. + */ +#define AMD_FMT_MOD_TILE_GFX9_64K_S 9 + +/* + * 64K_D for non-32 bpp is the same for GFX9/GFX10/GFX10_RBPLUS and hence has + * GFX9 as canonical version. + * + * 64K_D_2D on GFX12 is identical to 64K_D on GFX11. + */ +#define AMD_FMT_MOD_TILE_GFX9_64K_D 10 +#define AMD_FMT_MOD_TILE_GFX9_4K_D_X 22 +#define AMD_FMT_MOD_TILE_GFX9_64K_S_X 25 +#define AMD_FMT_MOD_TILE_GFX9_64K_D_X 26 +#define AMD_FMT_MOD_TILE_GFX9_64K_R_X 27 +#define AMD_FMT_MOD_TILE_GFX11_256K_R_X 31 + +/* Gfx12 swizzle modes: + * 0 - LINEAR + * 1 - 256B_2D - 2D block dimensions + * 2 - 4KB_2D + * 3 - 64KB_2D + * 4 - 256KB_2D + * 5 - 4KB_3D - 3D block dimensions + * 6 - 64KB_3D + * 7 - 256KB_3D + */ +#define AMD_FMT_MOD_TILE_GFX12_256B_2D 1 +#define AMD_FMT_MOD_TILE_GFX12_4K_2D 2 +#define AMD_FMT_MOD_TILE_GFX12_64K_2D 3 +#define AMD_FMT_MOD_TILE_GFX12_256K_2D 4 + +#define AMD_FMT_MOD_DCC_BLOCK_64B 0 +#define AMD_FMT_MOD_DCC_BLOCK_128B 1 +#define AMD_FMT_MOD_DCC_BLOCK_256B 2 + +#define AMD_FMT_MOD_TILE_VERSION_SHIFT 0 +#define AMD_FMT_MOD_TILE_VERSION_MASK 0xFF +#define AMD_FMT_MOD_TILE_SHIFT 8 +#define AMD_FMT_MOD_TILE_MASK 0x1F + +/* Whether DCC compression is enabled. */ +#define AMD_FMT_MOD_DCC_SHIFT 13 +#define AMD_FMT_MOD_DCC_MASK 0x1 + +/* + * Whether to include two DCC surfaces, one which is rb & pipe aligned, and + * one which is not-aligned. + */ +#define AMD_FMT_MOD_DCC_RETILE_SHIFT 14 +#define AMD_FMT_MOD_DCC_RETILE_MASK 0x1 + +/* Only set if DCC_RETILE = false */ +#define AMD_FMT_MOD_DCC_PIPE_ALIGN_SHIFT 15 +#define AMD_FMT_MOD_DCC_PIPE_ALIGN_MASK 0x1 + +#define AMD_FMT_MOD_DCC_INDEPENDENT_64B_SHIFT 16 +#define AMD_FMT_MOD_DCC_INDEPENDENT_64B_MASK 0x1 +#define AMD_FMT_MOD_DCC_INDEPENDENT_128B_SHIFT 17 +#define AMD_FMT_MOD_DCC_INDEPENDENT_128B_MASK 0x1 +#define AMD_FMT_MOD_DCC_MAX_COMPRESSED_BLOCK_SHIFT 18 +#define AMD_FMT_MOD_DCC_MAX_COMPRESSED_BLOCK_MASK 0x3 + +/* + * DCC supports embedding some clear colors directly in the DCC surface. + * However, on older GPUs the rendering HW ignores the embedded clear color + * and prefers the driver provided color. This necessitates doing a fastclear + * eliminate operation before a process transfers control. + * + * If this bit is set that means the fastclear eliminate is not needed for these + * embeddable colors. + */ +#define AMD_FMT_MOD_DCC_CONSTANT_ENCODE_SHIFT 20 +#define AMD_FMT_MOD_DCC_CONSTANT_ENCODE_MASK 0x1 + +/* + * The below fields are for accounting for per GPU differences. These are only + * relevant for GFX9 and later and if the tile field is *_X/_T. + * + * PIPE_XOR_BITS = always needed + * BANK_XOR_BITS = only for TILE_VER_GFX9 + * PACKERS = only for TILE_VER_GFX10_RBPLUS + * RB = only for TILE_VER_GFX9 & DCC + * PIPE = only for TILE_VER_GFX9 & DCC & (DCC_RETILE | DCC_PIPE_ALIGN) + */ +#define AMD_FMT_MOD_PIPE_XOR_BITS_SHIFT 21 +#define AMD_FMT_MOD_PIPE_XOR_BITS_MASK 0x7 +#define AMD_FMT_MOD_BANK_XOR_BITS_SHIFT 24 +#define AMD_FMT_MOD_BANK_XOR_BITS_MASK 0x7 +#define AMD_FMT_MOD_PACKERS_SHIFT 27 +#define AMD_FMT_MOD_PACKERS_MASK 0x7 +#define AMD_FMT_MOD_RB_SHIFT 30 +#define AMD_FMT_MOD_RB_MASK 0x7 +#define AMD_FMT_MOD_PIPE_SHIFT 33 +#define AMD_FMT_MOD_PIPE_MASK 0x7 + +#define AMD_FMT_MOD_SET(field, value) \ + ((__u64)(value) << AMD_FMT_MOD_##field##_SHIFT) +#define AMD_FMT_MOD_GET(field, value) \ + (((value) >> AMD_FMT_MOD_##field##_SHIFT) & AMD_FMT_MOD_##field##_MASK) +#define AMD_FMT_MOD_CLEAR(field) \ + (~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT)) + +#if defined(__cplusplus) +} +#endif + +#endif /* DRM_FOURCC_H */ diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/i915_drm.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/i915_drm.h new file mode 100644 index 0000000000..535cb68fdb --- /dev/null +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/i915_drm.h @@ -0,0 +1,3916 @@ +/* + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * 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, sub license, 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 (including the + * next paragraph) 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef _UAPI_I915_DRM_H_ +#define _UAPI_I915_DRM_H_ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +/** + * DOC: uevents generated by i915 on its device node + * + * I915_L3_PARITY_UEVENT - Generated when the driver receives a parity mismatch + * event from the GPU L3 cache. Additional information supplied is ROW, + * BANK, SUBBANK, SLICE of the affected cacheline. Userspace should keep + * track of these events, and if a specific cache-line seems to have a + * persistent error, remap it with the L3 remapping tool supplied in + * intel-gpu-tools. The value supplied with the event is always 1. + * + * I915_ERROR_UEVENT - Generated upon error detection, currently only via + * hangcheck. The error detection event is a good indicator of when things + * began to go badly. The value supplied with the event is a 1 upon error + * detection, and a 0 upon reset completion, signifying no more error + * exists. NOTE: Disabling hangcheck or reset via module parameter will + * cause the related events to not be seen. + * + * I915_RESET_UEVENT - Event is generated just before an attempt to reset the + * GPU. The value supplied with the event is always 1. NOTE: Disable + * reset via module parameter will cause this event to not be seen. + */ +#define I915_L3_PARITY_UEVENT "L3_PARITY_ERROR" +#define I915_ERROR_UEVENT "ERROR" +#define I915_RESET_UEVENT "RESET" + +/** + * struct i915_user_extension - Base class for defining a chain of extensions + * + * Many interfaces need to grow over time. In most cases we can simply + * extend the struct and have userspace pass in more data. Another option, + * as demonstrated by Vulkan's approach to providing extensions for forward + * and backward compatibility, is to use a list of optional structs to + * provide those extra details. + * + * The key advantage to using an extension chain is that it allows us to + * redefine the interface more easily than an ever growing struct of + * increasing complexity, and for large parts of that interface to be + * entirely optional. The downside is more pointer chasing; chasing across + * the __user boundary with pointers encapsulated inside u64. + * + * Example chaining: + * + * .. code-block:: C + * + * struct i915_user_extension ext3 { + * .next_extension = 0, // end + * .name = ..., + * }; + * struct i915_user_extension ext2 { + * .next_extension = (uintptr_t)&ext3, + * .name = ..., + * }; + * struct i915_user_extension ext1 { + * .next_extension = (uintptr_t)&ext2, + * .name = ..., + * }; + * + * Typically the struct i915_user_extension would be embedded in some uAPI + * struct, and in this case we would feed it the head of the chain(i.e ext1), + * which would then apply all of the above extensions. + * + */ +struct i915_user_extension { + /** + * @next_extension: + * + * Pointer to the next struct i915_user_extension, or zero if the end. + */ + __u64 next_extension; + /** + * @name: Name of the extension. + * + * Note that the name here is just some integer. + * + * Also note that the name space for this is not global for the whole + * driver, but rather its scope/meaning is limited to the specific piece + * of uAPI which has embedded the struct i915_user_extension. + */ + __u32 name; + /** + * @flags: MBZ + * + * All undefined bits must be zero. + */ + __u32 flags; + /** + * @rsvd: MBZ + * + * Reserved for future use; must be zero. + */ + __u32 rsvd[4]; +}; + +/* + * MOCS indexes used for GPU surfaces, defining the cacheability of the + * surface data and the coherency for this data wrt. CPU vs. GPU accesses. + */ +enum i915_mocs_table_index { + /* + * Not cached anywhere, coherency between CPU and GPU accesses is + * guaranteed. + */ + I915_MOCS_UNCACHED, + /* + * Cacheability and coherency controlled by the kernel automatically + * based on the DRM_I915_GEM_SET_CACHING IOCTL setting and the current + * usage of the surface (used for display scanout or not). + */ + I915_MOCS_PTE, + /* + * Cached in all GPU caches available on the platform. + * Coherency between CPU and GPU accesses to the surface is not + * guaranteed without extra synchronization. + */ + I915_MOCS_CACHED, +}; + +/** + * enum drm_i915_gem_engine_class - uapi engine type enumeration + * + * Different engines serve different roles, and there may be more than one + * engine serving each role. This enum provides a classification of the role + * of the engine, which may be used when requesting operations to be performed + * on a certain subset of engines, or for providing information about that + * group. + */ +enum drm_i915_gem_engine_class { + /** + * @I915_ENGINE_CLASS_RENDER: + * + * Render engines support instructions used for 3D, Compute (GPGPU), + * and programmable media workloads. These instructions fetch data and + * dispatch individual work items to threads that operate in parallel. + * The threads run small programs (called "kernels" or "shaders") on + * the GPU's execution units (EUs). + */ + I915_ENGINE_CLASS_RENDER = 0, + + /** + * @I915_ENGINE_CLASS_COPY: + * + * Copy engines (also referred to as "blitters") support instructions + * that move blocks of data from one location in memory to another, + * or that fill a specified location of memory with fixed data. + * Copy engines can perform pre-defined logical or bitwise operations + * on the source, destination, or pattern data. + */ + I915_ENGINE_CLASS_COPY = 1, + + /** + * @I915_ENGINE_CLASS_VIDEO: + * + * Video engines (also referred to as "bit stream decode" (BSD) or + * "vdbox") support instructions that perform fixed-function media + * decode and encode. + */ + I915_ENGINE_CLASS_VIDEO = 2, + + /** + * @I915_ENGINE_CLASS_VIDEO_ENHANCE: + * + * Video enhancement engines (also referred to as "vebox") support + * instructions related to image enhancement. + */ + I915_ENGINE_CLASS_VIDEO_ENHANCE = 3, + + /** + * @I915_ENGINE_CLASS_COMPUTE: + * + * Compute engines support a subset of the instructions available + * on render engines: compute engines support Compute (GPGPU) and + * programmable media workloads, but do not support the 3D pipeline. + */ + I915_ENGINE_CLASS_COMPUTE = 4, + + /* Values in this enum should be kept compact. */ + + /** + * @I915_ENGINE_CLASS_INVALID: + * + * Placeholder value to represent an invalid engine class assignment. + */ + I915_ENGINE_CLASS_INVALID = -1 +}; + +/** + * struct i915_engine_class_instance - Engine class/instance identifier + * + * There may be more than one engine fulfilling any role within the system. + * Each engine of a class is given a unique instance number and therefore + * any engine can be specified by its class:instance tuplet. APIs that allow + * access to any engine in the system will use struct i915_engine_class_instance + * for this identification. + */ +struct i915_engine_class_instance { + /** + * @engine_class: + * + * Engine class from enum drm_i915_gem_engine_class + */ + __u16 engine_class; +#define I915_ENGINE_CLASS_INVALID_NONE -1 +#define I915_ENGINE_CLASS_INVALID_VIRTUAL -2 + + /** + * @engine_instance: + * + * Engine instance. + */ + __u16 engine_instance; +}; + +/** + * DOC: perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915 + * + */ + +enum drm_i915_pmu_engine_sample { + I915_SAMPLE_BUSY = 0, + I915_SAMPLE_WAIT = 1, + I915_SAMPLE_SEMA = 2 +}; + +#define I915_PMU_SAMPLE_BITS (4) +#define I915_PMU_SAMPLE_MASK (0xf) +#define I915_PMU_SAMPLE_INSTANCE_BITS (8) +#define I915_PMU_CLASS_SHIFT \ + (I915_PMU_SAMPLE_BITS + I915_PMU_SAMPLE_INSTANCE_BITS) + +#define __I915_PMU_ENGINE(class, instance, sample) \ + ((class) << I915_PMU_CLASS_SHIFT | \ + (instance) << I915_PMU_SAMPLE_BITS | \ + (sample)) + +#define I915_PMU_ENGINE_BUSY(class, instance) \ + __I915_PMU_ENGINE(class, instance, I915_SAMPLE_BUSY) + +#define I915_PMU_ENGINE_WAIT(class, instance) \ + __I915_PMU_ENGINE(class, instance, I915_SAMPLE_WAIT) + +#define I915_PMU_ENGINE_SEMA(class, instance) \ + __I915_PMU_ENGINE(class, instance, I915_SAMPLE_SEMA) + +/* + * Top 4 bits of every non-engine counter are GT id. + */ +#define __I915_PMU_GT_SHIFT (60) + +#define ___I915_PMU_OTHER(gt, x) \ + (((__u64)__I915_PMU_ENGINE(0xff, 0xff, 0xf) + 1 + (x)) | \ + ((__u64)(gt) << __I915_PMU_GT_SHIFT)) + +#define __I915_PMU_OTHER(x) ___I915_PMU_OTHER(0, x) + +#define I915_PMU_ACTUAL_FREQUENCY __I915_PMU_OTHER(0) +#define I915_PMU_REQUESTED_FREQUENCY __I915_PMU_OTHER(1) +#define I915_PMU_INTERRUPTS __I915_PMU_OTHER(2) +#define I915_PMU_RC6_RESIDENCY __I915_PMU_OTHER(3) +#define I915_PMU_SOFTWARE_GT_AWAKE_TIME __I915_PMU_OTHER(4) + +#define I915_PMU_LAST /* Deprecated - do not use */ I915_PMU_RC6_RESIDENCY + +#define __I915_PMU_ACTUAL_FREQUENCY(gt) ___I915_PMU_OTHER(gt, 0) +#define __I915_PMU_REQUESTED_FREQUENCY(gt) ___I915_PMU_OTHER(gt, 1) +#define __I915_PMU_INTERRUPTS(gt) ___I915_PMU_OTHER(gt, 2) +#define __I915_PMU_RC6_RESIDENCY(gt) ___I915_PMU_OTHER(gt, 3) +#define __I915_PMU_SOFTWARE_GT_AWAKE_TIME(gt) ___I915_PMU_OTHER(gt, 4) + +/* Each region is a minimum of 16k, and there are at most 255 of them. + */ +#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use + * of chars for next/prev indices */ +#define I915_LOG_MIN_TEX_REGION_SIZE 14 + +typedef struct _drm_i915_init { + enum { + I915_INIT_DMA = 0x01, + I915_CLEANUP_DMA = 0x02, + I915_RESUME_DMA = 0x03 + } func; + unsigned int mmio_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; + unsigned int back_pitch; + unsigned int depth_pitch; + unsigned int cpp; + unsigned int chipset; +} drm_i915_init_t; + +typedef struct _drm_i915_sarea { + struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1]; + int last_upload; /* last time texture was uploaded */ + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int ctxOwner; /* last context to upload state */ + int texAge; + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; + int pf_current_page; /* which buffer is being displayed? */ + int perf_boxes; /* performance boxes to be displayed */ + int width, height; /* screen size in pixels */ + + drm_handle_t front_handle; + int front_offset; + int front_size; + + drm_handle_t back_handle; + int back_offset; + int back_size; + + drm_handle_t depth_handle; + int depth_offset; + int depth_size; + + drm_handle_t tex_handle; + int tex_offset; + int tex_size; + int log_tex_granularity; + int pitch; + int rotation; /* 0, 90, 180 or 270 */ + int rotated_offset; + int rotated_size; + int rotated_pitch; + int virtualX, virtualY; + + unsigned int front_tiled; + unsigned int back_tiled; + unsigned int depth_tiled; + unsigned int rotated_tiled; + unsigned int rotated2_tiled; + + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; + + /* fill out some space for old userspace triple buffer */ + drm_handle_t unused_handle; + __u32 unused1, unused2, unused3; + + /* buffer object handles for static buffers. May change + * over the lifetime of the client. + */ + __u32 front_bo_handle; + __u32 back_bo_handle; + __u32 unused_bo_handle; + __u32 depth_bo_handle; + +} drm_i915_sarea_t; + +/* due to userspace building against these headers we need some compat here */ +#define planeA_x pipeA_x +#define planeA_y pipeA_y +#define planeA_w pipeA_w +#define planeA_h pipeA_h +#define planeB_x pipeB_x +#define planeB_y pipeB_y +#define planeB_w pipeB_w +#define planeB_h pipeB_h + +/* Flags for perf_boxes + */ +#define I915_BOX_RING_EMPTY 0x1 +#define I915_BOX_FLIP 0x2 +#define I915_BOX_WAIT 0x4 +#define I915_BOX_TEXTURE_LOAD 0x8 +#define I915_BOX_LOST_CONTEXT 0x10 + +/* + * i915 specific ioctls. + * + * The device specific ioctl range is [DRM_COMMAND_BASE, DRM_COMMAND_END) ie + * [0x40, 0xa0) (a0 is excluded). The numbers below are defined as offset + * against DRM_COMMAND_BASE and should be between [0x0, 0x60). + */ +#define DRM_I915_INIT 0x00 +#define DRM_I915_FLUSH 0x01 +#define DRM_I915_FLIP 0x02 +#define DRM_I915_BATCHBUFFER 0x03 +#define DRM_I915_IRQ_EMIT 0x04 +#define DRM_I915_IRQ_WAIT 0x05 +#define DRM_I915_GETPARAM 0x06 +#define DRM_I915_SETPARAM 0x07 +#define DRM_I915_ALLOC 0x08 +#define DRM_I915_FREE 0x09 +#define DRM_I915_INIT_HEAP 0x0a +#define DRM_I915_CMDBUFFER 0x0b +#define DRM_I915_DESTROY_HEAP 0x0c +#define DRM_I915_SET_VBLANK_PIPE 0x0d +#define DRM_I915_GET_VBLANK_PIPE 0x0e +#define DRM_I915_VBLANK_SWAP 0x0f +#define DRM_I915_HWS_ADDR 0x11 +#define DRM_I915_GEM_INIT 0x13 +#define DRM_I915_GEM_EXECBUFFER 0x14 +#define DRM_I915_GEM_PIN 0x15 +#define DRM_I915_GEM_UNPIN 0x16 +#define DRM_I915_GEM_BUSY 0x17 +#define DRM_I915_GEM_THROTTLE 0x18 +#define DRM_I915_GEM_ENTERVT 0x19 +#define DRM_I915_GEM_LEAVEVT 0x1a +#define DRM_I915_GEM_CREATE 0x1b +#define DRM_I915_GEM_PREAD 0x1c +#define DRM_I915_GEM_PWRITE 0x1d +#define DRM_I915_GEM_MMAP 0x1e +#define DRM_I915_GEM_SET_DOMAIN 0x1f +#define DRM_I915_GEM_SW_FINISH 0x20 +#define DRM_I915_GEM_SET_TILING 0x21 +#define DRM_I915_GEM_GET_TILING 0x22 +#define DRM_I915_GEM_GET_APERTURE 0x23 +#define DRM_I915_GEM_MMAP_GTT 0x24 +#define DRM_I915_GET_PIPE_FROM_CRTC_ID 0x25 +#define DRM_I915_GEM_MADVISE 0x26 +#define DRM_I915_OVERLAY_PUT_IMAGE 0x27 +#define DRM_I915_OVERLAY_ATTRS 0x28 +#define DRM_I915_GEM_EXECBUFFER2 0x29 +#define DRM_I915_GEM_EXECBUFFER2_WR DRM_I915_GEM_EXECBUFFER2 +#define DRM_I915_GET_SPRITE_COLORKEY 0x2a +#define DRM_I915_SET_SPRITE_COLORKEY 0x2b +#define DRM_I915_GEM_WAIT 0x2c +#define DRM_I915_GEM_CONTEXT_CREATE 0x2d +#define DRM_I915_GEM_CONTEXT_DESTROY 0x2e +#define DRM_I915_GEM_SET_CACHING 0x2f +#define DRM_I915_GEM_GET_CACHING 0x30 +#define DRM_I915_REG_READ 0x31 +#define DRM_I915_GET_RESET_STATS 0x32 +#define DRM_I915_GEM_USERPTR 0x33 +#define DRM_I915_GEM_CONTEXT_GETPARAM 0x34 +#define DRM_I915_GEM_CONTEXT_SETPARAM 0x35 +#define DRM_I915_PERF_OPEN 0x36 +#define DRM_I915_PERF_ADD_CONFIG 0x37 +#define DRM_I915_PERF_REMOVE_CONFIG 0x38 +#define DRM_I915_QUERY 0x39 +#define DRM_I915_GEM_VM_CREATE 0x3a +#define DRM_I915_GEM_VM_DESTROY 0x3b +#define DRM_I915_GEM_CREATE_EXT 0x3c +/* Must be kept compact -- no holes */ + +#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) +#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) +#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP) +#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) +#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) +#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) +#define DRM_IOCTL_I915_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GETPARAM, drm_i915_getparam_t) +#define DRM_IOCTL_I915_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SETPARAM, drm_i915_setparam_t) +#define DRM_IOCTL_I915_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_ALLOC, drm_i915_mem_alloc_t) +#define DRM_IOCTL_I915_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t) +#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t) +#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t) +#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) +#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) +#define DRM_IOCTL_I915_HWS_ADDR DRM_IOW(DRM_COMMAND_BASE + DRM_I915_HWS_ADDR, struct drm_i915_gem_init) +#define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init) +#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer) +#define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2) +#define DRM_IOCTL_I915_GEM_EXECBUFFER2_WR DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2_WR, struct drm_i915_gem_execbuffer2) +#define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin) +#define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin) +#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy) +#define DRM_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_CACHING, struct drm_i915_gem_caching) +#define DRM_IOCTL_I915_GEM_GET_CACHING DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_GET_CACHING, struct drm_i915_gem_caching) +#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE) +#define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT) +#define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT) +#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create) +#define DRM_IOCTL_I915_GEM_CREATE_EXT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE_EXT, struct drm_i915_gem_create_ext) +#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread) +#define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) +#define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) +#define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt) +#define DRM_IOCTL_I915_GEM_MMAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_offset) +#define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain) +#define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish) +#define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling) +#define DRM_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling) +#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture) +#define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id) +#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise) +#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image) +#define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs) +#define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait) +#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) +#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create_ext) +#define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) +#define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) +#define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats) +#define DRM_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr) +#define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param) +#define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param) +#define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) +#define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) +#define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) +#define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query) +#define DRM_IOCTL_I915_GEM_VM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control) +#define DRM_IOCTL_I915_GEM_VM_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control) + +/* Allow drivers to submit batchbuffers directly to hardware, relying + * on the security mechanisms provided by hardware. + */ +typedef struct drm_i915_batchbuffer { + int start; /* agp offset */ + int used; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + struct drm_clip_rect __user *cliprects; /* pointer to userspace cliprects */ +} drm_i915_batchbuffer_t; + +/* As above, but pass a pointer to userspace buffer which can be + * validated by the kernel prior to sending to hardware. + */ +typedef struct _drm_i915_cmdbuffer { + char __user *buf; /* pointer to userspace command buffer */ + int sz; /* nr bytes in buf */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + struct drm_clip_rect __user *cliprects; /* pointer to userspace cliprects */ +} drm_i915_cmdbuffer_t; + +/* Userspace can request & wait on irq's: + */ +typedef struct drm_i915_irq_emit { + int __user *irq_seq; +} drm_i915_irq_emit_t; + +typedef struct drm_i915_irq_wait { + int irq_seq; +} drm_i915_irq_wait_t; + +/* + * Different modes of per-process Graphics Translation Table, + * see I915_PARAM_HAS_ALIASING_PPGTT + */ +#define I915_GEM_PPGTT_NONE 0 +#define I915_GEM_PPGTT_ALIASING 1 +#define I915_GEM_PPGTT_FULL 2 + +/* Ioctl to query kernel params: + */ +#define I915_PARAM_IRQ_ACTIVE 1 +#define I915_PARAM_ALLOW_BATCHBUFFER 2 +#define I915_PARAM_LAST_DISPATCH 3 +#define I915_PARAM_CHIPSET_ID 4 +#define I915_PARAM_HAS_GEM 5 +#define I915_PARAM_NUM_FENCES_AVAIL 6 +#define I915_PARAM_HAS_OVERLAY 7 +#define I915_PARAM_HAS_PAGEFLIPPING 8 +#define I915_PARAM_HAS_EXECBUF2 9 +#define I915_PARAM_HAS_BSD 10 +#define I915_PARAM_HAS_BLT 11 +#define I915_PARAM_HAS_RELAXED_FENCING 12 +#define I915_PARAM_HAS_COHERENT_RINGS 13 +#define I915_PARAM_HAS_EXEC_CONSTANTS 14 +#define I915_PARAM_HAS_RELAXED_DELTA 15 +#define I915_PARAM_HAS_GEN7_SOL_RESET 16 +#define I915_PARAM_HAS_LLC 17 +#define I915_PARAM_HAS_ALIASING_PPGTT 18 +#define I915_PARAM_HAS_WAIT_TIMEOUT 19 +#define I915_PARAM_HAS_SEMAPHORES 20 +#define I915_PARAM_HAS_PRIME_VMAP_FLUSH 21 +#define I915_PARAM_HAS_VEBOX 22 +#define I915_PARAM_HAS_SECURE_BATCHES 23 +#define I915_PARAM_HAS_PINNED_BATCHES 24 +#define I915_PARAM_HAS_EXEC_NO_RELOC 25 +#define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 +#define I915_PARAM_HAS_WT 27 +#define I915_PARAM_CMD_PARSER_VERSION 28 +#define I915_PARAM_HAS_COHERENT_PHYS_GTT 29 +#define I915_PARAM_MMAP_VERSION 30 +#define I915_PARAM_HAS_BSD2 31 +#define I915_PARAM_REVISION 32 +#define I915_PARAM_SUBSLICE_TOTAL 33 +#define I915_PARAM_EU_TOTAL 34 +#define I915_PARAM_HAS_GPU_RESET 35 +#define I915_PARAM_HAS_RESOURCE_STREAMER 36 +#define I915_PARAM_HAS_EXEC_SOFTPIN 37 +#define I915_PARAM_HAS_POOLED_EU 38 +#define I915_PARAM_MIN_EU_IN_POOL 39 +#define I915_PARAM_MMAP_GTT_VERSION 40 + +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports user defined execution + * priorities and the driver will attempt to execute batches in priority order. + * The param returns a capability bitmask, nonzero implies that the scheduler + * is enabled, with different features present according to the mask. + * + * The initial priority for each batch is supplied by the context and is + * controlled via I915_CONTEXT_PARAM_PRIORITY. + */ +#define I915_PARAM_HAS_SCHEDULER 41 +#define I915_SCHEDULER_CAP_ENABLED (1ul << 0) +#define I915_SCHEDULER_CAP_PRIORITY (1ul << 1) +#define I915_SCHEDULER_CAP_PREEMPTION (1ul << 2) +#define I915_SCHEDULER_CAP_SEMAPHORES (1ul << 3) +#define I915_SCHEDULER_CAP_ENGINE_BUSY_STATS (1ul << 4) +/* + * Indicates the 2k user priority levels are statically mapped into 3 buckets as + * follows: + * + * -1k to -1 Low priority + * 0 Normal priority + * 1 to 1k Highest priority + */ +#define I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP (1ul << 5) + +/* + * Query the status of HuC load. + * + * The query can fail in the following scenarios with the listed error codes: + * -ENODEV if HuC is not present on this platform, + * -EOPNOTSUPP if HuC firmware usage is disabled, + * -ENOPKG if HuC firmware fetch failed, + * -ENOEXEC if HuC firmware is invalid or mismatched, + * -ENOMEM if i915 failed to prepare the FW objects for transfer to the uC, + * -EIO if the FW transfer or the FW authentication failed. + * + * If the IOCTL is successful, the returned parameter will be set to one of the + * following values: + * * 0 if HuC firmware load is not complete, + * * 1 if HuC firmware is loaded and fully authenticated, + * * 2 if HuC firmware is loaded and authenticated for clear media only + */ +#define I915_PARAM_HUC_STATUS 42 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to opt-out of + * synchronisation with implicit fencing on individual objects. + * See EXEC_OBJECT_ASYNC. + */ +#define I915_PARAM_HAS_EXEC_ASYNC 43 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports explicit fence support - + * both being able to pass in a sync_file fd to wait upon before executing, + * and being able to return a new sync_file fd that is signaled when the + * current request is complete. See I915_EXEC_FENCE_IN and I915_EXEC_FENCE_OUT. + */ +#define I915_PARAM_HAS_EXEC_FENCE 44 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to capture + * user-specified buffers for post-mortem debugging of GPU hangs. See + * EXEC_OBJECT_CAPTURE. + */ +#define I915_PARAM_HAS_EXEC_CAPTURE 45 + +#define I915_PARAM_SLICE_MASK 46 + +/* Assuming it's uniform for each slice, this queries the mask of subslices + * per-slice for this system. + */ +#define I915_PARAM_SUBSLICE_MASK 47 + +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying the batch buffer + * as the first execobject as opposed to the last. See I915_EXEC_BATCH_FIRST. + */ +#define I915_PARAM_HAS_EXEC_BATCH_FIRST 48 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of + * drm_i915_gem_exec_fence structures. See I915_EXEC_FENCE_ARRAY. + */ +#define I915_PARAM_HAS_EXEC_FENCE_ARRAY 49 + +/* + * Query whether every context (both per-file default and user created) is + * isolated (insofar as HW supports). If this parameter is not true, then + * freshly created contexts may inherit values from an existing context, + * rather than default HW values. If true, it also ensures (insofar as HW + * supports) that all state set by this context will not leak to any other + * context. + * + * As not every engine across every gen support contexts, the returned + * value reports the support of context isolation for individual engines by + * returning a bitmask of each engine class set to true if that class supports + * isolation. + */ +#define I915_PARAM_HAS_CONTEXT_ISOLATION 50 + +/* Frequency of the command streamer timestamps given by the *_TIMESTAMP + * registers. This used to be fixed per platform but from CNL onwards, this + * might vary depending on the parts. + */ +#define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51 + +/* + * Once upon a time we supposed that writes through the GGTT would be + * immediately in physical memory (once flushed out of the CPU path). However, + * on a few different processors and chipsets, this is not necessarily the case + * as the writes appear to be buffered internally. Thus a read of the backing + * storage (physical memory) via a different path (with different physical tags + * to the indirect write via the GGTT) will see stale values from before + * the GGTT write. Inside the kernel, we can for the most part keep track of + * the different read/write domains in use (e.g. set-domain), but the assumption + * of coherency is baked into the ABI, hence reporting its true state in this + * parameter. + * + * Reports true when writes via mmap_gtt are immediately visible following an + * lfence to flush the WCB. + * + * Reports false when writes via mmap_gtt are indeterminately delayed in an in + * internal buffer and are _not_ immediately visible to third parties accessing + * directly via mmap_cpu/mmap_wc. Use of mmap_gtt as part of an IPC + * communications channel when reporting false is strongly disadvised. + */ +#define I915_PARAM_MMAP_GTT_COHERENT 52 + +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports coordination of parallel + * execution through use of explicit fence support. + * See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT. + */ +#define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53 + +/* + * Revision of the i915-perf uAPI. The value returned helps determine what + * i915-perf features are available. See drm_i915_perf_property_id. + */ +#define I915_PARAM_PERF_REVISION 54 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of + * timeline syncobj through drm_i915_gem_execbuffer_ext_timeline_fences. See + * I915_EXEC_USE_EXTENSIONS. + */ +#define I915_PARAM_HAS_EXEC_TIMELINE_FENCES 55 + +/* Query if the kernel supports the I915_USERPTR_PROBE flag. */ +#define I915_PARAM_HAS_USERPTR_PROBE 56 + +/* + * Frequency of the timestamps in OA reports. This used to be the same as the CS + * timestamp frequency, but differs on some platforms. + */ +#define I915_PARAM_OA_TIMESTAMP_FREQUENCY 57 + +/* + * Query the status of PXP support in i915. + * + * The query can fail in the following scenarios with the listed error codes: + * -ENODEV = PXP support is not available on the GPU device or in the + * kernel due to missing component drivers or kernel configs. + * + * If the IOCTL is successful, the returned parameter will be set to one of + * the following values: + * 1 = PXP feature is supported and is ready for use. + * 2 = PXP feature is supported but should be ready soon (pending + * initialization of non-i915 system dependencies). + * + * NOTE: When param is supported (positive return values), user space should + * still refer to the GEM PXP context-creation UAPI header specs to be + * aware of possible failure due to system state machine at the time. + */ +#define I915_PARAM_PXP_STATUS 58 + +/* + * Query if kernel allows marking a context to send a Freq hint to SLPC. This + * will enable use of the strategies allowed by the SLPC algorithm. + */ +#define I915_PARAM_HAS_CONTEXT_FREQ_HINT 59 + +/* Must be kept compact -- no holes and well documented */ + +/** + * struct drm_i915_getparam - Driver parameter query structure. + */ +struct drm_i915_getparam { + /** @param: Driver parameter to query. */ + __s32 param; + + /** + * @value: Address of memory where queried value should be put. + * + * WARNING: Using pointers instead of fixed-size u64 means we need to write + * compat32 code. Don't repeat this mistake. + */ + int __user *value; +}; + +/** + * typedef drm_i915_getparam_t - Driver parameter query structure. + * See struct drm_i915_getparam. + */ +typedef struct drm_i915_getparam drm_i915_getparam_t; + +/* Ioctl to set kernel params: + */ +#define I915_SETPARAM_USE_MI_BATCHBUFFER_START 1 +#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2 +#define I915_SETPARAM_ALLOW_BATCHBUFFER 3 +#define I915_SETPARAM_NUM_USED_FENCES 4 +/* Must be kept compact -- no holes */ + +typedef struct drm_i915_setparam { + int param; + int value; +} drm_i915_setparam_t; + +/* A memory manager for regions of shared memory: + */ +#define I915_MEM_REGION_AGP 1 + +typedef struct drm_i915_mem_alloc { + int region; + int alignment; + int size; + int __user *region_offset; /* offset from start of fb or agp */ +} drm_i915_mem_alloc_t; + +typedef struct drm_i915_mem_free { + int region; + int region_offset; +} drm_i915_mem_free_t; + +typedef struct drm_i915_mem_init_heap { + int region; + int size; + int start; +} drm_i915_mem_init_heap_t; + +/* Allow memory manager to be torn down and re-initialized (eg on + * rotate): + */ +typedef struct drm_i915_mem_destroy_heap { + int region; +} drm_i915_mem_destroy_heap_t; + +/* Allow X server to configure which pipes to monitor for vblank signals + */ +#define DRM_I915_VBLANK_PIPE_A 1 +#define DRM_I915_VBLANK_PIPE_B 2 + +typedef struct drm_i915_vblank_pipe { + int pipe; +} drm_i915_vblank_pipe_t; + +/* Schedule buffer swap at given vertical blank: + */ +typedef struct drm_i915_vblank_swap { + drm_drawable_t drawable; + enum drm_vblank_seq_type seqtype; + unsigned int sequence; +} drm_i915_vblank_swap_t; + +typedef struct drm_i915_hws_addr { + __u64 addr; +} drm_i915_hws_addr_t; + +struct drm_i915_gem_init { + /** + * Beginning offset in the GTT to be managed by the DRM memory + * manager. + */ + __u64 gtt_start; + /** + * Ending offset in the GTT to be managed by the DRM memory + * manager. + */ + __u64 gtt_end; +}; + +struct drm_i915_gem_create { + /** + * Requested size for the object. + * + * The (page-aligned) allocated size for the object will be returned. + */ + __u64 size; + /** + * Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; + __u32 pad; +}; + +struct drm_i915_gem_pread { + /** Handle for the object being read. */ + __u32 handle; + __u32 pad; + /** Offset into the object to read from */ + __u64 offset; + /** Length of data to read */ + __u64 size; + /** + * Pointer to write the data into. + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 data_ptr; +}; + +struct drm_i915_gem_pwrite { + /** Handle for the object being written to. */ + __u32 handle; + __u32 pad; + /** Offset into the object to write to */ + __u64 offset; + /** Length of data to write */ + __u64 size; + /** + * Pointer to read the data from. + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 data_ptr; +}; + +struct drm_i915_gem_mmap { + /** Handle for the object being mapped. */ + __u32 handle; + __u32 pad; + /** Offset in the object to map. */ + __u64 offset; + /** + * Length of data to map. + * + * The value will be page-aligned. + */ + __u64 size; + /** + * Returned pointer the data was mapped at. + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 addr_ptr; + + /** + * Flags for extended behaviour. + * + * Added in version 2. + */ + __u64 flags; +#define I915_MMAP_WC 0x1 +}; + +struct drm_i915_gem_mmap_gtt { + /** Handle for the object being mapped. */ + __u32 handle; + __u32 pad; + /** + * Fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; +}; + +/** + * struct drm_i915_gem_mmap_offset - Retrieve an offset so we can mmap this buffer object. + * + * This struct is passed as argument to the `DRM_IOCTL_I915_GEM_MMAP_OFFSET` ioctl, + * and is used to retrieve the fake offset to mmap an object specified by &handle. + * + * The legacy way of using `DRM_IOCTL_I915_GEM_MMAP` is removed on gen12+. + * `DRM_IOCTL_I915_GEM_MMAP_GTT` is an older supported alias to this struct, but will behave + * as setting the &extensions to 0, and &flags to `I915_MMAP_OFFSET_GTT`. + */ +struct drm_i915_gem_mmap_offset { + /** @handle: Handle for the object being mapped. */ + __u32 handle; + /** @pad: Must be zero */ + __u32 pad; + /** + * @offset: The fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; + + /** + * @flags: Flags for extended behaviour. + * + * It is mandatory that one of the `MMAP_OFFSET` types + * should be included: + * + * - `I915_MMAP_OFFSET_GTT`: Use mmap with the object bound to GTT. (Write-Combined) + * - `I915_MMAP_OFFSET_WC`: Use Write-Combined caching. + * - `I915_MMAP_OFFSET_WB`: Use Write-Back caching. + * - `I915_MMAP_OFFSET_FIXED`: Use object placement to determine caching. + * + * On devices with local memory `I915_MMAP_OFFSET_FIXED` is the only valid + * type. On devices without local memory, this caching mode is invalid. + * + * As caching mode when specifying `I915_MMAP_OFFSET_FIXED`, WC or WB will + * be used, depending on the object placement on creation. WB will be used + * when the object can only exist in system memory, WC otherwise. + */ + __u64 flags; + +#define I915_MMAP_OFFSET_GTT 0 +#define I915_MMAP_OFFSET_WC 1 +#define I915_MMAP_OFFSET_WB 2 +#define I915_MMAP_OFFSET_UC 3 +#define I915_MMAP_OFFSET_FIXED 4 + + /** + * @extensions: Zero-terminated chain of extensions. + * + * No current extensions defined; mbz. + */ + __u64 extensions; +}; + +/** + * struct drm_i915_gem_set_domain - Adjust the objects write or read domain, in + * preparation for accessing the pages via some CPU domain. + * + * Specifying a new write or read domain will flush the object out of the + * previous domain(if required), before then updating the objects domain + * tracking with the new domain. + * + * Note this might involve waiting for the object first if it is still active on + * the GPU. + * + * Supported values for @read_domains and @write_domain: + * + * - I915_GEM_DOMAIN_WC: Uncached write-combined domain + * - I915_GEM_DOMAIN_CPU: CPU cache domain + * - I915_GEM_DOMAIN_GTT: Mappable aperture domain + * + * All other domains are rejected. + * + * Note that for discrete, starting from DG1, this is no longer supported, and + * is instead rejected. On such platforms the CPU domain is effectively static, + * where we also only support a single &drm_i915_gem_mmap_offset cache mode, + * which can't be set explicitly and instead depends on the object placements, + * as per the below. + * + * Implicit caching rules, starting from DG1: + * + * - If any of the object placements (see &drm_i915_gem_create_ext_memory_regions) + * contain I915_MEMORY_CLASS_DEVICE then the object will be allocated and + * mapped as write-combined only. + * + * - Everything else is always allocated and mapped as write-back, with the + * guarantee that everything is also coherent with the GPU. + * + * Note that this is likely to change in the future again, where we might need + * more flexibility on future devices, so making this all explicit as part of a + * new &drm_i915_gem_create_ext extension is probable. + */ +struct drm_i915_gem_set_domain { + /** @handle: Handle for the object. */ + __u32 handle; + + /** @read_domains: New read domains. */ + __u32 read_domains; + + /** + * @write_domain: New write domain. + * + * Note that having something in the write domain implies it's in the + * read domain, and only that read domain. + */ + __u32 write_domain; +}; + +struct drm_i915_gem_sw_finish { + /** Handle for the object */ + __u32 handle; +}; + +struct drm_i915_gem_relocation_entry { + /** + * Handle of the buffer being pointed to by this relocation entry. + * + * It's appealing to make this be an index into the mm_validate_entry + * list to refer to the buffer, but this allows the driver to create + * a relocation list for state buffers and not re-write it per + * exec using the buffer. + */ + __u32 target_handle; + + /** + * Value to be added to the offset of the target buffer to make up + * the relocation entry. + */ + __u32 delta; + + /** Offset in the buffer the relocation entry will be written into */ + __u64 offset; + + /** + * Offset value of the target buffer that the relocation entry was last + * written as. + * + * If the buffer has the same offset as last time, we can skip syncing + * and writing the relocation. This value is written back out by + * the execbuffer ioctl when the relocation is written. + */ + __u64 presumed_offset; + + /** + * Target memory domains read by this operation. + */ + __u32 read_domains; + + /** + * Target memory domains written by this operation. + * + * Note that only one domain may be written by the whole + * execbuffer operation, so that where there are conflicts, + * the application will get -EINVAL back. + */ + __u32 write_domain; +}; + +/** @{ + * Intel memory domains + * + * Most of these just align with the various caches in + * the system and are used to flush and invalidate as + * objects end up cached in different domains. + */ +/** CPU cache */ +#define I915_GEM_DOMAIN_CPU 0x00000001 +/** Render cache, used by 2D and 3D drawing */ +#define I915_GEM_DOMAIN_RENDER 0x00000002 +/** Sampler cache, used by texture engine */ +#define I915_GEM_DOMAIN_SAMPLER 0x00000004 +/** Command queue, used to load batch buffers */ +#define I915_GEM_DOMAIN_COMMAND 0x00000008 +/** Instruction cache, used by shader programs */ +#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010 +/** Vertex address cache */ +#define I915_GEM_DOMAIN_VERTEX 0x00000020 +/** GTT domain - aperture and scanout */ +#define I915_GEM_DOMAIN_GTT 0x00000040 +/** WC domain - uncached access */ +#define I915_GEM_DOMAIN_WC 0x00000080 +/** @} */ + +struct drm_i915_gem_exec_object { + /** + * User's handle for a buffer to be bound into the GTT for this + * operation. + */ + __u32 handle; + + /** Number of relocations to be performed on this buffer */ + __u32 relocation_count; + /** + * Pointer to array of struct drm_i915_gem_relocation_entry containing + * the relocations to be performed in this buffer. + */ + __u64 relocs_ptr; + + /** Required alignment in graphics aperture */ + __u64 alignment; + + /** + * Returned value of the updated offset of the object, for future + * presumed_offset writes. + */ + __u64 offset; +}; + +/* DRM_IOCTL_I915_GEM_EXECBUFFER was removed in Linux 5.13 */ +struct drm_i915_gem_execbuffer { + /** + * List of buffers to be validated with their relocations to be + * performend on them. + * + * This is a pointer to an array of struct drm_i915_gem_validate_entry. + * + * These buffers must be listed in an order such that all relocations + * a buffer is performing refer to buffers that have already appeared + * in the validate list. + */ + __u64 buffers_ptr; + __u32 buffer_count; + + /** Offset in the batchbuffer to start execution from. */ + __u32 batch_start_offset; + /** Bytes used in batchbuffer from batch_start_offset */ + __u32 batch_len; + __u32 DR1; + __u32 DR4; + __u32 num_cliprects; + /** This is a struct drm_clip_rect *cliprects */ + __u64 cliprects_ptr; +}; + +struct drm_i915_gem_exec_object2 { + /** + * User's handle for a buffer to be bound into the GTT for this + * operation. + */ + __u32 handle; + + /** Number of relocations to be performed on this buffer */ + __u32 relocation_count; + /** + * Pointer to array of struct drm_i915_gem_relocation_entry containing + * the relocations to be performed in this buffer. + */ + __u64 relocs_ptr; + + /** Required alignment in graphics aperture */ + __u64 alignment; + + /** + * When the EXEC_OBJECT_PINNED flag is specified this is populated by + * the user with the GTT offset at which this object will be pinned. + * + * When the I915_EXEC_NO_RELOC flag is specified this must contain the + * presumed_offset of the object. + * + * During execbuffer2 the kernel populates it with the value of the + * current GTT offset of the object, for future presumed_offset writes. + * + * See struct drm_i915_gem_create_ext for the rules when dealing with + * alignment restrictions with I915_MEMORY_CLASS_DEVICE, on devices with + * minimum page sizes, like DG2. + */ + __u64 offset; + +#define EXEC_OBJECT_NEEDS_FENCE (1<<0) +#define EXEC_OBJECT_NEEDS_GTT (1<<1) +#define EXEC_OBJECT_WRITE (1<<2) +#define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3) +#define EXEC_OBJECT_PINNED (1<<4) +#define EXEC_OBJECT_PAD_TO_SIZE (1<<5) +/* The kernel implicitly tracks GPU activity on all GEM objects, and + * synchronises operations with outstanding rendering. This includes + * rendering on other devices if exported via dma-buf. However, sometimes + * this tracking is too coarse and the user knows better. For example, + * if the object is split into non-overlapping ranges shared between different + * clients or engines (i.e. suballocating objects), the implicit tracking + * by kernel assumes that each operation affects the whole object rather + * than an individual range, causing needless synchronisation between clients. + * The kernel will also forgo any CPU cache flushes prior to rendering from + * the object as the client is expected to be also handling such domain + * tracking. + * + * The kernel maintains the implicit tracking in order to manage resources + * used by the GPU - this flag only disables the synchronisation prior to + * rendering with this object in this execbuf. + * + * Opting out of implicit synhronisation requires the user to do its own + * explicit tracking to avoid rendering corruption. See, for example, + * I915_PARAM_HAS_EXEC_FENCE to order execbufs and execute them asynchronously. + */ +#define EXEC_OBJECT_ASYNC (1<<6) +/* Request that the contents of this execobject be copied into the error + * state upon a GPU hang involving this batch for post-mortem debugging. + * These buffers are recorded in no particular order as "user" in + * /sys/class/drm/cardN/error. Query I915_PARAM_HAS_EXEC_CAPTURE to see + * if the kernel supports this flag. + */ +#define EXEC_OBJECT_CAPTURE (1<<7) +/* All remaining bits are MBZ and RESERVED FOR FUTURE USE */ +#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_CAPTURE<<1) + __u64 flags; + + union { + __u64 rsvd1; + __u64 pad_to_size; + }; + __u64 rsvd2; +}; + +/** + * struct drm_i915_gem_exec_fence - An input or output fence for the execbuf + * ioctl. + * + * The request will wait for input fence to signal before submission. + * + * The returned output fence will be signaled after the completion of the + * request. + */ +struct drm_i915_gem_exec_fence { + /** @handle: User's handle for a drm_syncobj to wait on or signal. */ + __u32 handle; + + /** + * @flags: Supported flags are: + * + * I915_EXEC_FENCE_WAIT: + * Wait for the input fence before request submission. + * + * I915_EXEC_FENCE_SIGNAL: + * Return request completion fence as output + */ + __u32 flags; +#define I915_EXEC_FENCE_WAIT (1<<0) +#define I915_EXEC_FENCE_SIGNAL (1<<1) +#define __I915_EXEC_FENCE_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SIGNAL << 1)) +}; + +/** + * struct drm_i915_gem_execbuffer_ext_timeline_fences - Timeline fences + * for execbuf ioctl. + * + * This structure describes an array of drm_syncobj and associated points for + * timeline variants of drm_syncobj. It is invalid to append this structure to + * the execbuf if I915_EXEC_FENCE_ARRAY is set. + */ +struct drm_i915_gem_execbuffer_ext_timeline_fences { +#define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0 + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + + /** + * @fence_count: Number of elements in the @handles_ptr & @value_ptr + * arrays. + */ + __u64 fence_count; + + /** + * @handles_ptr: Pointer to an array of struct drm_i915_gem_exec_fence + * of length @fence_count. + */ + __u64 handles_ptr; + + /** + * @values_ptr: Pointer to an array of u64 values of length + * @fence_count. + * Values must be 0 for a binary drm_syncobj. A Value of 0 for a + * timeline drm_syncobj is invalid as it turns a drm_syncobj into a + * binary one. + */ + __u64 values_ptr; +}; + +/** + * struct drm_i915_gem_execbuffer2 - Structure for DRM_I915_GEM_EXECBUFFER2 + * ioctl. + */ +struct drm_i915_gem_execbuffer2 { + /** @buffers_ptr: Pointer to a list of gem_exec_object2 structs */ + __u64 buffers_ptr; + + /** @buffer_count: Number of elements in @buffers_ptr array */ + __u32 buffer_count; + + /** + * @batch_start_offset: Offset in the batchbuffer to start execution + * from. + */ + __u32 batch_start_offset; + + /** + * @batch_len: Length in bytes of the batch buffer, starting from the + * @batch_start_offset. If 0, length is assumed to be the batch buffer + * object size. + */ + __u32 batch_len; + + /** @DR1: deprecated */ + __u32 DR1; + + /** @DR4: deprecated */ + __u32 DR4; + + /** @num_cliprects: See @cliprects_ptr */ + __u32 num_cliprects; + + /** + * @cliprects_ptr: Kernel clipping was a DRI1 misfeature. + * + * It is invalid to use this field if I915_EXEC_FENCE_ARRAY or + * I915_EXEC_USE_EXTENSIONS flags are not set. + * + * If I915_EXEC_FENCE_ARRAY is set, then this is a pointer to an array + * of &drm_i915_gem_exec_fence and @num_cliprects is the length of the + * array. + * + * If I915_EXEC_USE_EXTENSIONS is set, then this is a pointer to a + * single &i915_user_extension and num_cliprects is 0. + */ + __u64 cliprects_ptr; + + /** @flags: Execbuf flags */ + __u64 flags; +#define I915_EXEC_RING_MASK (0x3f) +#define I915_EXEC_DEFAULT (0<<0) +#define I915_EXEC_RENDER (1<<0) +#define I915_EXEC_BSD (2<<0) +#define I915_EXEC_BLT (3<<0) +#define I915_EXEC_VEBOX (4<<0) + +/* Used for switching the constants addressing mode on gen4+ RENDER ring. + * Gen6+ only supports relative addressing to dynamic state (default) and + * absolute addressing. + * + * These flags are ignored for the BSD and BLT rings. + */ +#define I915_EXEC_CONSTANTS_MASK (3<<6) +#define I915_EXEC_CONSTANTS_REL_GENERAL (0<<6) /* default */ +#define I915_EXEC_CONSTANTS_ABSOLUTE (1<<6) +#define I915_EXEC_CONSTANTS_REL_SURFACE (2<<6) /* gen4/5 only */ + +/** Resets the SO write offset registers for transform feedback on gen7. */ +#define I915_EXEC_GEN7_SOL_RESET (1<<8) + +/** Request a privileged ("secure") batch buffer. Note only available for + * DRM_ROOT_ONLY | DRM_MASTER processes. + */ +#define I915_EXEC_SECURE (1<<9) + +/** Inform the kernel that the batch is and will always be pinned. This + * negates the requirement for a workaround to be performed to avoid + * an incoherent CS (such as can be found on 830/845). If this flag is + * not passed, the kernel will endeavour to make sure the batch is + * coherent with the CS before execution. If this flag is passed, + * userspace assumes the responsibility for ensuring the same. + */ +#define I915_EXEC_IS_PINNED (1<<10) + +/** Provide a hint to the kernel that the command stream and auxiliary + * state buffers already holds the correct presumed addresses and so the + * relocation process may be skipped if no buffers need to be moved in + * preparation for the execbuffer. + */ +#define I915_EXEC_NO_RELOC (1<<11) + +/** Use the reloc.handle as an index into the exec object array rather + * than as the per-file handle. + */ +#define I915_EXEC_HANDLE_LUT (1<<12) + +/** Used for switching BSD rings on the platforms with two BSD rings */ +#define I915_EXEC_BSD_SHIFT (13) +#define I915_EXEC_BSD_MASK (3 << I915_EXEC_BSD_SHIFT) +/* default ping-pong mode */ +#define I915_EXEC_BSD_DEFAULT (0 << I915_EXEC_BSD_SHIFT) +#define I915_EXEC_BSD_RING1 (1 << I915_EXEC_BSD_SHIFT) +#define I915_EXEC_BSD_RING2 (2 << I915_EXEC_BSD_SHIFT) + +/** Tell the kernel that the batchbuffer is processed by + * the resource streamer. + */ +#define I915_EXEC_RESOURCE_STREAMER (1<<15) + +/* Setting I915_EXEC_FENCE_IN implies that lower_32_bits(rsvd2) represent + * a sync_file fd to wait upon (in a nonblocking manner) prior to executing + * the batch. + * + * Returns -EINVAL if the sync_file fd cannot be found. + */ +#define I915_EXEC_FENCE_IN (1<<16) + +/* Setting I915_EXEC_FENCE_OUT causes the ioctl to return a sync_file fd + * in the upper_32_bits(rsvd2) upon success. Ownership of the fd is given + * to the caller, and it should be close() after use. (The fd is a regular + * file descriptor and will be cleaned up on process termination. It holds + * a reference to the request, but nothing else.) + * + * The sync_file fd can be combined with other sync_file and passed either + * to execbuf using I915_EXEC_FENCE_IN, to atomic KMS ioctls (so that a flip + * will only occur after this request completes), or to other devices. + * + * Using I915_EXEC_FENCE_OUT requires use of + * DRM_IOCTL_I915_GEM_EXECBUFFER2_WR ioctl so that the result is written + * back to userspace. Failure to do so will cause the out-fence to always + * be reported as zero, and the real fence fd to be leaked. + */ +#define I915_EXEC_FENCE_OUT (1<<17) + +/* + * Traditionally the execbuf ioctl has only considered the final element in + * the execobject[] to be the executable batch. Often though, the client + * will known the batch object prior to construction and being able to place + * it into the execobject[] array first can simplify the relocation tracking. + * Setting I915_EXEC_BATCH_FIRST tells execbuf to use element 0 of the + * execobject[] as the * batch instead (the default is to use the last + * element). + */ +#define I915_EXEC_BATCH_FIRST (1<<18) + +/* Setting I915_FENCE_ARRAY implies that num_cliprects and cliprects_ptr + * define an array of i915_gem_exec_fence structures which specify a set of + * dma fences to wait upon or signal. + */ +#define I915_EXEC_FENCE_ARRAY (1<<19) + +/* + * Setting I915_EXEC_FENCE_SUBMIT implies that lower_32_bits(rsvd2) represent + * a sync_file fd to wait upon (in a nonblocking manner) prior to executing + * the batch. + * + * Returns -EINVAL if the sync_file fd cannot be found. + */ +#define I915_EXEC_FENCE_SUBMIT (1 << 20) + +/* + * Setting I915_EXEC_USE_EXTENSIONS implies that + * drm_i915_gem_execbuffer2.cliprects_ptr is treated as a pointer to an linked + * list of i915_user_extension. Each i915_user_extension node is the base of a + * larger structure. The list of supported structures are listed in the + * drm_i915_gem_execbuffer_ext enum. + */ +#define I915_EXEC_USE_EXTENSIONS (1 << 21) +#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_USE_EXTENSIONS << 1)) + + /** @rsvd1: Context id */ + __u64 rsvd1; + + /** + * @rsvd2: in and out sync_file file descriptors. + * + * When I915_EXEC_FENCE_IN or I915_EXEC_FENCE_SUBMIT flag is set, the + * lower 32 bits of this field will have the in sync_file fd (input). + * + * When I915_EXEC_FENCE_OUT flag is set, the upper 32 bits of this + * field will have the out sync_file fd (output). + */ + __u64 rsvd2; +}; + +#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) +#define i915_execbuffer2_set_context_id(eb2, context) \ + (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK +#define i915_execbuffer2_get_context_id(eb2) \ + ((eb2).rsvd1 & I915_EXEC_CONTEXT_ID_MASK) + +struct drm_i915_gem_pin { + /** Handle of the buffer to be pinned. */ + __u32 handle; + __u32 pad; + + /** alignment required within the aperture */ + __u64 alignment; + + /** Returned GTT offset of the buffer. */ + __u64 offset; +}; + +struct drm_i915_gem_unpin { + /** Handle of the buffer to be unpinned. */ + __u32 handle; + __u32 pad; +}; + +struct drm_i915_gem_busy { + /** Handle of the buffer to check for busy */ + __u32 handle; + + /** Return busy status + * + * A return of 0 implies that the object is idle (after + * having flushed any pending activity), and a non-zero return that + * the object is still in-flight on the GPU. (The GPU has not yet + * signaled completion for all pending requests that reference the + * object.) An object is guaranteed to become idle eventually (so + * long as no new GPU commands are executed upon it). Due to the + * asynchronous nature of the hardware, an object reported + * as busy may become idle before the ioctl is completed. + * + * Furthermore, if the object is busy, which engine is busy is only + * provided as a guide and only indirectly by reporting its class + * (there may be more than one engine in each class). There are race + * conditions which prevent the report of which engines are busy from + * being always accurate. However, the converse is not true. If the + * object is idle, the result of the ioctl, that all engines are idle, + * is accurate. + * + * The returned dword is split into two fields to indicate both + * the engine classes on which the object is being read, and the + * engine class on which it is currently being written (if any). + * + * The low word (bits 0:15) indicate if the object is being written + * to by any engine (there can only be one, as the GEM implicit + * synchronisation rules force writes to be serialised). Only the + * engine class (offset by 1, I915_ENGINE_CLASS_RENDER is reported as + * 1 not 0 etc) for the last write is reported. + * + * The high word (bits 16:31) are a bitmask of which engines classes + * are currently reading from the object. Multiple engines may be + * reading from the object simultaneously. + * + * The value of each engine class is the same as specified in the + * I915_CONTEXT_PARAM_ENGINES context parameter and via perf, i.e. + * I915_ENGINE_CLASS_RENDER, I915_ENGINE_CLASS_COPY, etc. + * Some hardware may have parallel execution engines, e.g. multiple + * media engines, which are mapped to the same class identifier and so + * are not separately reported for busyness. + * + * Caveat emptor: + * Only the boolean result of this query is reliable; that is whether + * the object is idle or busy. The report of which engines are busy + * should be only used as a heuristic. + */ + __u32 busy; +}; + +/** + * struct drm_i915_gem_caching - Set or get the caching for given object + * handle. + * + * Allow userspace to control the GTT caching bits for a given object when the + * object is later mapped through the ppGTT(or GGTT on older platforms lacking + * ppGTT support, or if the object is used for scanout). Note that this might + * require unbinding the object from the GTT first, if its current caching value + * doesn't match. + * + * Note that this all changes on discrete platforms, starting from DG1, the + * set/get caching is no longer supported, and is now rejected. Instead the CPU + * caching attributes(WB vs WC) will become an immutable creation time property + * for the object, along with the GTT caching level. For now we don't expose any + * new uAPI for this, instead on DG1 this is all implicit, although this largely + * shouldn't matter since DG1 is coherent by default(without any way of + * controlling it). + * + * Implicit caching rules, starting from DG1: + * + * - If any of the object placements (see &drm_i915_gem_create_ext_memory_regions) + * contain I915_MEMORY_CLASS_DEVICE then the object will be allocated and + * mapped as write-combined only. + * + * - Everything else is always allocated and mapped as write-back, with the + * guarantee that everything is also coherent with the GPU. + * + * Note that this is likely to change in the future again, where we might need + * more flexibility on future devices, so making this all explicit as part of a + * new &drm_i915_gem_create_ext extension is probable. + * + * Side note: Part of the reason for this is that changing the at-allocation-time CPU + * caching attributes for the pages might be required(and is expensive) if we + * need to then CPU map the pages later with different caching attributes. This + * inconsistent caching behaviour, while supported on x86, is not universally + * supported on other architectures. So for simplicity we opt for setting + * everything at creation time, whilst also making it immutable, on discrete + * platforms. + */ +struct drm_i915_gem_caching { + /** + * @handle: Handle of the buffer to set/get the caching level. + */ + __u32 handle; + + /** + * @caching: The GTT caching level to apply or possible return value. + * + * The supported @caching values: + * + * I915_CACHING_NONE: + * + * GPU access is not coherent with CPU caches. Default for machines + * without an LLC. This means manual flushing might be needed, if we + * want GPU access to be coherent. + * + * I915_CACHING_CACHED: + * + * GPU access is coherent with CPU caches and furthermore the data is + * cached in last-level caches shared between CPU cores and the GPU GT. + * + * I915_CACHING_DISPLAY: + * + * Special GPU caching mode which is coherent with the scanout engines. + * Transparently falls back to I915_CACHING_NONE on platforms where no + * special cache mode (like write-through or gfdt flushing) is + * available. The kernel automatically sets this mode when using a + * buffer as a scanout target. Userspace can manually set this mode to + * avoid a costly stall and clflush in the hotpath of drawing the first + * frame. + */ +#define I915_CACHING_NONE 0 +#define I915_CACHING_CACHED 1 +#define I915_CACHING_DISPLAY 2 + __u32 caching; +}; + +#define I915_TILING_NONE 0 +#define I915_TILING_X 1 +#define I915_TILING_Y 2 +/* + * Do not add new tiling types here. The I915_TILING_* values are for + * de-tiling fence registers that no longer exist on modern platforms. Although + * the hardware may support new types of tiling in general (e.g., Tile4), we + * do not need to add them to the uapi that is specific to now-defunct ioctls. + */ +#define I915_TILING_LAST I915_TILING_Y + +#define I915_BIT_6_SWIZZLE_NONE 0 +#define I915_BIT_6_SWIZZLE_9 1 +#define I915_BIT_6_SWIZZLE_9_10 2 +#define I915_BIT_6_SWIZZLE_9_11 3 +#define I915_BIT_6_SWIZZLE_9_10_11 4 +/* Not seen by userland */ +#define I915_BIT_6_SWIZZLE_UNKNOWN 5 +/* Seen by userland. */ +#define I915_BIT_6_SWIZZLE_9_17 6 +#define I915_BIT_6_SWIZZLE_9_10_17 7 + +struct drm_i915_gem_set_tiling { + /** Handle of the buffer to have its tiling state updated */ + __u32 handle; + + /** + * Tiling mode for the object (I915_TILING_NONE, I915_TILING_X, + * I915_TILING_Y). + * + * This value is to be set on request, and will be updated by the + * kernel on successful return with the actual chosen tiling layout. + * + * The tiling mode may be demoted to I915_TILING_NONE when the system + * has bit 6 swizzling that can't be managed correctly by GEM. + * + * Buffer contents become undefined when changing tiling_mode. + */ + __u32 tiling_mode; + + /** + * Stride in bytes for the object when in I915_TILING_X or + * I915_TILING_Y. + */ + __u32 stride; + + /** + * Returned address bit 6 swizzling required for CPU access through + * mmap mapping. + */ + __u32 swizzle_mode; +}; + +struct drm_i915_gem_get_tiling { + /** Handle of the buffer to get tiling state for. */ + __u32 handle; + + /** + * Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X, + * I915_TILING_Y). + */ + __u32 tiling_mode; + + /** + * Returned address bit 6 swizzling required for CPU access through + * mmap mapping. + */ + __u32 swizzle_mode; + + /** + * Returned address bit 6 swizzling required for CPU access through + * mmap mapping whilst bound. + */ + __u32 phys_swizzle_mode; +}; + +struct drm_i915_gem_get_aperture { + /** Total size of the aperture used by i915_gem_execbuffer, in bytes */ + __u64 aper_size; + + /** + * Available space in the aperture used by i915_gem_execbuffer, in + * bytes + */ + __u64 aper_available_size; +}; + +struct drm_i915_get_pipe_from_crtc_id { + /** ID of CRTC being requested **/ + __u32 crtc_id; + + /** pipe of requested CRTC **/ + __u32 pipe; +}; + +#define I915_MADV_WILLNEED 0 +#define I915_MADV_DONTNEED 1 +#define __I915_MADV_PURGED 2 /* internal state */ + +struct drm_i915_gem_madvise { + /** Handle of the buffer to change the backing store advice */ + __u32 handle; + + /* Advice: either the buffer will be needed again in the near future, + * or won't be and could be discarded under memory pressure. + */ + __u32 madv; + + /** Whether the backing store still exists. */ + __u32 retained; +}; + +/* flags */ +#define I915_OVERLAY_TYPE_MASK 0xff +#define I915_OVERLAY_YUV_PLANAR 0x01 +#define I915_OVERLAY_YUV_PACKED 0x02 +#define I915_OVERLAY_RGB 0x03 + +#define I915_OVERLAY_DEPTH_MASK 0xff00 +#define I915_OVERLAY_RGB24 0x1000 +#define I915_OVERLAY_RGB16 0x2000 +#define I915_OVERLAY_RGB15 0x3000 +#define I915_OVERLAY_YUV422 0x0100 +#define I915_OVERLAY_YUV411 0x0200 +#define I915_OVERLAY_YUV420 0x0300 +#define I915_OVERLAY_YUV410 0x0400 + +#define I915_OVERLAY_SWAP_MASK 0xff0000 +#define I915_OVERLAY_NO_SWAP 0x000000 +#define I915_OVERLAY_UV_SWAP 0x010000 +#define I915_OVERLAY_Y_SWAP 0x020000 +#define I915_OVERLAY_Y_AND_UV_SWAP 0x030000 + +#define I915_OVERLAY_FLAGS_MASK 0xff000000 +#define I915_OVERLAY_ENABLE 0x01000000 + +struct drm_intel_overlay_put_image { + /* various flags and src format description */ + __u32 flags; + /* source picture description */ + __u32 bo_handle; + /* stride values and offsets are in bytes, buffer relative */ + __u16 stride_Y; /* stride for packed formats */ + __u16 stride_UV; + __u32 offset_Y; /* offset for packet formats */ + __u32 offset_U; + __u32 offset_V; + /* in pixels */ + __u16 src_width; + __u16 src_height; + /* to compensate the scaling factors for partially covered surfaces */ + __u16 src_scan_width; + __u16 src_scan_height; + /* output crtc description */ + __u32 crtc_id; + __u16 dst_x; + __u16 dst_y; + __u16 dst_width; + __u16 dst_height; +}; + +/* flags */ +#define I915_OVERLAY_UPDATE_ATTRS (1<<0) +#define I915_OVERLAY_UPDATE_GAMMA (1<<1) +#define I915_OVERLAY_DISABLE_DEST_COLORKEY (1<<2) +struct drm_intel_overlay_attrs { + __u32 flags; + __u32 color_key; + __s32 brightness; + __u32 contrast; + __u32 saturation; + __u32 gamma0; + __u32 gamma1; + __u32 gamma2; + __u32 gamma3; + __u32 gamma4; + __u32 gamma5; +}; + +/* + * Intel sprite handling + * + * Color keying works with a min/mask/max tuple. Both source and destination + * color keying is allowed. + * + * Source keying: + * Sprite pixels within the min & max values, masked against the color channels + * specified in the mask field, will be transparent. All other pixels will + * be displayed on top of the primary plane. For RGB surfaces, only the min + * and mask fields will be used; ranged compares are not allowed. + * + * Destination keying: + * Primary plane pixels that match the min value, masked against the color + * channels specified in the mask field, will be replaced by corresponding + * pixels from the sprite plane. + * + * Note that source & destination keying are exclusive; only one can be + * active on a given plane. + */ + +#define I915_SET_COLORKEY_NONE (1<<0) /* Deprecated. Instead set + * flags==0 to disable colorkeying. + */ +#define I915_SET_COLORKEY_DESTINATION (1<<1) +#define I915_SET_COLORKEY_SOURCE (1<<2) +struct drm_intel_sprite_colorkey { + __u32 plane_id; + __u32 min_value; + __u32 channel_mask; + __u32 max_value; + __u32 flags; +}; + +struct drm_i915_gem_wait { + /** Handle of BO we shall wait on */ + __u32 bo_handle; + __u32 flags; + /** Number of nanoseconds to wait, Returns time remaining. */ + __s64 timeout_ns; +}; + +struct drm_i915_gem_context_create { + __u32 ctx_id; /* output: id of new context*/ + __u32 pad; +}; + +/** + * struct drm_i915_gem_context_create_ext - Structure for creating contexts. + */ +struct drm_i915_gem_context_create_ext { + /** @ctx_id: Id of the created context (output) */ + __u32 ctx_id; + + /** + * @flags: Supported flags are: + * + * I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS: + * + * Extensions may be appended to this structure and driver must check + * for those. See @extensions. + * + * I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE + * + * Created context will have single timeline. + */ + __u32 flags; +#define I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS (1u << 0) +#define I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE (1u << 1) +#define I915_CONTEXT_CREATE_FLAGS_UNKNOWN \ + (-(I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE << 1)) + + /** + * @extensions: Zero-terminated chain of extensions. + * + * I915_CONTEXT_CREATE_EXT_SETPARAM: + * Context parameter to set or query during context creation. + * See struct drm_i915_gem_context_create_ext_setparam. + * + * I915_CONTEXT_CREATE_EXT_CLONE: + * This extension has been removed. On the off chance someone somewhere + * has attempted to use it, never re-use this extension number. + */ + __u64 extensions; +#define I915_CONTEXT_CREATE_EXT_SETPARAM 0 +#define I915_CONTEXT_CREATE_EXT_CLONE 1 +}; + +/** + * struct drm_i915_gem_context_param - Context parameter to set or query. + */ +struct drm_i915_gem_context_param { + /** @ctx_id: Context id */ + __u32 ctx_id; + + /** @size: Size of the parameter @value */ + __u32 size; + + /** @param: Parameter to set or query */ + __u64 param; +#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1 +/* I915_CONTEXT_PARAM_NO_ZEROMAP has been removed. On the off chance + * someone somewhere has attempted to use it, never re-use this context + * param number. + */ +#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2 +#define I915_CONTEXT_PARAM_GTT_SIZE 0x3 +#define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE 0x4 +#define I915_CONTEXT_PARAM_BANNABLE 0x5 +#define I915_CONTEXT_PARAM_PRIORITY 0x6 +#define I915_CONTEXT_MAX_USER_PRIORITY 1023 /* inclusive */ +#define I915_CONTEXT_DEFAULT_PRIORITY 0 +#define I915_CONTEXT_MIN_USER_PRIORITY -1023 /* inclusive */ + /* + * When using the following param, value should be a pointer to + * drm_i915_gem_context_param_sseu. + */ +#define I915_CONTEXT_PARAM_SSEU 0x7 + +/* + * Not all clients may want to attempt automatic recover of a context after + * a hang (for example, some clients may only submit very small incremental + * batches relying on known logical state of previous batches which will never + * recover correctly and each attempt will hang), and so would prefer that + * the context is forever banned instead. + * + * If set to false (0), after a reset, subsequent (and in flight) rendering + * from this context is discarded, and the client will need to create a new + * context to use instead. + * + * If set to true (1), the kernel will automatically attempt to recover the + * context by skipping the hanging batch and executing the next batch starting + * from the default context state (discarding the incomplete logical context + * state lost due to the reset). + * + * On creation, all new contexts are marked as recoverable. + */ +#define I915_CONTEXT_PARAM_RECOVERABLE 0x8 + + /* + * The id of the associated virtual memory address space (ppGTT) of + * this context. Can be retrieved and passed to another context + * (on the same fd) for both to use the same ppGTT and so share + * address layouts, and avoid reloading the page tables on context + * switches between themselves. + * + * See DRM_I915_GEM_VM_CREATE and DRM_I915_GEM_VM_DESTROY. + */ +#define I915_CONTEXT_PARAM_VM 0x9 + +/* + * I915_CONTEXT_PARAM_ENGINES: + * + * Bind this context to operate on this subset of available engines. Henceforth, + * the I915_EXEC_RING selector for DRM_IOCTL_I915_GEM_EXECBUFFER2 operates as + * an index into this array of engines; I915_EXEC_DEFAULT selecting engine[0] + * and upwards. Slots 0...N are filled in using the specified (class, instance). + * Use + * engine_class: I915_ENGINE_CLASS_INVALID, + * engine_instance: I915_ENGINE_CLASS_INVALID_NONE + * to specify a gap in the array that can be filled in later, e.g. by a + * virtual engine used for load balancing. + * + * Setting the number of engines bound to the context to 0, by passing a zero + * sized argument, will revert back to default settings. + * + * See struct i915_context_param_engines. + * + * Extensions: + * i915_context_engines_load_balance (I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE) + * i915_context_engines_bond (I915_CONTEXT_ENGINES_EXT_BOND) + * i915_context_engines_parallel_submit (I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT) + */ +#define I915_CONTEXT_PARAM_ENGINES 0xa + +/* + * I915_CONTEXT_PARAM_PERSISTENCE: + * + * Allow the context and active rendering to survive the process until + * completion. Persistence allows fire-and-forget clients to queue up a + * bunch of work, hand the output over to a display server and then quit. + * If the context is marked as not persistent, upon closing (either via + * an explicit DRM_I915_GEM_CONTEXT_DESTROY or implicitly from file closure + * or process termination), the context and any outstanding requests will be + * cancelled (and exported fences for cancelled requests marked as -EIO). + * + * By default, new contexts allow persistence. + */ +#define I915_CONTEXT_PARAM_PERSISTENCE 0xb + +/* This API has been removed. On the off chance someone somewhere has + * attempted to use it, never re-use this context param number. + */ +#define I915_CONTEXT_PARAM_RINGSIZE 0xc + +/* + * I915_CONTEXT_PARAM_PROTECTED_CONTENT: + * + * Mark that the context makes use of protected content, which will result + * in the context being invalidated when the protected content session is. + * Given that the protected content session is killed on suspend, the device + * is kept awake for the lifetime of a protected context, so the user should + * make sure to dispose of them once done. + * This flag can only be set at context creation time and, when set to true, + * must be preceded by an explicit setting of I915_CONTEXT_PARAM_RECOVERABLE + * to false. This flag can't be set to true in conjunction with setting the + * I915_CONTEXT_PARAM_BANNABLE flag to false. Creation example: + * + * .. code-block:: C + * + * struct drm_i915_gem_context_create_ext_setparam p_protected = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_PROTECTED_CONTENT, + * .value = 1, + * } + * }; + * struct drm_i915_gem_context_create_ext_setparam p_norecover = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * .next_extension = to_user_pointer(&p_protected), + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_RECOVERABLE, + * .value = 0, + * } + * }; + * struct drm_i915_gem_context_create_ext create = { + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + * .extensions = to_user_pointer(&p_norecover); + * }; + * + * ctx_id = gem_context_create_ext(drm_fd, &create); + * + * In addition to the normal failure cases, setting this flag during context + * creation can result in the following errors: + * + * -ENODEV: feature not available + * -EPERM: trying to mark a recoverable or not bannable context as protected + * -ENXIO: A dependency such as a component driver or firmware is not yet + * loaded so user space may need to attempt again. Depending on the + * device, this error may be reported if protected context creation is + * attempted very early after kernel start because the internal timeout + * waiting for such dependencies is not guaranteed to be larger than + * required (numbers differ depending on system and kernel config): + * - ADL/RPL: dependencies may take up to 3 seconds from kernel start + * while context creation internal timeout is 250 milisecs + * - MTL: dependencies may take up to 8 seconds from kernel start + * while context creation internal timeout is 250 milisecs + * NOTE: such dependencies happen once, so a subsequent call to create a + * protected context after a prior successful call will not experience + * such timeouts and will not return -ENXIO (unless the driver is reloaded, + * or, depending on the device, resumes from a suspended state). + * -EIO: The firmware did not succeed in creating the protected context. + */ +#define I915_CONTEXT_PARAM_PROTECTED_CONTENT 0xd + +/* + * I915_CONTEXT_PARAM_LOW_LATENCY: + * + * Mark this context as a low latency workload which requires aggressive GT + * frequency scaling. Use I915_PARAM_HAS_CONTEXT_FREQ_HINT to check if the kernel + * supports this per context flag. + */ +#define I915_CONTEXT_PARAM_LOW_LATENCY 0xe + +/* + * I915_CONTEXT_PARAM_CONTEXT_IMAGE: + * + * Allows userspace to provide own context images. + * + * Note that this is a debug API not available on production kernel builds. + */ +#define I915_CONTEXT_PARAM_CONTEXT_IMAGE 0xf +/* Must be kept compact -- no holes and well documented */ + + /** @value: Context parameter value to be set or queried */ + __u64 value; +}; + +/* + * Context SSEU programming + * + * It may be necessary for either functional or performance reason to configure + * a context to run with a reduced number of SSEU (where SSEU stands for Slice/ + * Sub-slice/EU). + * + * This is done by configuring SSEU configuration using the below + * @struct drm_i915_gem_context_param_sseu for every supported engine which + * userspace intends to use. + * + * Not all GPUs or engines support this functionality in which case an error + * code -ENODEV will be returned. + * + * Also, flexibility of possible SSEU configuration permutations varies between + * GPU generations and software imposed limitations. Requesting such a + * combination will return an error code of -EINVAL. + * + * NOTE: When perf/OA is active the context's SSEU configuration is ignored in + * favour of a single global setting. + */ +struct drm_i915_gem_context_param_sseu { + /* + * Engine class & instance to be configured or queried. + */ + struct i915_engine_class_instance engine; + + /* + * Unknown flags must be cleared to zero. + */ + __u32 flags; +#define I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX (1u << 0) + + /* + * Mask of slices to enable for the context. Valid values are a subset + * of the bitmask value returned for I915_PARAM_SLICE_MASK. + */ + __u64 slice_mask; + + /* + * Mask of subslices to enable for the context. Valid values are a + * subset of the bitmask value return by I915_PARAM_SUBSLICE_MASK. + */ + __u64 subslice_mask; + + /* + * Minimum/Maximum number of EUs to enable per subslice for the + * context. min_eus_per_subslice must be inferior or equal to + * max_eus_per_subslice. + */ + __u16 min_eus_per_subslice; + __u16 max_eus_per_subslice; + + /* + * Unused for now. Must be cleared to zero. + */ + __u32 rsvd; +}; + +/** + * DOC: Virtual Engine uAPI + * + * Virtual engine is a concept where userspace is able to configure a set of + * physical engines, submit a batch buffer, and let the driver execute it on any + * engine from the set as it sees fit. + * + * This is primarily useful on parts which have multiple instances of a same + * class engine, like for example GT3+ Skylake parts with their two VCS engines. + * + * For instance userspace can enumerate all engines of a certain class using the + * previously described `Engine Discovery uAPI`_. After that userspace can + * create a GEM context with a placeholder slot for the virtual engine (using + * `I915_ENGINE_CLASS_INVALID` and `I915_ENGINE_CLASS_INVALID_NONE` for class + * and instance respectively) and finally using the + * `I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE` extension place a virtual engine in + * the same reserved slot. + * + * Example of creating a virtual engine and submitting a batch buffer to it: + * + * .. code-block:: C + * + * I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(virtual, 2) = { + * .base.name = I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE, + * .engine_index = 0, // Place this virtual engine into engine map slot 0 + * .num_siblings = 2, + * .engines = { { I915_ENGINE_CLASS_VIDEO, 0 }, + * { I915_ENGINE_CLASS_VIDEO, 1 }, }, + * }; + * I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 1) = { + * .engines = { { I915_ENGINE_CLASS_INVALID, + * I915_ENGINE_CLASS_INVALID_NONE } }, + * .extensions = to_user_pointer(&virtual), // Chains after load_balance extension + * }; + * struct drm_i915_gem_context_create_ext_setparam p_engines = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_ENGINES, + * .value = to_user_pointer(&engines), + * .size = sizeof(engines), + * }, + * }; + * struct drm_i915_gem_context_create_ext create = { + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + * .extensions = to_user_pointer(&p_engines); + * }; + * + * ctx_id = gem_context_create_ext(drm_fd, &create); + * + * // Now we have created a GEM context with its engine map containing a + * // single virtual engine. Submissions to this slot can go either to + * // vcs0 or vcs1, depending on the load balancing algorithm used inside + * // the driver. The load balancing is dynamic from one batch buffer to + * // another and transparent to userspace. + * + * ... + * execbuf.rsvd1 = ctx_id; + * execbuf.flags = 0; // Submits to index 0 which is the virtual engine + * gem_execbuf(drm_fd, &execbuf); + */ + +/* + * i915_context_engines_load_balance: + * + * Enable load balancing across this set of engines. + * + * Into the I915_EXEC_DEFAULT slot [0], a virtual engine is created that when + * used will proxy the execbuffer request onto one of the set of engines + * in such a way as to distribute the load evenly across the set. + * + * The set of engines must be compatible (e.g. the same HW class) as they + * will share the same logical GPU context and ring. + * + * To intermix rendering with the virtual engine and direct rendering onto + * the backing engines (bypassing the load balancing proxy), the context must + * be defined to use a single timeline for all engines. + */ +struct i915_context_engines_load_balance { + struct i915_user_extension base; + + __u16 engine_index; + __u16 num_siblings; + __u32 flags; /* all undefined flags must be zero */ + + __u64 mbz64; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(name__, N__) struct { \ + struct i915_user_extension base; \ + __u16 engine_index; \ + __u16 num_siblings; \ + __u32 flags; \ + __u64 mbz64; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/* + * i915_context_engines_bond: + * + * Constructed bonded pairs for execution within a virtual engine. + * + * All engines are equal, but some are more equal than others. Given + * the distribution of resources in the HW, it may be preferable to run + * a request on a given subset of engines in parallel to a request on a + * specific engine. We enable this selection of engines within a virtual + * engine by specifying bonding pairs, for any given master engine we will + * only execute on one of the corresponding siblings within the virtual engine. + * + * To execute a request in parallel on the master engine and a sibling requires + * coordination with a I915_EXEC_FENCE_SUBMIT. + */ +struct i915_context_engines_bond { + struct i915_user_extension base; + + struct i915_engine_class_instance master; + + __u16 virtual_index; /* index of virtual engine in ctx->engines[] */ + __u16 num_bonds; + + __u64 flags; /* all undefined flags must be zero */ + __u64 mbz64[4]; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_BOND(name__, N__) struct { \ + struct i915_user_extension base; \ + struct i915_engine_class_instance master; \ + __u16 virtual_index; \ + __u16 num_bonds; \ + __u64 flags; \ + __u64 mbz64[4]; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/** + * struct i915_context_engines_parallel_submit - Configure engine for + * parallel submission. + * + * Setup a slot in the context engine map to allow multiple BBs to be submitted + * in a single execbuf IOCTL. Those BBs will then be scheduled to run on the GPU + * in parallel. Multiple hardware contexts are created internally in the i915 to + * run these BBs. Once a slot is configured for N BBs only N BBs can be + * submitted in each execbuf IOCTL and this is implicit behavior e.g. The user + * doesn't tell the execbuf IOCTL there are N BBs, the execbuf IOCTL knows how + * many BBs there are based on the slot's configuration. The N BBs are the last + * N buffer objects or first N if I915_EXEC_BATCH_FIRST is set. + * + * The default placement behavior is to create implicit bonds between each + * context if each context maps to more than 1 physical engine (e.g. context is + * a virtual engine). Also we only allow contexts of same engine class and these + * contexts must be in logically contiguous order. Examples of the placement + * behavior are described below. Lastly, the default is to not allow BBs to be + * preempted mid-batch. Rather insert coordinated preemption points on all + * hardware contexts between each set of BBs. Flags could be added in the future + * to change both of these default behaviors. + * + * Returns -EINVAL if hardware context placement configuration is invalid or if + * the placement configuration isn't supported on the platform / submission + * interface. + * Returns -ENODEV if extension isn't supported on the platform / submission + * interface. + * + * .. code-block:: none + * + * Examples syntax: + * CS[X] = generic engine of same class, logical instance X + * INVALID = I915_ENGINE_CLASS_INVALID, I915_ENGINE_CLASS_INVALID_NONE + * + * Example 1 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=1, + * engines=CS[0],CS[1]) + * + * Results in the following valid placement: + * CS[0], CS[1] + * + * Example 2 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=2, + * engines=CS[0],CS[2],CS[1],CS[3]) + * + * Results in the following valid placements: + * CS[0], CS[1] + * CS[2], CS[3] + * + * This can be thought of as two virtual engines, each containing two + * engines thereby making a 2D array. However, there are bonds tying the + * entries together and placing restrictions on how they can be scheduled. + * Specifically, the scheduler can choose only vertical columns from the 2D + * array. That is, CS[0] is bonded to CS[1] and CS[2] to CS[3]. So if the + * scheduler wants to submit to CS[0], it must also choose CS[1] and vice + * versa. Same for CS[2] requires also using CS[3]. + * VE[0] = CS[0], CS[2] + * VE[1] = CS[1], CS[3] + * + * Example 3 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=2, + * engines=CS[0],CS[1],CS[1],CS[3]) + * + * Results in the following valid and invalid placements: + * CS[0], CS[1] + * CS[1], CS[3] - Not logically contiguous, return -EINVAL + */ +struct i915_context_engines_parallel_submit { + /** + * @base: base user extension. + */ + struct i915_user_extension base; + + /** + * @engine_index: slot for parallel engine + */ + __u16 engine_index; + + /** + * @width: number of contexts per parallel engine or in other words the + * number of batches in each submission + */ + __u16 width; + + /** + * @num_siblings: number of siblings per context or in other words the + * number of possible placements for each submission + */ + __u16 num_siblings; + + /** + * @mbz16: reserved for future use; must be zero + */ + __u16 mbz16; + + /** + * @flags: all undefined flags must be zero, currently not defined flags + */ + __u64 flags; + + /** + * @mbz64: reserved for future use; must be zero + */ + __u64 mbz64[3]; + + /** + * @engines: 2-d array of engine instances to configure parallel engine + * + * length = width (i) * num_siblings (j) + * index = j + i * num_siblings + */ + struct i915_engine_class_instance engines[]; + +} __packed; + +#define I915_DEFINE_CONTEXT_ENGINES_PARALLEL_SUBMIT(name__, N__) struct { \ + struct i915_user_extension base; \ + __u16 engine_index; \ + __u16 width; \ + __u16 num_siblings; \ + __u16 mbz16; \ + __u64 flags; \ + __u64 mbz64[3]; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/** + * DOC: Context Engine Map uAPI + * + * Context engine map is a new way of addressing engines when submitting batch- + * buffers, replacing the existing way of using identifiers like `I915_EXEC_BLT` + * inside the flags field of `struct drm_i915_gem_execbuffer2`. + * + * To use it created GEM contexts need to be configured with a list of engines + * the user is intending to submit to. This is accomplished using the + * `I915_CONTEXT_PARAM_ENGINES` parameter and `struct + * i915_context_param_engines`. + * + * For such contexts the `I915_EXEC_RING_MASK` field becomes an index into the + * configured map. + * + * Example of creating such context and submitting against it: + * + * .. code-block:: C + * + * I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 2) = { + * .engines = { { I915_ENGINE_CLASS_RENDER, 0 }, + * { I915_ENGINE_CLASS_COPY, 0 } } + * }; + * struct drm_i915_gem_context_create_ext_setparam p_engines = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_ENGINES, + * .value = to_user_pointer(&engines), + * .size = sizeof(engines), + * }, + * }; + * struct drm_i915_gem_context_create_ext create = { + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + * .extensions = to_user_pointer(&p_engines); + * }; + * + * ctx_id = gem_context_create_ext(drm_fd, &create); + * + * // We have now created a GEM context with two engines in the map: + * // Index 0 points to rcs0 while index 1 points to bcs0. Other engines + * // will not be accessible from this context. + * + * ... + * execbuf.rsvd1 = ctx_id; + * execbuf.flags = 0; // Submits to index 0, which is rcs0 for this context + * gem_execbuf(drm_fd, &execbuf); + * + * ... + * execbuf.rsvd1 = ctx_id; + * execbuf.flags = 1; // Submits to index 0, which is bcs0 for this context + * gem_execbuf(drm_fd, &execbuf); + */ + +struct i915_context_param_engines { + __u64 extensions; /* linked chain of extension blocks, 0 terminates */ +#define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0 /* see i915_context_engines_load_balance */ +#define I915_CONTEXT_ENGINES_EXT_BOND 1 /* see i915_context_engines_bond */ +#define I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT 2 /* see i915_context_engines_parallel_submit */ + struct i915_engine_class_instance engines[]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_PARAM_ENGINES(name__, N__) struct { \ + __u64 extensions; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +struct i915_gem_context_param_context_image { + /** @engine: Engine class & instance to be configured. */ + struct i915_engine_class_instance engine; + + /** @flags: One of the supported flags or zero. */ + __u32 flags; +#define I915_CONTEXT_IMAGE_FLAG_ENGINE_INDEX (1u << 0) + + /** @size: Size of the image blob pointed to by @image. */ + __u32 size; + + /** @mbz: Must be zero. */ + __u32 mbz; + + /** @image: Userspace memory containing the context image. */ + __u64 image; +} __attribute__((packed)); + +/** + * struct drm_i915_gem_context_create_ext_setparam - Context parameter + * to set or query during context creation. + */ +struct drm_i915_gem_context_create_ext_setparam { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + + /** + * @param: Context parameter to set or query. + * See struct drm_i915_gem_context_param. + */ + struct drm_i915_gem_context_param param; +}; + +struct drm_i915_gem_context_destroy { + __u32 ctx_id; + __u32 pad; +}; + +/** + * struct drm_i915_gem_vm_control - Structure to create or destroy VM. + * + * DRM_I915_GEM_VM_CREATE - + * + * Create a new virtual memory address space (ppGTT) for use within a context + * on the same file. Extensions can be provided to configure exactly how the + * address space is setup upon creation. + * + * The id of new VM (bound to the fd) for use with I915_CONTEXT_PARAM_VM is + * returned in the outparam @id. + * + * An extension chain maybe provided, starting with @extensions, and terminated + * by the @next_extension being 0. Currently, no extensions are defined. + * + * DRM_I915_GEM_VM_DESTROY - + * + * Destroys a previously created VM id, specified in @vm_id. + * + * No extensions or flags are allowed currently, and so must be zero. + */ +struct drm_i915_gem_vm_control { + /** @extensions: Zero-terminated chain of extensions. */ + __u64 extensions; + + /** @flags: reserved for future usage, currently MBZ */ + __u32 flags; + + /** @vm_id: Id of the VM created or to be destroyed */ + __u32 vm_id; +}; + +struct drm_i915_reg_read { + /* + * Register offset. + * For 64bit wide registers where the upper 32bits don't immediately + * follow the lower 32bits, the offset of the lower 32bits must + * be specified + */ + __u64 offset; +#define I915_REG_READ_8B_WA (1ul << 0) + + __u64 val; /* Return value */ +}; + +/* Known registers: + * + * Render engine timestamp - 0x2358 + 64bit - gen7+ + * - Note this register returns an invalid value if using the default + * single instruction 8byte read, in order to workaround that pass + * flag I915_REG_READ_8B_WA in offset field. + * + */ + +/* + * struct drm_i915_reset_stats - Return global reset and other context stats + * + * Driver keeps few stats for each contexts and also global reset count. + * This struct can be used to query those stats. + */ +struct drm_i915_reset_stats { + /** @ctx_id: ID of the requested context */ + __u32 ctx_id; + + /** @flags: MBZ */ + __u32 flags; + + /** @reset_count: All resets since boot/module reload, for all contexts */ + __u32 reset_count; + + /** @batch_active: Number of batches lost when active in GPU, for this context */ + __u32 batch_active; + + /** @batch_pending: Number of batches lost pending for execution, for this context */ + __u32 batch_pending; + + /** @pad: MBZ */ + __u32 pad; +}; + +/** + * struct drm_i915_gem_userptr - Create GEM object from user allocated memory. + * + * Userptr objects have several restrictions on what ioctls can be used with the + * object handle. + */ +struct drm_i915_gem_userptr { + /** + * @user_ptr: The pointer to the allocated memory. + * + * Needs to be aligned to PAGE_SIZE. + */ + __u64 user_ptr; + + /** + * @user_size: + * + * The size in bytes for the allocated memory. This will also become the + * object size. + * + * Needs to be aligned to PAGE_SIZE, and should be at least PAGE_SIZE, + * or larger. + */ + __u64 user_size; + + /** + * @flags: + * + * Supported flags: + * + * I915_USERPTR_READ_ONLY: + * + * Mark the object as readonly, this also means GPU access can only be + * readonly. This is only supported on HW which supports readonly access + * through the GTT. If the HW can't support readonly access, an error is + * returned. + * + * I915_USERPTR_PROBE: + * + * Probe the provided @user_ptr range and validate that the @user_ptr is + * indeed pointing to normal memory and that the range is also valid. + * For example if some garbage address is given to the kernel, then this + * should complain. + * + * Returns -EFAULT if the probe failed. + * + * Note that this doesn't populate the backing pages, and also doesn't + * guarantee that the object will remain valid when the object is + * eventually used. + * + * The kernel supports this feature if I915_PARAM_HAS_USERPTR_PROBE + * returns a non-zero value. + * + * I915_USERPTR_UNSYNCHRONIZED: + * + * NOT USED. Setting this flag will result in an error. + */ + __u32 flags; +#define I915_USERPTR_READ_ONLY 0x1 +#define I915_USERPTR_PROBE 0x2 +#define I915_USERPTR_UNSYNCHRONIZED 0x80000000 + /** + * @handle: Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; +}; + +enum drm_i915_oa_format { + I915_OA_FORMAT_A13 = 1, /* HSW only */ + I915_OA_FORMAT_A29, /* HSW only */ + I915_OA_FORMAT_A13_B8_C8, /* HSW only */ + I915_OA_FORMAT_B4_C8, /* HSW only */ + I915_OA_FORMAT_A45_B8_C8, /* HSW only */ + I915_OA_FORMAT_B4_C8_A16, /* HSW only */ + I915_OA_FORMAT_C4_B8, /* HSW+ */ + + /* Gen8+ */ + I915_OA_FORMAT_A12, + I915_OA_FORMAT_A12_B8_C8, + I915_OA_FORMAT_A32u40_A4u32_B8_C8, + + /* DG2 */ + I915_OAR_FORMAT_A32u40_A4u32_B8_C8, + I915_OA_FORMAT_A24u40_A14u32_B8_C8, + + /* MTL OAM */ + I915_OAM_FORMAT_MPEC8u64_B8_C8, + I915_OAM_FORMAT_MPEC8u32_B8_C8, + + I915_OA_FORMAT_MAX /* non-ABI */ +}; + +enum drm_i915_perf_property_id { + /** + * Open the stream for a specific context handle (as used with + * execbuffer2). A stream opened for a specific context this way + * won't typically require root privileges. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_CTX_HANDLE = 1, + + /** + * A value of 1 requests the inclusion of raw OA unit reports as + * part of stream samples. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_SAMPLE_OA, + + /** + * The value specifies which set of OA unit metrics should be + * configured, defining the contents of any OA unit reports. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_OA_METRICS_SET, + + /** + * The value specifies the size and layout of OA unit reports. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_OA_FORMAT, + + /** + * Specifying this property implicitly requests periodic OA unit + * sampling and (at least on Haswell) the sampling frequency is derived + * from this exponent as follows: + * + * 80ns * 2^(period_exponent + 1) + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_OA_EXPONENT, + + /** + * Specifying this property is only valid when specify a context to + * filter with DRM_I915_PERF_PROP_CTX_HANDLE. Specifying this property + * will hold preemption of the particular context we want to gather + * performance data about. The execbuf2 submissions must include a + * drm_i915_gem_execbuffer_ext_perf parameter for this to apply. + * + * This property is available in perf revision 3. + */ + DRM_I915_PERF_PROP_HOLD_PREEMPTION, + + /** + * Specifying this pins all contexts to the specified SSEU power + * configuration for the duration of the recording. + * + * This parameter's value is a pointer to a struct + * drm_i915_gem_context_param_sseu. + * + * This property is available in perf revision 4. + */ + DRM_I915_PERF_PROP_GLOBAL_SSEU, + + /** + * This optional parameter specifies the timer interval in nanoseconds + * at which the i915 driver will check the OA buffer for available data. + * Minimum allowed value is 100 microseconds. A default value is used by + * the driver if this parameter is not specified. Note that larger timer + * values will reduce cpu consumption during OA perf captures. However, + * excessively large values would potentially result in OA buffer + * overwrites as captures reach end of the OA buffer. + * + * This property is available in perf revision 5. + */ + DRM_I915_PERF_PROP_POLL_OA_PERIOD, + + /** + * Multiple engines may be mapped to the same OA unit. The OA unit is + * identified by class:instance of any engine mapped to it. + * + * This parameter specifies the engine class and must be passed along + * with DRM_I915_PERF_PROP_OA_ENGINE_INSTANCE. + * + * This property is available in perf revision 6. + */ + DRM_I915_PERF_PROP_OA_ENGINE_CLASS, + + /** + * This parameter specifies the engine instance and must be passed along + * with DRM_I915_PERF_PROP_OA_ENGINE_CLASS. + * + * This property is available in perf revision 6. + */ + DRM_I915_PERF_PROP_OA_ENGINE_INSTANCE, + + DRM_I915_PERF_PROP_MAX /* non-ABI */ +}; + +struct drm_i915_perf_open_param { + __u32 flags; +#define I915_PERF_FLAG_FD_CLOEXEC (1<<0) +#define I915_PERF_FLAG_FD_NONBLOCK (1<<1) +#define I915_PERF_FLAG_DISABLED (1<<2) + + /** The number of u64 (id, value) pairs */ + __u32 num_properties; + + /** + * Pointer to array of u64 (id, value) pairs configuring the stream + * to open. + */ + __u64 properties_ptr; +}; + +/* + * Enable data capture for a stream that was either opened in a disabled state + * via I915_PERF_FLAG_DISABLED or was later disabled via + * I915_PERF_IOCTL_DISABLE. + * + * It is intended to be cheaper to disable and enable a stream than it may be + * to close and re-open a stream with the same configuration. + * + * It's undefined whether any pending data for the stream will be lost. + * + * This ioctl is available in perf revision 1. + */ +#define I915_PERF_IOCTL_ENABLE _IO('i', 0x0) + +/* + * Disable data capture for a stream. + * + * It is an error to try and read a stream that is disabled. + * + * This ioctl is available in perf revision 1. + */ +#define I915_PERF_IOCTL_DISABLE _IO('i', 0x1) + +/* + * Change metrics_set captured by a stream. + * + * If the stream is bound to a specific context, the configuration change + * will performed inline with that context such that it takes effect before + * the next execbuf submission. + * + * Returns the previously bound metrics set id, or a negative error code. + * + * This ioctl is available in perf revision 2. + */ +#define I915_PERF_IOCTL_CONFIG _IO('i', 0x2) + +/* + * Common to all i915 perf records + */ +struct drm_i915_perf_record_header { + __u32 type; + __u16 pad; + __u16 size; +}; + +enum drm_i915_perf_record_type { + + /** + * Samples are the work horse record type whose contents are extensible + * and defined when opening an i915 perf stream based on the given + * properties. + * + * Boolean properties following the naming convention + * DRM_I915_PERF_SAMPLE_xyz_PROP request the inclusion of 'xyz' data in + * every sample. + * + * The order of these sample properties given by userspace has no + * affect on the ordering of data within a sample. The order is + * documented here. + * + * struct { + * struct drm_i915_perf_record_header header; + * + * { u32 oa_report[]; } && DRM_I915_PERF_PROP_SAMPLE_OA + * }; + */ + DRM_I915_PERF_RECORD_SAMPLE = 1, + + /* + * Indicates that one or more OA reports were not written by the + * hardware. This can happen for example if an MI_REPORT_PERF_COUNT + * command collides with periodic sampling - which would be more likely + * at higher sampling frequencies. + */ + DRM_I915_PERF_RECORD_OA_REPORT_LOST = 2, + + /** + * An error occurred that resulted in all pending OA reports being lost. + */ + DRM_I915_PERF_RECORD_OA_BUFFER_LOST = 3, + + DRM_I915_PERF_RECORD_MAX /* non-ABI */ +}; + +/** + * struct drm_i915_perf_oa_config + * + * Structure to upload perf dynamic configuration into the kernel. + */ +struct drm_i915_perf_oa_config { + /** + * @uuid: + * + * String formatted like "%\08x-%\04x-%\04x-%\04x-%\012x" + */ + char uuid[36]; + + /** + * @n_mux_regs: + * + * Number of mux regs in &mux_regs_ptr. + */ + __u32 n_mux_regs; + + /** + * @n_boolean_regs: + * + * Number of boolean regs in &boolean_regs_ptr. + */ + __u32 n_boolean_regs; + + /** + * @n_flex_regs: + * + * Number of flex regs in &flex_regs_ptr. + */ + __u32 n_flex_regs; + + /** + * @mux_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_mux_regs). + */ + __u64 mux_regs_ptr; + + /** + * @boolean_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_boolean_regs). + */ + __u64 boolean_regs_ptr; + + /** + * @flex_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_flex_regs). + */ + __u64 flex_regs_ptr; +}; + +/** + * struct drm_i915_query_item - An individual query for the kernel to process. + * + * The behaviour is determined by the @query_id. Note that exactly what + * @data_ptr is also depends on the specific @query_id. + */ +struct drm_i915_query_item { + /** + * @query_id: + * + * The id for this query. Currently accepted query IDs are: + * - %DRM_I915_QUERY_TOPOLOGY_INFO (see struct drm_i915_query_topology_info) + * - %DRM_I915_QUERY_ENGINE_INFO (see struct drm_i915_engine_info) + * - %DRM_I915_QUERY_PERF_CONFIG (see struct drm_i915_query_perf_config) + * - %DRM_I915_QUERY_MEMORY_REGIONS (see struct drm_i915_query_memory_regions) + * - %DRM_I915_QUERY_HWCONFIG_BLOB (see `GuC HWCONFIG blob uAPI`) + * - %DRM_I915_QUERY_GEOMETRY_SUBSLICES (see struct drm_i915_query_topology_info) + * - %DRM_I915_QUERY_GUC_SUBMISSION_VERSION (see struct drm_i915_query_guc_submission_version) + */ + __u64 query_id; +#define DRM_I915_QUERY_TOPOLOGY_INFO 1 +#define DRM_I915_QUERY_ENGINE_INFO 2 +#define DRM_I915_QUERY_PERF_CONFIG 3 +#define DRM_I915_QUERY_MEMORY_REGIONS 4 +#define DRM_I915_QUERY_HWCONFIG_BLOB 5 +#define DRM_I915_QUERY_GEOMETRY_SUBSLICES 6 +#define DRM_I915_QUERY_GUC_SUBMISSION_VERSION 7 +/* Must be kept compact -- no holes and well documented */ + + /** + * @length: + * + * When set to zero by userspace, this is filled with the size of the + * data to be written at the @data_ptr pointer. The kernel sets this + * value to a negative value to signal an error on a particular query + * item. + */ + __s32 length; + + /** + * @flags: + * + * When &query_id == %DRM_I915_QUERY_TOPOLOGY_INFO, must be 0. + * + * When &query_id == %DRM_I915_QUERY_PERF_CONFIG, must be one of the + * following: + * + * - %DRM_I915_QUERY_PERF_CONFIG_LIST + * - %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID + * - %DRM_I915_QUERY_PERF_CONFIG_FOR_UUID + * + * When &query_id == %DRM_I915_QUERY_GEOMETRY_SUBSLICES must contain + * a struct i915_engine_class_instance that references a render engine. + */ + __u32 flags; +#define DRM_I915_QUERY_PERF_CONFIG_LIST 1 +#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID 2 +#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID 3 + + /** + * @data_ptr: + * + * Data will be written at the location pointed by @data_ptr when the + * value of @length matches the length of the data to be written by the + * kernel. + */ + __u64 data_ptr; +}; + +/** + * struct drm_i915_query - Supply an array of struct drm_i915_query_item for the + * kernel to fill out. + * + * Note that this is generally a two step process for each struct + * drm_i915_query_item in the array: + * + * 1. Call the DRM_IOCTL_I915_QUERY, giving it our array of struct + * drm_i915_query_item, with &drm_i915_query_item.length set to zero. The + * kernel will then fill in the size, in bytes, which tells userspace how + * memory it needs to allocate for the blob(say for an array of properties). + * + * 2. Next we call DRM_IOCTL_I915_QUERY again, this time with the + * &drm_i915_query_item.data_ptr equal to our newly allocated blob. Note that + * the &drm_i915_query_item.length should still be the same as what the + * kernel previously set. At this point the kernel can fill in the blob. + * + * Note that for some query items it can make sense for userspace to just pass + * in a buffer/blob equal to or larger than the required size. In this case only + * a single ioctl call is needed. For some smaller query items this can work + * quite well. + * + */ +struct drm_i915_query { + /** @num_items: The number of elements in the @items_ptr array */ + __u32 num_items; + + /** + * @flags: Unused for now. Must be cleared to zero. + */ + __u32 flags; + + /** + * @items_ptr: + * + * Pointer to an array of struct drm_i915_query_item. The number of + * array elements is @num_items. + */ + __u64 items_ptr; +}; + +/** + * struct drm_i915_query_topology_info + * + * Describes slice/subslice/EU information queried by + * %DRM_I915_QUERY_TOPOLOGY_INFO + */ +struct drm_i915_query_topology_info { + /** + * @flags: + * + * Unused for now. Must be cleared to zero. + */ + __u16 flags; + + /** + * @max_slices: + * + * The number of bits used to express the slice mask. + */ + __u16 max_slices; + + /** + * @max_subslices: + * + * The number of bits used to express the subslice mask. + */ + __u16 max_subslices; + + /** + * @max_eus_per_subslice: + * + * The number of bits in the EU mask that correspond to a single + * subslice's EUs. + */ + __u16 max_eus_per_subslice; + + /** + * @subslice_offset: + * + * Offset in data[] at which the subslice masks are stored. + */ + __u16 subslice_offset; + + /** + * @subslice_stride: + * + * Stride at which each of the subslice masks for each slice are + * stored. + */ + __u16 subslice_stride; + + /** + * @eu_offset: + * + * Offset in data[] at which the EU masks are stored. + */ + __u16 eu_offset; + + /** + * @eu_stride: + * + * Stride at which each of the EU masks for each subslice are stored. + */ + __u16 eu_stride; + + /** + * @data: + * + * Contains 3 pieces of information : + * + * - The slice mask with one bit per slice telling whether a slice is + * available. The availability of slice X can be queried with the + * following formula : + * + * .. code:: c + * + * (data[X / 8] >> (X % 8)) & 1 + * + * Starting with Xe_HP platforms, Intel hardware no longer has + * traditional slices so i915 will always report a single slice + * (hardcoded slicemask = 0x1) which contains all of the platform's + * subslices. I.e., the mask here does not reflect any of the newer + * hardware concepts such as "gslices" or "cslices" since userspace + * is capable of inferring those from the subslice mask. + * + * - The subslice mask for each slice with one bit per subslice telling + * whether a subslice is available. Starting with Gen12 we use the + * term "subslice" to refer to what the hardware documentation + * describes as a "dual-subslices." The availability of subslice Y + * in slice X can be queried with the following formula : + * + * .. code:: c + * + * (data[subslice_offset + X * subslice_stride + Y / 8] >> (Y % 8)) & 1 + * + * - The EU mask for each subslice in each slice, with one bit per EU + * telling whether an EU is available. The availability of EU Z in + * subslice Y in slice X can be queried with the following formula : + * + * .. code:: c + * + * (data[eu_offset + + * (X * max_subslices + Y) * eu_stride + + * Z / 8 + * ] >> (Z % 8)) & 1 + */ + __u8 data[]; +}; + +/** + * DOC: Engine Discovery uAPI + * + * Engine discovery uAPI is a way of enumerating physical engines present in a + * GPU associated with an open i915 DRM file descriptor. This supersedes the old + * way of using `DRM_IOCTL_I915_GETPARAM` and engine identifiers like + * `I915_PARAM_HAS_BLT`. + * + * The need for this interface came starting with Icelake and newer GPUs, which + * started to establish a pattern of having multiple engines of a same class, + * where not all instances were always completely functionally equivalent. + * + * Entry point for this uapi is `DRM_IOCTL_I915_QUERY` with the + * `DRM_I915_QUERY_ENGINE_INFO` as the queried item id. + * + * Example for getting the list of engines: + * + * .. code-block:: C + * + * struct drm_i915_query_engine_info *info; + * struct drm_i915_query_item item = { + * .query_id = DRM_I915_QUERY_ENGINE_INFO; + * }; + * struct drm_i915_query query = { + * .num_items = 1, + * .items_ptr = (uintptr_t)&item, + * }; + * int err, i; + * + * // First query the size of the blob we need, this needs to be large + * // enough to hold our array of engines. The kernel will fill out the + * // item.length for us, which is the number of bytes we need. + * // + * // Alternatively a large buffer can be allocated straightaway enabling + * // querying in one pass, in which case item.length should contain the + * // length of the provided buffer. + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * info = calloc(1, item.length); + * // Now that we allocated the required number of bytes, we call the ioctl + * // again, this time with the data_ptr pointing to our newly allocated + * // blob, which the kernel can then populate with info on all engines. + * item.data_ptr = (uintptr_t)&info; + * + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * // We can now access each engine in the array + * for (i = 0; i < info->num_engines; i++) { + * struct drm_i915_engine_info einfo = info->engines[i]; + * u16 class = einfo.engine.class; + * u16 instance = einfo.engine.instance; + * .... + * } + * + * free(info); + * + * Each of the enumerated engines, apart from being defined by its class and + * instance (see `struct i915_engine_class_instance`), also can have flags and + * capabilities defined as documented in i915_drm.h. + * + * For instance video engines which support HEVC encoding will have the + * `I915_VIDEO_CLASS_CAPABILITY_HEVC` capability bit set. + * + * Engine discovery only fully comes to its own when combined with the new way + * of addressing engines when submitting batch buffers using contexts with + * engine maps configured. + */ + +/** + * struct drm_i915_engine_info + * + * Describes one engine and its capabilities as known to the driver. + */ +struct drm_i915_engine_info { + /** @engine: Engine class and instance. */ + struct i915_engine_class_instance engine; + + /** @rsvd0: Reserved field. */ + __u32 rsvd0; + + /** @flags: Engine flags. */ + __u64 flags; +#define I915_ENGINE_INFO_HAS_LOGICAL_INSTANCE (1 << 0) + + /** @capabilities: Capabilities of this engine. */ + __u64 capabilities; +#define I915_VIDEO_CLASS_CAPABILITY_HEVC (1 << 0) +#define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC (1 << 1) + + /** @logical_instance: Logical instance of engine */ + __u16 logical_instance; + + /** @rsvd1: Reserved fields. */ + __u16 rsvd1[3]; + /** @rsvd2: Reserved fields. */ + __u64 rsvd2[3]; +}; + +/** + * struct drm_i915_query_engine_info + * + * Engine info query enumerates all engines known to the driver by filling in + * an array of struct drm_i915_engine_info structures. + */ +struct drm_i915_query_engine_info { + /** @num_engines: Number of struct drm_i915_engine_info structs following. */ + __u32 num_engines; + + /** @rsvd: MBZ */ + __u32 rsvd[3]; + + /** @engines: Marker for drm_i915_engine_info structures. */ + struct drm_i915_engine_info engines[]; +}; + +/** + * struct drm_i915_query_perf_config + * + * Data written by the kernel with query %DRM_I915_QUERY_PERF_CONFIG and + * %DRM_I915_QUERY_GEOMETRY_SUBSLICES. + */ +struct drm_i915_query_perf_config { + union { + /** + * @n_configs: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets this fields to + * the number of configurations available. + */ + __u64 n_configs; + + /** + * @config: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID, i915 will use the + * value in this field as configuration identifier to decide + * what data to write into config_ptr. + */ + __u64 config; + + /** + * @uuid: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID, i915 will use the + * value in this field as configuration identifier to decide + * what data to write into config_ptr. + * + * String formatted like "%08x-%04x-%04x-%04x-%012x" + */ + char uuid[36]; + }; + + /** + * @flags: + * + * Unused for now. Must be cleared to zero. + */ + __u32 flags; + + /** + * @data: + * + * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_LIST, + * i915 will write an array of __u64 of configuration identifiers. + * + * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_DATA, + * i915 will write a struct drm_i915_perf_oa_config. If the following + * fields of struct drm_i915_perf_oa_config are not set to 0, i915 will + * write into the associated pointers the values of submitted when the + * configuration was created : + * + * - &drm_i915_perf_oa_config.n_mux_regs + * - &drm_i915_perf_oa_config.n_boolean_regs + * - &drm_i915_perf_oa_config.n_flex_regs + */ + __u8 data[]; +}; + +/** + * enum drm_i915_gem_memory_class - Supported memory classes + */ +enum drm_i915_gem_memory_class { + /** @I915_MEMORY_CLASS_SYSTEM: System memory */ + I915_MEMORY_CLASS_SYSTEM = 0, + /** @I915_MEMORY_CLASS_DEVICE: Device local-memory */ + I915_MEMORY_CLASS_DEVICE, +}; + +/** + * struct drm_i915_gem_memory_class_instance - Identify particular memory region + */ +struct drm_i915_gem_memory_class_instance { + /** @memory_class: See enum drm_i915_gem_memory_class */ + __u16 memory_class; + + /** @memory_instance: Which instance */ + __u16 memory_instance; +}; + +/** + * struct drm_i915_memory_region_info - Describes one region as known to the + * driver. + * + * Note this is using both struct drm_i915_query_item and struct drm_i915_query. + * For this new query we are adding the new query id DRM_I915_QUERY_MEMORY_REGIONS + * at &drm_i915_query_item.query_id. + */ +struct drm_i915_memory_region_info { + /** @region: The class:instance pair encoding */ + struct drm_i915_gem_memory_class_instance region; + + /** @rsvd0: MBZ */ + __u32 rsvd0; + + /** + * @probed_size: Memory probed by the driver + * + * Note that it should not be possible to ever encounter a zero value + * here, also note that no current region type will ever return -1 here. + * Although for future region types, this might be a possibility. The + * same applies to the other size fields. + */ + __u64 probed_size; + + /** + * @unallocated_size: Estimate of memory remaining + * + * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable accounting. + * Without this (or if this is an older kernel) the value here will + * always equal the @probed_size. Note this is only currently tracked + * for I915_MEMORY_CLASS_DEVICE regions (for other types the value here + * will always equal the @probed_size). + */ + __u64 unallocated_size; + + union { + /** @rsvd1: MBZ */ + __u64 rsvd1[8]; + struct { + /** + * @probed_cpu_visible_size: Memory probed by the driver + * that is CPU accessible. + * + * This will be always be <= @probed_size, and the + * remainder (if there is any) will not be CPU + * accessible. + * + * On systems without small BAR, the @probed_size will + * always equal the @probed_cpu_visible_size, since all + * of it will be CPU accessible. + * + * Note this is only tracked for + * I915_MEMORY_CLASS_DEVICE regions (for other types the + * value here will always equal the @probed_size). + * + * Note that if the value returned here is zero, then + * this must be an old kernel which lacks the relevant + * small-bar uAPI support (including + * I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS), but on + * such systems we should never actually end up with a + * small BAR configuration, assuming we are able to load + * the kernel module. Hence it should be safe to treat + * this the same as when @probed_cpu_visible_size == + * @probed_size. + */ + __u64 probed_cpu_visible_size; + + /** + * @unallocated_cpu_visible_size: Estimate of CPU + * visible memory remaining. + * + * Note this is only tracked for + * I915_MEMORY_CLASS_DEVICE regions (for other types the + * value here will always equal the + * @probed_cpu_visible_size). + * + * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable + * accounting. Without this the value here will always + * equal the @probed_cpu_visible_size. Note this is only + * currently tracked for I915_MEMORY_CLASS_DEVICE + * regions (for other types the value here will also + * always equal the @probed_cpu_visible_size). + * + * If this is an older kernel the value here will be + * zero, see also @probed_cpu_visible_size. + */ + __u64 unallocated_cpu_visible_size; + }; + }; +}; + +/** + * struct drm_i915_query_memory_regions + * + * The region info query enumerates all regions known to the driver by filling + * in an array of struct drm_i915_memory_region_info structures. + * + * Example for getting the list of supported regions: + * + * .. code-block:: C + * + * struct drm_i915_query_memory_regions *info; + * struct drm_i915_query_item item = { + * .query_id = DRM_I915_QUERY_MEMORY_REGIONS; + * }; + * struct drm_i915_query query = { + * .num_items = 1, + * .items_ptr = (uintptr_t)&item, + * }; + * int err, i; + * + * // First query the size of the blob we need, this needs to be large + * // enough to hold our array of regions. The kernel will fill out the + * // item.length for us, which is the number of bytes we need. + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * info = calloc(1, item.length); + * // Now that we allocated the required number of bytes, we call the ioctl + * // again, this time with the data_ptr pointing to our newly allocated + * // blob, which the kernel can then populate with the all the region info. + * item.data_ptr = (uintptr_t)&info, + * + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * // We can now access each region in the array + * for (i = 0; i < info->num_regions; i++) { + * struct drm_i915_memory_region_info mr = info->regions[i]; + * u16 class = mr.region.class; + * u16 instance = mr.region.instance; + * + * .... + * } + * + * free(info); + */ +struct drm_i915_query_memory_regions { + /** @num_regions: Number of supported regions */ + __u32 num_regions; + + /** @rsvd: MBZ */ + __u32 rsvd[3]; + + /** @regions: Info about each supported region */ + struct drm_i915_memory_region_info regions[]; +}; + +/** + * struct drm_i915_query_guc_submission_version - query GuC submission interface version + */ +struct drm_i915_query_guc_submission_version { + /** @branch: Firmware branch version. */ + __u32 branch; + /** @major: Firmware major version. */ + __u32 major; + /** @minor: Firmware minor version. */ + __u32 minor; + /** @patch: Firmware patch version. */ + __u32 patch; +}; + +/** + * DOC: GuC HWCONFIG blob uAPI + * + * The GuC produces a blob with information about the current device. + * i915 reads this blob from GuC and makes it available via this uAPI. + * + * The format and meaning of the blob content are documented in the + * Programmer's Reference Manual. + */ + +/** + * struct drm_i915_gem_create_ext - Existing gem_create behaviour, with added + * extension support using struct i915_user_extension. + * + * Note that new buffer flags should be added here, at least for the stuff that + * is immutable. Previously we would have two ioctls, one to create the object + * with gem_create, and another to apply various parameters, however this + * creates some ambiguity for the params which are considered immutable. Also in + * general we're phasing out the various SET/GET ioctls. + */ +struct drm_i915_gem_create_ext { + /** + * @size: Requested size for the object. + * + * The (page-aligned) allocated size for the object will be returned. + * + * On platforms like DG2/ATS the kernel will always use 64K or larger + * pages for I915_MEMORY_CLASS_DEVICE. The kernel also requires a + * minimum of 64K GTT alignment for such objects. + * + * NOTE: Previously the ABI here required a minimum GTT alignment of 2M + * on DG2/ATS, due to how the hardware implemented 64K GTT page support, + * where we had the following complications: + * + * 1) The entire PDE (which covers a 2MB virtual address range), must + * contain only 64K PTEs, i.e mixing 4K and 64K PTEs in the same + * PDE is forbidden by the hardware. + * + * 2) We still need to support 4K PTEs for I915_MEMORY_CLASS_SYSTEM + * objects. + * + * However on actual production HW this was completely changed to now + * allow setting a TLB hint at the PTE level (see PS64), which is a lot + * more flexible than the above. With this the 2M restriction was + * dropped where we now only require 64K. + */ + __u64 size; + + /** + * @handle: Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; + + /** + * @flags: Optional flags. + * + * Supported values: + * + * I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS - Signal to the kernel that + * the object will need to be accessed via the CPU. + * + * Only valid when placing objects in I915_MEMORY_CLASS_DEVICE, and only + * strictly required on configurations where some subset of the device + * memory is directly visible/mappable through the CPU (which we also + * call small BAR), like on some DG2+ systems. Note that this is quite + * undesirable, but due to various factors like the client CPU, BIOS etc + * it's something we can expect to see in the wild. See + * &drm_i915_memory_region_info.probed_cpu_visible_size for how to + * determine if this system applies. + * + * Note that one of the placements MUST be I915_MEMORY_CLASS_SYSTEM, to + * ensure the kernel can always spill the allocation to system memory, + * if the object can't be allocated in the mappable part of + * I915_MEMORY_CLASS_DEVICE. + * + * Also note that since the kernel only supports flat-CCS on objects + * that can *only* be placed in I915_MEMORY_CLASS_DEVICE, we therefore + * don't support I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS together with + * flat-CCS. + * + * Without this hint, the kernel will assume that non-mappable + * I915_MEMORY_CLASS_DEVICE is preferred for this object. Note that the + * kernel can still migrate the object to the mappable part, as a last + * resort, if userspace ever CPU faults this object, but this might be + * expensive, and so ideally should be avoided. + * + * On older kernels which lack the relevant small-bar uAPI support (see + * also &drm_i915_memory_region_info.probed_cpu_visible_size), + * usage of the flag will result in an error, but it should NEVER be + * possible to end up with a small BAR configuration, assuming we can + * also successfully load the i915 kernel module. In such cases the + * entire I915_MEMORY_CLASS_DEVICE region will be CPU accessible, and as + * such there are zero restrictions on where the object can be placed. + */ +#define I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS (1 << 0) + __u32 flags; + + /** + * @extensions: The chain of extensions to apply to this object. + * + * This will be useful in the future when we need to support several + * different extensions, and we need to apply more than one when + * creating the object. See struct i915_user_extension. + * + * If we don't supply any extensions then we get the same old gem_create + * behaviour. + * + * For I915_GEM_CREATE_EXT_MEMORY_REGIONS usage see + * struct drm_i915_gem_create_ext_memory_regions. + * + * For I915_GEM_CREATE_EXT_PROTECTED_CONTENT usage see + * struct drm_i915_gem_create_ext_protected_content. + * + * For I915_GEM_CREATE_EXT_SET_PAT usage see + * struct drm_i915_gem_create_ext_set_pat. + */ +#define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0 +#define I915_GEM_CREATE_EXT_PROTECTED_CONTENT 1 +#define I915_GEM_CREATE_EXT_SET_PAT 2 + __u64 extensions; +}; + +/** + * struct drm_i915_gem_create_ext_memory_regions - The + * I915_GEM_CREATE_EXT_MEMORY_REGIONS extension. + * + * Set the object with the desired set of placements/regions in priority + * order. Each entry must be unique and supported by the device. + * + * This is provided as an array of struct drm_i915_gem_memory_class_instance, or + * an equivalent layout of class:instance pair encodings. See struct + * drm_i915_query_memory_regions and DRM_I915_QUERY_MEMORY_REGIONS for how to + * query the supported regions for a device. + * + * As an example, on discrete devices, if we wish to set the placement as + * device local-memory we can do something like: + * + * .. code-block:: C + * + * struct drm_i915_gem_memory_class_instance region_lmem = { + * .memory_class = I915_MEMORY_CLASS_DEVICE, + * .memory_instance = 0, + * }; + * struct drm_i915_gem_create_ext_memory_regions regions = { + * .base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS }, + * .regions = (uintptr_t)®ion_lmem, + * .num_regions = 1, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = 16 * PAGE_SIZE, + * .extensions = (uintptr_t)®ions, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + * + * At which point we get the object handle in &drm_i915_gem_create_ext.handle, + * along with the final object size in &drm_i915_gem_create_ext.size, which + * should account for any rounding up, if required. + * + * Note that userspace has no means of knowing the current backing region + * for objects where @num_regions is larger than one. The kernel will only + * ensure that the priority order of the @regions array is honoured, either + * when initially placing the object, or when moving memory around due to + * memory pressure + * + * On Flat-CCS capable HW, compression is supported for the objects residing + * in I915_MEMORY_CLASS_DEVICE. When such objects (compressed) have other + * memory class in @regions and migrated (by i915, due to memory + * constraints) to the non I915_MEMORY_CLASS_DEVICE region, then i915 needs to + * decompress the content. But i915 doesn't have the required information to + * decompress the userspace compressed objects. + * + * So i915 supports Flat-CCS, on the objects which can reside only on + * I915_MEMORY_CLASS_DEVICE regions. + */ +struct drm_i915_gem_create_ext_memory_regions { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + + /** @pad: MBZ */ + __u32 pad; + /** @num_regions: Number of elements in the @regions array. */ + __u32 num_regions; + /** + * @regions: The regions/placements array. + * + * An array of struct drm_i915_gem_memory_class_instance. + */ + __u64 regions; +}; + +/** + * struct drm_i915_gem_create_ext_protected_content - The + * I915_OBJECT_PARAM_PROTECTED_CONTENT extension. + * + * If this extension is provided, buffer contents are expected to be protected + * by PXP encryption and require decryption for scan out and processing. This + * is only possible on platforms that have PXP enabled, on all other scenarios + * using this extension will cause the ioctl to fail and return -ENODEV. The + * flags parameter is reserved for future expansion and must currently be set + * to zero. + * + * The buffer contents are considered invalid after a PXP session teardown. + * + * The encryption is guaranteed to be processed correctly only if the object + * is submitted with a context created using the + * I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. This will also enable extra checks + * at submission time on the validity of the objects involved. + * + * Below is an example on how to create a protected object: + * + * .. code-block:: C + * + * struct drm_i915_gem_create_ext_protected_content protected_ext = { + * .base = { .name = I915_GEM_CREATE_EXT_PROTECTED_CONTENT }, + * .flags = 0, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = PAGE_SIZE, + * .extensions = (uintptr_t)&protected_ext, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + */ +struct drm_i915_gem_create_ext_protected_content { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + /** @flags: reserved for future usage, currently MBZ */ + __u32 flags; +}; + +/** + * struct drm_i915_gem_create_ext_set_pat - The + * I915_GEM_CREATE_EXT_SET_PAT extension. + * + * If this extension is provided, the specified caching policy (PAT index) is + * applied to the buffer object. + * + * Below is an example on how to create an object with specific caching policy: + * + * .. code-block:: C + * + * struct drm_i915_gem_create_ext_set_pat set_pat_ext = { + * .base = { .name = I915_GEM_CREATE_EXT_SET_PAT }, + * .pat_index = 0, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = PAGE_SIZE, + * .extensions = (uintptr_t)&set_pat_ext, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + */ +struct drm_i915_gem_create_ext_set_pat { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + /** + * @pat_index: PAT index to be set + * PAT index is a bit field in Page Table Entry to control caching + * behaviors for GPU accesses. The definition of PAT index is + * platform dependent and can be found in hardware specifications, + */ + __u32 pat_index; + /** @rsvd: reserved for future use */ + __u32 rsvd; +}; + +/* ID of the protected content session managed by i915 when PXP is active */ +#define I915_PROTECTED_CONTENT_DEFAULT_SESSION 0xf + +#if defined(__cplusplus) +} +#endif + +#endif /* _UAPI_I915_DRM_H_ */ diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/virtgpu_drm.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/virtgpu_drm.h new file mode 100644 index 0000000000..95587e12ae --- /dev/null +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/drm/virtgpu_drm.h @@ -0,0 +1,281 @@ +/* + * Copyright 2013 Red Hat + * All Rights Reserved. + * + * 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 (including the next + * paragraph) 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 AND/OR ITS SUPPLIERS 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. + */ +#ifndef VIRTGPU_DRM_H +#define VIRTGPU_DRM_H + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + * + * Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel + * compatibility Keep fields aligned to their size + */ + +#define DRM_VIRTGPU_MAP 0x01 +#define DRM_VIRTGPU_EXECBUFFER 0x02 +#define DRM_VIRTGPU_GETPARAM 0x03 +#define DRM_VIRTGPU_RESOURCE_CREATE 0x04 +#define DRM_VIRTGPU_RESOURCE_INFO 0x05 +#define DRM_VIRTGPU_TRANSFER_FROM_HOST 0x06 +#define DRM_VIRTGPU_TRANSFER_TO_HOST 0x07 +#define DRM_VIRTGPU_WAIT 0x08 +#define DRM_VIRTGPU_GET_CAPS 0x09 +#define DRM_VIRTGPU_RESOURCE_CREATE_BLOB 0x0a +#define DRM_VIRTGPU_CONTEXT_INIT 0x0b + +#define VIRTGPU_EXECBUF_FENCE_FD_IN 0x01 +#define VIRTGPU_EXECBUF_FENCE_FD_OUT 0x02 +#define VIRTGPU_EXECBUF_RING_IDX 0x04 +#define VIRTGPU_EXECBUF_FLAGS (\ + VIRTGPU_EXECBUF_FENCE_FD_IN |\ + VIRTGPU_EXECBUF_FENCE_FD_OUT |\ + VIRTGPU_EXECBUF_RING_IDX |\ + 0) + +struct drm_virtgpu_map { + __u64 offset; /* use for mmap system call */ + __u32 handle; + __u32 pad; +}; + +#define VIRTGPU_EXECBUF_SYNCOBJ_RESET 0x01 +#define VIRTGPU_EXECBUF_SYNCOBJ_FLAGS ( \ + VIRTGPU_EXECBUF_SYNCOBJ_RESET | \ + 0) +struct drm_virtgpu_execbuffer_syncobj { + __u32 handle; + __u32 flags; + __u64 point; +}; + +/* fence_fd is modified on success if VIRTGPU_EXECBUF_FENCE_FD_OUT flag is set. */ +struct drm_virtgpu_execbuffer { + __u32 flags; + __u32 size; + __u64 command; /* void* */ + __u64 bo_handles; + __u32 num_bo_handles; + __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */ + __u32 ring_idx; /* command ring index (see VIRTGPU_EXECBUF_RING_IDX) */ + __u32 syncobj_stride; /* size of @drm_virtgpu_execbuffer_syncobj */ + __u32 num_in_syncobjs; + __u32 num_out_syncobjs; + __u64 in_syncobjs; + __u64 out_syncobjs; +}; + +#define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ +#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */ +#define VIRTGPU_PARAM_RESOURCE_BLOB 3 /* DRM_VIRTGPU_RESOURCE_CREATE_BLOB */ +#define VIRTGPU_PARAM_HOST_VISIBLE 4 /* Host blob resources are mappable */ +#define VIRTGPU_PARAM_CROSS_DEVICE 5 /* Cross virtio-device resource sharing */ +#define VIRTGPU_PARAM_CONTEXT_INIT 6 /* DRM_VIRTGPU_CONTEXT_INIT */ +#define VIRTGPU_PARAM_SUPPORTED_CAPSET_IDs 7 /* Bitmask of supported capability set ids */ +#define VIRTGPU_PARAM_EXPLICIT_DEBUG_NAME 8 /* Ability to set debug name from userspace */ +#define VIRTGPU_PARAM_BLOB_ALIGNMENT 9 /* Device alignment requirements for blobs */ + +struct drm_virtgpu_getparam { + __u64 param; + __u64 value; +}; + +/* NO_BO flags? NO resource flag? */ +/* resource flag for y_0_top */ +struct drm_virtgpu_resource_create { + __u32 target; + __u32 format; + __u32 bind; + __u32 width; + __u32 height; + __u32 depth; + __u32 array_size; + __u32 last_level; + __u32 nr_samples; + __u32 flags; + __u32 bo_handle; /* if this is set - recreate a new resource attached to this bo ? */ + __u32 res_handle; /* returned by kernel */ + __u32 size; /* validate transfer in the host */ + __u32 stride; /* validate transfer in the host */ +}; + +struct drm_virtgpu_resource_info { + __u32 bo_handle; + __u32 res_handle; + __u32 size; + __u32 blob_mem; +}; + +struct drm_virtgpu_3d_box { + __u32 x; + __u32 y; + __u32 z; + __u32 w; + __u32 h; + __u32 d; +}; + +struct drm_virtgpu_3d_transfer_to_host { + __u32 bo_handle; + struct drm_virtgpu_3d_box box; + __u32 level; + __u32 offset; + __u32 stride; + __u32 layer_stride; +}; + +struct drm_virtgpu_3d_transfer_from_host { + __u32 bo_handle; + struct drm_virtgpu_3d_box box; + __u32 level; + __u32 offset; + __u32 stride; + __u32 layer_stride; +}; + +#define VIRTGPU_WAIT_NOWAIT 1 /* like it */ +struct drm_virtgpu_3d_wait { + __u32 handle; /* 0 is an invalid handle */ + __u32 flags; +}; + +#define VIRTGPU_DRM_CAPSET_VIRGL 1 +#define VIRTGPU_DRM_CAPSET_VIRGL2 2 +#define VIRTGPU_DRM_CAPSET_GFXSTREAM_VULKAN 3 +#define VIRTGPU_DRM_CAPSET_VENUS 4 +#define VIRTGPU_DRM_CAPSET_CROSS_DOMAIN 5 +#define VIRTGPU_DRM_CAPSET_DRM 6 +struct drm_virtgpu_get_caps { + __u32 cap_set_id; + __u32 cap_set_ver; + __u64 addr; + __u32 size; + __u32 pad; +}; + +struct drm_virtgpu_resource_create_blob { +#define VIRTGPU_BLOB_MEM_GUEST 0x0001 +#define VIRTGPU_BLOB_MEM_HOST3D 0x0002 +#define VIRTGPU_BLOB_MEM_HOST3D_GUEST 0x0003 + +#define VIRTGPU_BLOB_FLAG_USE_MAPPABLE 0x0001 +#define VIRTGPU_BLOB_FLAG_USE_SHAREABLE 0x0002 +#define VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004 + /* zero is invalid blob_mem */ + __u32 blob_mem; + __u32 blob_flags; + __u32 bo_handle; + __u32 res_handle; + __u64 size; + + /* + * for 3D contexts with VIRTGPU_BLOB_MEM_HOST3D_GUEST and + * VIRTGPU_BLOB_MEM_HOST3D otherwise, must be zero. + */ + __u32 pad; + __u32 cmd_size; + __u64 cmd; + __u64 blob_id; + +#define DRM_VIRTGPU_BLOB_FLAG_HINT_DEFER_MAPPING 0x0001 + __u32 blob_hints; + __u32 pad2; +}; + +#define VIRTGPU_CONTEXT_PARAM_CAPSET_ID 0x0001 +#define VIRTGPU_CONTEXT_PARAM_NUM_RINGS 0x0002 +#define VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK 0x0003 +#define VIRTGPU_CONTEXT_PARAM_DEBUG_NAME 0x0004 +struct drm_virtgpu_context_set_param { + __u64 param; + __u64 value; +}; + +struct drm_virtgpu_context_init { + __u32 num_params; + __u32 pad; + + /* pointer to drm_virtgpu_context_set_param array */ + __u64 ctx_set_params; +}; + +/* + * Event code that's given when VIRTGPU_CONTEXT_PARAM_POLL_RINGS_MASK is in + * effect. The event size is sizeof(drm_event), since there is no additional + * payload. + */ +#define VIRTGPU_EVENT_FENCE_SIGNALED 0x90000000 + +#define DRM_IOCTL_VIRTGPU_MAP \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map) + +#define DRM_IOCTL_VIRTGPU_EXECBUFFER \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\ + struct drm_virtgpu_execbuffer) + +#define DRM_IOCTL_VIRTGPU_GETPARAM \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GETPARAM,\ + struct drm_virtgpu_getparam) + +#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE, \ + struct drm_virtgpu_resource_create) + +#define DRM_IOCTL_VIRTGPU_RESOURCE_INFO \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_INFO, \ + struct drm_virtgpu_resource_info) + +#define DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_FROM_HOST, \ + struct drm_virtgpu_3d_transfer_from_host) + +#define DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_TO_HOST, \ + struct drm_virtgpu_3d_transfer_to_host) + +#define DRM_IOCTL_VIRTGPU_WAIT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_WAIT, \ + struct drm_virtgpu_3d_wait) + +#define DRM_IOCTL_VIRTGPU_GET_CAPS \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GET_CAPS, \ + struct drm_virtgpu_get_caps) + +#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE_BLOB, \ + struct drm_virtgpu_resource_create_blob) + +#define DRM_IOCTL_VIRTGPU_CONTEXT_INIT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_CONTEXT_INIT, \ + struct drm_virtgpu_context_init) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/types.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/types.h index f3b66b3df5..06a4313d38 100644 --- a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/types.h +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/types.h @@ -11,11 +11,21 @@ typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; +typedef u8 __u8; +typedef u16 __u16; +typedef u32 __u32; +typedef u64 __u64; + typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; +typedef s8 __s8; +typedef s16 __s16; +typedef s32 __s32; +typedef s64 __s64; + typedef u64 phys_addr_t; typedef u64 dma_addr_t; diff --git a/local/recipes/drivers/ohcid/Cargo.toml b/local/recipes/drivers/ohcid/Cargo.toml index 0e3209276e..6efa793711 100644 --- a/local/recipes/drivers/ohcid/Cargo.toml +++ b/local/recipes/drivers/ohcid/Cargo.toml @@ -10,5 +10,5 @@ path = "src/main.rs" [dependencies] usb-core = { path = "../../usb-core/source" } -redox_syscall = { path = "../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../local/sources/syscall" } log = "0.4" diff --git a/local/recipes/drivers/ohcid/source/Cargo.toml b/local/recipes/drivers/ohcid/source/Cargo.toml index 2647c2b01b..253a2890aa 100644 --- a/local/recipes/drivers/ohcid/source/Cargo.toml +++ b/local/recipes/drivers/ohcid/source/Cargo.toml @@ -10,11 +10,11 @@ path = "src/main.rs" [dependencies] usb-core = { path = "../../usb-core/source" } -syscall = { package = "redox_syscall", path = "../../../../../recipes/core/base/syscall", features = ["std"] } +syscall = { package = "redox_syscall", path = "../../../../../local/sources/syscall", features = ["std"] } redox-driver-sys = { path = "../../redox-driver-sys/source" } log = "0.4" [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } diff --git a/local/recipes/drivers/redbear-btusb/source/Cargo.toml b/local/recipes/drivers/redbear-btusb/source/Cargo.toml index 913a5625f9..6cf56592bb 100644 --- a/local/recipes/drivers/redbear-btusb/source/Cargo.toml +++ b/local/recipes/drivers/redbear-btusb/source/Cargo.toml @@ -9,12 +9,12 @@ path = "src/main.rs" [dependencies] libc = "0.2" -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { package = "redox_syscall", path = "../../../../../recipes/core/base/syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { package = "redox_syscall", path = "../../../../../local/sources/syscall", features = ["std"] } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } diff --git a/local/recipes/drivers/redox-driver-pci/Cargo.toml b/local/recipes/drivers/redox-driver-pci/Cargo.toml index b5255516fa..5f4f6c9f19 100644 --- a/local/recipes/drivers/redox-driver-pci/Cargo.toml +++ b/local/recipes/drivers/redox-driver-pci/Cargo.toml @@ -6,4 +6,4 @@ description = "PCI bus backend for redox-driver-core" [dependencies] redox-driver-core = { path = "../redox-driver-core" } -redox_syscall = { path = "../../../../recipes/core/base/syscall" } \ No newline at end of file +redox_syscall = { path = "../../../../local/sources/syscall" } \ No newline at end of file diff --git a/local/recipes/drivers/redox-driver-pci/source/Cargo.toml b/local/recipes/drivers/redox-driver-pci/source/Cargo.toml index 1d2ebac1a1..deaa659e02 100644 --- a/local/recipes/drivers/redox-driver-pci/source/Cargo.toml +++ b/local/recipes/drivers/redox-driver-pci/source/Cargo.toml @@ -6,8 +6,8 @@ description = "PCI bus backend for redox-driver-core" [dependencies] redox-driver-core = { path = "../../redox-driver-core/source" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../../local/sources/syscall" } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/drivers/redox-driver-sys/source/Cargo.toml b/local/recipes/drivers/redox-driver-sys/source/Cargo.toml index 2a1af1bc06..628008dc20 100644 --- a/local/recipes/drivers/redox-driver-sys/source/Cargo.toml +++ b/local/recipes/drivers/redox-driver-sys/source/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" description = "Safe Rust wrappers for Redox OS scheme-based hardware access" [dependencies] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall", features = ["std"] } +libredox = { path = "../../../../../local/sources/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall", features = ["std"] } log = "0.4" thiserror = "2" bitflags = "2" @@ -30,5 +30,5 @@ harness = false required-features = ["redox"] [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/drivers/uhcid/Cargo.toml b/local/recipes/drivers/uhcid/Cargo.toml index af7070eecf..0ffe21a4f5 100644 --- a/local/recipes/drivers/uhcid/Cargo.toml +++ b/local/recipes/drivers/uhcid/Cargo.toml @@ -10,5 +10,5 @@ path = "src/main.rs" [dependencies] usb-core = { path = "../../usb-core/source" } -redox_syscall = { path = "../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../local/sources/syscall" } log = "0.4" diff --git a/local/recipes/drivers/uhcid/source/Cargo.toml b/local/recipes/drivers/uhcid/source/Cargo.toml index bc54916775..a3950e2456 100644 --- a/local/recipes/drivers/uhcid/source/Cargo.toml +++ b/local/recipes/drivers/uhcid/source/Cargo.toml @@ -10,12 +10,12 @@ path = "src/main.rs" [dependencies] usb-core = { path = "../../usb-core/source" } -syscall = { package = "redox_syscall", path = "../../../../../recipes/core/base/syscall", features = ["std"] } +syscall = { package = "redox_syscall", path = "../../../../../local/sources/syscall", features = ["std"] } redox-driver-sys = { path = "../../redox-driver-sys/source" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = "0.4" [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } diff --git a/local/recipes/drivers/virtio-inputd/source/Cargo.toml b/local/recipes/drivers/virtio-inputd/source/Cargo.toml index 55af585e0b..36cfdf60e5 100644 --- a/local/recipes/drivers/virtio-inputd/source/Cargo.toml +++ b/local/recipes/drivers/virtio-inputd/source/Cargo.toml @@ -11,13 +11,13 @@ path = "src/main.rs" [dependencies] anyhow = "1" log = "0.4" -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } -redox_syscall = { path = "../../../../../recipes/core/base/syscall", features = ["std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } +redox_syscall = { path = "../../../../../local/sources/syscall", features = ["std"] } redox-driver-sys = { path = "../../redox-driver-sys/source" } -syscall = { package = "redox_syscall", path = "../../../../../recipes/core/base/syscall", features = ["std"] } +syscall = { package = "redox_syscall", path = "../../../../../local/sources/syscall", features = ["std"] } inputd = { path = "../../../../sources/base/drivers/inputd" } common = { path = "../../../../sources/base/drivers/common" } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/gpu/redox-drm/source/src/scheme.rs b/local/recipes/gpu/redox-drm/source/src/scheme.rs index 3e441c1805..b24189172f 100644 --- a/local/recipes/gpu/redox-drm/source/src/scheme.rs +++ b/local/recipes/gpu/redox-drm/source/src/scheme.rs @@ -1563,7 +1563,7 @@ impl DrmScheme { if cmd_len == 0 || cmd_len > 16 * 1024 * 1024 { return Err(Error::new(EINVAL)); } - let cmd_start = 16; // command bytes start at offset 16 + let cmd_start: usize = 16; // command bytes start at offset 16 let cmd_end = cmd_start.checked_add(cmd_len).ok_or_else(|| Error::new(EINVAL))?; if cmd_end > payload.len() { return Err(Error::new(EINVAL)); diff --git a/local/recipes/kde/kwin/recipe.toml b/local/recipes/kde/kwin/recipe.toml index 2dd5a97d6e..bde0122c3a 100644 --- a/local/recipes/kde/kwin/recipe.toml +++ b/local/recipes/kde/kwin/recipe.toml @@ -1,13 +1,10 @@ # KWin — real cmake build of the KDE Wayland compositor/window manager. # null+8 Wayland crash is verified FIXED in qtwaylandscanner (commits # de2d74c37e + 882c2974ec). Cross-build still bounded by: -# - libudev-stub: policy debt; real libudev recipe exists but source is -# not yet populated. Stub provides UDev::UDev cmake target KWin needs. # - libepoxy: switched from stub to real libepoxy v6.0 2026 (2026-07-09). # Provides epoxy::epoxy cmake target with real EGL/GLES function pointer # dispatch, replacing the hardcoded-zero stub. -# - KF6Svg: KF6::Svg is not built on Redox. KWin's CMakeLists touches -# the target in optional paths; the recipe stubs it locally. +# - KF6Svg: built by local/recipes/kde/kf6-ksvg and consumed by KWin. # - Sensors / UiTools: removed from CMakeLists.txt (these components # are not yet in-tree for Redox; sed-removal keeps the cmake build # bounded). @@ -43,9 +40,10 @@ dependencies = [ "kf6-kio", "kdecoration", "kf6-kcmutils", + "kf6-ksvg", "plasma-wayland-protocols", "libepoxy", - "libudev-stub", + "libudev", "wayland-protocols", "redbear-compositor", ] @@ -72,9 +70,6 @@ sed -i '/include(ECMQmlModule)/s/^/#/' "${COOKBOOK_SOURCE}/CMakeLists.txt" 2>/de sed -i '/^ UiTools$/d' "${COOKBOOK_SOURCE}/CMakeLists.txt" sed -i '/^ Sensors$/d' "${COOKBOOK_SOURCE}/CMakeLists.txt" -# Remove KF6::Svg references (not available in cross-build) -find "${COOKBOOK_SOURCE}" -name "CMakeLists.txt" -exec sed -i '/KF6::Svg/d' {} + - rm -f CMakeCache.txt rm -rf CMakeFiles @@ -92,12 +87,6 @@ if [ -d "${COOKBOOK_SYSROOT}/usr/plugins" ] && [ -d "${COOKBOOK_SYSROOT}/plugins done fi -# Stub missing KF6 packages needed by dependencies (KF6Svg not built on Redox) -mkdir -p "${COOKBOOK_SYSROOT}/lib/cmake/KF6Svg" -cat > "${COOKBOOK_SYSROOT}/lib/cmake/KF6Svg/KF6SvgConfig.cmake" << 'KF6EOF' -set(KF6Svg_FOUND TRUE) -KF6EOF - cmake "${COOKBOOK_SOURCE}" \ -DCMAKE_TOOLCHAIN_FILE="${COOKBOOK_ROOT}/local/recipes/qt/redox-toolchain.cmake" \ -DQT_HOST_PATH="${HOST_BUILD}" \ diff --git a/local/recipes/kde/kwin/source/CMakeLists.txt b/local/recipes/kde/kwin/source/CMakeLists.txt index 326ea13df7..67ea327610 100644 --- a/local/recipes/kde/kwin/source/CMakeLists.txt +++ b/local/recipes/kde/kwin/source/CMakeLists.txt @@ -46,6 +46,10 @@ include(ECMGenerateQmlTypes) include(ECMDeprecationSettings) include(ECMGenerateQDoc) +if(NOT TARGET KF6::Svg) + find_package(KF6Svg REQUIRED) +endif() + option(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON) option(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON) option(KWIN_BUILD_NOTIFICATIONS "Enable building of KWin with knotifications support" ON) diff --git a/local/recipes/libs/libdrm/recipe.toml b/local/recipes/libs/libdrm/recipe.toml index 1b23bbcb71..a8d3dd9c4a 100644 --- a/local/recipes/libs/libdrm/recipe.toml +++ b/local/recipes/libs/libdrm/recipe.toml @@ -4,11 +4,21 @@ blake3 = "4b2f4a35c204ec3e3edd894969e301cf73054c8be5f13d4304a982bdb3b686ae" patches = ["redox.patch"] [build] -template = "meson" -mesonflags = [ - "-Damdgpu=enabled", - "-Dintel=disabled", - "-Dnouveau=disabled", - "-Dradeon=disabled", - "-Dvmwgfx=disabled", +template = "custom" +dependencies = [ + "libpciaccess", + "linux-kpi", ] +script = """ +DYNAMIC_INIT + +export CFLAGS+=" -I${COOKBOOK_SYSROOT}/include/linux-kpi" +export CPPFLAGS+=" -I${COOKBOOK_SYSROOT}/include/linux-kpi" + +cookbook_meson \ + -Damdgpu=enabled \ + -Dintel=enabled \ + -Dnouveau=disabled \ + -Dradeon=disabled \ + -Dvmwgfx=disabled +""" diff --git a/local/recipes/libs/libinput/recipe.toml b/local/recipes/libs/libinput/recipe.toml index 69d8e8b56d..254d7c6dbe 100644 --- a/local/recipes/libs/libinput/recipe.toml +++ b/local/recipes/libs/libinput/recipe.toml @@ -1,4 +1,4 @@ -#TODO: needs libevdev working; udev integration via libudev-stub (scheme:udev) +#TODO: needs libevdev working; udev integration via real libudev (scheme:udev) [source] tar = "https://gitlab.freedesktop.org/libinput/libinput/-/archive/1.31.3/libinput-1.31.3.tar.bz2" blake3 = "ae74b2c2202357119ec0f6e65951a9b2b38332ae5c8c3f59b05f6d80598ef033" @@ -15,5 +15,5 @@ mesonflags = [ ] dependencies = [ "libevdev", - "libudev-stub", + "libudev", ] diff --git a/local/recipes/libs/libpciaccess/recipe.toml b/local/recipes/libs/libpciaccess/recipe.toml new file mode 100644 index 0000000000..97d8f7f471 --- /dev/null +++ b/local/recipes/libs/libpciaccess/recipe.toml @@ -0,0 +1,41 @@ +[source] +path = "source" + +[build] +template = "custom" +script = """ +DYNAMIC_INIT + +mkdir -p "${COOKBOOK_STAGE}/usr/include" +mkdir -p "${COOKBOOK_STAGE}/usr/lib/pkgconfig" + +x86_64-unknown-redox-gcc \ + -shared \ + -fPIC \ + -std=c11 \ + -Wall \ + -Wextra \ + -Wl,-soname,libpciaccess.so \ + -I"${COOKBOOK_SOURCE}/include" \ + -o "${COOKBOOK_STAGE}/usr/lib/libpciaccess.so" \ + "${COOKBOOK_SOURCE}/libpciaccess.c" + +cp "${COOKBOOK_SOURCE}/include/pciaccess.h" "${COOKBOOK_STAGE}/usr/include/pciaccess.h" + +cat > "${COOKBOOK_STAGE}/usr/lib/pkgconfig/pciaccess.pc" << 'EOF' +prefix=/usr +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: pciaccess +Description: Minimal PCI access library for Redox +Version: 0.18.1 +Libs: -L${libdir} -lpciaccess +Cflags: -I${includedir} +EOF +""" + +[package] +version = "0.18.1" +description = "libpciaccess — minimal Redox PCI access library for libdrm_intel. Reads PCI config space via /scheme/pci." diff --git a/local/recipes/libs/libpciaccess/source/include/pciaccess.h b/local/recipes/libs/libpciaccess/source/include/pciaccess.h new file mode 100644 index 0000000000..3cef5c36db --- /dev/null +++ b/local/recipes/libs/libpciaccess/source/include/pciaccess.h @@ -0,0 +1,54 @@ +#ifndef PCIACCESS_H +#define PCIACCESS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint64_t pciaddr_t; + +#define PCIREGION_TYPE_MEMORY 1 +#define PCIREGION_TYPE_IO 2 + +struct pci_device_region { + int type; + pciaddr_t bus_addr; + pciaddr_t base_addr; + pciaddr_t size; + int is_IO; + int is_prefetchable; + int is_64; +}; + +struct pci_device { + unsigned int domain; + unsigned int bus; + unsigned int dev; + unsigned int func; + unsigned int vendor_id; + unsigned int device_id; + unsigned int revision; + unsigned int class_code; + unsigned int subclass; + unsigned int prog_if; + struct pci_device_region regions[6]; + void *_internal; +}; + +int pci_system_init(void); +void pci_system_cleanup(void); + +struct pci_device *pci_device_find_by_slot(unsigned int domain, + unsigned int bus, + unsigned int dev, + unsigned int func); +int pci_device_probe(struct pci_device *dev); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/local/recipes/libs/libpciaccess/source/libpciaccess.c b/local/recipes/libs/libpciaccess/source/libpciaccess.c new file mode 100644 index 0000000000..8d8ccd02e8 --- /dev/null +++ b/local/recipes/libs/libpciaccess/source/libpciaccess.c @@ -0,0 +1,272 @@ +#define _DEFAULT_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct pci_device *pci_devices = NULL; +static int pci_device_count = 0; + +static uint32_t read_dword(const uint8_t *data, size_t offset) { + return (uint32_t)data[offset] + | ((uint32_t)data[offset + 1] << 8) + | ((uint32_t)data[offset + 2] << 16) + | ((uint32_t)data[offset + 3] << 24); +} + +static uint16_t read_word(const uint8_t *data, size_t offset) { + return (uint16_t)data[offset] + | ((uint16_t)data[offset + 1] << 8); +} + +static int read_config(const char *path, uint8_t *data, size_t len) { + int fd = open(path, O_RDONLY); + if (fd < 0) { + return -1; + } + size_t total = 0; + while (total < len) { + ssize_t n = read(fd, data + total, len - total); + if (n < 0) { + close(fd); + return -1; + } + if (n == 0) { + break; + } + total += n; + } + close(fd); + return total == len ? 0 : -1; +} + +static int probe_bar_size(int fd, unsigned int offset, int is_io, uint64_t *size) { + uint32_t original, inverted; + uint32_t mask = is_io ? 0xFFFFFFFC : 0xFFFFFFF0; + + if (lseek(fd, offset, SEEK_SET) < 0) { + return -1; + } + if (read(fd, &original, sizeof(original)) != (ssize_t)sizeof(original)) { + return -1; + } + + uint32_t probe = 0xFFFFFFFF; + if (lseek(fd, offset, SEEK_SET) < 0) { + return -1; + } + if (write(fd, &probe, sizeof(probe)) != (ssize_t)sizeof(probe)) { + lseek(fd, offset, SEEK_SET); + write(fd, &original, sizeof(original)); + return -1; + } + + if (lseek(fd, offset, SEEK_SET) < 0) { + lseek(fd, offset, SEEK_SET); + write(fd, &original, sizeof(original)); + return -1; + } + if (read(fd, &inverted, sizeof(inverted)) != (ssize_t)sizeof(inverted)) { + lseek(fd, offset, SEEK_SET); + write(fd, &original, sizeof(original)); + return -1; + } + + lseek(fd, offset, SEEK_SET); + write(fd, &original, sizeof(original)); + + if ((inverted & mask) == 0) { + *size = 0; + return 0; + } + + *size = ((uint64_t)(~(inverted & mask) & mask)) + 1; + return 0; +} + +static int parse_bars(int config_fd, const uint8_t *config, struct pci_device *dev) { + unsigned int bar_idx = 0; + unsigned int offset = 0x10; + + memset(dev->regions, 0, sizeof(dev->regions)); + + while (bar_idx < 6 && offset <= 0x24) { + uint32_t val = read_dword(config, offset); + int is_io = (val & 0x1) != 0; + + if (is_io) { + dev->regions[bar_idx].type = PCIREGION_TYPE_IO; + dev->regions[bar_idx].is_IO = 1; + dev->regions[bar_idx].bus_addr = (pciaddr_t)(val & 0xFFFFFFFC); + if (probe_bar_size(config_fd, offset, 1, &dev->regions[bar_idx].size) != 0) { + dev->regions[bar_idx].size = 0; + } + bar_idx += 1; + offset += 4; + } else { + int is_64 = ((val >> 1) & 0x3) == 2; + dev->regions[bar_idx].is_prefetchable = ((val >> 3) & 0x1) != 0; + dev->regions[bar_idx].type = PCIREGION_TYPE_MEMORY; + dev->regions[bar_idx].is_IO = 0; + + if (is_64) { + if (offset + 4 > 0x24) { + break; + } + dev->regions[bar_idx].is_64 = 1; + uint32_t val_hi = read_dword(config, offset + 4); + dev->regions[bar_idx].bus_addr = ((pciaddr_t)val_hi << 32) | (val & 0xFFFFFFF0); + + uint64_t size_lo = 0, size_hi = 0; + if (probe_bar_size(config_fd, offset, 0, &size_lo) == 0) { + probe_bar_size(config_fd, offset + 4, 0, &size_hi); + } + dev->regions[bar_idx].size = (size_hi << 32) | size_lo; + bar_idx += 2; + offset += 8; + } else { + dev->regions[bar_idx].bus_addr = (pciaddr_t)(val & 0xFFFFFFF0); + if (probe_bar_size(config_fd, offset, 0, &dev->regions[bar_idx].size) != 0) { + dev->regions[bar_idx].size = 0; + } + bar_idx += 1; + offset += 4; + } + } + } + + return 0; +} + +static int parse_device(const char *name, struct pci_device *dev) { + unsigned int domain, bus, device, func; + if (sscanf(name, "%x--%x--%x.%x", &domain, &bus, &device, &func) != 4) { + return -1; + } + if (device > 0x1F || func > 0x7) { + return -1; + } + + char config_path[256]; + snprintf(config_path, sizeof(config_path), "/scheme/pci/%s/config", name); + + uint8_t config[256]; + if (read_config(config_path, config, sizeof(config)) != 0) { + return -1; + } + + dev->domain = domain; + dev->bus = bus; + dev->dev = device; + dev->func = func; + dev->vendor_id = read_word(config, 0x00); + dev->device_id = read_word(config, 0x02); + dev->revision = config[0x08]; + dev->class_code = config[0x0B]; + dev->subclass = config[0x0A]; + dev->prog_if = config[0x09]; + + int config_fd = open(config_path, O_RDWR); + if (config_fd < 0) { + config_fd = open(config_path, O_RDONLY); + } + if (config_fd >= 0) { + parse_bars(config_fd, config, dev); + close(config_fd); + } + + dev->_internal = NULL; + return 0; +} + +int pci_system_init(void) { + if (pci_devices) { + return 0; + } + + DIR *dir = opendir("/scheme/pci"); + if (!dir) { + return -1; + } + + int capacity = 0; + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (entry->d_name[0] == '.') { + continue; + } + + struct pci_device probe; + memset(&probe, 0, sizeof(probe)); + if (parse_device(entry->d_name, &probe) != 0) { + continue; + } + + if (pci_device_count >= capacity) { + capacity = capacity ? capacity * 2 : 8; + struct pci_device *new_devices = realloc(pci_devices, capacity * sizeof(struct pci_device)); + if (!new_devices) { + closedir(dir); + return -1; + } + pci_devices = new_devices; + } + + pci_devices[pci_device_count++] = probe; + } + + closedir(dir); + return 0; +} + +void pci_system_cleanup(void) { + if (pci_devices) { + free(pci_devices); + pci_devices = NULL; + pci_device_count = 0; + } +} + +struct pci_device *pci_device_find_by_slot(unsigned int domain, + unsigned int bus, + unsigned int dev, + unsigned int func) { + for (int i = 0; i < pci_device_count; i++) { + if (pci_devices[i].domain == domain && + pci_devices[i].bus == bus && + pci_devices[i].dev == dev && + pci_devices[i].func == func) { + return &pci_devices[i]; + } + } + return NULL; +} + +int pci_device_probe(struct pci_device *dev) { + char config_path[256]; + snprintf(config_path, sizeof(config_path), + "/scheme/pci/%04x--%02x--%02x.%x/config", + dev->domain, dev->bus, dev->dev, dev->func); + + uint8_t config[256]; + if (read_config(config_path, config, sizeof(config)) != 0) { + return -1; + } + + int config_fd = open(config_path, O_RDWR); + if (config_fd < 0) { + config_fd = open(config_path, O_RDONLY); + } + if (config_fd >= 0) { + parse_bars(config_fd, config, dev); + close(config_fd); + return 0; + } + return -1; +} diff --git a/local/recipes/libs/libudev/recipe.toml b/local/recipes/libs/libudev/recipe.toml index 30cef4538b..9e5796a7c3 100644 --- a/local/recipes/libs/libudev/recipe.toml +++ b/local/recipes/libs/libudev/recipe.toml @@ -30,7 +30,7 @@ x86_64-unknown-redox-gcc \ cat > "${COOKBOOK_STAGE}/usr/lib/cmake/UDev/UDevConfig.cmake" << 'EOF' set(UDev_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/../../../include") set(UDev_LIBRARIES "${CMAKE_CURRENT_LIST_DIR}/../../../lib/libudev.so") -set(UDev_VERSION "0.2.3") +set(UDev_VERSION "0.3.0") if(NOT TARGET UDev::UDev) add_library(UDev::UDev SHARED IMPORTED) set_target_properties(UDev::UDev PROPERTIES @@ -48,13 +48,13 @@ libdir=${exec_prefix}/lib includedir=${prefix}/include Name: libudev -Description: Real scheme:udev-backed libudev provider for Red Bear (v6.0 2026) -Version: 0.2.3 +Description: Real scheme:udev-backed libudev provider for Red Bear +Version: 0.3.0 Libs: -L${libdir} -ludev Cflags: -I${includedir} EOF """ [package] -version = "0.2.3" -description = "libudev — real scheme:udev-backed libudev.so for Red Bear (v6.0 2026). Full enumerate / device / monitor / list-entry API in 1314 lines of C backed by /scheme/udev/devices plus udev-shim. Provides UDev::UDev CMake target, libudev.pc, and libudev.h for KWin tablet/input discovery. Hotplug event delivery remains bounded by scheme:udev semantics." +version = "0.3.0" +description = "libudev — real scheme:udev-backed libudev.so for Red Bear. Full enumerate / device / monitor / list-entry API in 1314 lines of C backed by /scheme/udev/devices plus udev-shim. Provides UDev::UDev CMake target, libudev.pc, and libudev.h for KWin tablet/input discovery. Hotplug event delivery remains bounded by scheme:udev semantics." diff --git a/local/recipes/libs/libudev/source/.gitkeep b/local/recipes/libs/libudev/source/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/libudev/source/include/libudev.h b/local/recipes/libs/libudev/source/include/libudev.h new file mode 100644 index 0000000000..c67c9223a4 --- /dev/null +++ b/local/recipes/libs/libudev/source/include/libudev.h @@ -0,0 +1,73 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct udev; +struct udev_device; +struct udev_enumerate; +struct udev_list_entry; +struct udev_monitor; + +#define udev_list_entry_foreach(list_entry, first_entry) \ + for ((list_entry) = (first_entry); (list_entry) != NULL; (list_entry) = udev_list_entry_get_next(list_entry)) + +struct udev *udev_new(void); +struct udev *udev_ref(struct udev *udev); +struct udev *udev_unref(struct udev *udev); + +struct udev_enumerate *udev_enumerate_new(struct udev *udev); +struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); +struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate); +struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate); +int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); +int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname); +int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value); +int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); +int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate); +struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); + +struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry); +const char *udev_list_entry_get_name(struct udev_list_entry *list_entry); +const char *udev_list_entry_get_value(struct udev_list_entry *list_entry); + +struct udev_device *udev_device_ref(struct udev_device *udev_device); +struct udev_device *udev_device_unref(struct udev_device *udev_device); +struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath); +struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum); +struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname); +struct udev *udev_device_get_udev(struct udev_device *udev_device); +const char *udev_device_get_devnode(struct udev_device *udev_device); +dev_t udev_device_get_devnum(struct udev_device *udev_device); +const char *udev_device_get_action(struct udev_device *udev_device); +const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key); +struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device); +struct udev_device *udev_device_get_parent(struct udev_device *udev_device); +struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype); +const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr); +const char *udev_device_get_devpath(struct udev_device *udev_device); +const char *udev_device_get_syspath(struct udev_device *udev_device); +const char *udev_device_get_subsystem(struct udev_device *udev_device); +const char *udev_device_get_devtype(struct udev_device *udev_device); +const char *udev_device_get_sysname(struct udev_device *udev_device); +const char *udev_device_get_sysnum(struct udev_device *udev_device); +const char *udev_device_get_driver(struct udev_device *udev_device); +int udev_device_get_is_initialized(struct udev_device *udev_device); +int udev_device_has_tag(struct udev_device *udev_device, const char *tag); + +struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name); +struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor); +struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor); +int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype); +int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); +int udev_monitor_get_fd(struct udev_monitor *udev_monitor); +struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor); + +#ifdef __cplusplus +} +#endif diff --git a/local/recipes/libs/libudev/source/libudev.c b/local/recipes/libs/libudev/source/libudev.c new file mode 100644 index 0000000000..0da3e4de37 --- /dev/null +++ b/local/recipes/libs/libudev/source/libudev.c @@ -0,0 +1,1314 @@ +#define _POSIX_C_SOURCE 200809L + +#include "libudev.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct udev_list_entry { + char *name; + char *value; + struct udev_list_entry *next; +}; + +struct udev { + int refcount; +}; + +struct udev_match_property { + char *key; + char *value; + struct udev_match_property *next; +}; + +struct udev_device { + int refcount; + struct udev *udev; + char *syspath; + char *devpath; + char *devnode; + char *subsystem; + char *devtype; + char *sysname; + char *sysnum; + char *driver; + char *action; + dev_t devnum; + struct udev_list_entry *properties; + struct udev_list_entry *devlinks; + struct udev_list_entry *sysattrs; + struct udev_device *parent; +}; + +struct udev_enumerate { + int refcount; + struct udev *udev; + char *match_subsystem; + char *match_sysname; + struct udev_match_property *match_properties; + struct udev_list_entry *list; +}; + +struct udev_monitor_filter { + char *subsystem; + char *devtype; + struct udev_monitor_filter *next; +}; + +struct udev_monitor { + int refcount; + struct udev *udev; + int read_fd; + int write_fd; + bool enabled; + struct udev_monitor_filter *filters; + struct udev_monitor_event *pending_head; + struct udev_monitor_event *pending_tail; +}; + +struct udev_monitor_event { + struct udev_device *device; + struct udev_monitor_event *next; +}; + +static char *xstrdup(const char *value) +{ + if (!value) { + return NULL; + } + + size_t len = strlen(value) + 1; + char *copy = malloc(len); + if (!copy) { + return NULL; + } + + memcpy(copy, value, len); + return copy; +} + +static void free_list_entries(struct udev_list_entry *entry) +{ + while (entry) { + struct udev_list_entry *next = entry->next; + free(entry->name); + free(entry->value); + free(entry); + entry = next; + } +} + +static void free_match_properties(struct udev_match_property *entry) +{ + while (entry) { + struct udev_match_property *next = entry->next; + free(entry->key); + free(entry->value); + free(entry); + entry = next; + } +} + +static void free_monitor_filters(struct udev_monitor_filter *entry) +{ + while (entry) { + struct udev_monitor_filter *next = entry->next; + free(entry->subsystem); + free(entry->devtype); + free(entry); + entry = next; + } +} + +static void free_monitor_events(struct udev_monitor_event *entry) +{ + while (entry) { + struct udev_monitor_event *next = entry->next; + udev_device_unref(entry->device); + free(entry); + entry = next; + } +} + +static int list_entry_append(struct udev_list_entry **head, const char *name, const char *value) +{ + struct udev_list_entry *entry = calloc(1, sizeof(*entry)); + if (!entry) { + return -1; + } + + entry->name = xstrdup(name); + entry->value = xstrdup(value); + if ((name && !entry->name) || (value && !entry->value)) { + free(entry->name); + free(entry->value); + free(entry); + return -1; + } + + if (!*head) { + *head = entry; + return 0; + } + + struct udev_list_entry *tail = *head; + while (tail->next) { + tail = tail->next; + } + tail->next = entry; + return 0; +} + +static const char *list_entry_find_value(const struct udev_list_entry *entry, const char *name) +{ + while (entry) { + if (entry->name && name && strcmp(entry->name, name) == 0) { + return entry->value; + } + entry = entry->next; + } + return NULL; +} + +static bool list_entry_has_name(const struct udev_list_entry *entry, const char *name) +{ + while (entry) { + if (entry->name && name && strcmp(entry->name, name) == 0) { + return true; + } + entry = entry->next; + } + return false; +} + +static bool string_matches(const char *left, const char *right) +{ + return left && right && strcmp(left, right) == 0; +} + +static char *read_text_file(const char *path) +{ + FILE *file = fopen(path, "r"); + if (!file) { + return NULL; + } + + size_t cap = 1024; + size_t len = 0; + char *buffer = malloc(cap); + if (!buffer) { + fclose(file); + return NULL; + } + + for (;;) { + if (len + 512 >= cap) { + size_t next_cap = cap * 2; + char *next = realloc(buffer, next_cap); + if (!next) { + free(buffer); + fclose(file); + return NULL; + } + buffer = next; + cap = next_cap; + } + + size_t read_bytes = fread(buffer + len, 1, cap - len - 1, file); + len += read_bytes; + if (read_bytes == 0) { + if (ferror(file)) { + free(buffer); + fclose(file); + return NULL; + } + break; + } + } + + buffer[len] = '\0'; + fclose(file); + return buffer; +} + +static char *dup_basename(const char *path) +{ + if (!path) { + return NULL; + } + + const char *base = strrchr(path, '/'); + base = base ? base + 1 : path; + return xstrdup(base); +} + +static char *dup_sysnum(const char *sysname) +{ + if (!sysname) { + return NULL; + } + + const char *end = sysname + strlen(sysname); + const char *start = end; + while (start > sysname && start[-1] >= '0' && start[-1] <= '9') { + start--; + } + + if (start == end) { + return NULL; + } + + size_t len = (size_t)(end - start); + char *copy = malloc(len + 1); + if (!copy) { + return NULL; + } + + memcpy(copy, start, len); + copy[len] = '\0'; + return copy; +} + +static int replace_string(char **slot, const char *value) +{ + char *copy = xstrdup(value); + if (value && !copy) { + return -1; + } + + free(*slot); + *slot = copy; + return 0; +} + +static dev_t devnum_from_node(const char *devnode) +{ + if (!devnode) { + return 0; + } + + struct stat st; + if (stat(devnode, &st) != 0) { + return 0; + } + + return st.st_rdev; +} + +static void udev_device_destroy(struct udev_device *device) +{ + if (!device) { + return; + } + + if (device->parent) { + udev_device_destroy(device->parent); + } + + udev_unref(device->udev); + free(device->syspath); + free(device->devpath); + free(device->devnode); + free(device->subsystem); + free(device->devtype); + free(device->sysname); + free(device->sysnum); + free(device->driver); + free(device->action); + free_list_entries(device->properties); + free_list_entries(device->devlinks); + free_list_entries(device->sysattrs); + free(device); +} + +static struct udev_device *udev_device_alloc(struct udev *udev) +{ + struct udev_device *device = calloc(1, sizeof(*device)); + if (!device) { + return NULL; + } + + device->refcount = 1; + device->udev = udev_ref(udev); + if (!device->udev) { + free(device); + return NULL; + } + + return device; +} + +static bool is_primary_drm_device(const struct udev_device *device) +{ + return device && device->subsystem && strcmp(device->subsystem, "drm") == 0 && device->sysname && strcmp(device->sysname, "card0") == 0; +} + +static struct udev_device *make_pci_parent(struct udev_device *child) +{ + if (!child || !child->syspath || strncmp(child->syspath, "/devices/pci/", 13) != 0) { + return NULL; + } + if (child->subsystem && strcmp(child->subsystem, "pci") == 0) { + return NULL; + } + + struct udev_device *parent = udev_device_alloc(child->udev); + if (!parent) { + return NULL; + } + + if (replace_string(&parent->syspath, child->syspath) != 0 || replace_string(&parent->devpath, child->devpath ? child->devpath : child->syspath) != 0 || replace_string(&parent->subsystem, "pci") != 0 || !(parent->sysname = dup_basename(child->syspath))) { + udev_device_destroy(parent); + return NULL; + } + + parent->sysnum = dup_sysnum(parent->sysname); + if (list_entry_append(&parent->properties, "DEVPATH", parent->devpath) != 0 || list_entry_append(&parent->properties, "SUBSYSTEM", "pci") != 0) { + udev_device_destroy(parent); + return NULL; + } + + const char *vendor_id = list_entry_find_value(child->properties, "PCI_VENDOR_ID"); + const char *device_id = list_entry_find_value(child->properties, "PCI_DEVICE_ID"); + const char *pci_class = list_entry_find_value(child->properties, "PCI_CLASS"); + + if ((vendor_id && list_entry_append(&parent->properties, "PCI_VENDOR_ID", vendor_id) != 0) || (device_id && list_entry_append(&parent->properties, "PCI_DEVICE_ID", device_id) != 0) || (pci_class && list_entry_append(&parent->properties, "PCI_CLASS", pci_class) != 0) || list_entry_append(&parent->sysattrs, "boot_vga", is_primary_drm_device(child) ? "1" : "0") != 0) { + udev_device_destroy(parent); + return NULL; + } + + return parent; +} + +static struct udev_device *parse_device_record(struct udev *udev, const char *content, const char *action) +{ + char *buffer = xstrdup(content); + if (!buffer) { + return NULL; + } + + struct udev_device *device = udev_device_alloc(udev); + if (!device) { + free(buffer); + return NULL; + } + + char *save = NULL; + for (char *line = strtok_r(buffer, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) { + if (strncmp(line, "P=", 2) == 0) { + if (replace_string(&device->syspath, line + 2) != 0 || replace_string(&device->devpath, line + 2) != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + } else if (strncmp(line, "E=", 2) == 0) { + char *payload = line + 2; + char *separator = strchr(payload, '='); + if (!separator) { + continue; + } + + *separator = '\0'; + const char *key = payload; + const char *value = separator + 1; + if (list_entry_append(&device->properties, key, value) != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + + if (strcmp(key, "DEVPATH") == 0) { + if (replace_string(&device->devpath, value) != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + } else if (strcmp(key, "SUBSYSTEM") == 0) { + if (replace_string(&device->subsystem, value) != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + } else if (strcmp(key, "DEVNAME") == 0) { + if (replace_string(&device->devnode, value) != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + } + } else if (strncmp(line, "S=", 2) == 0) { + const char *value = line + 2; + if (*value == '\0') { + continue; + } + + char *devlink = NULL; + if (value[0] == '/') { + devlink = xstrdup(value); + } else { + size_t len = strlen(value) + 2; + devlink = malloc(len); + if (devlink) { + snprintf(devlink, len, "/%s", value); + } + } + + if (!devlink || list_entry_append(&device->devlinks, devlink, NULL) != 0) { + free(devlink); + udev_device_destroy(device); + free(buffer); + return NULL; + } + + free(devlink); + } + } + + if (!device->syspath && device->devpath && replace_string(&device->syspath, device->devpath) != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + + if (!device->sysname) { + device->sysname = dup_basename(device->devnode ? device->devnode : device->syspath); + } + if (device->sysname && !device->sysnum) { + device->sysnum = dup_sysnum(device->sysname); + } + if (device->devnode) { + device->devnum = devnum_from_node(device->devnode); + } + if (action && replace_string(&device->action, action) != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + if (!device->subsystem && replace_string(&device->subsystem, "unknown") != 0) { + udev_device_destroy(device); + free(buffer); + return NULL; + } + + device->parent = make_pci_parent(device); + free(buffer); + return device; +} + +typedef int (*device_callback_fn)(struct udev_device *device, void *ctx); + +static int scan_scheme_devices(struct udev *udev, device_callback_fn callback, void *ctx) +{ + char *listing = read_text_file("/scheme/udev/devices"); + if (!listing) { + return 0; + } + + int result = 0; + char *save = NULL; + for (char *line = strtok_r(listing, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) { + if (*line == '\0') { + continue; + } + + char path[256]; + snprintf(path, sizeof(path), "/scheme/udev/devices/%s", line); + + char *content = read_text_file(path); + if (!content) { + continue; + } + + struct udev_device *device = parse_device_record(udev, content, NULL); + free(content); + if (!device) { + continue; + } + + result = callback(device, ctx); + udev_device_unref(device); + if (result != 0) { + break; + } + } + + free(listing); + return result; +} + +struct find_by_syspath_ctx { + struct udev_device *result; + const char *target; +}; + +static int find_by_syspath_cb(struct udev_device *device, void *ctx) +{ + struct find_by_syspath_ctx *state = ctx; + if (string_matches(device->syspath, state->target) || string_matches(device->devnode, state->target) || list_entry_has_name(device->devlinks, state->target)) { + state->result = udev_device_ref(device); + return 1; + } + return 0; +} + +struct find_by_devnum_ctx { + struct udev_device *result; + dev_t target; +}; + +static int find_by_devnum_cb(struct udev_device *device, void *ctx) +{ + struct find_by_devnum_ctx *state = ctx; + if (device->devnum != 0 && device->devnum == state->target) { + state->result = udev_device_ref(device); + return 1; + } + return 0; +} + +struct find_by_subsystem_sysname_ctx { + struct udev_device *result; + const char *subsystem; + const char *sysname; +}; + +static int find_by_subsystem_sysname_cb(struct udev_device *device, void *ctx) +{ + struct find_by_subsystem_sysname_ctx *state = ctx; + if (string_matches(device->subsystem, state->subsystem) && string_matches(device->sysname, state->sysname)) { + state->result = udev_device_ref(device); + return 1; + } + return 0; +} + +static bool device_matches_enumerate(const struct udev_enumerate *enumerate, const struct udev_device *device) +{ + if (enumerate->match_subsystem && !string_matches(enumerate->match_subsystem, device->subsystem)) { + return false; + } + + if (enumerate->match_sysname && (!device->sysname || fnmatch(enumerate->match_sysname, device->sysname, 0) != 0)) { + return false; + } + + for (const struct udev_match_property *entry = enumerate->match_properties; entry; entry = entry->next) { + const char *value = list_entry_find_value(device->properties, entry->key); + if (!value) { + return false; + } + if (entry->value && strcmp(value, entry->value) != 0) { + return false; + } + } + + return true; +} + +static bool device_matches_monitor_filters(const struct udev_monitor *monitor, const struct udev_device *device) +{ + const struct udev_monitor_filter *filter; + + if (!monitor->filters) { + return true; + } + + for (filter = monitor->filters; filter; filter = filter->next) { + if (!string_matches(filter->subsystem, device->subsystem)) { + continue; + } + if (filter->devtype && !string_matches(filter->devtype, device->devtype)) { + continue; + } + return true; + } + + return false; +} + +static int monitor_queue_device(struct udev_monitor *monitor, struct udev_device *device, const char *action) +{ + struct udev_monitor_event *event; + struct udev_device *copy; + + if (!monitor || !device || !device_matches_monitor_filters(monitor, device)) { + return 0; + } + + copy = udev_device_ref(device); + if (!copy) { + errno = ENOMEM; + return -1; + } + + free(copy->action); + copy->action = xstrdup(action ? action : "change"); + if (!copy->action) { + udev_device_unref(copy); + errno = ENOMEM; + return -1; + } + + event = calloc(1, sizeof(*event)); + if (!event) { + udev_device_unref(copy); + errno = ENOMEM; + return -1; + } + + event->device = copy; + if (monitor->pending_tail) { + monitor->pending_tail->next = event; + } else { + monitor->pending_head = event; + } + monitor->pending_tail = event; + return 0; +} + +static int monitor_emit_pending(struct udev_monitor *monitor) +{ + struct udev_monitor_event *event; + + if (!monitor || monitor->write_fd < 0) { + return 0; + } + + for (event = monitor->pending_head; event; event = event->next) { + if (write(monitor->write_fd, "u", 1) < 0) { + return -1; + } + } + + return 0; +} + +static int monitor_seed_existing_devices_cb(struct udev_device *device, void *ctx) +{ + return monitor_queue_device(ctx, device, "change"); +} + +static void clear_enumerate_list(struct udev_enumerate *enumerate) +{ + free_list_entries(enumerate->list); + enumerate->list = NULL; +} + +struct enumerate_devices_ctx { + struct udev_enumerate *enumerate; + int failed; +}; + +static int enumerate_devices_cb(struct udev_device *device, void *ctx) +{ + struct enumerate_devices_ctx *state = ctx; + if (!device_matches_enumerate(state->enumerate, device)) { + return 0; + } + + if (list_entry_append(&state->enumerate->list, device->syspath, NULL) != 0) { + state->failed = 1; + return 1; + } + + return 0; +} + +struct enumerate_subsystems_ctx { + struct udev_enumerate *enumerate; + int failed; +}; + +static int enumerate_subsystems_cb(struct udev_device *device, void *ctx) +{ + struct enumerate_subsystems_ctx *state = ctx; + if (!device->subsystem || list_entry_has_name(state->enumerate->list, device->subsystem)) { + return 0; + } + + if (list_entry_append(&state->enumerate->list, device->subsystem, NULL) != 0) { + state->failed = 1; + return 1; + } + + return 0; +} + +struct udev *udev_new(void) +{ + struct udev *udev = calloc(1, sizeof(*udev)); + if (!udev) { + return NULL; + } + + udev->refcount = 1; + return udev; +} + +struct udev *udev_ref(struct udev *udev) +{ + if (udev) { + udev->refcount++; + } + return udev; +} + +struct udev *udev_unref(struct udev *udev) +{ + if (!udev) { + return NULL; + } + + udev->refcount--; + if (udev->refcount <= 0) { + free(udev); + return NULL; + } + + return udev; +} + +struct udev_enumerate *udev_enumerate_new(struct udev *udev) +{ + if (!udev) { + errno = EINVAL; + return NULL; + } + + struct udev_enumerate *enumerate = calloc(1, sizeof(*enumerate)); + if (!enumerate) { + return NULL; + } + + enumerate->refcount = 1; + enumerate->udev = udev_ref(udev); + return enumerate; +} + +struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) +{ + if (udev_enumerate) { + udev_enumerate->refcount++; + } + return udev_enumerate; +} + +struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) +{ + if (!udev_enumerate) { + return NULL; + } + + udev_enumerate->refcount--; + if (udev_enumerate->refcount <= 0) { + udev_unref(udev_enumerate->udev); + free(udev_enumerate->match_subsystem); + free(udev_enumerate->match_sysname); + free_match_properties(udev_enumerate->match_properties); + clear_enumerate_list(udev_enumerate); + free(udev_enumerate); + return NULL; + } + + return udev_enumerate; +} + +struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) +{ + return udev_enumerate ? udev_enumerate->udev : NULL; +} + +int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +{ + if (!udev_enumerate || !subsystem) { + errno = EINVAL; + return -1; + } + + return replace_string(&udev_enumerate->match_subsystem, subsystem); +} + +int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) +{ + if (!udev_enumerate || !sysname) { + errno = EINVAL; + return -1; + } + + return replace_string(&udev_enumerate->match_sysname, sysname); +} + +int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) +{ + if (!udev_enumerate || !property) { + errno = EINVAL; + return -1; + } + + struct udev_match_property *entry = calloc(1, sizeof(*entry)); + if (!entry) { + return -1; + } + + entry->key = xstrdup(property); + entry->value = xstrdup(value); + if (!entry->key || (value && !entry->value)) { + free(entry->key); + free(entry->value); + free(entry); + return -1; + } + + if (!udev_enumerate->match_properties) { + udev_enumerate->match_properties = entry; + return 0; + } + + struct udev_match_property *tail = udev_enumerate->match_properties; + while (tail->next) { + tail = tail->next; + } + tail->next = entry; + return 0; +} + +int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) +{ + if (!udev_enumerate) { + errno = EINVAL; + return -1; + } + + clear_enumerate_list(udev_enumerate); + struct enumerate_devices_ctx ctx = { + .enumerate = udev_enumerate, + .failed = 0, + }; + scan_scheme_devices(udev_enumerate->udev, enumerate_devices_cb, &ctx); + if (ctx.failed) { + errno = ENOMEM; + return -1; + } + return 0; +} + +int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) +{ + if (!udev_enumerate) { + errno = EINVAL; + return -1; + } + + clear_enumerate_list(udev_enumerate); + struct enumerate_subsystems_ctx ctx = { + .enumerate = udev_enumerate, + .failed = 0, + }; + scan_scheme_devices(udev_enumerate->udev, enumerate_subsystems_cb, &ctx); + if (ctx.failed) { + errno = ENOMEM; + return -1; + } + return 0; +} + +struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) +{ + return udev_enumerate ? udev_enumerate->list : NULL; +} + +struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) +{ + return list_entry ? list_entry->next : NULL; +} + +const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) +{ + return list_entry ? list_entry->name : NULL; +} + +const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) +{ + return list_entry ? list_entry->value : NULL; +} + +struct udev_device *udev_device_ref(struct udev_device *udev_device) +{ + if (udev_device) { + udev_device->refcount++; + } + return udev_device; +} + +struct udev_device *udev_device_unref(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + udev_device->refcount--; + if (udev_device->refcount <= 0) { + udev_device_destroy(udev_device); + return NULL; + } + + return udev_device; +} + +struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) +{ + if (!udev || !syspath) { + errno = EINVAL; + return NULL; + } + + struct find_by_syspath_ctx ctx = { + .result = NULL, + .target = syspath, + }; + scan_scheme_devices(udev, find_by_syspath_cb, &ctx); + if (!ctx.result) { + errno = ENOENT; + } + return ctx.result; +} + +struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) +{ + (void)type; + if (!udev) { + errno = EINVAL; + return NULL; + } + + struct find_by_devnum_ctx ctx = { + .result = NULL, + .target = devnum, + }; + scan_scheme_devices(udev, find_by_devnum_cb, &ctx); + if (!ctx.result) { + errno = ENOENT; + } + return ctx.result; +} + +struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) +{ + if (!udev || !subsystem || !sysname) { + errno = EINVAL; + return NULL; + } + + struct find_by_subsystem_sysname_ctx ctx = { + .result = NULL, + .subsystem = subsystem, + .sysname = sysname, + }; + scan_scheme_devices(udev, find_by_subsystem_sysname_cb, &ctx); + if (!ctx.result) { + errno = ENOENT; + } + return ctx.result; +} + +struct udev *udev_device_get_udev(struct udev_device *udev_device) +{ + return udev_device ? udev_device->udev : NULL; +} + +const char *udev_device_get_devnode(struct udev_device *udev_device) +{ + return udev_device ? udev_device->devnode : NULL; +} + +dev_t udev_device_get_devnum(struct udev_device *udev_device) +{ + return udev_device ? udev_device->devnum : 0; +} + +const char *udev_device_get_action(struct udev_device *udev_device) +{ + return udev_device ? udev_device->action : NULL; +} + +const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) +{ + return udev_device ? list_entry_find_value(udev_device->properties, key) : NULL; +} + +struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) +{ + return udev_device ? udev_device->properties : NULL; +} + +struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) +{ + return udev_device ? udev_device->devlinks : NULL; +} + +struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) +{ + return udev_device ? udev_device->sysattrs : NULL; +} + +struct udev_device *udev_device_get_parent(struct udev_device *udev_device) +{ + return udev_device ? udev_device->parent : NULL; +} + +struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) +{ + if (!udev_device || !subsystem) { + return NULL; + } + + if (string_matches(udev_device->subsystem, subsystem) && (!devtype || string_matches(udev_device->devtype, devtype))) { + return udev_device; + } + + if (udev_device->parent && string_matches(udev_device->parent->subsystem, subsystem) && (!devtype || string_matches(udev_device->parent->devtype, devtype))) { + return udev_device->parent; + } + + return NULL; +} + +const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) +{ + return udev_device ? list_entry_find_value(udev_device->sysattrs, sysattr) : NULL; +} + +const char *udev_device_get_devpath(struct udev_device *udev_device) +{ + return udev_device ? udev_device->devpath : NULL; +} + +const char *udev_device_get_syspath(struct udev_device *udev_device) +{ + return udev_device ? udev_device->syspath : NULL; +} + +const char *udev_device_get_subsystem(struct udev_device *udev_device) +{ + return udev_device ? udev_device->subsystem : NULL; +} + +const char *udev_device_get_devtype(struct udev_device *udev_device) +{ + return udev_device ? udev_device->devtype : NULL; +} + +const char *udev_device_get_sysname(struct udev_device *udev_device) +{ + return udev_device ? udev_device->sysname : NULL; +} + +const char *udev_device_get_sysnum(struct udev_device *udev_device) +{ + return udev_device ? udev_device->sysnum : NULL; +} + +const char *udev_device_get_driver(struct udev_device *udev_device) +{ + return udev_device ? udev_device->driver : NULL; +} + +int udev_device_get_is_initialized(struct udev_device *udev_device) +{ + return udev_device ? 1 : 0; +} + +int udev_device_has_tag(struct udev_device *udev_device, const char *tag) +{ + const char *tags = udev_device_get_property_value(udev_device, "TAGS"); + if (!tags || !tag || *tag == '\0') { + return 0; + } + + size_t tag_len = strlen(tag); + const char *cursor = tags; + while (*cursor) { + while (*cursor == ':' || *cursor == ' ') { + cursor++; + } + + const char *end = cursor; + while (*end && *end != ':') { + end++; + } + + if ((size_t)(end - cursor) == tag_len && strncmp(cursor, tag, tag_len) == 0) { + return 1; + } + + cursor = end; + } + + return 0; +} + +struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) +{ + int pipe_fds[2]; + + if (!udev || !name || strcmp(name, "udev") != 0) { + errno = EINVAL; + return NULL; + } + + struct udev_monitor *monitor = calloc(1, sizeof(*monitor)); + if (!monitor) { + return NULL; + } + + if (pipe(pipe_fds) != 0) { + free(monitor); + return NULL; + } + + int flags = fcntl(pipe_fds[0], F_GETFL); + if (flags >= 0) { + (void)fcntl(pipe_fds[0], F_SETFL, flags | O_NONBLOCK); + } + + monitor->refcount = 1; + monitor->udev = udev_ref(udev); + monitor->read_fd = pipe_fds[0]; + monitor->write_fd = pipe_fds[1]; + return monitor; +} + +struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) +{ + if (udev_monitor) { + udev_monitor->refcount++; + } + return udev_monitor; +} + +struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) +{ + if (!udev_monitor) { + return NULL; + } + + udev_monitor->refcount--; + if (udev_monitor->refcount <= 0) { + if (udev_monitor->read_fd >= 0) { + close(udev_monitor->read_fd); + } + if (udev_monitor->write_fd >= 0) { + close(udev_monitor->write_fd); + } + free_monitor_filters(udev_monitor->filters); + free_monitor_events(udev_monitor->pending_head); + udev_unref(udev_monitor->udev); + free(udev_monitor); + return NULL; + } + + return udev_monitor; +} + +int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) +{ + if (!udev_monitor || !subsystem) { + errno = EINVAL; + return -1; + } + + struct udev_monitor_filter *filter = calloc(1, sizeof(*filter)); + if (!filter) { + return -1; + } + + filter->subsystem = xstrdup(subsystem); + filter->devtype = xstrdup(devtype); + if (!filter->subsystem || (devtype && !filter->devtype)) { + free(filter->subsystem); + free(filter->devtype); + free(filter); + return -1; + } + + if (!udev_monitor->filters) { + udev_monitor->filters = filter; + return 0; + } + + struct udev_monitor_filter *tail = udev_monitor->filters; + while (tail->next) { + tail = tail->next; + } + tail->next = filter; + return 0; +} + +int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) +{ + if (!udev_monitor) { + errno = EINVAL; + return -1; + } + + if (udev_monitor->enabled) { + return 0; + } + + if (udev_monitor->read_fd < 0 || udev_monitor->write_fd < 0) { + errno = EINVAL; + return -1; + } + + if (scan_scheme_devices(udev_monitor->udev, monitor_seed_existing_devices_cb, udev_monitor) != 0) { + return -1; + } + + if (monitor_emit_pending(udev_monitor) != 0) { + return -1; + } + + udev_monitor->enabled = true; + return 0; +} + +int udev_monitor_get_fd(struct udev_monitor *udev_monitor) +{ + return udev_monitor ? udev_monitor->read_fd : -1; +} + +struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) +{ + struct udev_monitor_event *event; + + if (!udev_monitor || udev_monitor->read_fd < 0) { + return NULL; + } + + char byte; + ssize_t read_bytes = read(udev_monitor->read_fd, &byte, sizeof(byte)); + if (read_bytes <= 0) { + return NULL; + } + + event = udev_monitor->pending_head; + if (!event) { + return NULL; + } + + udev_monitor->pending_head = event->next; + if (!udev_monitor->pending_head) { + udev_monitor->pending_tail = NULL; + } + + struct udev_device *device = event->device; + free(event); + return device; +} diff --git a/local/recipes/qt/qtbase/source.tar b/local/recipes/qt/qtbase/source.tar index dcae380507..7580c763a7 100644 Binary files a/local/recipes/qt/qtbase/source.tar and b/local/recipes/qt/qtbase/source.tar differ diff --git a/local/recipes/system/coretempd/source/Cargo.toml b/local/recipes/system/coretempd/source/Cargo.toml index 665f28dc96..aa6b4634a4 100644 --- a/local/recipes/system/coretempd/source/Cargo.toml +++ b/local/recipes/system/coretempd/source/Cargo.toml @@ -9,11 +9,11 @@ path = "src/main.rs" [dependencies] libc = "0.2" -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/cpufreqd/Cargo.toml b/local/recipes/system/cpufreqd/Cargo.toml index a281c75cf0..e50c61e067 100644 --- a/local/recipes/system/cpufreqd/Cargo.toml +++ b/local/recipes/system/cpufreqd/Cargo.toml @@ -8,5 +8,5 @@ name = "cpufreqd" path = "src/main.rs" [dependencies] -redox_syscall = { path = "../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../local/sources/syscall" } log = "0.4" diff --git a/local/recipes/system/cpufreqd/source/Cargo.toml b/local/recipes/system/cpufreqd/source/Cargo.toml index 2a5f8472c3..61a30bc81f 100644 --- a/local/recipes/system/cpufreqd/source/Cargo.toml +++ b/local/recipes/system/cpufreqd/source/Cargo.toml @@ -8,8 +8,8 @@ name = "cpufreqd" path = "src/main.rs" [dependencies] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../../local/sources/syscall" } log = "0.4" [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/devfsd/source/Cargo.toml b/local/recipes/system/devfsd/source/Cargo.toml index 8d2e9119af..c61b8e45e9 100644 --- a/local/recipes/system/devfsd/source/Cargo.toml +++ b/local/recipes/system/devfsd/source/Cargo.toml @@ -8,11 +8,11 @@ name = "devfsd" path = "src/main.rs" [dependencies] -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } log = "0.4" [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/diskd/source/Cargo.toml b/local/recipes/system/diskd/source/Cargo.toml index 37b059e5fe..12b5d34b62 100644 --- a/local/recipes/system/diskd/source/Cargo.toml +++ b/local/recipes/system/diskd/source/Cargo.toml @@ -10,9 +10,9 @@ name = "diskd" path = "src/main.rs" [dependencies] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } log = "0.4" [profile.release] @@ -20,5 +20,5 @@ opt-level = 3 lto = true [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/driver-manager/Cargo.toml b/local/recipes/system/driver-manager/Cargo.toml index 9353183b49..415b8b28a0 100644 --- a/local/recipes/system/driver-manager/Cargo.toml +++ b/local/recipes/system/driver-manager/Cargo.toml @@ -12,7 +12,7 @@ path = "src/main.rs" redox-driver-core = { path = "../../drivers/redox-driver-core" } redox-driver-pci = { path = "../../drivers/redox-driver-pci" } pcid_interface = { path = "../../../../local/sources/base/drivers/pcid", package = "pcid" } -redox_syscall = { path = "../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../local/sources/syscall" } log = "0.4" toml = "0.8" serde = { version = "1", features = ["derive"] } diff --git a/local/recipes/system/driver-manager/source/Cargo.toml b/local/recipes/system/driver-manager/source/Cargo.toml index 2e43572532..34c6ad4ebf 100644 --- a/local/recipes/system/driver-manager/source/Cargo.toml +++ b/local/recipes/system/driver-manager/source/Cargo.toml @@ -12,13 +12,13 @@ path = "src/main.rs" redox-driver-core = { path = "../../../drivers/redox-driver-core/source" } redox-driver-pci = { path = "../../../drivers/redox-driver-pci/source" } pcid_interface = { path = "../../../../../local/sources/base/drivers/pcid", package = "pcid" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { package = "redox_syscall", path = "../../../../../recipes/core/base/syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { package = "redox_syscall", path = "../../../../../local/sources/syscall", features = ["std"] } log = "0.4" toml = "0.8" serde = { version = "1", features = ["derive"] } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } \ No newline at end of file +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } \ No newline at end of file diff --git a/local/recipes/system/driver-params/Cargo.toml b/local/recipes/system/driver-params/Cargo.toml index 0b131829c4..e1d63b3fa1 100644 --- a/local/recipes/system/driver-params/Cargo.toml +++ b/local/recipes/system/driver-params/Cargo.toml @@ -8,7 +8,7 @@ name = "driver-params" path = "src/main.rs" [dependencies] -redox_syscall = { path = "../../../../recipes/core/base/syscall" } -redox-scheme = { path = "../../../../recipes/core/base/redox-scheme" } -libredox = { path = "../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../local/sources/syscall" } +redox-scheme = { path = "../../../../../../local/sources/redox-scheme" } +libredox = { path = "../../../../local/sources/libredox" } log = "0.4" diff --git a/local/recipes/system/driver-params/source/Cargo.toml b/local/recipes/system/driver-params/source/Cargo.toml index f64ce27081..935516fedc 100644 --- a/local/recipes/system/driver-params/source/Cargo.toml +++ b/local/recipes/system/driver-params/source/Cargo.toml @@ -8,12 +8,12 @@ name = "driver-params" path = "src/main.rs" [dependencies] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +libredox = { path = "../../../../../local/sources/libredox" } log = "0.4" [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/evdevd/source/Cargo.toml b/local/recipes/system/evdevd/source/Cargo.toml index e9331b72a5..065bbd4fdd 100644 --- a/local/recipes/system/evdevd/source/Cargo.toml +++ b/local/recipes/system/evdevd/source/Cargo.toml @@ -4,8 +4,8 @@ version = "0.3.0" edition = "2021" [dependencies] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall" } log = { version = "0.4", features = ["std"] } thiserror = "2" orbclient = { version = "0.3", default-features = false } @@ -16,5 +16,5 @@ redox_event = "0.4" [workspace] [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/firmware-loader/source/Cargo.toml b/local/recipes/system/firmware-loader/source/Cargo.toml index 1bd3745b26..e839ea3ff6 100644 --- a/local/recipes/system/firmware-loader/source/Cargo.toml +++ b/local/recipes/system/firmware-loader/source/Cargo.toml @@ -5,15 +5,15 @@ edition = "2021" [dependencies] libc = "0.2" -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } -redox_scheme = { path = "../../../../../recipes/core/base/redox-scheme", package = "redox-scheme" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } +redox_scheme = { path = "../../../../../local/sources/redox-scheme", package = "redox-scheme" } +libredox = { path = "../../../../../local/sources/libredox" } log = { version = "0.4", features = ["std"] } sha2 = "0.10" thiserror = "2" toml = "0.8" [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/hwrngd/Cargo.toml b/local/recipes/system/hwrngd/Cargo.toml index 27b1defb71..4cadbdbf4b 100644 --- a/local/recipes/system/hwrngd/Cargo.toml +++ b/local/recipes/system/hwrngd/Cargo.toml @@ -8,7 +8,7 @@ name = "hwrngd" path = "source/src/main.rs" [dependencies] -libredox = { path = "../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } \ No newline at end of file +redox-scheme = { path = "../../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } \ No newline at end of file diff --git a/local/recipes/system/hwrngd/source/Cargo.toml b/local/recipes/system/hwrngd/source/Cargo.toml index f74bdf70c2..a377f2bdfc 100644 --- a/local/recipes/system/hwrngd/source/Cargo.toml +++ b/local/recipes/system/hwrngd/source/Cargo.toml @@ -8,10 +8,10 @@ name = "hwrngd" path = "src/main.rs" [dependencies] -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/iommu/source/Cargo.toml b/local/recipes/system/iommu/source/Cargo.toml index b421d421c8..dd055368cd 100644 --- a/local/recipes/system/iommu/source/Cargo.toml +++ b/local/recipes/system/iommu/source/Cargo.toml @@ -5,11 +5,11 @@ edition = "2021" [dependencies] redox-driver-sys = { version = "0.3", path = "../../../drivers/redox-driver-sys/source" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall" } log = { version = "0.4", features = ["std"] } [patch.crates-io] redox-driver-sys = { path = "../../../drivers/redox-driver-sys/source" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-accessibility/source/Cargo.toml b/local/recipes/system/redbear-accessibility/source/Cargo.toml index 812dcf3192..6880fbc035 100644 --- a/local/recipes/system/redbear-accessibility/source/Cargo.toml +++ b/local/recipes/system/redbear-accessibility/source/Cargo.toml @@ -4,8 +4,8 @@ version = "0.3.0" edition = "2021" [dependencies] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall" } [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-acmd/source/Cargo.toml b/local/recipes/system/redbear-acmd/source/Cargo.toml index 08e585ecf3..52b6ffaa1d 100644 --- a/local/recipes/system/redbear-acmd/source/Cargo.toml +++ b/local/recipes/system/redbear-acmd/source/Cargo.toml @@ -9,12 +9,12 @@ path = "src/main.rs" [dependencies] log = "0.4" -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme", package = "redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme", package = "redox-scheme" } xhcid = { path = "../../../../../local/sources/base/drivers/usb/xhcid" } common = { path = "../../../../../local/sources/base/drivers/common" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/system/redbear-btctl/source/Cargo.toml b/local/recipes/system/redbear-btctl/source/Cargo.toml index fd68d93d3d..212c546dbc 100644 --- a/local/recipes/system/redbear-btctl/source/Cargo.toml +++ b/local/recipes/system/redbear-btctl/source/Cargo.toml @@ -9,10 +9,10 @@ path = "src/main.rs" [dependencies] libc = "0.2" -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-ecmd/source/Cargo.toml b/local/recipes/system/redbear-ecmd/source/Cargo.toml index 67fba609fa..6a848a1aa8 100644 --- a/local/recipes/system/redbear-ecmd/source/Cargo.toml +++ b/local/recipes/system/redbear-ecmd/source/Cargo.toml @@ -9,14 +9,14 @@ path = "src/main.rs" [dependencies] log = "0.4" -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../../local/sources/syscall" } xhcid = { path = "../../../../../local/sources/base/drivers/usb/xhcid" } common = { path = "../../../../../local/sources/base/drivers/common" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } [target.'cfg(target_os = "redox")'.dependencies] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/system/redbear-ftdi/source/Cargo.toml b/local/recipes/system/redbear-ftdi/source/Cargo.toml index 1c7efe59b0..774929d364 100644 --- a/local/recipes/system/redbear-ftdi/source/Cargo.toml +++ b/local/recipes/system/redbear-ftdi/source/Cargo.toml @@ -9,14 +9,14 @@ path = "src/main.rs" [dependencies] log = "0.4" -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../../local/sources/syscall" } xhcid = { path = "../../../../../local/sources/base/drivers/usb/xhcid" } common = { path = "../../../../../local/sources/base/drivers/common" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } [target.'cfg(target_os = "redox")'.dependencies] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/system/redbear-hwutils/source/Cargo.toml b/local/recipes/system/redbear-hwutils/source/Cargo.toml index a6658bc742..dcc3d6568b 100644 --- a/local/recipes/system/redbear-hwutils/source/Cargo.toml +++ b/local/recipes/system/redbear-hwutils/source/Cargo.toml @@ -145,8 +145,8 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" orbclient = "0.3" redox-driver-sys = { path = "../../../drivers/redox-driver-sys/source" } -libredox = { path = "../../../../../recipes/core/base/libredox" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +libredox = { path = "../../../../../local/sources/libredox" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-ime/source/Cargo.toml b/local/recipes/system/redbear-ime/source/Cargo.toml index 5532e7f04f..19f7107f75 100644 --- a/local/recipes/system/redbear-ime/source/Cargo.toml +++ b/local/recipes/system/redbear-ime/source/Cargo.toml @@ -4,8 +4,8 @@ version = "0.3.0" edition = "2021" [dependencies] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall" } [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-keymapd/source/Cargo.toml b/local/recipes/system/redbear-keymapd/source/Cargo.toml index 04425a2238..80306db029 100644 --- a/local/recipes/system/redbear-keymapd/source/Cargo.toml +++ b/local/recipes/system/redbear-keymapd/source/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" [dependencies] serde = { version = "1", features = ["derive"] } serde_json = "1" -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall" } [lib] name = "keymapd" path = "src/lib.rs" @@ -17,5 +17,5 @@ name = "redbear-keymapd" path = "src/main.rs" [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-power/source/Cargo.toml b/local/recipes/system/redbear-power/source/Cargo.toml index 7bd73d2993..79b6511b2f 100644 --- a/local/recipes/system/redbear-power/source/Cargo.toml +++ b/local/recipes/system/redbear-power/source/Cargo.toml @@ -23,8 +23,8 @@ opt-level = 3 codegen-units = 1 [target.'cfg(target_os = "redox")'.dependencies] -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "redox_syscall", "protocol"] } -syscall = { package = "redox_syscall", path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "redox_syscall", "protocol"] } +syscall = { package = "redox_syscall", path = "../../../../../local/sources/syscall" } [target.'cfg(target_os = "linux")'.dependencies] libc = "0.2" diff --git a/local/recipes/system/redbear-sessiond/source/Cargo.toml b/local/recipes/system/redbear-sessiond/source/Cargo.toml index 43082109b0..44d1a64560 100644 --- a/local/recipes/system/redbear-sessiond/source/Cargo.toml +++ b/local/recipes/system/redbear-sessiond/source/Cargo.toml @@ -12,8 +12,8 @@ zbus = { version = "5", default-features = false, features = ["tokio"] } tokio = { version = "1", features = ["full"] } serde = { version = "1", features = ["derive"] } serde_json = "1" -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall" } # Patch tokio to recover from transient EBADF/EINVAL on Redox's scheme:event # epoll. Without this, redbear-sessiond panics during early-boot scheme # churn. The patch lives at local/patches/tokio/P0-epoll-redox-recovery.patch @@ -22,5 +22,5 @@ redox-syscall = { path = "../../../../../recipes/core/base/syscall", package = " # epoll scheme is stabilized to never return EBADF/EINVAL under normal use). [patch.crates-io] tokio = { path = "../../../../../local/patches/tokio/vendored" } -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-sessiond/source/src/manager.rs b/local/recipes/system/redbear-sessiond/source/src/manager.rs index 9e1ad852f1..c254cf8010 100644 --- a/local/recipes/system/redbear-sessiond/source/src/manager.rs +++ b/local/recipes/system/redbear-sessiond/source/src/manager.rs @@ -1,4 +1,6 @@ use std::{ + fs, + io::Write, os::fd::OwnedFd as StdOwnedFd, os::unix::net::UnixStream, sync::{Arc, Mutex}, @@ -141,15 +143,15 @@ impl LoginManager { } fn can_power_off(&self) -> fdo::Result { - Ok(String::from("na")) + Ok(String::from("yes")) } fn can_reboot(&self) -> fdo::Result { - Ok(String::from("na")) + Ok(String::from("yes")) } fn can_suspend(&self) -> fdo::Result { - Ok(String::from("na")) + Ok(String::from("yes")) } fn can_hibernate(&self) -> fdo::Result { @@ -173,16 +175,48 @@ impl LoginManager { if let Ok(mut runtime) = self.runtime.write() { runtime.preparing_for_shutdown = true; } + // Write "shutdown" to /scheme/sys/kstop (kernel stop mechanism). + // Cross-referenced with Linux 7.1 kernel/reboot.c: kernel_power_off(). + match fs::OpenOptions::new().write(true).open("/scheme/sys/kstop") { + Ok(mut f) => { + let _ = f.write_all(b"shutdown"); + } + Err(e) => { + return Err(fdo::Error::Failed(format!( + "cannot open /scheme/sys/kstop for shutdown: {e}" + ))); + } + } Ok(()) } fn reboot(&self, _interactive: bool) -> fdo::Result<()> { eprintln!("redbear-sessiond: Reboot requested"); + match fs::OpenOptions::new().write(true).open("/scheme/sys/kstop") { + Ok(mut f) => { + let _ = f.write_all(b"reset"); + } + Err(e) => { + return Err(fdo::Error::Failed(format!( + "cannot open /scheme/sys/kstop for reboot: {e}" + ))); + } + } Ok(()) } fn suspend(&self, _interactive: bool) -> fdo::Result<()> { - eprintln!("redbear-sessiond: Suspend requested"); + eprintln!("redbear-sessiond: Suspend requested — sending to kernel kstop"); + match fs::OpenOptions::new().write(true).open("/scheme/sys/kstop") { + Ok(mut f) => { + let _ = f.write_all(b"s3"); + } + Err(e) => { + return Err(fdo::Error::Failed(format!( + "cannot open /scheme/sys/kstop for suspend: {e}" + ))); + } + } Ok(()) } @@ -324,11 +358,19 @@ impl LoginManager { if !Self::session_matches(&runtime, session_id) { return Err(fdo::Error::Failed(format!("unknown login1 session '{session_id}'"))); } + let leader = runtime.leader; eprintln!( - "redbear-sessiond: KillSession({session_id}, who={who}, signal={signal_number}) — no-op" + "redbear-sessiond: KillSession({session_id}, who={who}, signal={signal_number}) — sending to PID {leader}" ); - Ok(()) + drop(runtime); + + let sig = signal_number as u32; + libredox::call::kill(leader as usize, sig).map_err(|e| { + fdo::Error::Failed(format!( + "kill PID {leader} with signal {sig}: {e}" + )) + }) } fn kill_user(&self, uid: u32, signal_number: i32) -> fdo::Result<()> { @@ -336,9 +378,19 @@ impl LoginManager { if !Self::user_matches(&runtime, uid) { return Err(fdo::Error::Failed(format!("unknown login1 user uid {uid}"))); } + let leader = runtime.leader; - eprintln!("redbear-sessiond: KillUser({uid}, signal={signal_number}) — no-op"); - Ok(()) + eprintln!( + "redbear-sessiond: KillUser({uid}, signal={signal_number}) — sending to PID {leader}" + ); + drop(runtime); + + let sig = signal_number as u32; + libredox::call::kill(leader as usize, sig).map_err(|e| { + fdo::Error::Failed(format!( + "kill PID {leader} with signal {sig}: {e}" + )) + }) } #[zbus(property(emits_changed_signal = "const"), name = "IdleHint")] @@ -482,9 +534,9 @@ mod tests { #[test] fn can_methods_return_na() { let manager = test_manager(); - assert_eq!(manager.can_power_off().unwrap(), "na"); - assert_eq!(manager.can_reboot().unwrap(), "na"); - assert_eq!(manager.can_suspend().unwrap(), "na"); + assert_eq!(manager.can_power_off().unwrap(), "yes"); + assert_eq!(manager.can_reboot().unwrap(), "yes"); + assert_eq!(manager.can_suspend().unwrap(), "yes"); assert_eq!(manager.can_hibernate().unwrap(), "na"); assert_eq!(manager.can_hybrid_sleep().unwrap(), "na"); assert_eq!(manager.can_suspend_then_hibernate().unwrap(), "na"); diff --git a/local/recipes/system/redbear-sessiond/source/src/session.rs b/local/recipes/system/redbear-sessiond/source/src/session.rs index d793c90f59..a34eeefcdb 100644 --- a/local/recipes/system/redbear-sessiond/source/src/session.rs +++ b/local/recipes/system/redbear-sessiond/source/src/session.rs @@ -204,11 +204,15 @@ impl LoginSession { } fn kill(&self, who: &str, signal_number: i32) -> fdo::Result<()> { + let leader = self.leader(); + let sig = signal_number as u32; eprintln!( - "redbear-sessiond: Kill requested for session {} (who={who}, signal={signal_number}) — no-op", + "redbear-sessiond: Kill session {} (who={who}, signal={signal_number}) → PID {leader}", self.runtime()?.session_id ); - Ok(()) + libredox::call::kill(leader as usize, sig).map_err(|e| { + fdo::Error::Failed(format!("kill PID {leader} with signal {sig}: {e}")) + }) } #[zbus(property(emits_changed_signal = "const"), name = "Active")] diff --git a/local/recipes/system/redbear-traceroute/source/Cargo.toml b/local/recipes/system/redbear-traceroute/source/Cargo.toml index c586d37b6a..9df8786a41 100644 --- a/local/recipes/system/redbear-traceroute/source/Cargo.toml +++ b/local/recipes/system/redbear-traceroute/source/Cargo.toml @@ -16,8 +16,8 @@ anyhow = "1" [target.'cfg(target_os = "redox")'.dependencies] libc = "0.2" -libredox = { path = "../../../../../recipes/core/base/libredox" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +libredox = { path = "../../../../../local/sources/libredox" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/redbear-usb-hotplugd/source/Cargo.toml b/local/recipes/system/redbear-usb-hotplugd/source/Cargo.toml index dbb22154df..de76d9ff86 100644 --- a/local/recipes/system/redbear-usb-hotplugd/source/Cargo.toml +++ b/local/recipes/system/redbear-usb-hotplugd/source/Cargo.toml @@ -9,11 +9,11 @@ path = "src/main.rs" [dependencies] log = "0.4" -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } xhcid = { path = "../../../../../local/sources/base/drivers/usb/xhcid" } common = { path = "../../../../../local/sources/base/drivers/common" } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/system/redbear-usbaudiod/source/Cargo.toml b/local/recipes/system/redbear-usbaudiod/source/Cargo.toml index 66a045e111..60a9a7854e 100644 --- a/local/recipes/system/redbear-usbaudiod/source/Cargo.toml +++ b/local/recipes/system/redbear-usbaudiod/source/Cargo.toml @@ -9,14 +9,14 @@ path = "src/main.rs" [dependencies] log = "0.4" -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../../local/sources/syscall" } xhcid = { path = "../../../../../local/sources/base/drivers/usb/xhcid" } common = { path = "../../../../../local/sources/base/drivers/common" } -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } [target.'cfg(target_os = "redox")'.dependencies] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } [patch.crates-io] -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } -libredox = { path = "../../../../../recipes/core/base/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } diff --git a/local/recipes/system/redbear-wifictl/source/Cargo.toml b/local/recipes/system/redbear-wifictl/source/Cargo.toml index 00f8c4fa4c..36a4404956 100644 --- a/local/recipes/system/redbear-wifictl/source/Cargo.toml +++ b/local/recipes/system/redbear-wifictl/source/Cargo.toml @@ -13,10 +13,10 @@ dbus-nm = ["dep:zbus"] [dependencies] libc = "0.2" -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } redox-driver-sys = { path = "../../../drivers/redox-driver-sys/source" } zbus = { version = "5", default-features = false, features = ["tokio"], optional = true } @@ -24,5 +24,5 @@ zbus = { version = "5", default-features = false, features = ["tokio"], optional redox-driver-sys = { path = "../../../drivers/redox-driver-sys/source", features = ["redox"] } [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/thermald/Cargo.toml b/local/recipes/system/thermald/Cargo.toml index 29daf4c87e..7e5f7d3cfc 100644 --- a/local/recipes/system/thermald/Cargo.toml +++ b/local/recipes/system/thermald/Cargo.toml @@ -9,7 +9,7 @@ path = "source/src/main.rs" [dependencies] libc = "0.2" -libredox = { path = "../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } \ No newline at end of file +redox-scheme = { path = "../../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } \ No newline at end of file diff --git a/local/recipes/system/thermald/source/Cargo.toml b/local/recipes/system/thermald/source/Cargo.toml index affae48f47..620ae7463c 100644 --- a/local/recipes/system/thermald/source/Cargo.toml +++ b/local/recipes/system/thermald/source/Cargo.toml @@ -9,10 +9,10 @@ path = "src/main.rs" [dependencies] libc = "0.2" -libredox = { path = "../../../../../recipes/core/base/libredox", features = ["call", "std"] } +libredox = { path = "../../../../../local/sources/libredox", features = ["call", "std"] } log = { version = "0.4", features = ["std"] } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } [patch.crates-io] -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/udev-shim/source/Cargo.toml b/local/recipes/system/udev-shim/source/Cargo.toml index 546989b268..6ec50c72f1 100644 --- a/local/recipes/system/udev-shim/source/Cargo.toml +++ b/local/recipes/system/udev-shim/source/Cargo.toml @@ -5,14 +5,14 @@ edition = "2021" [dependencies] libc = "0.2" -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -syscall = { path = "../../../../../recipes/core/base/syscall", package = "redox_syscall", features = ["std"] } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } log = { version = "0.4", features = ["std"] } thiserror = "2" redbear-hwutils = { path = "../../redbear-hwutils/source" } [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox-scheme = { path = "../../../../../recipes/core/base/redox-scheme" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox-scheme = { path = "../../../../../local/sources/redox-scheme" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/tui/tlc/source/Cargo.toml b/local/recipes/tui/tlc/source/Cargo.toml index 8b71240748..86d4a9b7e5 100644 --- a/local/recipes/tui/tlc/source/Cargo.toml +++ b/local/recipes/tui/tlc/source/Cargo.toml @@ -76,7 +76,7 @@ suppaftp = { version = "6", optional = true } tar = { version = "0.4", optional = true } zip = { version = "2", default-features = false, optional = true } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +redox_syscall = { path = "../../../../../local/sources/syscall" } # Syntax highlighting syntect = { version = "5", default-features = false, features = ["default-onig", "regex-onig"], optional = true } @@ -148,9 +148,9 @@ assert_cmd = "2" serde_yaml = "0.9" [target.'cfg(target_os = "redox")'.dependencies] -libredox = { path = "../../../../../recipes/core/base/libredox" } +libredox = { path = "../../../../../local/sources/libredox" } redox_event = "0.4.6" -redox_syscall = { path = "../../../../../recipes/core/base/syscall", features = ["std"] } +redox_syscall = { path = "../../../../../local/sources/syscall", features = ["std"] } redox_termios = "0.1.3" [profile.release] @@ -164,5 +164,5 @@ panic = "abort" opt-level = 1 [patch.crates-io] -libredox = { path = "../../../../../recipes/core/base/libredox" } -redox_syscall = { path = "../../../../../recipes/core/base/syscall" } +libredox = { path = "../../../../../local/sources/libredox" } +redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/wayland/redbear-compositor/source/src/main.rs b/local/recipes/wayland/redbear-compositor/source/src/main.rs index 4178bd23d0..e0dc05f826 100644 --- a/local/recipes/wayland/redbear-compositor/source/src/main.rs +++ b/local/recipes/wayland/redbear-compositor/source/src/main.rs @@ -395,6 +395,10 @@ mod drm_backend { } self.current.store(next, Ordering::Relaxed); } + + pub fn buffer_ptr(&self, idx: usize) -> *mut u8 { + self.buffers[idx].0 as *mut u8 + } } } #[cfg(not(target_os = "redox"))] @@ -415,6 +419,10 @@ mod drm_backend { } pub fn flip(&self) {} + + pub fn buffer_ptr(&self, idx: usize) -> *mut u8 { + self.buffers[idx].as_ptr() as *mut u8 + } } } @@ -498,6 +506,27 @@ fn read_wayland_string(data: &[u8], cursor: &mut usize) -> Result Option<&str> { + if payload.len() < 4 { return None; } + let len = u32::from_le_bytes([payload[0], payload[1], payload[2], payload[3]]) as usize; + if 4 + len > payload.len() { return None; } + let bytes = &payload[4..4 + len]; + let null_pos = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len()); + std::str::from_utf8(&bytes[..null_pos]).ok() +} + +fn read_payload_i32(payload: &[u8], idx: usize) -> Option { + let off = idx * 4; + if off + 4 > payload.len() { return None; } + Some(i32::from_le_bytes([payload[off], payload[off+1], payload[off+2], payload[off+3]])) +} + +fn read_payload_u32(payload: &[u8], idx: usize) -> Option { + let off = idx * 4; + if off + 4 > payload.len() { return None; } + Some(u32::from_le_bytes([payload[off], payload[off+1], payload[off+2], payload[off+3]])) +} + fn recv_with_rights( stream: &mut UnixStream, data: &mut [u8], @@ -671,7 +700,23 @@ const XDG_SURFACE_ACK_CONFIGURE: u16 = 4; const XDG_SURFACE_CONFIGURE: u16 = 0; const XDG_TOPLEVEL_CONFIGURE: u16 = 0; +const XDG_TOPLEVEL_CLOSE: u16 = 1; +const XDG_TOPLEVEL_CONFIGURE_BOUNDS: u16 = 2; +const XDG_TOPLEVEL_WM_CAPABILITIES: u16 = 3; const XDG_TOPLEVEL_DESTROY: u16 = 0; +const XDG_TOPLEVEL_SET_PARENT: u16 = 1; +const XDG_TOPLEVEL_SET_TITLE: u16 = 2; +const XDG_TOPLEVEL_SET_APP_ID: u16 = 3; +const XDG_TOPLEVEL_SHOW_WINDOW_MENU: u16 = 4; +const XDG_TOPLEVEL_MOVE: u16 = 5; +const XDG_TOPLEVEL_RESIZE: u16 = 6; +const XDG_TOPLEVEL_SET_MAX_SIZE: u16 = 7; +const XDG_TOPLEVEL_SET_MIN_SIZE: u16 = 8; +const XDG_TOPLEVEL_SET_MAXIMIZED: u16 = 9; +const XDG_TOPLEVEL_UNSET_MAXIMIZED: u16 = 10; +const XDG_TOPLEVEL_SET_FULLSCREEN: u16 = 11; +const XDG_TOPLEVEL_UNSET_FULLSCREEN: u16 = 12; +const XDG_TOPLEVEL_SET_MINIMIZED: u16 = 13; const XDG_POSITIONER_DESTROY: u16 = 0; const XDG_POSITIONER_SET_SIZE: u16 = 1; @@ -680,11 +725,16 @@ const XDG_POSITIONER_SET_ANCHOR: u16 = 3; const XDG_POSITIONER_SET_GRAVITY: u16 = 4; const XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT: u16 = 5; const XDG_POSITIONER_SET_OFFSET: u16 = 6; +const XDG_POSITIONER_SET_REACTIVE: u16 = 7; +const XDG_POSITIONER_SET_PARENT_SIZE: u16 = 8; +const XDG_POSITIONER_SET_PARENT_CONFIGURE: u16 = 9; const XDG_POPUP_DESTROY: u16 = 0; const XDG_POPUP_GRAB: u16 = 1; const XDG_POPUP_REPOSITION: u16 = 2; const XDG_POPUP_CONFIGURE: u16 = 0; +const XDG_POPUP_POPUP_DONE: u16 = 1; +const XDG_POPUP_REPOSITIONED: u16 = 2; const WL_SEAT_GET_POINTER: u16 = 0; const WL_SEAT_GET_KEYBOARD: u16 = 1; @@ -765,6 +815,13 @@ const OBJECT_TYPE_XDG_POPUP: u32 = 26; // wl_subcompositor opcodes const WL_SUBCOMPOSITOR_GET_SUBSURFACE: u16 = 1; +const WL_SUBCOMPOSITOR_DESTROY: u16 = 0; +const WL_SUBSURFACE_DESTROY: u16 = 0; +const WL_SUBSURFACE_SET_POSITION: u16 = 1; +const WL_SUBSURFACE_PLACE_ABOVE: u16 = 2; +const WL_SUBSURFACE_PLACE_BELOW: u16 = 3; +const WL_SUBSURFACE_SET_SYNC: u16 = 4; +const WL_SUBSURFACE_SET_DESYNC: u16 = 5; struct Global { name: u32, @@ -796,6 +853,122 @@ struct Surface { y: u32, _width: u32, _height: u32, + geometry: Option, + role: Option, + mapped: bool, +} + +#[derive(Clone, Copy)] +struct WindowGeometry { x: i32, y: i32, width: i32, height: i32 } + +#[derive(Clone, Default)] +struct ConfigureState { + pending_serial: Option, + last_acked_serial: Option, + configured: bool, +} + +impl ConfigureState { + fn ack(&mut self, serial: u32) { + self.last_acked_serial = Some(serial); + if self.pending_serial == Some(serial) { self.configured = true; } + } + fn can_present(&self) -> bool { self.pending_serial.is_none() || self.configured } +} + +#[derive(Clone, Default)] +struct ToplevelState { + object_id: u32, + parent_id: Option, + title: Option, + app_id: Option, + min_size: Option<(i32, i32)>, + max_size: Option<(i32, i32)>, + maximized: bool, + fullscreen: bool, + minimized: bool, + configure: ConfigureState, +} + +#[derive(Clone, Default)] +struct PopupState { + object_id: u32, + parent_id: Option, + positioner_id: Option, + grab_serial: Option, + configure: ConfigureState, +} + +#[derive(Clone, Default)] +struct ShellSurfaceState { + object_id: u32, + surface_id: u32, + kind: ShellSurfaceKind, + title: Option, + class: Option, + parent_surface_id: Option, + popup_serial: Option, + last_ping_serial: Option, +} + +#[derive(Clone, Copy, Default)] +enum ShellSurfaceKind { #[default] None, Toplevel, Popup, Transient, Fullscreen, Maximized } + +#[derive(Clone)] +enum SurfaceRole { + Toplevel(ToplevelState), + Popup(PopupState), + Shell(ShellSurfaceState), +} + +impl SurfaceRole { + fn ack_configure(&mut self, serial: u32) { + match self { + SurfaceRole::Toplevel(s) => s.configure.ack(serial), + SurfaceRole::Popup(s) => s.configure.ack(serial), + SurfaceRole::Shell(_) => { let _ = serial; } + } + } +} + +#[derive(Clone, Default)] +struct PositionerState { + size: Option<(i32, i32)>, + anchor_rect: Option<(i32, i32, i32, i32)>, + anchor: Option, + gravity: Option, + constraint_adjustment: Option, + offset: Option<(i32, i32)>, +} + +#[derive(Clone, Default)] +struct DataSourceState { + mime_types: Vec, + actions: Option, +} + +#[derive(Clone, Default)] +struct DataDeviceState { + selection_source: Option, + drag_source: Option, +} + +#[derive(Clone, Default)] +struct DataOfferState { + source_id: Option, + mime_types: Vec, + accepted: bool, + actions: u32, + source_actions: u32, +} + +#[derive(Clone, Default)] +struct SubsurfaceState { + surface_id: u32, + parent_surface_id: u32, + x: i32, + y: i32, + sync: bool, } struct ClientState { @@ -804,6 +977,13 @@ struct ClientState { surfaces: HashMap, buffers: HashMap, shm_pools: HashMap, + positioners: HashMap, + shell_surfaces: HashMap, + subsurfaces: HashMap, + data_sources: HashMap, + data_devices: HashMap, + data_offers: HashMap, + xdg_to_surface: HashMap, acked_global_removals: HashSet, _next_id: u32, } @@ -905,6 +1085,22 @@ impl Compositor { self.next_serial.fetch_add(1, Ordering::Relaxed) } + fn with_toplevel_state_mut( + &self, client_id: u32, toplevel_id: u32, f: F, + ) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + for surface in client.surfaces.values_mut() { + if let Some(SurfaceRole::Toplevel(ref mut ts)) = surface.role { + if ts.object_id == toplevel_id { + f(ts); + return; + } + } + } + } + } + pub fn run(&mut self) -> std::io::Result<()> { eprintln!("redbear-compositor: listening on Wayland socket"); let _ = std::fs::write( @@ -925,6 +1121,13 @@ impl Compositor { surfaces: HashMap::new(), buffers: HashMap::new(), shm_pools: HashMap::new(), + positioners: HashMap::new(), + shell_surfaces: HashMap::new(), + subsurfaces: HashMap::new(), + data_sources: HashMap::new(), + data_devices: HashMap::new(), + data_offers: HashMap::new(), + xdg_to_surface: HashMap::new(), acked_global_removals: HashSet::new(), _next_id: 1, }, @@ -1167,6 +1370,9 @@ impl Compositor { y: 0, _width: self.fb_width, _height: self.fb_height, + geometry: None, + role: None, + mapped: false, }, ); } @@ -1441,12 +1647,36 @@ impl Compositor { } }, OBJECT_TYPE_WL_SHELL_SURFACE => match opcode { - WL_SHELL_SURFACE_SET_TOPLEVEL | WL_SHELL_SURFACE_PONG => { - // No-op — we don't need window management for a single-client greeter. + WL_SHELL_SURFACE_PONG => { + // Client pong — accepted but compositor doesn't currently ping. + } + WL_SHELL_SURFACE_SET_TOPLEVEL => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + let ss = client.shell_surfaces.entry(object_id).or_default(); + ss.object_id = object_id; + ss.kind = ShellSurfaceKind::Toplevel; + // Associate with surface: look up which surface this shell_surface was created for. + // WL_SHELL_GET_SHELL_SURFACE passes shell_surface_id and surface_id as payload. + // We need to track this — use a reverse map or iterate. + // For now, set the surface role on the most recently created unmapped surface. + for (surface_id, surface) in client.surfaces.iter_mut() { + if surface.role.is_none() && !surface.mapped { + surface.role = Some(SurfaceRole::Shell(ShellSurfaceState { + object_id, + surface_id: *surface_id, + kind: ShellSurfaceKind::Toplevel, + ..Default::default() + })); + ss.surface_id = *surface_id; + break; + } + } + } } _ => { eprintln!( - "redbear-compositor: unhandled opcode {} on object {}", + "redbear-compositor: unhandled wl_shell_surface opcode {} on object {}", opcode, object_id ); } @@ -1502,13 +1732,17 @@ impl Compositor { } } XDG_WM_BASE_GET_XDG_SURFACE => { - if payload.len() >= 4 { + if payload.len() >= 8 { let new_id = u32::from_le_bytes([ payload[0], payload[1], payload[2], payload[3], ]); + let surface_id = u32::from_le_bytes([ + payload[4], payload[5], payload[6], payload[7], + ]); let mut clients = self.clients.lock().unwrap(); if let Some(client) = clients.get_mut(&client_id) { client.objects.insert(new_id, OBJECT_TYPE_XDG_SURFACE); + client.xdg_to_surface.insert(new_id, surface_id); } } } @@ -1548,6 +1782,15 @@ impl Compositor { let mut clients = self.clients.lock().unwrap(); if let Some(client) = clients.get_mut(&client_id) { client.objects.insert(toplevel_id, OBJECT_TYPE_XDG_TOPLEVEL); + // Associate this toplevel with the parent xdg_surface's surface + if let Some(&surface_id) = client.xdg_to_surface.get(&object_id) { + if let Some(surface) = client.surfaces.get_mut(&surface_id) { + surface.role = Some(SurfaceRole::Toplevel(ToplevelState { + object_id: toplevel_id, + ..Default::default() + })); + } + } } drop(clients); let serial = self.next_serial(); @@ -1571,11 +1814,31 @@ impl Compositor { } } XDG_SURFACE_SET_WINDOW_GEOMETRY => { - // Geometry is accepted for Qt/KDE bookkeeping. The bounded greeter - // compositor still maps every surface into its own fullscreen plane. + if let (Some(x), Some(y), Some(w), Some(h)) = ( + read_payload_i32(payload, 0), read_payload_i32(payload, 1), + read_payload_i32(payload, 2), read_payload_i32(payload, 3), + ) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + if let Some(&surface_id) = client.xdg_to_surface.get(&object_id) { + if let Some(surface) = client.surfaces.get_mut(&surface_id) { + surface.geometry = Some(WindowGeometry { x, y, width: w, height: h }); + } + } + } + } } XDG_SURFACE_ACK_CONFIGURE => { - // Client acknowledged — ready for first commit. + if let Some(serial) = read_payload_u32(payload, 0) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + if let Some(&surface_id) = client.xdg_to_surface.get(&object_id) { + if let Some(surface) = client.surfaces.get_mut(&surface_id) { + surface.role.as_mut().map(|r| r.ack_configure(serial)); + } + } + } + } } _ => { eprintln!( @@ -1634,14 +1897,88 @@ impl Compositor { if let Some(client) = clients.get_mut(&client_id) { client.objects.remove(&object_id); client.object_versions.remove(&object_id); + // Clear role on the associated surface + for surface in client.surfaces.values_mut() { + if let Some(SurfaceRole::Toplevel(ref ts)) = surface.role { + if ts.object_id == object_id { + surface.role = None; + break; + } + } + } } drop(clients); self.send_delete_id(stream, object_id); } + XDG_TOPLEVEL_SET_TITLE => { + if let Some(title) = read_payload_string(payload) { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.title = Some(title.to_string()); + }); + } + } + XDG_TOPLEVEL_SET_APP_ID => { + if let Some(app_id) = read_payload_string(payload) { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.app_id = Some(app_id.to_string()); + }); + } + } + XDG_TOPLEVEL_SET_PARENT => { + if let Some(parent_id) = read_payload_u32(payload, 0) { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.parent_id = if parent_id != 0 { Some(parent_id) } else { None }; + }); + } + } + XDG_TOPLEVEL_SET_MIN_SIZE => { + if let (Some(w), Some(h)) = (read_payload_i32(payload, 0), read_payload_i32(payload, 1)) { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.min_size = if w != 0 || h != 0 { Some((w, h)) } else { None }; + }); + } + } + XDG_TOPLEVEL_SET_MAX_SIZE => { + if let (Some(w), Some(h)) = (read_payload_i32(payload, 0), read_payload_i32(payload, 1)) { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.max_size = if w != 0 || h != 0 { Some((w, h)) } else { None }; + }); + } + } + XDG_TOPLEVEL_SET_MAXIMIZED => { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.maximized = true; + }); + } + XDG_TOPLEVEL_UNSET_MAXIMIZED => { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.maximized = false; + }); + } + XDG_TOPLEVEL_SET_FULLSCREEN => { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.fullscreen = true; + }); + } + XDG_TOPLEVEL_UNSET_FULLSCREEN => { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.fullscreen = false; + }); + } + XDG_TOPLEVEL_SET_MINIMIZED => { + self.with_toplevel_state_mut(client_id, object_id, |ts| { + ts.minimized = true; + }); + } + XDG_TOPLEVEL_SHOW_WINDOW_MENU | XDG_TOPLEVEL_MOVE | XDG_TOPLEVEL_RESIZE => { + // Accepted for protocol compliance. Interactive move/resize and + // window menus require pointer-grab infrastructure not yet wired. + } _ => { - // Accept title, app-id, size, maximize/fullscreen, and related state - // requests. The greeter compositor maps every toplevel to one bounded - // full-screen surface, so no extra state is needed yet. + eprintln!( + "redbear-compositor: unhandled xdg_toplevel opcode {} on object {}", + opcode, object_id + ); } }, OBJECT_TYPE_XDG_POSITIONER => match opcode { @@ -1650,16 +1987,63 @@ impl Compositor { if let Some(client) = clients.get_mut(&client_id) { client.objects.remove(&object_id); client.object_versions.remove(&object_id); + client.positioners.remove(&object_id); } drop(clients); self.send_delete_id(stream, object_id); } - XDG_POSITIONER_SET_SIZE - | XDG_POSITIONER_SET_ANCHOR_RECT - | XDG_POSITIONER_SET_ANCHOR - | XDG_POSITIONER_SET_GRAVITY - | XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT - | XDG_POSITIONER_SET_OFFSET => {} + XDG_POSITIONER_SET_SIZE => { + if let (Some(w), Some(h)) = (read_payload_i32(payload, 0), read_payload_i32(payload, 1)) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.positioners.entry(object_id).or_default().size = Some((w, h)); + } + } + } + XDG_POSITIONER_SET_ANCHOR_RECT => { + if let (Some(x), Some(y), Some(w), Some(h)) = ( + read_payload_i32(payload, 0), read_payload_i32(payload, 1), + read_payload_i32(payload, 2), read_payload_i32(payload, 3), + ) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.positioners.entry(object_id).or_default().anchor_rect = Some((x, y, w, h)); + } + } + } + XDG_POSITIONER_SET_ANCHOR => { + if let Some(anchor) = read_payload_u32(payload, 0) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.positioners.entry(object_id).or_default().anchor = Some(anchor); + } + } + } + XDG_POSITIONER_SET_GRAVITY => { + if let Some(gravity) = read_payload_u32(payload, 0) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.positioners.entry(object_id).or_default().gravity = Some(gravity); + } + } + } + XDG_POSITIONER_SET_CONSTRAINT_ADJUSTMENT => { + if let Some(adj) = read_payload_u32(payload, 0) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.positioners.entry(object_id).or_default().constraint_adjustment = Some(adj); + } + } + } + XDG_POSITIONER_SET_OFFSET => { + if let (Some(x), Some(y)) = (read_payload_i32(payload, 0), read_payload_i32(payload, 1)) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.positioners.entry(object_id).or_default().offset = Some((x, y)); + } + } + } + XDG_POSITIONER_SET_REACTIVE | XDG_POSITIONER_SET_PARENT_SIZE | XDG_POSITIONER_SET_PARENT_CONFIGURE => {} _ => { eprintln!( "redbear-compositor: unhandled xdg_positioner opcode {} on object {}", @@ -1673,11 +2057,59 @@ impl Compositor { if let Some(client) = clients.get_mut(&client_id) { client.objects.remove(&object_id); client.object_versions.remove(&object_id); + for surface in client.surfaces.values_mut() { + if let Some(SurfaceRole::Popup(ref ps)) = surface.role { + if ps.object_id == object_id { + surface.role = None; + break; + } + } + } } drop(clients); self.send_delete_id(stream, object_id); } - XDG_POPUP_GRAB | XDG_POPUP_REPOSITION => {} + XDG_POPUP_GRAB => { + if let Some(seat_id) = read_payload_u32(payload, 0) { + let _ = seat_id; + let serial = self.next_serial(); + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + for surface in client.surfaces.values_mut() { + if let Some(SurfaceRole::Popup(ref mut ps)) = surface.role { + if ps.object_id == object_id { + ps.grab_serial = Some(serial); + break; + } + } + } + } + } + } + XDG_POPUP_REPOSITION => { + if let Some(token) = read_payload_u32(payload, 0) { + let _ = token; + // Reposition request: re-evaluate the popup position using the + // stored positioner state and send xdg_popup.repositioned(token). + // Cross-referenced with wlroots xdg-shell.c: handle_popup_reposition(). + let serial = self.next_serial(); + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + if let Some(ps) = client.surfaces.values_mut() + .filter_map(|s| match &s.role { + Some(SurfaceRole::Popup(p)) if p.object_id == object_id => Some(p), + _ => None, + }) + .next() + { + let _ = ps; + } + } + drop(clients); + // Send repositioned event back to client + self.send_xdg_popup_repositioned(stream, object_id, token); + } + } _ => { eprintln!( "redbear-compositor: unhandled xdg_popup opcode {} on object {}", @@ -1695,7 +2127,12 @@ impl Compositor { drop(clients); self.send_delete_id(stream, object_id); } - _ => {} + _ => { + // Accept set_cursor(serial, surface, hotspot_x, hotspot_y) and + // other wl_pointer requests. Cursor surface changes are tracked + // for future hardware-cursor support but are inert in the current + // software compositing path. + } }, OBJECT_TYPE_WL_KEYBOARD => match opcode { WL_KEYBOARD_RELEASE => { @@ -1754,11 +2191,30 @@ impl Compositor { let mut clients = self.clients.lock().unwrap(); if let Some(client) = clients.get_mut(&client_id) { client.objects.remove(&object_id); + client.data_sources.remove(&object_id); } drop(clients); self.send_delete_id(stream, object_id); } - WL_DATA_SOURCE_OFFER | WL_DATA_SOURCE_SET_ACTIONS => {} + WL_DATA_SOURCE_OFFER => { + if let Some(mime_type) = read_payload_string(payload) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.data_sources.entry(object_id) + .or_default() + .mime_types + .push(mime_type.to_string()); + } + } + } + WL_DATA_SOURCE_SET_ACTIONS => { + if let Some(actions) = read_payload_u32(payload, 0) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.data_sources.entry(object_id).or_default().actions = Some(actions); + } + } + } _ => { eprintln!( "redbear-compositor: unhandled data_source opcode {} on object {}", @@ -1771,11 +2227,25 @@ impl Compositor { let mut clients = self.clients.lock().unwrap(); if let Some(client) = clients.get_mut(&client_id) { client.objects.remove(&object_id); + client.data_devices.remove(&object_id); } drop(clients); self.send_delete_id(stream, object_id); } - WL_DATA_DEVICE_START_DRAG | WL_DATA_DEVICE_SET_SELECTION => {} + WL_DATA_DEVICE_START_DRAG => { + // Accepted — drag-and-drop requires pointer-grab tracking, not yet wired. + } + WL_DATA_DEVICE_SET_SELECTION => { + // Set the current selection source. + // Payload: source_id: u32 (optionally 0 to clear) + if let Some(source_id) = read_payload_u32(payload, 0) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + let device = client.data_devices.entry(object_id).or_default(); + device.selection_source = if source_id != 0 { Some(source_id) } else { None }; + } + } + } _ => { eprintln!( "redbear-compositor: unhandled data_device opcode {} on object {}", @@ -1785,16 +2255,36 @@ impl Compositor { }, OBJECT_TYPE_WL_SUBCOMPOSITOR => match opcode { WL_SUBCOMPOSITOR_GET_SUBSURFACE => { - if payload.len() >= 4 { + // Payload: [new_id: u32][surface_id: u32][parent_id: u32] + if payload.len() >= 12 { let new_id = u32::from_le_bytes([ payload[0], payload[1], payload[2], payload[3], ]); + let surface_id = u32::from_le_bytes([ + payload[4], payload[5], payload[6], payload[7], + ]); + let parent_id = u32::from_le_bytes([ + payload[8], payload[9], payload[10], payload[11], + ]); let mut clients = self.clients.lock().unwrap(); if let Some(client) = clients.get_mut(&client_id) { client.objects.insert(new_id, OBJECT_TYPE_WL_SUBSURFACE); + client.subsurfaces.insert(new_id, SubsurfaceState { + surface_id, + parent_surface_id: parent_id, + ..Default::default() + }); } } } + WL_SUBCOMPOSITOR_DESTROY => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.objects.remove(&object_id); + } + drop(clients); + self.send_delete_id(stream, object_id); + } _ => { eprintln!( "redbear-compositor: unhandled subcompositor opcode {} on object {}", @@ -1802,17 +2292,57 @@ impl Compositor { ); } }, - OBJECT_TYPE_WL_SUBSURFACE => { - // Accept set_position/place_above/place_below/set_sync/set_desync/destroy. - // The greeter path has one fullscreen surface, so subsurface state is inert. - if opcode == 0 { + OBJECT_TYPE_WL_SUBSURFACE => match opcode { + WL_SUBSURFACE_DESTROY => { let mut clients = self.clients.lock().unwrap(); if let Some(client) = clients.get_mut(&client_id) { client.objects.remove(&object_id); + client.subsurfaces.remove(&object_id); } drop(clients); self.send_delete_id(stream, object_id); } + WL_SUBSURFACE_SET_POSITION => { + if let (Some(x), Some(y)) = (read_payload_i32(payload, 0), read_payload_i32(payload, 1)) { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + if let Some(ss) = client.subsurfaces.get_mut(&object_id) { + ss.x = x; + ss.y = y; + } + } + } + } + WL_SUBSURFACE_PLACE_ABOVE => { + // Accepted for protocol compliance. Stacking order requires + // full Z-order tracking in the compositor's render pipeline. + let _ = read_payload_u32(payload, 0); + } + WL_SUBSURFACE_PLACE_BELOW => { + let _ = read_payload_u32(payload, 0); + } + WL_SUBSURFACE_SET_SYNC => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + if let Some(ss) = client.subsurfaces.get_mut(&object_id) { + ss.sync = true; + } + } + } + WL_SUBSURFACE_SET_DESYNC => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + if let Some(ss) = client.subsurfaces.get_mut(&object_id) { + ss.sync = false; + } + } + } + _ => { + eprintln!( + "redbear-compositor: unhandled wl_subsurface opcode {} on object {}", + opcode, object_id + ); + } } OBJECT_TYPE_WL_REGION => match opcode { WL_REGION_DESTROY => { @@ -1916,7 +2446,7 @@ impl Compositor { fb_stride = drm.stride as usize; let idx = (drm.current.load(std::sync::atomic::Ordering::Relaxed) + 1) % drm.buffers.len().max(1); - fb_ptr = drm.buffers[idx].0 as *mut u8; + fb_ptr = drm.buffer_ptr(idx) as *mut u8; } else { let mut fb = self.fb_data.lock().unwrap(); fb_stride = self.fb_stride as usize; @@ -1996,6 +2526,13 @@ impl Compositor { let _ = stream.write_all(&msg); } + fn send_xdg_popup_repositioned(&self, stream: &mut UnixStream, popup_id: u32, token: u32) { + let mut msg = Vec::with_capacity(12); + push_header(&mut msg, popup_id, XDG_POPUP_REPOSITIONED, 4); + push_u32(&mut msg, token); + let _ = stream.write_all(&msg); + } + fn send_shm_format(&self, stream: &mut UnixStream, shm_id: u32, format: u32) { let mut msg = Vec::with_capacity(12); push_header(&mut msg, shm_id, WL_SHM_FORMAT, 4); diff --git a/local/recipes/wayland/redbear-compositor/source/src/state.rs b/local/recipes/wayland/redbear-compositor/source/src/state.rs index 4d2fb1fbe4..e560a58e56 100644 --- a/local/recipes/wayland/redbear-compositor/source/src/state.rs +++ b/local/recipes/wayland/redbear-compositor/source/src/state.rs @@ -235,6 +235,7 @@ pub struct ClientState { pub linux_dmabuf_params: HashMap, pub xdg_outputs: HashMap, pub toplevel_decorations: HashMap, + pub xdg_to_surface: HashMap, pub keyboard_object_id: Option, pub pointer_object_id: Option, pub touch_object_id: Option, diff --git a/recipes/core/bootloader/redox-scheme b/local/sources/redox-scheme/redox-scheme similarity index 100% rename from recipes/core/bootloader/redox-scheme rename to local/sources/redox-scheme/redox-scheme diff --git a/recipes/core/base/relibc b/recipes/core/base/relibc deleted file mode 120000 index 956bd85bb8..0000000000 --- a/recipes/core/base/relibc +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/relibc \ No newline at end of file diff --git a/recipes/core/bootloader/libredox b/recipes/core/bootloader/libredox deleted file mode 120000 index 083ac86176..0000000000 --- a/recipes/core/bootloader/libredox +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/libredox \ No newline at end of file diff --git a/recipes/core/bootloader/redoxfs b/recipes/core/bootloader/redoxfs deleted file mode 120000 index 27eefcec30..0000000000 --- a/recipes/core/bootloader/redoxfs +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/redoxfs \ No newline at end of file diff --git a/recipes/core/bootloader/syscall b/recipes/core/bootloader/syscall deleted file mode 120000 index ba6a37507b..0000000000 --- a/recipes/core/bootloader/syscall +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/syscall \ No newline at end of file diff --git a/recipes/core/installer/libredox b/recipes/core/installer/libredox deleted file mode 120000 index 083ac86176..0000000000 --- a/recipes/core/installer/libredox +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/libredox \ No newline at end of file diff --git a/recipes/core/installer/redox-scheme b/recipes/core/installer/redox-scheme deleted file mode 120000 index 80ac12acb7..0000000000 --- a/recipes/core/installer/redox-scheme +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/redox-scheme \ No newline at end of file diff --git a/recipes/core/installer/redoxfs b/recipes/core/installer/redoxfs deleted file mode 120000 index 27eefcec30..0000000000 --- a/recipes/core/installer/redoxfs +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/redoxfs \ No newline at end of file diff --git a/recipes/core/installer/syscall b/recipes/core/installer/syscall deleted file mode 120000 index ba6a37507b..0000000000 --- a/recipes/core/installer/syscall +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/syscall \ No newline at end of file diff --git a/recipes/core/kernel/libredox b/recipes/core/kernel/libredox deleted file mode 120000 index 083ac86176..0000000000 --- a/recipes/core/kernel/libredox +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/libredox \ No newline at end of file diff --git a/recipes/core/kernel/redox-scheme b/recipes/core/kernel/redox-scheme deleted file mode 120000 index 80ac12acb7..0000000000 --- a/recipes/core/kernel/redox-scheme +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/redox-scheme \ No newline at end of file diff --git a/recipes/core/kernel/syscall b/recipes/core/kernel/syscall deleted file mode 120000 index ba6a37507b..0000000000 --- a/recipes/core/kernel/syscall +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/syscall \ No newline at end of file diff --git a/recipes/core/redoxfs/libredox b/recipes/core/redoxfs/libredox deleted file mode 120000 index 083ac86176..0000000000 --- a/recipes/core/redoxfs/libredox +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/libredox \ No newline at end of file diff --git a/recipes/core/redoxfs/redox-scheme b/recipes/core/redoxfs/redox-scheme deleted file mode 120000 index 80ac12acb7..0000000000 --- a/recipes/core/redoxfs/redox-scheme +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/redox-scheme \ No newline at end of file diff --git a/recipes/core/redoxfs/syscall b/recipes/core/redoxfs/syscall deleted file mode 120000 index ba6a37507b..0000000000 --- a/recipes/core/redoxfs/syscall +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/syscall \ No newline at end of file diff --git a/recipes/core/userutils/libredox b/recipes/core/userutils/libredox deleted file mode 120000 index 083ac86176..0000000000 --- a/recipes/core/userutils/libredox +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/libredox \ No newline at end of file diff --git a/recipes/core/userutils/redox-scheme b/recipes/core/userutils/redox-scheme deleted file mode 120000 index 80ac12acb7..0000000000 --- a/recipes/core/userutils/redox-scheme +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/redox-scheme \ No newline at end of file diff --git a/recipes/core/userutils/relibc b/recipes/core/userutils/relibc deleted file mode 120000 index 956bd85bb8..0000000000 --- a/recipes/core/userutils/relibc +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/relibc \ No newline at end of file diff --git a/recipes/core/userutils/syscall b/recipes/core/userutils/syscall deleted file mode 120000 index ba6a37507b..0000000000 --- a/recipes/core/userutils/syscall +++ /dev/null @@ -1 +0,0 @@ -../../../local/sources/syscall \ No newline at end of file diff --git a/recipes/libs/expat/recipe.toml b/recipes/libs/expat/recipe.toml index 87ec9d5a41..d9d803a3f9 100644 --- a/recipes/libs/expat/recipe.toml +++ b/recipes/libs/expat/recipe.toml @@ -9,6 +9,8 @@ autotools_recursive_regenerate template = "custom" script = """ DYNAMIC_STATIC_INIT +export CFLAGS="${CFLAGS} -fPIC" +export CXXFLAGS="${CXXFLAGS} -fPIC" COOKBOOK_CONFIGURE_FLAGS+=( --without-docbook --without-examples diff --git a/recipes/libs/libpciaccess b/recipes/libs/libpciaccess new file mode 120000 index 0000000000..c9d09eec12 --- /dev/null +++ b/recipes/libs/libpciaccess @@ -0,0 +1 @@ +../../local/recipes/libs/libpciaccess \ No newline at end of file diff --git a/recipes/libs/mesa/recipe.toml b/recipes/libs/mesa/recipe.toml index 9fcd506582..4e10c3d364 100644 --- a/recipes/libs/mesa/recipe.toml +++ b/recipes/libs/mesa/recipe.toml @@ -17,6 +17,7 @@ dependencies = [ "expat", "libdrm", "liborbital", + "linux-kpi", "llvm21", "zlib", ] @@ -27,7 +28,7 @@ script = """ DYNAMIC_INIT #TODO: Should be CPPFLAGS but cookbook_meson isn't reading it -export CFLAGS+=" -DHAVE_PTHREAD=1 -I${COOKBOOK_SYSROOT}/include/libdrm" +export CFLAGS+=" -DHAVE_PTHREAD=1 -I${COOKBOOK_SYSROOT}/include/libdrm -I${COOKBOOK_SYSROOT}/include/linux-kpi" export LLVM_CONFIG="${TARGET}-llvm-config" if [ -x "${HOME}/.redoxer/${TARGET}/toolchain/bin/llvm-config" ]; then export COOKBOOK_HOST_SYSROOT="${HOME}/.redoxer/${TARGET}/toolchain" @@ -64,7 +65,7 @@ cookbook_meson \ -Degl=enabled \ -Dgbm=enabled \ -Dglx=disabled \ - -Dgallium-drivers=swrast,virgl \ + -Dgallium-drivers=swrast,virgl,crocus \ -Dllvm=enabled \ -Dosmesa=true \ -Dplatforms=redox \ diff --git a/scripts/run_mini1.sh b/scripts/run_mini1.sh index 8f031f1a42..753b03751b 100755 --- a/scripts/run_mini1.sh +++ b/scripts/run_mini1.sh @@ -11,7 +11,7 @@ esac # virtio-gl, native CPU, net boost -qemu-system-x86_64 -m 2G -smp 8 -device qemu-xhci -net nic,model=virtio -net user --enable-kvm -cpu host -display gtk,gl=on -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd -drive file=/home/kellito/Builds/RedBear-OS/build/x86_64/redbear-mini.iso,format=raw -device virtio-gpu-pci -enable-kvm -serial mon:stdio +qemu-system-x86_64 -m 8G -smp 8 -device qemu-xhci -net nic,model=virtio -net user --enable-kvm -cpu host -display gtk,gl=on -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd -drive file=/home/kellito/Builds/RedBear-OS/build/x86_64/redbear-mini.iso,format=raw -device virtio-gpu-pci -enable-kvm -serial mon:stdio #qemu-system-x86_64 -m 12G -smp 8 -device qemu-xhci -net nic,model=virtio -net user --enable-kvm -cpu host -display gtk,gl=on -drive if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd -drive file=/home/kellito/Builds/RedBear-OS/build/x86_64/redbear-full.iso,format=raw -device virtio-gpu-pci -enable-kvm -serial mon:stdio diff --git a/src/cook/fetch.rs b/src/cook/fetch.rs index 6402f5d71e..beed38d18d 100644 --- a/src/cook/fetch.rs +++ b/src/cook/fetch.rs @@ -127,11 +127,7 @@ fn redbear_protected_recipe(name: &str) -> bool { | "dbus" | "glib" // Red Bear library stubs and custom libs - | "libepoxy-stub" - | "libdisplay-info-stub" - | "lcms2-stub" - | "libxcvt-stub" - | "libudev-stub" + | "libudev" | "zbus" | "libqrencode" // Red Bear Wayland