Compare commits
6 Commits
instrument
...
dde48f287b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dde48f287b | ||
|
|
fc89e68155 | ||
|
|
289c2f3a3e | ||
|
|
1e5648c9a5 | ||
|
|
d031d7c513 | ||
|
|
03362b59fe |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -94,6 +94,7 @@ node_modules/.bin/
|
|||||||
/build/
|
/build/
|
||||||
/build-arm64/
|
/build-arm64/
|
||||||
/build-x64/
|
/build-x64/
|
||||||
|
/build-cross/
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Local-only paths
|
# Local-only paths
|
||||||
|
|||||||
@@ -82,6 +82,23 @@ file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/scratch")
|
|||||||
# Python for shader compilation scripts
|
# Python for shader compilation scripts
|
||||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||||
|
|
||||||
|
# Generate build-tree version.h via xenia-build.py's generate_version_h()
|
||||||
|
# (normally invoked by `xb premake`/`xb build`; CMake-direct flows need it too).
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${Python3_EXECUTABLE} -c
|
||||||
|
"import importlib.util,sys; \
|
||||||
|
spec=importlib.util.spec_from_file_location('xb',r'${PROJECT_SOURCE_DIR}/xenia-build.py'); \
|
||||||
|
m=importlib.util.module_from_spec(spec); spec.loader.exec_module(m); \
|
||||||
|
m.generate_version_h(r'${CMAKE_BINARY_DIR}')"
|
||||||
|
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE _xenia_version_rc
|
||||||
|
)
|
||||||
|
if(NOT _xenia_version_rc EQUAL 0)
|
||||||
|
message(WARNING "version.h generation failed (rc=${_xenia_version_rc}); writing stub.")
|
||||||
|
file(WRITE "${CMAKE_BINARY_DIR}/version.h"
|
||||||
|
"#ifndef GENERATED_VERSION_H_\n#define GENERATED_VERSION_H_\n#define XE_BUILD_BRANCH \"unknown\"\n#define XE_BUILD_COMMIT \"unknown\"\n#define XE_BUILD_COMMIT_SHORT \"unknown\"\n#define XE_BUILD_DATE __DATE__\n#endif\n")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Include helpers
|
# Include helpers
|
||||||
include(cmake/XeniaHelpers.cmake)
|
include(cmake/XeniaHelpers.cmake)
|
||||||
|
|
||||||
@@ -146,8 +163,14 @@ if(MSVC)
|
|||||||
|
|
||||||
# --- Per-configuration MSVC flags ---
|
# --- Per-configuration MSVC flags ---
|
||||||
# Checked
|
# Checked
|
||||||
string(APPEND CMAKE_C_FLAGS_CHECKED " /RTCsu /fsanitize=address")
|
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"
|
||||||
string(APPEND CMAKE_CXX_FLAGS_CHECKED " /RTCsu /fsanitize=address")
|
AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
|
string(APPEND CMAKE_C_FLAGS_CHECKED " /RTCsu /fsanitize=address")
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_CHECKED " /RTCsu /fsanitize=address")
|
||||||
|
else()
|
||||||
|
string(APPEND CMAKE_C_FLAGS_CHECKED " /fsanitize=address")
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_CHECKED " /fsanitize=address")
|
||||||
|
endif()
|
||||||
string(APPEND CMAKE_EXE_LINKER_FLAGS_CHECKED " /INCREMENTAL:NO")
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_CHECKED " /INCREMENTAL:NO")
|
||||||
add_compile_definitions($<$<CONFIG:Checked>:DEBUG>)
|
add_compile_definitions($<$<CONFIG:Checked>:DEBUG>)
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,22 @@
|
|||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_SYSTEM_PROCESSOR": "ARM64"
|
"CMAKE_SYSTEM_PROCESSOR": "ARM64"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cross-win-clangcl",
|
||||||
|
"displayName": "Cross (Linux→Win MSVC) clang-cl + xwin",
|
||||||
|
"generator": "Ninja Multi-Config",
|
||||||
|
"binaryDir": "${sourceDir}/build-cross",
|
||||||
|
"toolchainFile": "${sourceDir}/cmake/toolchains/linux-to-win-msvc.cmake",
|
||||||
|
"condition": {
|
||||||
|
"type": "notEquals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
},
|
||||||
|
"cacheVariables": {
|
||||||
|
"XWIN_DIR": "$env{HOME}/.xwin/splat",
|
||||||
|
"FXC_PATH": "$env{HOME}/.local/share/xenia-cross/fxc/fxc.exe"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"buildPresets": [
|
"buildPresets": [
|
||||||
@@ -89,6 +105,9 @@
|
|||||||
"name": "vs-arm64-checked",
|
"name": "vs-arm64-checked",
|
||||||
"configurePreset": "vs-arm64",
|
"configurePreset": "vs-arm64",
|
||||||
"configuration": "Checked"
|
"configuration": "Checked"
|
||||||
}
|
},
|
||||||
|
{ "name": "cross-debug", "configurePreset": "cross-win-clangcl", "configuration": "Debug" },
|
||||||
|
{ "name": "cross-release", "configurePreset": "cross-win-clangcl", "configuration": "Release" },
|
||||||
|
{ "name": "cross-checked", "configurePreset": "cross-win-clangcl", "configuration": "Checked" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,6 +192,12 @@ function(xe_shader_rules_dxbc target shader_dir)
|
|||||||
set(_valid_stages vs hs ds gs ps cs)
|
set(_valid_stages vs hs ds gs ps cs)
|
||||||
set(_commands)
|
set(_commands)
|
||||||
set(_bytecode_dir "${shader_dir}/bytecode/d3d12_5_1")
|
set(_bytecode_dir "${shader_dir}/bytecode/d3d12_5_1")
|
||||||
|
# Propagate FXC_PATH from the configure-time env so ninja-spawned python
|
||||||
|
# subprocesses can find fxc.exe (CMake `set(ENV{...})` doesn't reach build).
|
||||||
|
set(_env_prefix "")
|
||||||
|
if(DEFINED ENV{FXC_PATH})
|
||||||
|
set(_env_prefix ${CMAKE_COMMAND} -E env "FXC_PATH=$ENV{FXC_PATH}")
|
||||||
|
endif()
|
||||||
list(APPEND _commands COMMAND ${CMAKE_COMMAND} -E make_directory "${_bytecode_dir}")
|
list(APPEND _commands COMMAND ${CMAKE_COMMAND} -E make_directory "${_bytecode_dir}")
|
||||||
foreach(src ${_sources})
|
foreach(src ${_sources})
|
||||||
get_filename_component(_name ${src} NAME)
|
get_filename_component(_name ${src} NAME)
|
||||||
@@ -206,7 +212,7 @@ function(xe_shader_rules_dxbc target shader_dir)
|
|||||||
if(NOT _stage IN_LIST _valid_stages)
|
if(NOT _stage IN_LIST _valid_stages)
|
||||||
continue()
|
continue()
|
||||||
endif()
|
endif()
|
||||||
list(APPEND _commands COMMAND ${Python3_EXECUTABLE} "${_script}" "${src}" "${_bytecode_dir}/${_id}.h")
|
list(APPEND _commands COMMAND ${_env_prefix} ${Python3_EXECUTABLE} "${_script}" "${src}" "${_bytecode_dir}/${_id}.h")
|
||||||
endforeach()
|
endforeach()
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT "${_stamp}"
|
OUTPUT "${_stamp}"
|
||||||
|
|||||||
119
cmake/toolchains/linux-to-win-msvc.cmake
Normal file
119
cmake/toolchains/linux-to-win-msvc.cmake
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
# cmake/toolchains/linux-to-win-msvc.cmake
|
||||||
|
# Linux host -> Windows MSVC-ABI cross toolchain using clang-cl + lld-link
|
||||||
|
# + xwin-supplied Win10 SDK/CRT. Driven by Ninja Multi-Config.
|
||||||
|
|
||||||
|
set(CMAKE_SYSTEM_NAME Windows)
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||||
|
|
||||||
|
if(NOT DEFINED XWIN_DIR)
|
||||||
|
if(DEFINED ENV{XWIN_DIR})
|
||||||
|
set(XWIN_DIR "$ENV{XWIN_DIR}")
|
||||||
|
else()
|
||||||
|
set(XWIN_DIR "$ENV{HOME}/.xwin/splat")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
set(XWIN_DIR "${XWIN_DIR}" CACHE PATH "xwin splat root (contains crt/ and sdk/)")
|
||||||
|
|
||||||
|
if(NOT EXISTS "${XWIN_DIR}/crt/include")
|
||||||
|
message(FATAL_ERROR "XWIN_DIR=${XWIN_DIR} missing crt/include - run xwin splat.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER clang-cl)
|
||||||
|
set(CMAKE_CXX_COMPILER clang-cl)
|
||||||
|
set(CMAKE_LINKER lld-link)
|
||||||
|
set(CMAKE_RC_COMPILER llvm-rc)
|
||||||
|
set(CMAKE_AR llvm-lib)
|
||||||
|
set(CMAKE_MT llvm-mt)
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER_TARGET x86_64-pc-windows-msvc)
|
||||||
|
set(CMAKE_CXX_COMPILER_TARGET x86_64-pc-windows-msvc)
|
||||||
|
|
||||||
|
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||||
|
|
||||||
|
# Force /MD (release CRT) for every config. xenia's CMakeLists.txt does a
|
||||||
|
# `string(REPLACE "/MDd" "/MD" ...)` on CMAKE_CXX_FLAGS_DEBUG, but with
|
||||||
|
# clang-cl, the runtime selection comes from CMAKE_MSVC_RUNTIME_LIBRARY
|
||||||
|
# (which expands to -MDd in dash form), so the substitution misses.
|
||||||
|
# Pinning the policy here avoids the need for non-redistributable debug
|
||||||
|
# CRT DLLs (MSVCP140D.dll etc) at runtime, which xwin doesn't ship.
|
||||||
|
cmake_policy(SET CMP0091 NEW)
|
||||||
|
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL")
|
||||||
|
|
||||||
|
# xwin's default splat is a flat layout (crt/include, sdk/include/{ucrt,um,shared,...}),
|
||||||
|
# which clang-cl's /winsysroot does NOT understand. Use explicit -imsvc + -libpath:
|
||||||
|
# instead. Re-running `xwin splat --use-winsysroot-style` would also work but
|
||||||
|
# requires re-downloading ~600 MB.
|
||||||
|
# Use SHELL: prefix so CMake doesn't deduplicate repeated -imsvc tokens.
|
||||||
|
add_compile_options(
|
||||||
|
"SHELL:-imsvc \"${XWIN_DIR}/crt/include\""
|
||||||
|
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/ucrt\""
|
||||||
|
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/um\""
|
||||||
|
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/shared\""
|
||||||
|
"SHELL:-imsvc \"${XWIN_DIR}/sdk/include/winrt\""
|
||||||
|
)
|
||||||
|
add_link_options(
|
||||||
|
"/libpath:${XWIN_DIR}/crt/lib/x86_64"
|
||||||
|
"/libpath:${XWIN_DIR}/sdk/lib/ucrt/x86_64"
|
||||||
|
"/libpath:${XWIN_DIR}/sdk/lib/um/x86_64"
|
||||||
|
)
|
||||||
|
# xwin pulls the latest MSVC STL which now hard-asserts Clang >= 19. Our host
|
||||||
|
# has Clang 18, which works fine in practice — opt out of the version check.
|
||||||
|
# (See yvals_core.h STL1000 in $XWIN_DIR/crt/include.)
|
||||||
|
add_compile_definitions(_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH)
|
||||||
|
# llvm-rc needs SDK headers explicitly + the resource file's own dir so the
|
||||||
|
# RC's relative ICON path (../../../assets/icon/icon.ico) resolves.
|
||||||
|
get_filename_component(_toolchain_dir "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||||
|
get_filename_component(_xenia_root "${_toolchain_dir}/../.." ABSOLUTE)
|
||||||
|
set(CMAKE_RC_FLAGS_INIT
|
||||||
|
"/I \"${XWIN_DIR}/sdk/include/um\" /I \"${XWIN_DIR}/sdk/include/shared\" /I \"${_xenia_root}/src/xenia/app\"")
|
||||||
|
|
||||||
|
# Quiet MSVC-STL false positives and xenia-specific warnings that clang-cl
|
||||||
|
# emits but cl.exe doesn't (treated as errors under /WX).
|
||||||
|
add_compile_options(
|
||||||
|
-Wno-microsoft-include
|
||||||
|
-Wno-unused-command-line-argument
|
||||||
|
-Wno-ignored-pragma-intrinsic
|
||||||
|
-Wno-nonportable-include-path
|
||||||
|
-Wno-pragma-pack
|
||||||
|
-Wno-tautological-pointer-compare
|
||||||
|
-Wno-microsoft-cast
|
||||||
|
-Wno-deprecated-declarations
|
||||||
|
# These are silenced for native Linux Clang in CMakeLists.txt's else() branch,
|
||||||
|
# but the if(MSVC) branch fires under clang-cl and skips them — so re-add.
|
||||||
|
-Wno-switch
|
||||||
|
-Wno-attributes
|
||||||
|
-Wno-deprecated-register
|
||||||
|
-Wno-deprecated-volatile
|
||||||
|
-Wno-deprecated-enum-enum-conversion
|
||||||
|
# cl.exe accepts __pragma(optimize("s",on)); clang-cl only knows the empty
|
||||||
|
# argument form. xenia gates XE_MSVC_OPTIMIZE_SMALL on _MSC_VER so the
|
||||||
|
# rejected pragma still emits from the clang-cl path. Treat as no-op.
|
||||||
|
-Wno-ignored-pragmas
|
||||||
|
# xenia decorates several `virtual` methods with XE_FORCEINLINE; clang-cl
|
||||||
|
# then complains that the inline body isn't visible in includer TUs
|
||||||
|
# (definitions live in command_processor.cc). cl.exe accepts this silently.
|
||||||
|
-Wno-undefined-inline
|
||||||
|
-Wno-sizeof-pointer-memaccess
|
||||||
|
# `'ZM'` (PE magic, stored little-endian as "MZ" in the binary) — cl.exe
|
||||||
|
# accepts the multi-char constant silently; clang-cl errors under /WX.
|
||||||
|
-Wno-multichar
|
||||||
|
)
|
||||||
|
# _mm_cvtsi64x_si128 is an MSVC-only alias for the standard _mm_cvtsi64_si128.
|
||||||
|
# Used (gated on XE_PLATFORM_WIN32) in xenia/gpu/draw_util.cc.
|
||||||
|
add_compile_definitions(_mm_cvtsi64x_si128=_mm_cvtsi64_si128)
|
||||||
|
|
||||||
|
# Plumb FXC for tools/build/compile_shader_dxbc.py (wine fxc auto-prepend).
|
||||||
|
# Use real Win10 SDK fxc.exe 10.x (supports SM 5_1, produces vkd3d-proton-
|
||||||
|
# acceptable DXBC).
|
||||||
|
if(DEFINED ENV{FXC_PATH})
|
||||||
|
set(ENV_FXC "$ENV{FXC_PATH}")
|
||||||
|
else()
|
||||||
|
set(ENV_FXC "$ENV{HOME}/.local/share/xenia-cross/fxc/fxc.exe")
|
||||||
|
endif()
|
||||||
|
set(ENV{FXC_PATH} "${ENV_FXC}")
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH "${XWIN_DIR}")
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
55
cmake/toolchains/xwin-case-symlinks.py
Executable file
55
cmake/toolchains/xwin-case-symlinks.py
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Scan xenia source for #include <...> directives and ensure case-aliases
|
||||||
|
exist in xwin's flat SDK/CRT include dirs. Idempotent — safe to re-run."""
|
||||||
|
from __future__ import annotations
|
||||||
|
import os, re, sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
INCLUDE_RE = re.compile(r'^\s*#\s*include\s*<([A-Za-z][A-Za-z0-9_/.\-]*\.h)>',
|
||||||
|
re.MULTILINE)
|
||||||
|
SOURCE_ROOTS = ["src", "third_party/SDL2/src", "third_party/SDL2/include",
|
||||||
|
"third_party/discord-rpc/src", "third_party/fmt",
|
||||||
|
"third_party/imgui"]
|
||||||
|
SOURCE_EXTS = {".h", ".hpp", ".inc", ".c", ".cc", ".cpp", ".cxx"}
|
||||||
|
|
||||||
|
def collect_includes(repo_root: Path) -> set[str]:
|
||||||
|
seen: set[str] = set()
|
||||||
|
for root in SOURCE_ROOTS:
|
||||||
|
base = repo_root / root
|
||||||
|
if not base.exists(): continue
|
||||||
|
for path in base.rglob("*"):
|
||||||
|
if path.suffix.lower() not in SOURCE_EXTS: continue
|
||||||
|
try: txt = path.read_text(encoding="utf-8", errors="ignore")
|
||||||
|
except OSError: continue
|
||||||
|
for m in INCLUDE_RE.finditer(txt):
|
||||||
|
seen.add(m.group(1))
|
||||||
|
return seen
|
||||||
|
|
||||||
|
def fix_dir(target_dir: Path, want: set[str]) -> int:
|
||||||
|
if not target_dir.is_dir(): return 0
|
||||||
|
idx = {e.name.lower(): e.name for e in target_dir.iterdir()}
|
||||||
|
created = 0
|
||||||
|
for name in want:
|
||||||
|
if "/" in name: continue
|
||||||
|
actual = idx.get(name.lower())
|
||||||
|
if actual is None or actual == name: continue
|
||||||
|
link = target_dir / name
|
||||||
|
if link.exists() or link.is_symlink(): continue
|
||||||
|
try:
|
||||||
|
link.symlink_to(actual)
|
||||||
|
created += 1
|
||||||
|
except OSError: pass
|
||||||
|
return created
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
sys.exit("usage: xwin-case-symlinks.py <xenia-canary-root> <xwin-splat-dir>")
|
||||||
|
repo = Path(sys.argv[1]).resolve()
|
||||||
|
xwin = Path(sys.argv[2]).resolve()
|
||||||
|
want = collect_includes(repo)
|
||||||
|
total = 0
|
||||||
|
for d in (xwin/"crt/include", xwin/"sdk/include/ucrt",
|
||||||
|
xwin/"sdk/include/um", xwin/"sdk/include/shared",
|
||||||
|
xwin/"sdk/include/winrt"):
|
||||||
|
total += fix_dir(d, want)
|
||||||
|
print(f"Created {total} case-symlinks across {len(want)} unique includes.")
|
||||||
100
docs/CROSS_BUILD_SETUP.md
Normal file
100
docs/CROSS_BUILD_SETUP.md
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# Building and Running Xenia Canary Windows Debug from Linux
|
||||||
|
|
||||||
|
## What we built and why
|
||||||
|
|
||||||
|
A Windows-MSVC debug `xenia_canary.exe` cross-compiled on Linux, runnable under Wine. This serves as the audit oracle for the xenia-rs Rust port: the Linux-native canary build stalls before the front-end UI, so all audit comparisons (memory entries audit_044–audit_059) need the Wine-targeted debug binary as the ground-truth reference engine.
|
||||||
|
|
||||||
|
## Phase 1 — Host setup (run in your terminal)
|
||||||
|
|
||||||
|
sudo apt install -y clang-18 lld-18 llvm-18 # clang-cl driver mode + lld-link + binutils
|
||||||
|
sudo ln -s /usr/bin/clang-18 /usr/bin/clang-cl # activates MSVC-compatible driver mode
|
||||||
|
xwin --accept-license --arch x86_64 splat --include-debug-libs --output ~/.xwin/splat
|
||||||
|
# ~807 MB Win10 SDK + MSVC CRT sysroot
|
||||||
|
curl ... linkid=2361406 -o ~/winsdk.iso # Win10 SDK ISO for real fxc.exe (SM 5_1)
|
||||||
|
winetricks -q vkd3d # vkd3d-proton d3d12core.dll (5.96 MB)
|
||||||
|
winetricks -q dxvk # DXVK dxgi.dll (2.95 MB)
|
||||||
|
|
||||||
|
Ubuntu's clang-18 / lld-18 apt packages ship binutils suffixed (llvm-lib-18, lld-link-18, etc.); the toolchain expects unsuffixed names on PATH. Create 4 symlinks in `~/.local/bin/` (no sudo needed since it was already on PATH).
|
||||||
|
|
||||||
|
## Phase 2 — In-tree edits
|
||||||
|
|
||||||
|
### 8 build-fix patches (compile-time only; zero runtime semantics changes)
|
||||||
|
|
||||||
|
| § | File | What changed |
|
||||||
|
|---|---|---|
|
||||||
|
| 7.1 | `src/xenia/base/mapped_memory_win.cc:30` | `constexpr` → `const` for `kFileHandleInvalid` (clang-cl rejects `reinterpret_cast` in constant expressions) |
|
||||||
|
| 7.2 | `src/xenia/app/main_resources.rc:3` | `..\\..\\..\\assets\\icon\\icon.ico` → forward slashes (llvm-rc backslash literalism) |
|
||||||
|
| 7.3 | `third_party/snappy/snappy-stubs-public.h` | Already in place via the `fabi/sylpheed-crossbuild` snappy fork submodule |
|
||||||
|
| 7.4 | `third_party/zlib-ng/zconf-ng.h:113` | `#if 1` → `#if !defined(_WIN32)` for `Z_HAVE_UNISTD_H` (header was pre-generated on Linux) |
|
||||||
|
| 7.5 | `third_party/CMakeLists.txt:335` | Extended `if(NOT MSVC)` → `if(NOT MSVC OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")` for zlib-ng AVX flags |
|
||||||
|
| 7.6a | `CMakeLists.txt` | Wrapped `/RTCsu` appends in `CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC" AND NOT … "Clang"` |
|
||||||
|
| 7.6b | `CMakeLists.txt:85-101` | Inserted `execute_process` block invoking `xenia-build.py:generate_version_h()` so CMake-direct flow produces `version.h` |
|
||||||
|
| 7.7 | `cmake/XeniaHelpers.cmake` | Added `_env_prefix` to wrap per-shader commands in `cmake -E env FXC_PATH=…` (`cmake set(ENV{…})` doesn't survive ninja's subprocess spawn) |
|
||||||
|
| 7.8 | `tools/build/compile_shader_dxbc.py:74` | Added `_wineify()` helper translating unix paths via `winepath -w` before fxc sees them (fxc parses `/home/…` as a `/h` switch) |
|
||||||
|
|
||||||
|
### 3 new cross-compile config files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `cmake/toolchains/linux-to-win-msvc.cmake` | clang-cl + lld-link + xwin sysroot driver. Forces `MultiThreadedDLL` runtime (no debug-CRT DLLs needed), feeds `-imsvc` flags via `SHELL:` prefix, suppresses 15+ clang-cl-specific warnings, defines `_mm_cvtsi64x_si128` alias, opts out of MSVC STL's Clang≥19 assertion, plumbs `FXC_PATH` |
|
||||||
|
| `cmake/toolchains/xwin-case-symlinks.py` | Scans xenia includes for mixed-case Windows headers and creates the missing case-aliases in xwin's flat splat (5 needed: `ObjBase.h`, `Psapi.h`, etc.) |
|
||||||
|
| `CMakePresets.json` | Added `cross-win-clangcl` configure preset + `cross-debug` / `cross-release` / `cross-checked` build presets, gated on `${hostSystemName}` ≠ Windows |
|
||||||
|
|
||||||
|
## Phase 3 — Configure + build
|
||||||
|
|
||||||
|
python3 cmake/toolchains/xwin-case-symlinks.py "$PWD" "$HOME/.xwin/splat"
|
||||||
|
# Created 5 case-symlinks across 556 unique includes
|
||||||
|
|
||||||
|
cmake --preset cross-win-clangcl
|
||||||
|
# Generates build-cross/ with build-Debug.ninja + auto-generated version.h
|
||||||
|
|
||||||
|
cmake --build build-cross --preset cross-debug --target xenia-app -j6
|
||||||
|
# 936 ninja targets. -j6 not -j12 because host RAM is tight (~3.4 GiB free at start)
|
||||||
|
# Wall time ~25 min total
|
||||||
|
|
||||||
|
Final output: `xenia_canary.exe` (27 MB PE32+ GUI x86-64) + `xenia_canary.pdb` (116 MB CodeView).
|
||||||
|
|
||||||
|
## Phase 4 — Running the game
|
||||||
|
|
||||||
|
cd "/home/fabi/RE Project Sylpheed/xenia-canary/build-cross/bin/Windows/Debug"
|
||||||
|
WINEDEBUG=-all wine ./xenia_canary.exe --mute=true \
|
||||||
|
"/home/fabi/RE Project Sylpheed/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja).iso"
|
||||||
|
|
||||||
|
Kill after the boot phase completes (the audit workflow only needs ~30 s of trajectory):
|
||||||
|
|
||||||
|
sleep 30
|
||||||
|
wineserver -k
|
||||||
|
|
||||||
|
### Expected boot signals in `xenia.log`
|
||||||
|
|
||||||
|
| Signal | Value | Meaning |
|
||||||
|
|---|---|---|
|
||||||
|
| Total log lines | 1091 | Healthy boot (≥1000 = passes) |
|
||||||
|
| `^x>` fatals | 0 | No `xe::FatalError()` triggered |
|
||||||
|
| `^!>` errors | 28 | Non-fatal (occasional pipeline misses — normal) |
|
||||||
|
| `^w>` warnings | 28 | Normal startup |
|
||||||
|
| `i> Setup: Initializing chain` | Memory → Exports → Processor → Audio → Graphics → HID → VFS → Kernel | All eight subsystems came up |
|
||||||
|
| `i> Setup: Starting graphics_system + Starting audio_system` | present | Threads spawned cleanly |
|
||||||
|
| DXGI adapter | NVIDIA GeForce GTX 1070 Ti | vkd3d-proton + DXVK loaded |
|
||||||
|
| `K> XThread::Execute thid N count` | 29 | Guest threads spawned (game is past `XexLoadImage`) |
|
||||||
|
| `Skipping draw - pipeline not ready: VS … PS …` repeating | yes | D3D12 backend is async-compiling pipelines — expected on cold boot |
|
||||||
|
| `F>` channel | 321 lines | VFS is mounting and walking the disc image |
|
||||||
|
| `K>` channel | 29 lines | Kernel dispatching XThread creation |
|
||||||
|
|
||||||
|
## Audit-workflow integration
|
||||||
|
|
||||||
|
The cross-build is now the sole canary oracle. The Linux-native `xenia-canary/build/bin/Linux/Debug/xenia_canary` is deprecated for audits.
|
||||||
|
|
||||||
|
All canary launches must include `--mute=true` (project policy 2026-05-12). XAudio2 still initializes — same code paths, silent output. Do not substitute `--apu=nop`; that switches backend entirely.
|
||||||
|
|
||||||
|
Point logs at `audit-runs` with `--log_file=`:
|
||||||
|
|
||||||
|
LOG="$XENIA_RS_ROOT/xenia-rs/audit-runs/audit_NN/canary.log" \
|
||||||
|
WINEDEBUG=-all wine xenia_canary.exe \
|
||||||
|
--mute=true --log_file="$LOG" \
|
||||||
|
--audit_NN_my_probe=true \
|
||||||
|
"$ISO_PATH"
|
||||||
|
|
||||||
|
Add new audit instrumentation as cvars in `cpu_flags.h` / `gpu_flags.h` / `kernel_flags.h`, guard with `if (cvars::audit_NN_my_probe)`, emit `XELOGI("AUDIT-NN-EVENT …")`. Rebuild incrementally — only the touched TU recompiles, ≤60 s.
|
||||||
|
|
||||||
|
The build is observation-only: cvars + `XELOG*()` + `#if`-gated diagnostic blocks are permitted; changing control flow, return values, struct layouts, or timing is forbidden, since that would invalidate every downstream audit comparison.
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
//{{NO_DEPENDENCIES}}
|
//{{NO_DEPENDENCIES}}
|
||||||
|
|
||||||
MAINICON ICON "..\\..\\..\\assets\\icon\\icon.ico"
|
MAINICON ICON "../../../assets/icon/icon.ico"
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ namespace xe {
|
|||||||
class Win32MappedMemory : public MappedMemory {
|
class Win32MappedMemory : public MappedMemory {
|
||||||
public:
|
public:
|
||||||
// CreateFile returns INVALID_HANDLE_VALUE in case of failure.
|
// CreateFile returns INVALID_HANDLE_VALUE in case of failure.
|
||||||
// chrispy: made inline const to get around clang error
|
// INVALID_HANDLE_VALUE expands to a reinterpret_cast which MSVC accepts
|
||||||
static inline constexpr HANDLE kFileHandleInvalid = INVALID_HANDLE_VALUE;
|
// in constexpr as an extension; clang-cl rejects it per C++ standard.
|
||||||
|
static inline const HANDLE kFileHandleInvalid = INVALID_HANDLE_VALUE;
|
||||||
// CreateFileMapping returns nullptr in case of failure.
|
// CreateFileMapping returns nullptr in case of failure.
|
||||||
static constexpr HANDLE kMappingHandleInvalid = nullptr;
|
static constexpr HANDLE kMappingHandleInvalid = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,14 @@
|
|||||||
|
|
||||||
DEFINE_bool(debugprint_trap_log, false,
|
DEFINE_bool(debugprint_trap_log, false,
|
||||||
"Log debugprint traps to the active debugger", "CPU");
|
"Log debugprint traps to the active debugger", "CPU");
|
||||||
|
DEFINE_uint32(audit_jit_prolog_pc, 0,
|
||||||
|
"Guest function entry PC at which to emit one XELOGKERNEL line "
|
||||||
|
"per JIT-compiled entry. When non-zero, the x64 emitter inserts "
|
||||||
|
"a CallNative to AuditLogJitPrologArgs at the start of the JIT "
|
||||||
|
"body of the matching guest function. Dumps r3..r10, LR, and 64 "
|
||||||
|
"bytes at host(r3). Zero (default) disables the probe. Audit-059 "
|
||||||
|
"round 7+ JIT-prolog probe — generic PC-configurable variant.",
|
||||||
|
"Auditing");
|
||||||
DEFINE_bool(ignore_undefined_externs, true,
|
DEFINE_bool(ignore_undefined_externs, true,
|
||||||
"Don't exit when an undefined extern is called.", "CPU");
|
"Don't exit when an undefined extern is called.", "CPU");
|
||||||
DEFINE_bool(emit_source_annotations, false,
|
DEFINE_bool(emit_source_annotations, false,
|
||||||
@@ -270,6 +278,17 @@ bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
|
|||||||
count on no other code modifying it. mov(GetMembaseReg(),
|
count on no other code modifying it. mov(GetMembaseReg(),
|
||||||
qword[GetContextReg() + offsetof(ppc::PPCContext, virtual_membase)]);
|
qword[GetContextReg() + offsetof(ppc::PPCContext, virtual_membase)]);
|
||||||
*/
|
*/
|
||||||
|
// Audit-059: PC-configurable JIT-prolog probe. Runtime-gated on the cvar
|
||||||
|
// audit_jit_prolog_pc (uint32; 0 disables). When non-zero and the current
|
||||||
|
// guest function's entry PC matches, emit a single CallNative to
|
||||||
|
// AuditLogJitPrologArgs that dumps r3..r10, LR, and 64 bytes at host(r3).
|
||||||
|
// Emits *before* any body instruction runs, so r3..r10 / LR in PPCContext
|
||||||
|
// still reflect the caller's args (no LOAD/STORE_CONTEXT has executed yet).
|
||||||
|
if (cvars::audit_jit_prolog_pc != 0u &&
|
||||||
|
current_guest_function_ == cvars::audit_jit_prolog_pc) {
|
||||||
|
extern uint64_t AuditLogJitPrologArgs(void* raw_context, uint64_t arg0);
|
||||||
|
CallNative(AuditLogJitPrologArgs, 0);
|
||||||
|
}
|
||||||
// Body.
|
// Body.
|
||||||
auto block = builder->first_block();
|
auto block = builder->first_block();
|
||||||
synchronize_stack_on_next_instruction_ = false;
|
synchronize_stack_on_next_instruction_ = false;
|
||||||
@@ -438,6 +457,55 @@ uint64_t TrapDebugBreak(void* raw_context, uint64_t address) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Audit-059 JIT-prolog probe: dump r3..r10, LR, and 64 bytes at host(r3)
|
||||||
|
// when the guest hits the JIT-compiled entry of the function whose entry PC
|
||||||
|
// matches cvars::audit_jit_prolog_pc. Generic PC-configurable variant of the
|
||||||
|
// round-7 sub_824F7800 hook. The hook logs the current guest PC so multiple
|
||||||
|
// instrumentation campaigns can share log output.
|
||||||
|
uint64_t AuditLogJitPrologArgs(void* raw_context, uint64_t /*unused*/) {
|
||||||
|
auto* ctx = reinterpret_cast<ppc::PPCContext_s*>(raw_context);
|
||||||
|
uint32_t pc = static_cast<uint32_t>(cvars::audit_jit_prolog_pc);
|
||||||
|
uint32_t r3 = static_cast<uint32_t>(ctx->r[3]);
|
||||||
|
uint32_t r4 = static_cast<uint32_t>(ctx->r[4]);
|
||||||
|
uint32_t r5 = static_cast<uint32_t>(ctx->r[5]);
|
||||||
|
uint32_t r6 = static_cast<uint32_t>(ctx->r[6]);
|
||||||
|
uint32_t r7 = static_cast<uint32_t>(ctx->r[7]);
|
||||||
|
uint32_t r8 = static_cast<uint32_t>(ctx->r[8]);
|
||||||
|
uint32_t r9 = static_cast<uint32_t>(ctx->r[9]);
|
||||||
|
uint32_t r10 = static_cast<uint32_t>(ctx->r[10]);
|
||||||
|
uint32_t lr = static_cast<uint32_t>(ctx->lr);
|
||||||
|
|
||||||
|
uint32_t tid = ctx->thread_state ? ctx->thread_state->thread_id() : 0u;
|
||||||
|
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC JitProlog pc={:08X} tid={:08X} r3={:08X} r4={:08X} r5={:08X} "
|
||||||
|
"r6={:08X} r7={:08X} r8={:08X} r9={:08X} r10={:08X} lr={:08X}",
|
||||||
|
pc, tid, r3, r4, r5, r6, r7, r8, r9, r10, lr);
|
||||||
|
|
||||||
|
// Dump 64 bytes at host(r3) if r3 looks like a plausible guest VA.
|
||||||
|
if (r3 >= 0x10000 && r3 < 0xE0000000) {
|
||||||
|
uint8_t* host = ctx->TranslateVirtual(r3);
|
||||||
|
if (host) {
|
||||||
|
for (uint32_t off = 0; off < 0x40; off += 16) {
|
||||||
|
uint32_t d0 = xe::load_and_swap<uint32_t>(host + off + 0);
|
||||||
|
uint32_t d1 = xe::load_and_swap<uint32_t>(host + off + 4);
|
||||||
|
uint32_t d2 = xe::load_and_swap<uint32_t>(host + off + 8);
|
||||||
|
uint32_t d3 = xe::load_and_swap<uint32_t>(host + off + 12);
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC JitProlog pc={:08X} r3+{:02X}: {:08X} {:08X} {:08X} "
|
||||||
|
"{:08X}",
|
||||||
|
pc, off, d0, d1, d2, d3);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
XELOGKERNEL("AUDIT-HLC JitProlog pc={:08X} r3 translate failed", pc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
XELOGKERNEL("AUDIT-HLC JitProlog pc={:08X} r3 out of VA range, skipping dump",
|
||||||
|
pc);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void X64Emitter::Trap(uint16_t trap_type) {
|
void X64Emitter::Trap(uint16_t trap_type) {
|
||||||
switch (trap_type) {
|
switch (trap_type) {
|
||||||
case 20:
|
case 20:
|
||||||
|
|||||||
@@ -14,3 +14,7 @@ DEFINE_bool(headless, false,
|
|||||||
"UI");
|
"UI");
|
||||||
DEFINE_bool(log_high_frequency_kernel_calls, false,
|
DEFINE_bool(log_high_frequency_kernel_calls, false,
|
||||||
"Log kernel calls with the kHighFrequency tag.", "Logging");
|
"Log kernel calls with the kHighFrequency tag.", "Logging");
|
||||||
|
DEFINE_bool(audit_handle_lifecycle, false,
|
||||||
|
"Emit XELOGKERNEL on Event/Semaphore/Wait lifecycle "
|
||||||
|
"(create/set/wait/complete). Audit oracle probe — off by default.",
|
||||||
|
"Auditing");
|
||||||
|
|||||||
@@ -13,5 +13,6 @@
|
|||||||
|
|
||||||
DECLARE_bool(headless);
|
DECLARE_bool(headless);
|
||||||
DECLARE_bool(log_high_frequency_kernel_calls);
|
DECLARE_bool(log_high_frequency_kernel_calls);
|
||||||
|
DECLARE_bool(audit_handle_lifecycle);
|
||||||
|
|
||||||
#endif // XENIA_KERNEL_KERNEL_FLAGS_H_
|
#endif // XENIA_KERNEL_KERNEL_FLAGS_H_
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/emulator.h"
|
#include "xenia/emulator.h"
|
||||||
#include "xenia/hid/input_system.h"
|
#include "xenia/hid/input_system.h"
|
||||||
|
#include "xenia/kernel/kernel_flags.h"
|
||||||
#include "xenia/kernel/user_module.h"
|
#include "xenia/kernel/user_module.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_memory.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_memory.h"
|
||||||
@@ -1373,6 +1374,13 @@ void KernelState::EmulateCPInterruptDPC(uint32_t interrupt_callback,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cvars::audit_handle_lifecycle) {
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC EmulateCPInterruptDPC callback={:08X} data={:08X} source={} "
|
||||||
|
"cpu={}",
|
||||||
|
interrupt_callback, interrupt_callback_data, source, cpu);
|
||||||
|
}
|
||||||
|
|
||||||
auto thread = kernel::XThread::GetCurrentThread();
|
auto thread = kernel::XThread::GetCurrentThread();
|
||||||
assert_not_null(thread);
|
assert_not_null(thread);
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
|
||||||
|
#include <atomic>
|
||||||
#include "xenia/base/atomic.h"
|
#include "xenia/base/atomic.h"
|
||||||
#include "xenia/base/clock.h"
|
#include "xenia/base/clock.h"
|
||||||
#include "xenia/base/platform.h"
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
|
#include "xenia/kernel/kernel_flags.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||||
#include "xenia/kernel/xsemaphore.h"
|
#include "xenia/kernel/xsemaphore.h"
|
||||||
@@ -22,6 +24,9 @@ namespace xe {
|
|||||||
namespace kernel {
|
namespace kernel {
|
||||||
namespace xboxkrnl {
|
namespace xboxkrnl {
|
||||||
|
|
||||||
|
// AUDIT-HLC: one-shot guard for silph::WorkerCtx context dump (round5).
|
||||||
|
static std::atomic<bool> g_audit_silph_ctx_dumped{false};
|
||||||
|
|
||||||
// r13 + 0x100: pointer to thread local state
|
// r13 + 0x100: pointer to thread local state
|
||||||
// Thread local state:
|
// Thread local state:
|
||||||
// 0x058: kernel time
|
// 0x058: kernel time
|
||||||
@@ -547,6 +552,48 @@ uint32_t xeKeSetEvent(X_KEVENT* event_ptr, uint32_t increment, uint32_t wait) {
|
|||||||
|
|
||||||
dword_result_t KeSetEvent_entry(pointer_t<X_KEVENT> event_ptr,
|
dword_result_t KeSetEvent_entry(pointer_t<X_KEVENT> event_ptr,
|
||||||
dword_t increment, dword_t wait) {
|
dword_t increment, dword_t wait) {
|
||||||
|
if (cvars::audit_handle_lifecycle) {
|
||||||
|
uint32_t lr = static_cast<uint32_t>(cpu::ThreadState::Get()->context()->lr);
|
||||||
|
XELOGKERNEL("AUDIT-HLC KeSetEvent guest_ptr={:08X} lr={:08X}",
|
||||||
|
uint32_t(event_ptr.guest_address()), lr);
|
||||||
|
// AUDIT-HLC round5: one-shot hexdump of the silph::WorkerCtx context when
|
||||||
|
// KeSetEvent first fires into the silph UI PKEVENT cluster
|
||||||
|
// (0xBCE25214/24/34/44 in current builds; widened a bit for allocator
|
||||||
|
// drift). Used by iterate 2.BF context-replication.
|
||||||
|
uint32_t ev_addr = uint32_t(event_ptr.guest_address());
|
||||||
|
if (ev_addr >= 0xBCE25200 && ev_addr < 0xBCE25300) {
|
||||||
|
if (!g_audit_silph_ctx_dumped.exchange(true)) {
|
||||||
|
// Events live at ctx+0x54, +0x64, +0x74, +0x84 (16-byte stride).
|
||||||
|
// Compute ctx_base assuming the canonical layout (lowest event at
|
||||||
|
// ctx+0x54 → ctx_base = 0xBCE251C0 when ev_addr == 0xBCE25214).
|
||||||
|
uint32_t event_offset_in_ctx = ev_addr - 0xBCE251C0;
|
||||||
|
uint32_t ctx_base = ev_addr - event_offset_in_ctx;
|
||||||
|
auto* ctx = cpu::ThreadState::Get()->context();
|
||||||
|
uint8_t* host = ctx->TranslateVirtual(ctx_base);
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC silph_ctx_dump ctx_base={:08X} (event {:08X} at +{:02X})",
|
||||||
|
ctx_base, ev_addr, event_offset_in_ctx);
|
||||||
|
for (uint32_t off = 0; off < 0x300; off += 16) {
|
||||||
|
uint32_t d0 = xe::load_and_swap<uint32_t>(host + off + 0);
|
||||||
|
uint32_t d1 = xe::load_and_swap<uint32_t>(host + off + 4);
|
||||||
|
uint32_t d2 = xe::load_and_swap<uint32_t>(host + off + 8);
|
||||||
|
uint32_t d3 = xe::load_and_swap<uint32_t>(host + off + 12);
|
||||||
|
XELOGKERNEL("AUDIT-HLC DUMP {:08X}: {:08X} {:08X} {:08X} {:08X}",
|
||||||
|
ctx_base + off, d0, d1, d2, d3);
|
||||||
|
}
|
||||||
|
XELOGKERNEL("AUDIT-HLC silph_ctx event-slots:");
|
||||||
|
for (uint32_t i = 0; i < 8; ++i) {
|
||||||
|
uint32_t ev_off = 0x54 + i * 0x10;
|
||||||
|
uint32_t hdr = xe::load_and_swap<uint32_t>(host + ev_off + 0);
|
||||||
|
uint32_t state = xe::load_and_swap<uint32_t>(host + ev_off + 4);
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC slot[{}] off=+{:02X} addr={:08X} hdr={:08X} "
|
||||||
|
"state={:08X}",
|
||||||
|
i, ev_off, ctx_base + ev_off, hdr, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return xeKeSetEvent(event_ptr, increment, wait);
|
return xeKeSetEvent(event_ptr, increment, wait);
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency);
|
DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency);
|
||||||
@@ -604,6 +651,14 @@ dword_result_t NtCreateEvent_entry(
|
|||||||
if (handle_ptr) {
|
if (handle_ptr) {
|
||||||
*handle_ptr = ev->handle();
|
*handle_ptr = ev->handle();
|
||||||
}
|
}
|
||||||
|
if (cvars::audit_handle_lifecycle) {
|
||||||
|
uint32_t lr = static_cast<uint32_t>(cpu::ThreadState::Get()->context()->lr);
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC NtCreateEvent handle={:08X} type={} initial_state={} "
|
||||||
|
"lr={:08X}",
|
||||||
|
handle_ptr ? uint32_t(*handle_ptr) : 0u, uint32_t(event_type),
|
||||||
|
uint32_t(initial_state), lr);
|
||||||
|
}
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(NtCreateEvent, kThreading, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(NtCreateEvent, kThreading, kImplemented);
|
||||||
@@ -629,6 +684,11 @@ uint32_t xeNtSetEvent(uint32_t handle, xe::be<uint32_t>* previous_state_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dword_result_t NtSetEvent_entry(dword_t handle, lpdword_t previous_state_ptr) {
|
dword_result_t NtSetEvent_entry(dword_t handle, lpdword_t previous_state_ptr) {
|
||||||
|
if (cvars::audit_handle_lifecycle) {
|
||||||
|
uint32_t lr = static_cast<uint32_t>(cpu::ThreadState::Get()->context()->lr);
|
||||||
|
XELOGKERNEL("AUDIT-HLC NtSetEvent handle={:08X} lr={:08X}",
|
||||||
|
uint32_t(handle), lr);
|
||||||
|
}
|
||||||
return xeNtSetEvent(handle, previous_state_ptr);
|
return xeNtSetEvent(handle, previous_state_ptr);
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT2(NtSetEvent, kThreading, kImplemented, kHighFrequency);
|
DECLARE_XBOXKRNL_EXPORT2(NtSetEvent, kThreading, kImplemented, kHighFrequency);
|
||||||
@@ -1003,9 +1063,43 @@ dword_result_t NtWaitForSingleObjectEx_entry(dword_t object_handle,
|
|||||||
dword_t wait_mode,
|
dword_t wait_mode,
|
||||||
dword_t alertable,
|
dword_t alertable,
|
||||||
lpqword_t timeout_ptr) {
|
lpqword_t timeout_ptr) {
|
||||||
|
uint32_t lr_enter = 0;
|
||||||
|
uint32_t guest_lr = 0;
|
||||||
|
if (cvars::audit_handle_lifecycle) {
|
||||||
|
auto* ctx = cpu::ThreadState::Get()->context();
|
||||||
|
lr_enter = static_cast<uint32_t>(ctx->lr);
|
||||||
|
// Walk one PPC stack frame up from the wait wrapper's frame to recover
|
||||||
|
// the GUEST caller's LR (lr_enter is just the kernel-internal wait
|
||||||
|
// wrapper's return address; we want the function that called *it*).
|
||||||
|
// Xbox 360 PPC convention: prologue stores caller's LR at [old_sp - 8]
|
||||||
|
// *before* bumping r1 to the new frame, so from any frame, the LR saved
|
||||||
|
// by that frame's prologue lives at (back_chain - 8). See xenia-rs
|
||||||
|
// walk_guest_back_chain in crates/xenia-kernel/src/state.rs.
|
||||||
|
uint32_t sp = static_cast<uint32_t>(ctx->r[1]);
|
||||||
|
uint32_t back1 = xe::load_and_swap<uint32_t>(ctx->TranslateVirtual(sp));
|
||||||
|
if (back1) {
|
||||||
|
uint32_t back2 =
|
||||||
|
xe::load_and_swap<uint32_t>(ctx->TranslateVirtual(back1));
|
||||||
|
if (back2) {
|
||||||
|
guest_lr = xe::load_and_swap<uint32_t>(
|
||||||
|
ctx->TranslateVirtual(back2 - 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC NtWaitForSingleObjectEx handle={:08X} alertable={} "
|
||||||
|
"lr={:08X} guest_lr={:08X}",
|
||||||
|
uint32_t(object_handle), uint32_t(alertable), lr_enter, guest_lr);
|
||||||
|
}
|
||||||
uint64_t timeout = timeout_ptr ? static_cast<uint64_t>(*timeout_ptr) : 0u;
|
uint64_t timeout = timeout_ptr ? static_cast<uint64_t>(*timeout_ptr) : 0u;
|
||||||
return NtWaitForSingleObjectEx(object_handle, wait_mode, alertable,
|
uint32_t result = NtWaitForSingleObjectEx(object_handle, wait_mode, alertable,
|
||||||
timeout_ptr ? &timeout : nullptr);
|
timeout_ptr ? &timeout : nullptr);
|
||||||
|
if (cvars::audit_handle_lifecycle) {
|
||||||
|
XELOGKERNEL(
|
||||||
|
"AUDIT-HLC NtWaitForSingleObjectEx_done handle={:08X} result={:08X} "
|
||||||
|
"lr={:08X} guest_lr={:08X}",
|
||||||
|
uint32_t(object_handle), result, lr_enter, guest_lr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT3(NtWaitForSingleObjectEx, kThreading, kImplemented,
|
DECLARE_XBOXKRNL_EXPORT3(NtWaitForSingleObjectEx, kThreading, kImplemented,
|
||||||
kBlocking, kHighFrequency);
|
kBlocking, kHighFrequency);
|
||||||
|
|||||||
2
third_party/CMakeLists.txt
vendored
2
third_party/CMakeLists.txt
vendored
@@ -332,7 +332,7 @@ else()
|
|||||||
X86_AVX512VNNI
|
X86_AVX512VNNI
|
||||||
WITH_GZFILEOP
|
WITH_GZFILEOP
|
||||||
)
|
)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
# GCC/Clang have native __builtin_ctz/__builtin_ctzll (MSVC gets these
|
# GCC/Clang have native __builtin_ctz/__builtin_ctzll (MSVC gets these
|
||||||
# from fallback_builtins.h). Defining these enables optimized compare256
|
# from fallback_builtins.h). Defining these enables optimized compare256
|
||||||
# and longest_match codepaths.
|
# and longest_match codepaths.
|
||||||
|
|||||||
2
third_party/snappy
vendored
2
third_party/snappy
vendored
Submodule third_party/snappy updated: 6af9287fbd...77c78fad94
@@ -73,6 +73,16 @@ def main():
|
|||||||
|
|
||||||
# Start with base command — use wine on non-Windows platforms.
|
# Start with base command — use wine on non-Windows platforms.
|
||||||
if sys.platform != "win32":
|
if sys.platform != "win32":
|
||||||
|
def _wineify(p):
|
||||||
|
try:
|
||||||
|
out = subprocess.check_output(["winepath", "-w", p],
|
||||||
|
stderr=subprocess.DEVNULL)
|
||||||
|
return out.decode("utf-8", "replace").strip()
|
||||||
|
except (OSError, subprocess.CalledProcessError):
|
||||||
|
return p
|
||||||
|
input_path = _wineify(input_path)
|
||||||
|
output_path = _wineify(output_path)
|
||||||
|
src_dir = _wineify(src_dir)
|
||||||
compiler_args = ["wine", fxc]
|
compiler_args = ["wine", fxc]
|
||||||
else:
|
else:
|
||||||
compiler_args = [fxc]
|
compiler_args = [fxc]
|
||||||
|
|||||||
Reference in New Issue
Block a user