diff --git a/README.md b/README.md index 7b68ed5f6..6b088e1d4 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2798. +This is the source code for early-access 2799. ## Legal Notice diff --git a/externals/dynarmic/CMakeLists.txt b/externals/dynarmic/CMakeLists.txt index b5fd5f1ec..7fe7570d8 100755 --- a/externals/dynarmic/CMakeLists.txt +++ b/externals/dynarmic/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.8) -project(dynarmic LANGUAGES C CXX ASM VERSION 5) +project(dynarmic LANGUAGES C CXX ASM VERSION 6.0.1) # Determine if we're built as a subproject (using add_subdirectory) # or if this is the master project. diff --git a/externals/dynarmic/src/dynarmic/backend/x64/constants.h b/externals/dynarmic/src/dynarmic/backend/x64/constants.h index 13bf36960..d4044a82f 100755 --- a/externals/dynarmic/src/dynarmic/backend/x64/constants.h +++ b/externals/dynarmic/src/dynarmic/backend/x64/constants.h @@ -97,13 +97,13 @@ constexpr u8 SNaN = 0b10000000; // Opcodes for use with vfixupimm enum class FpFixup : u8 { - A = 0b0000, // A - B = 0b0001, // B - QNaN_B = 0b0010, // QNaN with sign of B + Dest = 0b0000, // Preserve destination + Norm_Src = 0b0001, // Source operand (Denormal as positive-zero) + QNaN_Src = 0b0010, // QNaN with sign of source (Denormal as positive-zero) IndefNaN = 0b0011, // Indefinite QNaN (Negative QNaN with no payload on x86) NegInf = 0b0100, // -Infinity PosInf = 0b0101, // +Infinity - Inf_B = 0b0110, // Infinity with sign of B + Inf_Src = 0b0110, // Infinity with sign of source (Denormal as positive-zero) NegZero = 0b0111, // -0.0 PosZero = 0b1000, // +0.0 NegOne = 0b1001, // -1.0 @@ -116,14 +116,14 @@ enum class FpFixup : u8 { }; // Generates 32-bit LUT for vfixupimm instruction -constexpr u32 FixupLUT(FpFixup src_qnan = FpFixup::A, - FpFixup src_snan = FpFixup::A, - FpFixup src_zero = FpFixup::A, - FpFixup src_posone = FpFixup::A, - FpFixup src_neginf = FpFixup::A, - FpFixup src_posinf = FpFixup::A, - FpFixup src_pos = FpFixup::A, - FpFixup src_neg = FpFixup::A) { +constexpr u32 FixupLUT(FpFixup src_qnan = FpFixup::Dest, + FpFixup src_snan = FpFixup::Dest, + FpFixup src_zero = FpFixup::Dest, + FpFixup src_posone = FpFixup::Dest, + FpFixup src_neginf = FpFixup::Dest, + FpFixup src_posinf = FpFixup::Dest, + FpFixup src_pos = FpFixup::Dest, + FpFixup src_neg = FpFixup::Dest) { u32 fixup_lut = 0; fixup_lut = mcl::bit::set_bits<0, 3, u32>(fixup_lut, static_cast(src_qnan)); fixup_lut = mcl::bit::set_bits<4, 7, u32>(fixup_lut, static_cast(src_snan)); diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp index 1f067f287..d45e97ba9 100755 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_floating_point.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/block_of_code.h" @@ -79,6 +80,27 @@ constexpr u64 f64_max_s64_lim = 0x43e0000000000000u; // 2^63 as a double (actua template void DenormalsAreZero(BlockOfCode& code, EmitContext& ctx, std::initializer_list to_daz) { if (ctx.FPCR().FZ()) { + if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) { + constexpr u32 denormal_to_zero = FixupLUT( + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src); + constexpr u64 denormal_to_zero64 = mcl::bit::replicate_element(denormal_to_zero); + + const Xbyak::Xmm tmp = xmm16; + FCODE(vmovap)(tmp, code.MConst(xword, u64(denormal_to_zero64), u64(denormal_to_zero64))); + + for (const Xbyak::Xmm& xmm : to_daz) { + FCODE(vfixupimms)(xmm, xmm, tmp, u8(0)); + } + return; + } + for (const Xbyak::Xmm& xmm : to_daz) { code.movaps(xmm0, code.MConst(xword, fsize == 32 ? f32_non_sign_mask : f64_non_sign_mask)); code.andps(xmm0, xmm); @@ -114,7 +136,11 @@ void ZeroIfNaN(BlockOfCode& code, Xbyak::Xmm xmm_value, Xbyak::Xmm xmm_scratch) template void ForceToDefaultNaN(BlockOfCode& code, Xbyak::Xmm result) { - if (code.HasHostFeature(HostFeature::AVX)) { + if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) { + const Xbyak::Opmask nan_mask = k1; + FCODE(vfpclasss)(nan_mask, result, u8(FpClass::QNaN | FpClass::SNaN)); + FCODE(vblendmp)(result | nan_mask, result, code.MConst(ptr_b, fsize == 32 ? f32_nan : f64_nan)); + } else if (code.HasHostFeature(HostFeature::AVX)) { FCODE(vcmpunords)(xmm0, result, result); FCODE(blendvp)(result, code.MConst(xword, fsize == 32 ? f32_nan : f64_nan)); } else { diff --git a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp index 8ce25004c..c34ac3d62 100755 --- a/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp +++ b/externals/dynarmic/src/dynarmic/backend/x64/emit_x64_vector_floating_point.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "dynarmic/backend/x64/abi.h" #include "dynarmic/backend/x64/block_of_code.h" @@ -189,11 +190,16 @@ Xbyak::Address GetVectorOf(BlockOfCode& code) { template void ForceToDefaultNaN(BlockOfCode& code, FP::FPCR fpcr, Xbyak::Xmm result) { if (fpcr.DN()) { - const Xbyak::Xmm nan_mask = xmm0; - if (code.HasHostFeature(HostFeature::AVX)) { + if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) { + const Xbyak::Opmask nan_mask = k1; + FCODE(vfpclassp)(nan_mask, result, u8(FpClass::QNaN | FpClass::SNaN)); + FCODE(vblendmp)(result | nan_mask, result, GetNaNVector(code)); + } else if (code.HasHostFeature(HostFeature::AVX)) { + const Xbyak::Xmm nan_mask = xmm0; FCODE(vcmpunordp)(nan_mask, result, result); FCODE(blendvp)(result, GetNaNVector(code)); } else { + const Xbyak::Xmm nan_mask = xmm0; code.movaps(nan_mask, result); FCODE(cmpordp)(nan_mask, nan_mask); code.andps(result, nan_mask); @@ -223,6 +229,26 @@ void ZeroIfNaN(BlockOfCode& code, Xbyak::Xmm result) { template void DenormalsAreZero(BlockOfCode& code, FP::FPCR fpcr, std::initializer_list to_daz, Xbyak::Xmm tmp) { if (fpcr.FZ()) { + if (code.HasHostFeature(HostFeature::AVX512_OrthoFloat)) { + constexpr u32 denormal_to_zero = FixupLUT( + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src, + FpFixup::Norm_Src); + constexpr u64 denormal_to_zero64 = mcl::bit::replicate_element(denormal_to_zero); + + FCODE(vmovap)(tmp, code.MConst(xword, u64(denormal_to_zero64), u64(denormal_to_zero64))); + + for (const Xbyak::Xmm& xmm : to_daz) { + FCODE(vfixupimmp)(xmm, xmm, tmp, u8(0)); + } + return; + } + if (fpcr.RMode() != FP::RoundingMode::TowardsMinusInfinity) { code.movaps(tmp, GetNegativeZeroVector(code)); } else { diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp index 95c704dad..8db6cab9a 100755 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp @@ -28,19 +28,22 @@ IR::Block TranslateArm(LocationDescriptor descriptor, TranslateCallbacks* tcb, c bool should_continue = true; do { const u32 arm_pc = visitor.ir.current_location.PC(); - const u32 arm_instruction = tcb->MemoryReadCode(arm_pc); visitor.current_instruction_size = 4; - tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir); + if (const auto arm_instruction = tcb->MemoryReadCode(arm_pc)) { + tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir); - if (const auto vfp_decoder = DecodeVFP(arm_instruction)) { - should_continue = vfp_decoder->get().call(visitor, arm_instruction); - } else if (const auto asimd_decoder = DecodeASIMD(arm_instruction)) { - should_continue = asimd_decoder->get().call(visitor, arm_instruction); - } else if (const auto decoder = DecodeArm(arm_instruction)) { - should_continue = decoder->get().call(visitor, arm_instruction); + if (const auto vfp_decoder = DecodeVFP(*arm_instruction)) { + should_continue = vfp_decoder->get().call(visitor, *arm_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(*arm_instruction)) { + should_continue = asimd_decoder->get().call(visitor, *arm_instruction); + } else if (const auto decoder = DecodeArm(*arm_instruction)) { + should_continue = decoder->get().call(visitor, *arm_instruction); + } else { + should_continue = visitor.arm_UDF(); + } } else { - should_continue = visitor.arm_UDF(); + should_continue = visitor.RaiseException(Exception::NoExecuteFault); } if (visitor.cond_state == ConditionalState::Break) { diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_callbacks.h b/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_callbacks.h index 8e0bba3ac..a9d8e0433 100755 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_callbacks.h +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_callbacks.h @@ -4,18 +4,19 @@ */ #pragma once -#include +#include +#include namespace Dynarmic::A32 { -using VAddr = u32; +using VAddr = std::uint32_t; class IREmitter; struct TranslateCallbacks { // All reads through this callback are 4-byte aligned. // Memory must be interpreted as little endian. - virtual std::uint32_t MemoryReadCode(VAddr vaddr) = 0; + virtual std::optional MemoryReadCode(VAddr vaddr) = 0; // Thus function is called before the instruction at pc is interpreted. // IR code can be emitted by the callee prior to translation of the instruction. diff --git a/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp b/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp index 9716f11f2..f2b39a6ca 100755 --- a/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -44,28 +44,40 @@ bool IsUnconditionalInstruction(bool is_thumb_16, u32 instruction) { return false; } -std::tuple ReadThumbInstruction(u32 arm_pc, TranslateCallbacks* tcb) { - u32 first_part = tcb->MemoryReadCode(arm_pc & 0xFFFFFFFC); - if ((arm_pc & 0x2) != 0) { - first_part >>= 16; - } - first_part &= 0xFFFF; +std::optional> ReadThumbInstruction(u32 arm_pc, TranslateCallbacks* tcb) { + u32 instruction; - if (IsThumb16(static_cast(first_part))) { + const std::optional first_part = tcb->MemoryReadCode(arm_pc & 0xFFFFFFFC); + if (!first_part) + return std::nullopt; + + if ((arm_pc & 0x2) != 0) { + instruction = *first_part >> 16; + } else { + instruction = *first_part & 0xFFFF; + } + + if (IsThumb16(static_cast(instruction))) { // 16-bit thumb instruction - return std::make_tuple(first_part, ThumbInstSize::Thumb16); + return std::make_tuple(instruction, ThumbInstSize::Thumb16); } // 32-bit thumb instruction // These always start with 0b11101, 0b11110 or 0b11111. - u32 second_part = tcb->MemoryReadCode((arm_pc + 2) & 0xFFFFFFFC); - if (((arm_pc + 2) & 0x2) != 0) { - second_part >>= 16; - } - second_part &= 0xFFFF; + instruction <<= 16; - return std::make_tuple(static_cast((first_part << 16) | second_part), ThumbInstSize::Thumb32); + const std::optional second_part = tcb->MemoryReadCode((arm_pc + 2) & 0xFFFFFFFC); + if (!second_part) + return std::nullopt; + + if (((arm_pc + 2) & 0x2) != 0) { + instruction |= *second_part >> 16; + } else { + instruction |= *second_part & 0xFFFF; + } + + return std::make_tuple(instruction, ThumbInstSize::Thumb32); } // Convert from thumb ASIMD format to ARM ASIMD format. @@ -97,43 +109,48 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, TranslateCallbacks* tcb, bool should_continue = true; do { const u32 arm_pc = visitor.ir.current_location.PC(); - const auto [thumb_instruction, inst_size] = ReadThumbInstruction(arm_pc, tcb); - const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16; - visitor.current_instruction_size = is_thumb_16 ? 2 : 4; + if (const auto maybe_instruction = ReadThumbInstruction(arm_pc, tcb)) { + const auto [thumb_instruction, inst_size] = *maybe_instruction; + const bool is_thumb_16 = inst_size == ThumbInstSize::Thumb16; + visitor.current_instruction_size = is_thumb_16 ? 2 : 4; - tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir); + tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir); - if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) { - if (is_thumb_16) { - if (const auto decoder = DecodeThumb16(static_cast(thumb_instruction))) { - should_continue = decoder->get().call(visitor, static_cast(thumb_instruction)); + if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) { + if (is_thumb_16) { + if (const auto decoder = DecodeThumb16(static_cast(thumb_instruction))) { + should_continue = decoder->get().call(visitor, static_cast(thumb_instruction)); + } else { + should_continue = visitor.thumb16_UDF(); + } } else { - should_continue = visitor.thumb16_UDF(); - } - } else { - if (MaybeVFPOrASIMDInstruction(thumb_instruction)) { - if (const auto vfp_decoder = DecodeVFP(thumb_instruction)) { - should_continue = vfp_decoder->get().call(visitor, thumb_instruction); - } else if (const auto asimd_decoder = DecodeASIMD(ConvertASIMDInstruction(thumb_instruction))) { - should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction)); + if (MaybeVFPOrASIMDInstruction(thumb_instruction)) { + if (const auto vfp_decoder = DecodeVFP(thumb_instruction)) { + should_continue = vfp_decoder->get().call(visitor, thumb_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(ConvertASIMDInstruction(thumb_instruction))) { + should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction)); + } else if (const auto decoder = DecodeThumb32(thumb_instruction)) { + should_continue = decoder->get().call(visitor, thumb_instruction); + } else { + should_continue = visitor.thumb32_UDF(); + } } else if (const auto decoder = DecodeThumb32(thumb_instruction)) { should_continue = decoder->get().call(visitor, thumb_instruction); } else { should_continue = visitor.thumb32_UDF(); } - } else if (const auto decoder = DecodeThumb32(thumb_instruction)) { - should_continue = decoder->get().call(visitor, thumb_instruction); - } else { - should_continue = visitor.thumb32_UDF(); } } + } else { + visitor.current_instruction_size = 2; + should_continue = visitor.RaiseException(Exception::NoExecuteFault); } if (visitor.cond_state == ConditionalState::Break) { break; } - visitor.ir.current_location = visitor.ir.current_location.AdvancePC(is_thumb_16 ? 2 : 4).AdvanceIT(); + visitor.ir.current_location = visitor.ir.current_location.AdvancePC(static_cast(visitor.current_instruction_size)).AdvanceIT(); block.CycleCount()++; } while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir) && !single_step); diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp b/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp index 84c5201a6..05996aeb6 100755 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp @@ -22,12 +22,15 @@ IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory bool should_continue = true; do { const u64 pc = visitor.ir.current_location->PC(); - const u32 instruction = memory_read_code(pc); - if (auto decoder = Decode(instruction)) { - should_continue = decoder->get().call(visitor, instruction); + if (const auto instruction = memory_read_code(pc)) { + if (auto decoder = Decode(*instruction)) { + should_continue = decoder->get().call(visitor, *instruction); + } else { + should_continue = visitor.InterpretThisInstruction(); + } } else { - should_continue = visitor.InterpretThisInstruction(); + should_continue = visitor.RaiseException(Exception::NoExecuteFault); } visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4); diff --git a/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h b/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h index 8befe5fa2..61402a2fd 100755 --- a/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h +++ b/externals/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include @@ -18,7 +19,7 @@ namespace A64 { class LocationDescriptor; -using MemoryReadCodeFuncType = std::function; +using MemoryReadCodeFuncType = std::function(u64 vaddr)>; struct TranslationOptions { /// This changes what IR we emit when we translate an unpredictable instruction. diff --git a/externals/dynarmic/src/dynarmic/interface/A32/config.h b/externals/dynarmic/src/dynarmic/interface/A32/config.h index 55eed1133..ef13b0e07 100755 --- a/externals/dynarmic/src/dynarmic/interface/A32/config.h +++ b/externals/dynarmic/src/dynarmic/interface/A32/config.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "dynarmic/frontend/A32/translate/translate_callbacks.h" #include "dynarmic/interface/A32/arch_version.h" @@ -51,6 +52,9 @@ enum class Exception { PreloadDataWithIntentToWrite, /// A PLI instruction was executed. (Hint instruction.) PreloadInstruction, + /// Attempted to execute a code block at an address for which MemoryReadCode returned std::nullopt. + /// (Intended to be used to emulate memory protection faults.) + NoExecuteFault, }; /// These function pointers may be inserted into compiled code. @@ -59,7 +63,7 @@ struct UserCallbacks : public TranslateCallbacks { // All reads through this callback are 4-byte aligned. // Memory must be interpreted as little endian. - std::uint32_t MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); } + std::optional MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); } // Thus function is called before the instruction at pc is interpreted. // IR code can be emitted by the callee prior to translation of the instruction. diff --git a/externals/dynarmic/src/dynarmic/interface/A64/config.h b/externals/dynarmic/src/dynarmic/interface/A64/config.h index f8ba8f498..35b6b1ad4 100755 --- a/externals/dynarmic/src/dynarmic/interface/A64/config.h +++ b/externals/dynarmic/src/dynarmic/interface/A64/config.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "dynarmic/interface/optimization_flags.h" @@ -45,6 +46,9 @@ enum class Exception { Yield, /// A BRK instruction was executed. (Hint instruction.) Breakpoint, + /// Attempted to execute a code block at an address for which MemoryReadCode returned std::nullopt. + /// (Intended to be used to emulate memory protection faults.) + NoExecuteFault, }; enum class DataCacheOperation { @@ -82,7 +86,7 @@ struct UserCallbacks { // All reads through this callback are 4-byte aligned. // Memory must be interpreted as little endian. - virtual std::uint32_t MemoryReadCode(VAddr vaddr) { return MemoryRead32(vaddr); } + virtual std::optional MemoryReadCode(VAddr vaddr) { return MemoryRead32(vaddr); } // Reads through these callbacks may not be aligned. virtual std::uint8_t MemoryRead8(VAddr vaddr) = 0; diff --git a/externals/dynarmic/src/dynarmic/ir/opt/a64_merge_interpret_blocks.cpp b/externals/dynarmic/src/dynarmic/ir/opt/a64_merge_interpret_blocks.cpp index d9b2558d8..00a0e1b67 100755 --- a/externals/dynarmic/src/dynarmic/ir/opt/a64_merge_interpret_blocks.cpp +++ b/externals/dynarmic/src/dynarmic/ir/opt/a64_merge_interpret_blocks.cpp @@ -16,10 +16,12 @@ namespace Dynarmic::Optimization { void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb) { const auto is_interpret_instruction = [cb](A64::LocationDescriptor location) { - const u32 instruction = cb->MemoryReadCode(location.PC()); + const auto instruction = cb->MemoryReadCode(location.PC()); + if (!instruction) + return false; IR::Block new_block{location}; - A64::TranslateSingleInstruction(new_block, location, instruction); + A64::TranslateSingleInstruction(new_block, location, *instruction); if (!new_block.Instructions().empty()) return false; diff --git a/externals/dynarmic/tests/A32/testenv.h b/externals/dynarmic/tests/A32/testenv.h index ac7921ec7..bc6775ac1 100755 --- a/externals/dynarmic/tests/A32/testenv.h +++ b/externals/dynarmic/tests/A32/testenv.h @@ -48,7 +48,7 @@ public: return vaddr < sizeof(InstructionType) * code_mem.size(); } - std::uint32_t MemoryReadCode(u32 vaddr) override { + std::optional MemoryReadCode(u32 vaddr) override { if (IsInCodeMem(vaddr)) { u32 value; std::memcpy(&value, &code_mem[vaddr / sizeof(InstructionType)], sizeof(u32)); @@ -95,11 +95,11 @@ public: MemoryWrite32(vaddr + 4, static_cast(value >> 32)); } - void InterpreterFallback(u32 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:08x}, {}) code = {:08x}", pc, num_instructions, MemoryReadCode(pc)); } + void InterpreterFallback(u32 pc, size_t num_instructions) override { ASSERT_MSG(false, "InterpreterFallback({:08x}, {}) code = {:08x}", pc, num_instructions, *MemoryReadCode(pc)); } void CallSVC(std::uint32_t swi) override { ASSERT_MSG(false, "CallSVC({})", swi); } - void ExceptionRaised(u32 pc, Dynarmic::A32::Exception /*exception*/) override { ASSERT_MSG(false, "ExceptionRaised({:08x}) code = {:08x}", pc, MemoryReadCode(pc)); } + void ExceptionRaised(u32 pc, Dynarmic::A32::Exception /*exception*/) override { ASSERT_MSG(false, "ExceptionRaised({:08x}) code = {:08x}", pc, *MemoryReadCode(pc)); } void AddTicks(std::uint64_t ticks) override { if (ticks > ticks_left) { @@ -135,7 +135,7 @@ public: memcpy(backing_memory + vaddr, &value, sizeof(T)); } - std::uint32_t MemoryReadCode(std::uint32_t vaddr) override { + std::optional MemoryReadCode(std::uint32_t vaddr) override { return read(vaddr); } diff --git a/externals/dynarmic/tests/A64/testenv.h b/externals/dynarmic/tests/A64/testenv.h index 596d01142..73525242c 100755 --- a/externals/dynarmic/tests/A64/testenv.h +++ b/externals/dynarmic/tests/A64/testenv.h @@ -30,7 +30,7 @@ public: return vaddr >= code_mem_start_address && vaddr < code_mem_start_address + code_mem.size() * 4; } - std::uint32_t MemoryReadCode(u64 vaddr) override { + std::optional MemoryReadCode(u64 vaddr) override { if (!IsInCodeMem(vaddr)) { return 0x14000000; // B . } @@ -145,7 +145,7 @@ public: memcpy(backing_memory + vaddr, &value, sizeof(T)); } - std::uint32_t MemoryReadCode(u64 vaddr) override { + std::optional MemoryReadCode(u64 vaddr) override { return read(vaddr); } diff --git a/externals/dynarmic/tests/print_info.cpp b/externals/dynarmic/tests/print_info.cpp index d7978fd80..ac07e3ca5 100755 --- a/externals/dynarmic/tests/print_info.cpp +++ b/externals/dynarmic/tests/print_info.cpp @@ -157,7 +157,7 @@ public: } void InterpreterFallback(u32 pc, size_t num_instructions) override { - fmt::print("> InterpreterFallback({:08x}, {}) code = {:08x}\n", pc, num_instructions, MemoryReadCode(pc)); + fmt::print("> InterpreterFallback({:08x}, {}) code = {:08x}\n", pc, num_instructions, *MemoryReadCode(pc)); } void CallSVC(std::uint32_t swi) override { fmt::print("> CallSVC({})\n", swi); diff --git a/externals/dynarmic/tests/unicorn_emu/a32_unicorn.cpp b/externals/dynarmic/tests/unicorn_emu/a32_unicorn.cpp index f3ffa0daf..ed8be3d19 100755 --- a/externals/dynarmic/tests/unicorn_emu/a32_unicorn.cpp +++ b/externals/dynarmic/tests/unicorn_emu/a32_unicorn.cpp @@ -52,7 +52,7 @@ void A32Unicorn::Run() { return; } if (auto cerr_ = uc_emu_start(uc, pc, END_ADDRESS, 0, 1)) { - fmt::print("uc_emu_start failed @ {:08x} (code = {:08x}) with error {} ({})", pc, testenv.MemoryReadCode(pc), cerr_, uc_strerror(cerr_)); + fmt::print("uc_emu_start failed @ {:08x} (code = {:08x}) with error {} ({})", pc, *testenv.MemoryReadCode(pc), cerr_, uc_strerror(cerr_)); throw "A32Unicorn::Run() failure"; } testenv.ticks_left--; diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 6425e131f..0efc3732f 100755 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -95,7 +95,7 @@ void ARM_Interface::Run() { using Kernel::SuspendType; while (true) { - Kernel::KThread* current_thread{system.Kernel().CurrentScheduler()->GetCurrentThread()}; + Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())}; Dynarmic::HaltReason hr{}; // Notify the debugger and go to sleep if a step was performed @@ -119,16 +119,23 @@ void ARM_Interface::Run() { } system.ExitDynarmicProfile(); - // Notify the debugger and go to sleep if a breakpoint was hit. - if (Has(hr, breakpoint)) { + // Notify the debugger and go to sleep if a breakpoint was hit, + // or if the thread is unable to continue for any reason. + if (Has(hr, breakpoint) || Has(hr, no_execute)) { RewindBreakpointInstruction(); - system.GetDebugger().NotifyThreadStopped(current_thread); - current_thread->RequestSuspend(SuspendType::Debug); + if (system.DebuggerEnabled()) { + system.GetDebugger().NotifyThreadStopped(current_thread); + } + current_thread->RequestSuspend(Kernel::SuspendType::Debug); break; } + + // Notify the debugger and go to sleep if a watchpoint was hit. if (Has(hr, watchpoint)) { RewindBreakpointInstruction(); - system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint()); + if (system.DebuggerEnabled()) { + system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint()); + } current_thread->RequestSuspend(SuspendType::Debug); break; } diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 4e431e27a..8a066ed91 100755 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -204,6 +204,7 @@ public: static constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3; static constexpr Dynarmic::HaltReason breakpoint = Dynarmic::HaltReason::UserDefined4; static constexpr Dynarmic::HaltReason watchpoint = Dynarmic::HaltReason::UserDefined5; + static constexpr Dynarmic::HaltReason no_execute = Dynarmic::HaltReason::UserDefined6; protected: /// System context that this ARM interface is running under. diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 4f3e0a9f8..9e31ff652 100755 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -48,6 +48,12 @@ public: CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); return memory.Read64(vaddr); } + std::optional MemoryReadCode(u32 vaddr) override { + if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { + return std::nullopt; + } + return MemoryRead32(vaddr); + } void MemoryWrite8(u32 vaddr, u8 value) override { if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { @@ -89,21 +95,28 @@ public: void InterpreterFallback(u32 pc, std::size_t num_instructions) override { parent.LogBacktrace(); - UNIMPLEMENTED_MSG("This should never happen, pc = {:08X}, code = {:08X}", pc, - MemoryReadCode(pc)); + LOG_ERROR(Core_ARM, + "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, + num_instructions, MemoryRead32(pc)); } void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { - if (debugger_enabled) { - parent.SaveContext(parent.breakpoint_context); - parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); + switch (exception) { + case Dynarmic::A32::Exception::NoExecuteFault: + LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc); + ReturnException(pc, ARM_Interface::no_execute); return; - } + default: + if (debugger_enabled) { + ReturnException(pc, ARM_Interface::breakpoint); + return; + } - parent.LogBacktrace(); - LOG_CRITICAL(Core_ARM, - "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", - exception, pc, MemoryReadCode(pc), parent.IsInThumbMode()); + parent.LogBacktrace(); + LOG_CRITICAL(Core_ARM, + "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", + exception, pc, MemoryRead32(pc), parent.IsInThumbMode()); + } } void CallSVC(u32 swi) override { @@ -148,15 +161,20 @@ public: const auto match{parent.MatchingWatchpoint(addr, size, type)}; if (match) { - parent.SaveContext(parent.breakpoint_context); - parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); parent.halted_watchpoint = match; + ReturnException(parent.jit.load()->Regs()[15], ARM_Interface::watchpoint); return false; } return true; } + void ReturnException(u32 pc, Dynarmic::HaltReason hr) { + parent.SaveContext(parent.breakpoint_context); + parent.breakpoint_context.cpu_registers[15] = pc; + parent.jit.load()->HaltExecution(hr); + } + ARM_Dynarmic_32& parent; Core::Memory::Memory& memory; std::size_t num_interpreted_instructions{}; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 8f3806648..680aa24e9 100755 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -52,6 +52,12 @@ public: CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; } + std::optional MemoryReadCode(u64 vaddr) override { + if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { + return std::nullopt; + } + return MemoryRead32(vaddr); + } void MemoryWrite8(u64 vaddr, u8 value) override { if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { @@ -105,7 +111,7 @@ public: parent.LogBacktrace(); LOG_ERROR(Core_ARM, "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, - num_instructions, MemoryReadCode(pc)); + num_instructions, MemoryRead32(pc)); } void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, @@ -138,16 +144,19 @@ public: case Dynarmic::A64::Exception::SendEventLocal: case Dynarmic::A64::Exception::Yield: return; + case Dynarmic::A64::Exception::NoExecuteFault: + LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc); + ReturnException(pc, ARM_Interface::no_execute); + return; default: if (debugger_enabled) { - parent.SaveContext(parent.breakpoint_context); - parent.jit.load()->HaltExecution(ARM_Interface::breakpoint); + ReturnException(pc, ARM_Interface::breakpoint); return; } parent.LogBacktrace(); - ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", - static_cast(exception), pc, MemoryReadCode(pc)); + LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", + static_cast(exception), pc, MemoryRead32(pc)); } } @@ -195,15 +204,20 @@ public: const auto match{parent.MatchingWatchpoint(addr, size, type)}; if (match) { - parent.SaveContext(parent.breakpoint_context); - parent.jit.load()->HaltExecution(ARM_Interface::watchpoint); parent.halted_watchpoint = match; + ReturnException(parent.jit.load()->GetPC(), ARM_Interface::watchpoint); return false; } return true; } + void ReturnException(u64 pc, Dynarmic::HaltReason hr) { + parent.SaveContext(parent.breakpoint_context); + parent.breakpoint_context.pc = pc; + parent.jit.load()->HaltExecution(hr); + } + ARM_Dynarmic_64& parent; Core::Memory::Memory& memory; u64 tpidrro_el0 = 0; diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index d69b2602a..fd6928105 100755 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -95,7 +95,7 @@ void* CpuManager::GetStartFuncParameter() { void CpuManager::MultiCoreRunGuestThread() { auto& kernel = system.Kernel(); kernel.CurrentScheduler()->OnThreadStart(); - auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); + auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); auto& host_context = thread->GetHostContext(); host_context->SetRewindPoint(GuestRewindFunction, this); MultiCoreRunGuestLoop(); @@ -132,7 +132,7 @@ void CpuManager::MultiCoreRunIdleThread() { void CpuManager::SingleCoreRunGuestThread() { auto& kernel = system.Kernel(); kernel.CurrentScheduler()->OnThreadStart(); - auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); + auto* thread = kernel.CurrentScheduler()->GetSchedulerCurrentThread(); auto& host_context = thread->GetHostContext(); host_context->SetRewindPoint(GuestRewindFunction, this); SingleCoreRunGuestLoop(); @@ -172,7 +172,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { { auto& kernel = system.Kernel(); auto& scheduler = kernel.Scheduler(current_core); - Kernel::KThread* current_thread = scheduler.GetCurrentThread(); + Kernel::KThread* current_thread = scheduler.GetSchedulerCurrentThread(); if (idle_count >= 4 || from_running_enviroment) { if (!from_running_enviroment) { system.CoreTiming().Idle(); @@ -184,7 +184,7 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { } current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); system.CoreTiming().ResetTicks(); - scheduler.Unload(scheduler.GetCurrentThread()); + scheduler.Unload(scheduler.GetSchedulerCurrentThread()); auto& next_scheduler = kernel.Scheduler(current_core); Common::Fiber::YieldTo(current_thread->GetHostContext(), *next_scheduler.ControlContext()); @@ -193,10 +193,8 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { // May have changed scheduler { auto& scheduler = system.Kernel().Scheduler(current_core); - scheduler.Reload(scheduler.GetCurrentThread()); - if (!scheduler.IsIdle()) { - idle_count = 0; - } + scheduler.Reload(scheduler.GetSchedulerCurrentThread()); + idle_count = 0; } } @@ -237,7 +235,8 @@ void CpuManager::RunThread(std::size_t core) { system.GPU().ObtainContext(); } - auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); + auto* current_thread = system.Kernel().CurrentScheduler()->GetIdleThread(); + Kernel::SetCurrentThread(system.Kernel(), current_thread); Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); } diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 9f76f9bcb..e49223016 100755 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -272,6 +272,7 @@ enum class VibrationDeviceType : u32 { Unknown = 0, LinearResonantActuator = 1, GcErm = 2, + N64 = 3, }; // This is nn::hid::VibrationGcErmCommand diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 04cf86d52..5fa67bae1 100755 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp @@ -234,7 +234,7 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement, s64 timeout) { // Prepare to wait. - KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* cur_thread = GetCurrentThreadPointer(kernel); ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree)); { @@ -287,7 +287,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { // Prepare to wait. - KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* cur_thread = GetCurrentThreadPointer(kernel); ThreadQueueImplForKAddressArbiter wait_queue(kernel, std::addressof(thread_tree)); { diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index 43bcd253d..a8b5411e3 100755 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp @@ -106,7 +106,7 @@ KConditionVariable::KConditionVariable(Core::System& system_) KConditionVariable::~KConditionVariable() = default; ResultCode KConditionVariable::SignalToAddress(VAddr addr) { - KThread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* owner_thread = GetCurrentThreadPointer(kernel); // Signal the address. { @@ -147,7 +147,7 @@ ResultCode KConditionVariable::SignalToAddress(VAddr addr) { } ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) { - KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread(); + KThread* cur_thread = GetCurrentThreadPointer(kernel); ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel); // Wait for the address. diff --git a/src/core/hle/kernel/k_interrupt_manager.cpp b/src/core/hle/kernel/k_interrupt_manager.cpp index cf9ed80d0..d606a7f86 100755 --- a/src/core/hle/kernel/k_interrupt_manager.cpp +++ b/src/core/hle/kernel/k_interrupt_manager.cpp @@ -15,8 +15,7 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) { return; } - auto& scheduler = kernel.Scheduler(core_id); - auto& current_thread = *scheduler.GetCurrentThread(); + auto& current_thread = GetCurrentThread(kernel); // If the user disable count is set, we may need to pin the current thread. if (current_thread.GetUserDisableCount() && !process->GetPinnedThread(core_id)) { @@ -26,7 +25,7 @@ void HandleInterrupt(KernelCore& kernel, s32 core_id) { process->PinCurrentThread(core_id); // Set the interrupt flag for the thread. - scheduler.GetCurrentThread()->SetInterruptFlag(); + GetCurrentThread(kernel).SetInterruptFlag(); } } diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index cb84c20e3..b477c6e55 100755 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -176,7 +176,8 @@ void KProcess::PinCurrentThread(s32 core_id) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Get the current thread. - KThread* cur_thread = kernel.Scheduler(static_cast(core_id)).GetCurrentThread(); + KThread* cur_thread = + kernel.Scheduler(static_cast(core_id)).GetSchedulerCurrentThread(); // If the thread isn't terminated, pin it. if (!cur_thread->IsTerminationRequested()) { @@ -193,7 +194,8 @@ void KProcess::UnpinCurrentThread(s32 core_id) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Get the current thread. - KThread* cur_thread = kernel.Scheduler(static_cast(core_id)).GetCurrentThread(); + KThread* cur_thread = + kernel.Scheduler(static_cast(core_id)).GetSchedulerCurrentThread(); // Unpin it. cur_thread->Unpin(); @@ -420,11 +422,11 @@ void KProcess::PrepareForTermination() { ChangeStatus(ProcessStatus::Exiting); const auto stop_threads = [this](const std::vector& in_thread_list) { - for (auto& thread : in_thread_list) { + for (auto* thread : in_thread_list) { if (thread->GetOwnerProcess() != this) continue; - if (thread == kernel.CurrentScheduler()->GetCurrentThread()) + if (thread == GetCurrentThreadPointer(kernel)) continue; // TODO(Subv): When are the other running/ready threads terminated? diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index fb3b84f3d..d586b3f5c 100755 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -317,7 +317,7 @@ void KScheduler::RotateScheduledQueue(s32 cpu_core_id, s32 priority) { { KThread* best_thread = priority_queue.GetScheduledFront(cpu_core_id); - if (best_thread == GetCurrentThread()) { + if (best_thread == GetCurrentThreadPointer(kernel)) { best_thread = priority_queue.GetScheduledNext(cpu_core_id, best_thread); } @@ -424,7 +424,7 @@ void KScheduler::YieldWithoutCoreMigration(KernelCore& kernel) { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = Kernel::GetCurrentThread(kernel); + KThread& cur_thread = GetCurrentThread(kernel); KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -463,7 +463,7 @@ void KScheduler::YieldWithCoreMigration(KernelCore& kernel) { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = Kernel::GetCurrentThread(kernel); + KThread& cur_thread = GetCurrentThread(kernel); KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -551,7 +551,7 @@ void KScheduler::YieldToAnyThread(KernelCore& kernel) { ASSERT(kernel.CurrentProcess() != nullptr); // Get the current thread and process. - KThread& cur_thread = Kernel::GetCurrentThread(kernel); + KThread& cur_thread = GetCurrentThread(kernel); KProcess& cur_process = *kernel.CurrentProcess(); // If the thread's yield count matches, there's nothing for us to do. @@ -642,7 +642,7 @@ KScheduler::~KScheduler() { ASSERT(!idle_thread); } -KThread* KScheduler::GetCurrentThread() const { +KThread* KScheduler::GetSchedulerCurrentThread() const { if (auto result = current_thread.load(); result) { return result; } @@ -654,7 +654,7 @@ u64 KScheduler::GetLastContextSwitchTicks() const { } void KScheduler::RescheduleCurrentCore() { - ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1); + ASSERT(GetCurrentThread(system.Kernel()).GetDisableDispatchCount() == 1); auto& phys_core = system.Kernel().PhysicalCore(core_id); if (phys_core.IsInterrupted()) { @@ -665,7 +665,7 @@ void KScheduler::RescheduleCurrentCore() { if (state.needs_scheduling.load()) { Schedule(); } else { - GetCurrentThread()->EnableDispatch(); + GetCurrentThread(system.Kernel()).EnableDispatch(); guard.Unlock(); } } @@ -718,13 +718,18 @@ void KScheduler::Reload(KThread* thread) { void KScheduler::SwitchContextStep2() { // Load context of new thread - Reload(GetCurrentThread()); + Reload(GetCurrentThreadPointer(system.Kernel())); RescheduleCurrentCore(); } +void KScheduler::Schedule() { + ASSERT(GetCurrentThread(system.Kernel()).GetDisableDispatchCount() == 1); + this->ScheduleImpl(); +} + void KScheduler::ScheduleImpl() { - KThread* previous_thread = GetCurrentThread(); + KThread* previous_thread = GetCurrentThreadPointer(system.Kernel()); KThread* next_thread = state.highest_priority_thread; state.needs_scheduling.store(false); @@ -762,6 +767,7 @@ void KScheduler::ScheduleImpl() { old_context = &previous_thread->GetHostContext(); // Set the new thread. + SetCurrentThread(system.Kernel(), next_thread); current_thread.store(next_thread); guard.Unlock(); @@ -805,6 +811,7 @@ void KScheduler::SwitchToCurrent() { } } auto thread = next_thread ? next_thread : idle_thread; + SetCurrentThread(system.Kernel(), thread); Common::Fiber::YieldTo(switch_fiber, *thread->GetHostContext()); } while (!is_switch_pending()); } diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 729e006f2..3f90656ee 100755 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -48,18 +48,13 @@ public: void Reload(KThread* thread); /// Gets the current running thread - [[nodiscard]] KThread* GetCurrentThread() const; + [[nodiscard]] KThread* GetSchedulerCurrentThread() const; /// Gets the idle thread [[nodiscard]] KThread* GetIdleThread() const { return idle_thread; } - /// Returns true if the scheduler is idle - [[nodiscard]] bool IsIdle() const { - return GetCurrentThread() == idle_thread; - } - /// Gets the timestamp for the last context switch in ticks. [[nodiscard]] u64 GetLastContextSwitchTicks() const; @@ -149,10 +144,7 @@ private: void RotateScheduledQueue(s32 cpu_core_id, s32 priority); - void Schedule() { - ASSERT(GetCurrentThread()->GetDisableDispatchCount() == 1); - this->ScheduleImpl(); - } + void Schedule(); /// Switches the CPU's active thread context to that of the specified thread void ScheduleImpl(); diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index c0a091bb6..fa5352847 100755 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -382,7 +382,7 @@ void KThread::FinishTermination() { for (std::size_t i = 0; i < static_cast(Core::Hardware::NUM_CPU_CORES); ++i) { KThread* core_thread{}; do { - core_thread = kernel.Scheduler(i).GetCurrentThread(); + core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread(); } while (core_thread == this); } } @@ -631,7 +631,7 @@ ResultCode KThread::SetCoreMask(s32 core_id_, u64 v_affinity_mask) { s32 thread_core; for (thread_core = 0; thread_core < static_cast(Core::Hardware::NUM_CPU_CORES); ++thread_core) { - if (kernel.Scheduler(thread_core).GetCurrentThread() == this) { + if (kernel.Scheduler(thread_core).GetSchedulerCurrentThread() == this) { thread_is_current = true; break; } @@ -756,7 +756,7 @@ void KThread::WaitUntilSuspended() { for (std::size_t i = 0; i < static_cast(Core::Hardware::NUM_CPU_CORES); ++i) { KThread* core_thread{}; do { - core_thread = kernel.Scheduler(i).GetCurrentThread(); + core_thread = kernel.Scheduler(i).GetSchedulerCurrentThread(); } while (core_thread == this); } } @@ -822,7 +822,7 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { // Check if the thread is currently running. // If it is, we'll need to retry. for (auto i = 0; i < static_cast(Core::Hardware::NUM_CPU_CORES); ++i) { - if (kernel.Scheduler(i).GetCurrentThread() == this) { + if (kernel.Scheduler(i).GetSchedulerCurrentThread() == this) { thread_is_current = true; break; } @@ -1175,6 +1175,10 @@ std::shared_ptr& KThread::GetHostContext() { return host_context; } +void SetCurrentThread(KernelCore& kernel, KThread* thread) { + kernel.SetCurrentEmuThread(thread); +} + KThread* GetCurrentThreadPointer(KernelCore& kernel) { return kernel.GetCurrentEmuThread(); } diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 8c1f8a344..c6ca37f56 100755 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -106,6 +106,7 @@ enum class StepState : u32 { StepPerformed, ///< Thread has stepped, waiting to be scheduled again }; +void SetCurrentThread(KernelCore& kernel, KThread* thread); [[nodiscard]] KThread* GetCurrentThreadPointer(KernelCore& kernel); [[nodiscard]] KThread& GetCurrentThread(KernelCore& kernel); [[nodiscard]] s32 GetCurrentCoreId(KernelCore& kernel); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 94953e257..0009193be 100755 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -331,6 +331,8 @@ struct KernelCore::Impl { return is_shutting_down.load(std::memory_order_relaxed); } + static inline thread_local KThread* current_thread{nullptr}; + KThread* GetCurrentEmuThread() { // If we are shutting down the kernel, none of this is relevant anymore. if (IsShuttingDown()) { @@ -341,7 +343,12 @@ struct KernelCore::Impl { if (thread_id >= Core::Hardware::NUM_CPU_CORES) { return GetHostDummyThread(); } - return schedulers[thread_id]->GetCurrentThread(); + + return current_thread; + } + + void SetCurrentEmuThread(KThread* thread) { + current_thread = thread; } void DeriveInitialMemoryLayout() { @@ -1024,6 +1031,10 @@ KThread* KernelCore::GetCurrentEmuThread() const { return impl->GetCurrentEmuThread(); } +void KernelCore::SetCurrentEmuThread(KThread* thread) { + impl->SetCurrentEmuThread(thread); +} + KMemoryManager& KernelCore::MemoryManager() { return *impl->memory_manager; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 4e7beab0e..aa0ebaa02 100755 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -226,6 +226,9 @@ public: /// Gets the current host_thread/guest_thread pointer. KThread* GetCurrentEmuThread() const; + /// Sets the current guest_thread pointer. + void SetCurrentEmuThread(KThread* thread); + /// Gets the current host_thread handle. u32 GetCurrentHostThreadID() const; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 2ff6d5fa6..2b34fc19d 100755 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -327,7 +327,6 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); - auto thread = kernel.CurrentScheduler()->GetCurrentThread(); { KScopedSchedulerLock lock(kernel); @@ -337,7 +336,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { session->SendSyncRequest(&GetCurrentThread(kernel), system.Memory(), system.CoreTiming()); } - return thread->GetWaitResult(); + return GetCurrentThread(kernel).GetWaitResult(); } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { @@ -624,7 +623,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { handle_debug_buffer(info1, info2); - auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); + auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); const auto thread_processor_id = current_thread->GetActiveCore(); system.ArmInterface(static_cast(thread_processor_id)).LogBacktrace(); } @@ -884,7 +883,7 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle const auto& core_timing = system.CoreTiming(); const auto& scheduler = *system.Kernel().CurrentScheduler(); - const auto* const current_thread = scheduler.GetCurrentThread(); + const auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); const bool same_thread = current_thread == thread.GetPointerUnsafe(); const u64 prev_ctx_ticks = scheduler.GetLastContextSwitchTicks(); @@ -1103,7 +1102,7 @@ static ResultCode GetThreadContext(Core::System& system, VAddr out_context, Hand if (thread->GetRawState() != ThreadState::Runnable) { bool current = false; for (auto i = 0; i < static_cast(Core::Hardware::NUM_CPU_CORES); ++i) { - if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetCurrentThread()) { + if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetSchedulerCurrentThread()) { current = true; break; } @@ -1851,7 +1850,7 @@ static ResultCode StartThread32(Core::System& system, Handle thread_handle) { static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); - auto* const current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); + auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); system.GlobalSchedulerContext().RemoveThread(current_thread); current_thread->Exit(); system.Kernel().UnregisterInUseObject(current_thread); @@ -2993,7 +2992,7 @@ void Call(Core::System& system, u32 immediate) { auto& kernel = system.Kernel(); kernel.EnterSVCProfile(); - auto* thread = kernel.CurrentScheduler()->GetCurrentThread(); + auto* thread = GetCurrentThreadPointer(kernel); thread->SetIsCallingSvc(); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index ac5c38cc6..cc8fd7837 100755 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -49,28 +49,42 @@ bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { } } -bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) { +ResultCode Controller_NPad::IsDeviceHandleValid( + const Core::HID::VibrationDeviceHandle& device_handle) { const auto npad_id = IsNpadIdValid(static_cast(device_handle.npad_id)); const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; - return npad_id && npad_type && device_index; + + if (npad_type) { + return VibrationInvalidStyleIndex; + } + if (npad_id) { + return VibrationInvalidNpadId; + } + if (device_index) { + return VibrationDeviceIndexOutOfRange; + } + + return ResultSuccess; } ResultCode Controller_NPad::VerifyValidSixAxisSensorHandle( const Core::HID::SixAxisSensorHandle& device_handle) { const auto npad_id = IsNpadIdValid(static_cast(device_handle.npad_id)); + const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; + const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; + if (!npad_id) { return InvalidNpadId; } - const bool device_index = device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; if (!device_index) { return NpadDeviceIndexOutOfRange; } // This doesn't get validated on nnsdk - const bool npad_type = device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType; if (!npad_type) { return NpadInvalidHandle; } + return ResultSuccess; } @@ -705,6 +719,12 @@ Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const { } void Controller_NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode) { + if (activation_mode != NpadHandheldActivationMode::None && + activation_mode != NpadHandheldActivationMode::Single) { + ASSERT_MSG(false, "Activation mode should be always None or Single"); + return; + } + handheld_activation_mode = activation_mode; } @@ -840,7 +860,7 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, void Controller_NPad::VibrateController( const Core::HID::VibrationDeviceHandle& vibration_device_handle, const Core::HID::VibrationValue& vibration_value) { - if (!IsDeviceHandleValid(vibration_device_handle)) { + if (IsDeviceHandleValid(vibration_device_handle).IsError()) { return; } @@ -903,7 +923,7 @@ void Controller_NPad::VibrateControllers( Core::HID::VibrationValue Controller_NPad::GetLastVibration( const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { - if (!IsDeviceHandleValid(vibration_device_handle)) { + if (IsDeviceHandleValid(vibration_device_handle).IsError()) { return {}; } @@ -914,7 +934,7 @@ Core::HID::VibrationValue Controller_NPad::GetLastVibration( void Controller_NPad::InitializeVibrationDevice( const Core::HID::VibrationDeviceHandle& vibration_device_handle) { - if (!IsDeviceHandleValid(vibration_device_handle)) { + if (IsDeviceHandleValid(vibration_device_handle).IsError()) { return; } @@ -941,7 +961,7 @@ void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { bool Controller_NPad::IsVibrationDeviceMounted( const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { - if (!IsDeviceHandleValid(vibration_device_handle)) { + if (IsDeviceHandleValid(vibration_device_handle).IsError()) { return false; } diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 0b662b7f8..6f3991803 100755 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -197,7 +197,7 @@ public: Core::HID::NpadButton GetAndResetPressState(); static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); - static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); + static ResultCode IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); static ResultCode VerifyValidSixAxisSensorHandle( const Core::HID::SixAxisSensorHandle& device_handle); diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h index 6c8ad04af..823dac2d5 100755 --- a/src/core/hle/service/hid/errors.h +++ b/src/core/hle/service/hid/errors.h @@ -9,6 +9,9 @@ namespace Service::HID { constexpr ResultCode NpadInvalidHandle{ErrorModule::HID, 100}; constexpr ResultCode NpadDeviceIndexOutOfRange{ErrorModule::HID, 107}; +constexpr ResultCode VibrationInvalidStyleIndex{ErrorModule::HID, 122}; +constexpr ResultCode VibrationInvalidNpadId{ErrorModule::HID, 123}; +constexpr ResultCode VibrationDeviceIndexOutOfRange{ErrorModule::HID, 124}; constexpr ResultCode InvalidSixAxisFusionRange{ErrorModule::HID, 423}; constexpr ResultCode NpadIsDualJoycon{ErrorModule::HID, 601}; constexpr ResultCode NpadIsSameType{ErrorModule::HID, 602}; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index dc5d0366d..78efffc50 100755 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -778,7 +778,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { bool is_at_rest{}; auto& controller = GetAppletResource()->GetController(HidController::NPad); - const auto result = controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest); + controller.IsSixAxisSensorAtRest(parameters.sixaxis_handle, is_at_rest); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -786,7 +786,7 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); + rb.Push(ResultSuccess); rb.Push(is_at_rest); } @@ -803,8 +803,8 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c bool is_firmware_available{}; auto& controller = GetAppletResource()->GetController(HidController::NPad); - const auto result = controller.IsFirmwareUpdateAvailableForSixAxisSensor( - parameters.sixaxis_handle, is_firmware_available); + controller.IsFirmwareUpdateAvailableForSixAxisSensor(parameters.sixaxis_handle, + is_firmware_available); LOG_WARNING( Service_HID, @@ -813,7 +813,7 @@ void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& c parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(result); + rb.Push(ResultSuccess); rb.Push(is_firmware_available); } @@ -1083,13 +1083,13 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; auto& controller = GetAppletResource()->GetController(HidController::NPad); - const auto result = controller.DisconnectNpad(parameters.npad_id); + controller.DisconnectNpad(parameters.npad_id); LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + rb.Push(ResultSuccess); } void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { @@ -1165,15 +1165,14 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx const auto parameters{rp.PopRaw()}; auto& controller = GetAppletResource()->GetController(HidController::NPad); - const auto result = - controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, - Controller_NPad::NpadJoyAssignmentMode::Single); + controller.SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyDeviceType::Left, + Controller_NPad::NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + rb.Push(ResultSuccess); } void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { @@ -1189,15 +1188,15 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; auto& controller = GetAppletResource()->GetController(HidController::NPad); - const auto result = controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, - Controller_NPad::NpadJoyAssignmentMode::Single); + controller.SetNpadMode(parameters.npad_id, parameters.npad_joy_device_type, + Controller_NPad::NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", parameters.npad_id, parameters.applet_resource_user_id, parameters.npad_joy_device_type); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + rb.Push(ResultSuccess); } void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { @@ -1212,14 +1211,13 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; auto& controller = GetAppletResource()->GetController(HidController::NPad); - const auto result = controller.SetNpadMode(parameters.npad_id, {}, - Controller_NPad::NpadJoyAssignmentMode::Dual); + controller.SetNpadMode(parameters.npad_id, {}, Controller_NPad::NpadJoyAssignmentMode::Dual); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); + rb.Push(ResultSuccess); } void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { @@ -1412,8 +1410,11 @@ void Hid::ClearNpadCaptureButtonAssignment(Kernel::HLERequestContext& ctx) { void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto vibration_device_handle{rp.PopRaw()}; + const auto& controller = + GetAppletResource()->GetController(HidController::NPad); Core::HID::VibrationDeviceInfo vibration_device_info; + bool check_device_index = false; switch (vibration_device_handle.npad_type) { case Core::HID::NpadStyleIndex::ProController: @@ -1421,34 +1422,46 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { case Core::HID::NpadStyleIndex::JoyconDual: case Core::HID::NpadStyleIndex::JoyconLeft: case Core::HID::NpadStyleIndex::JoyconRight: - default: vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; + check_device_index = true; break; case Core::HID::NpadStyleIndex::GameCube: vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; break; - case Core::HID::NpadStyleIndex::Pokeball: + case Core::HID::NpadStyleIndex::N64: + vibration_device_info.type = Core::HID::VibrationDeviceType::N64; + break; + default: vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; break; } - switch (vibration_device_handle.device_index) { - case Core::HID::DeviceIndex::Left: - vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; - break; - case Core::HID::DeviceIndex::Right: - vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; - break; - case Core::HID::DeviceIndex::None: - default: - ASSERT_MSG(false, "DeviceIndex should never be None!"); - vibration_device_info.position = Core::HID::VibrationDevicePosition::None; - break; + vibration_device_info.position = Core::HID::VibrationDevicePosition::None; + if (check_device_index) { + switch (vibration_device_handle.device_index) { + case Core::HID::DeviceIndex::Left: + vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; + break; + case Core::HID::DeviceIndex::Right: + vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; + break; + case Core::HID::DeviceIndex::None: + default: + ASSERT_MSG(false, "DeviceIndex should never be None!"); + break; + } } LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}", vibration_device_info.type, vibration_device_info.position); + const auto result = controller.IsDeviceHandleValid(vibration_device_handle); + if (result.IsError()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; + } + IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); rb.PushRaw(vibration_device_info); diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index 283c04cd5..790edbb2a 100755 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -52,8 +52,8 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system, : QWebEngineView(parent), input_subsystem{input_subsystem_}, url_interceptor(std::make_unique()), input_interpreter(std::make_unique(system)), - default_profile{QWebEngineProfile::defaultProfile()}, - global_settings{QWebEngineSettings::globalSettings()} { + default_profile{QWebEngineProfile::defaultProfile()}, global_settings{ + default_profile->settings()} { default_profile->setPersistentStoragePath(QString::fromStdString(Common::FS::PathToUTF8String( Common::FS::GetYuzuPath(Common::FS::YuzuPath::YuzuDir) / "qtwebengine"))); @@ -78,7 +78,7 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system, default_profile->scripts()->insert(gamepad); default_profile->scripts()->insert(window_nx); - default_profile->setRequestInterceptor(url_interceptor.get()); + default_profile->setUrlRequestInterceptor(url_interceptor.get()); global_settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); global_settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);