From 9f82a9a2444a232e746992fa89084b928255cb63 Mon Sep 17 00:00:00 2001 From: FearlessTobi Date: Wed, 20 May 2020 21:28:16 +0200 Subject: crypto: Make KeyManager a singleton class Previously, we were reading the keys everytime a KeyManager object was created, causing yuzu to reread the keys file multiple hundreds of times when loading the game list. With this change, it is only loaded once. On my system, this decreased game list loading times by a factor of 20. --- src/core/hle/service/es/es.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index f8e9df4b1..ad6841a64 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -263,7 +263,7 @@ private: rb.Push(write_size); } - Core::Crypto::KeyManager keys; + Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); }; void InstallInterfaces(SM::ServiceManager& service_manager) { -- cgit v1.2.3 From 2b1cc232bce45e12d466fc606f78b484bb13a3a8 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sun, 31 May 2020 18:49:51 +0200 Subject: ldr: Update NRR/NRO structs This was based on Switchbrew pages: https://switchbrew.org/wiki/NRR https://switchbrew.org/wiki/NRO--- src/core/hle/service/ldr/ldr.cpp | 112 +++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 40 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 6ad3be1b3..62d4bfc08 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -39,47 +39,68 @@ constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200}; +struct Certification { + u64_le application_id_mask; + u64_le application_id_pattern; + std::array reserved; + std::array public_key; // Also known as modulus + std::array signature; +}; +static_assert(sizeof(Certification) == 0x220, "Certification has invalid size!"); + +using SHA256Hash = std::array; + struct NRRHeader { u32_le magic; - INSERT_PADDING_BYTES(12); - u64_le title_id_mask; - u64_le title_id_pattern; - INSERT_PADDING_BYTES(16); - std::array modulus; - std::array signature_1; - std::array signature_2; - u64_le title_id; + u32_le certification_signature_key_generation; // 9.0.0+ + u64_le reserved; + Certification certification; + std::array signature; + u64_le application_id; u32_le size; - INSERT_PADDING_BYTES(4); + u8 nrr_kind; + std::array reserved_2; u32_le hash_offset; u32_le hash_count; - INSERT_PADDING_BYTES(8); + u64_le reserved_3; + + // Must be dynamically allocated because, according to + // SwitchBrew, its size is (0x20 * hash_count) and + // it's impossible to determine the value of hash_count + // (SwitchBrew calls it "NumHash") before runtime, + // therefore it's not possible to calculate a SHA-256 + std::vector NroHashList; }; -static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size."); + +struct SegmentHeader { + u32_le memory_offset; + u32_le memory_size; +}; +static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size!"); struct NROHeader { - INSERT_PADDING_WORDS(1); + // Switchbrew calls this "Start" (0x10) + u32_le unused; u32_le mod_offset; - INSERT_PADDING_WORDS(2); + u64_le padding; + + // Switchbrew calls this "Header" (0x70) u32_le magic; u32_le version; u32_le nro_size; u32_le flags; - u32_le text_offset; - u32_le text_size; - u32_le ro_offset; - u32_le ro_size; - u32_le rw_offset; - u32_le rw_size; + // .text, .ro, .data (yuzu previously called it "rw" instead of "data") + std::array segment_headers; u32_le bss_size; - INSERT_PADDING_WORDS(1); + u32_le reserved; std::array build_id; - INSERT_PADDING_BYTES(0x20); + u32_le dso_handle_offset; + u32_le unused_2; + // .apiInfo, .dynstr, .dynsym + std::array segment_headers_2; }; static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); -using SHA256Hash = std::array; - struct NROInfo { SHA256Hash hash{}; VAddr nro_address{}; @@ -226,11 +247,11 @@ public: return; } - if (system.CurrentProcess()->GetTitleID() != header.title_id) { + if (system.CurrentProcess()->GetTitleID() != header.application_id) { LOG_ERROR(Service_LDR, "Attempting to load NRR with title ID other than current process. (actual " "{:016X})!", - header.title_id); + header.application_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ERROR_INVALID_NRR); return; @@ -348,10 +369,10 @@ public: ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, VAddr start) const { - const VAddr text_start{start + nro_header.text_offset}; - const VAddr ro_start{start + nro_header.ro_offset}; - const VAddr data_start{start + nro_header.rw_offset}; - const VAddr bss_start{data_start + nro_header.rw_size}; + const VAddr text_start{start + nro_header.segment_headers[0].memory_offset}; + const VAddr ro_start{start + nro_header.segment_headers[1].memory_offset}; + const VAddr data_start{start + nro_header.segment_headers[2].memory_offset}; + const VAddr bss_start{data_start + nro_header.segment_headers[2].memory_size}; const VAddr bss_end_addr{ Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)}; @@ -360,9 +381,12 @@ public: system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size()); }}; - CopyCode(nro_addr + nro_header.text_offset, text_start, nro_header.text_size); - CopyCode(nro_addr + nro_header.ro_offset, ro_start, nro_header.ro_size); - CopyCode(nro_addr + nro_header.rw_offset, data_start, nro_header.rw_size); + CopyCode(nro_addr + nro_header.segment_headers[0].memory_offset, text_start, + nro_header.segment_headers[0].memory_size); + CopyCode(nro_addr + nro_header.segment_headers[1].memory_offset, ro_start, + nro_header.segment_headers[1].memory_size); + CopyCode(nro_addr + nro_header.segment_headers[2].memory_offset, data_start, + nro_header.segment_headers[2].memory_size); CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute)); @@ -484,9 +508,11 @@ public: } // Track the loaded NRO - nro.insert_or_assign(*map_result, NROInfo{hash, *map_result, nro_size, bss_address, - bss_size, header.text_size, header.ro_size, - header.rw_size, nro_address}); + nro.insert_or_assign(*map_result, + NROInfo{hash, *map_result, nro_size, bss_address, bss_size, + header.segment_headers[0].memory_size, + header.segment_headers[1].memory_size, + header.segment_headers[2].memory_size, nro_address}); // Invalidate JIT caches for the newly mapped process code system.InvalidateCpuInstructionCaches(); @@ -584,11 +610,17 @@ private: static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && header.nro_size == nro_size && header.bss_size == bss_size && - header.ro_offset == header.text_offset + header.text_size && - header.rw_offset == header.ro_offset + header.ro_size && - nro_size == header.rw_offset + header.rw_size && - Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) && - Common::Is4KBAligned(header.rw_size); + header.segment_headers[1].memory_offset == + header.segment_headers[0].memory_offset + + header.segment_headers[0].memory_size && + header.segment_headers[2].memory_offset == + header.segment_headers[1].memory_offset + + header.segment_headers[1].memory_size && + nro_size == header.segment_headers[2].memory_offset + + header.segment_headers[2].memory_size && + Common::Is4KBAligned(header.segment_headers[0].memory_size) && + Common::Is4KBAligned(header.segment_headers[1].memory_size) && + Common::Is4KBAligned(header.segment_headers[2].memory_size); } Core::System& system; }; -- cgit v1.2.3 From a087b3365a26b14ea6733b213998df5ff318afb3 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sun, 31 May 2020 19:12:09 +0200 Subject: Add comment to nrr_kind According to Atmosphére (https://github.com/Atmosphere-NX/Atmosphere/blob/c7026b90940a1d88f9c10a6d98263bf22e654fa5/libraries/libstratosphere/include/stratosphere/ro/ro_types.hpp), nrr_kind (Atmosphére calls it "type") is 7.0.0+--- src/core/hle/service/ldr/ldr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 62d4bfc08..252b79d2c 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -58,7 +58,7 @@ struct NRRHeader { std::array signature; u64_le application_id; u32_le size; - u8 nrr_kind; + u8 nrr_kind; // 7.0.0+ std::array reserved_2; u32_le hash_offset; u32_le hash_count; -- cgit v1.2.3 From dfd1badc125ca5a4a4fa4587b81f2e51bebb2a07 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Tue, 2 Jun 2020 17:54:10 +0200 Subject: Address review comments --- src/core/hle/service/ldr/ldr.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 252b79d2c..69caf3aae 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -59,7 +59,7 @@ struct NRRHeader { u64_le application_id; u32_le size; u8 nrr_kind; // 7.0.0+ - std::array reserved_2; + std::array reserved_2; u32_le hash_offset; u32_le hash_count; u64_le reserved_3; @@ -89,15 +89,15 @@ struct NROHeader { u32_le version; u32_le nro_size; u32_le flags; - // .text, .ro, .data (yuzu previously called it "rw" instead of "data") - std::array segment_headers; + // .text, .ro, .data + std::array segment_headers; u32_le bss_size; u32_le reserved; std::array build_id; u32_le dso_handle_offset; u32_le unused_2; // .apiInfo, .dynstr, .dynsym - std::array segment_headers_2; + std::array segment_headers_2; }; static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); -- cgit v1.2.3 From 151a3fe7b327c8adad2bc103029457c353b261c0 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sun, 14 Jun 2020 19:28:39 +0200 Subject: Attempt to fix crashes in SSBU and refactor IsValidNRO --- src/core/hle/service/ldr/ldr.cpp | 95 +++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 36 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 69caf3aae..5b372b7db 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -39,22 +39,27 @@ constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200}; -struct Certification { +constexpr std::size_t TEXT_INDEX{0}; +constexpr std::size_t RO_INDEX{1}; +constexpr std::size_t DATA_INDEX{2}; + +struct NRRCertification { u64_le application_id_mask; u64_le application_id_pattern; std::array reserved; std::array public_key; // Also known as modulus std::array signature; }; -static_assert(sizeof(Certification) == 0x220, "Certification has invalid size!"); +static_assert(sizeof(NRRCertification) == 0x220, "Certification has invalid size!"); using SHA256Hash = std::array; +#pragma pack(1) struct NRRHeader { u32_le magic; u32_le certification_signature_key_generation; // 9.0.0+ u64_le reserved; - Certification certification; + NRRCertification certification; std::array signature; u64_le application_id; u32_le size; @@ -63,21 +68,19 @@ struct NRRHeader { u32_le hash_offset; u32_le hash_count; u64_le reserved_3; - - // Must be dynamically allocated because, according to - // SwitchBrew, its size is (0x20 * hash_count) and - // it's impossible to determine the value of hash_count - // (SwitchBrew calls it "NumHash") before runtime, - // therefore it's not possible to calculate a SHA-256 - std::vector NroHashList; }; +#pragma pack() +static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size!"); +#pragma pack(1) struct SegmentHeader { u32_le memory_offset; u32_le memory_size; }; +#pragma pack() static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size!"); +#pragma pack(1) struct NROHeader { // Switchbrew calls this "Start" (0x10) u32_le unused; @@ -99,8 +102,10 @@ struct NROHeader { // .apiInfo, .dynstr, .dynsym std::array segment_headers_2; }; +#pragma pack() static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); +#pragma pack(1) struct NROInfo { SHA256Hash hash{}; VAddr nro_address{}; @@ -112,6 +117,8 @@ struct NROInfo { std::size_t data_size{}; VAddr src_addr{}; }; +#pragma pack() +static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size."); class DebugMonitor final : public ServiceFramework { public: @@ -369,10 +376,10 @@ public: ResultCode LoadNro(Kernel::Process* process, const NROHeader& nro_header, VAddr nro_addr, VAddr start) const { - const VAddr text_start{start + nro_header.segment_headers[0].memory_offset}; - const VAddr ro_start{start + nro_header.segment_headers[1].memory_offset}; - const VAddr data_start{start + nro_header.segment_headers[2].memory_offset}; - const VAddr bss_start{data_start + nro_header.segment_headers[2].memory_size}; + const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset}; + const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset}; + const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset}; + const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size}; const VAddr bss_end_addr{ Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)}; @@ -381,12 +388,12 @@ public: system.Memory().ReadBlock(src_addr, source_data.data(), source_data.size()); system.Memory().WriteBlock(dst_addr, source_data.data(), source_data.size()); }}; - CopyCode(nro_addr + nro_header.segment_headers[0].memory_offset, text_start, - nro_header.segment_headers[0].memory_size); - CopyCode(nro_addr + nro_header.segment_headers[1].memory_offset, ro_start, - nro_header.segment_headers[1].memory_size); - CopyCode(nro_addr + nro_header.segment_headers[2].memory_offset, data_start, - nro_header.segment_headers[2].memory_size); + CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start, + nro_header.segment_headers[TEXT_INDEX].memory_size); + CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start, + nro_header.segment_headers[RO_INDEX].memory_size); + CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, + nro_header.segment_headers[DATA_INDEX].memory_size); CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute)); @@ -510,9 +517,9 @@ public: // Track the loaded NRO nro.insert_or_assign(*map_result, NROInfo{hash, *map_result, nro_size, bss_address, bss_size, - header.segment_headers[0].memory_size, - header.segment_headers[1].memory_size, - header.segment_headers[2].memory_size, nro_address}); + header.segment_headers[TEXT_INDEX].memory_size, + header.segment_headers[RO_INDEX].memory_size, + header.segment_headers[DATA_INDEX].memory_size, nro_address}); // Invalidate JIT caches for the newly mapped process code system.InvalidateCpuInstructionCaches(); @@ -608,19 +615,35 @@ private: } static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { - return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && - header.nro_size == nro_size && header.bss_size == bss_size && - header.segment_headers[1].memory_offset == - header.segment_headers[0].memory_offset + - header.segment_headers[0].memory_size && - header.segment_headers[2].memory_offset == - header.segment_headers[1].memory_offset + - header.segment_headers[1].memory_size && - nro_size == header.segment_headers[2].memory_offset + - header.segment_headers[2].memory_size && - Common::Is4KBAligned(header.segment_headers[0].memory_size) && - Common::Is4KBAligned(header.segment_headers[1].memory_size) && - Common::Is4KBAligned(header.segment_headers[2].memory_size); + + const bool valid_magic = header.magic == Common::MakeMagic('N', 'R', 'O', '0'); + + const bool valid_nro_size = header.nro_size == nro_size; + + const bool valid_bss_size = header.bss_size == bss_size; + + const bool valid_ro_offset = header.segment_headers[RO_INDEX].memory_offset == + header.segment_headers[TEXT_INDEX].memory_offset + + header.segment_headers[TEXT_INDEX].memory_size; + + const bool valid_rw_offset = header.segment_headers[DATA_INDEX].memory_offset == + header.segment_headers[RO_INDEX].memory_offset + + header.segment_headers[RO_INDEX].memory_size; + + const bool valid_nro_calculated_size = + nro_size == header.segment_headers[DATA_INDEX].memory_offset + + header.segment_headers[DATA_INDEX].memory_size; + + const bool text_aligned = + Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size); + + const bool ro_aligned = Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size); + + const bool rw_aligned = + Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); + + return valid_magic && valid_nro_size && valid_bss_size && valid_ro_offset && + valid_rw_offset && valid_nro_calculated_size && text_aligned && ro_aligned && rw_aligned; } Core::System& system; }; -- cgit v1.2.3 From 761d2060493c5c4e1c920659d3b00d8a56164941 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sun, 14 Jun 2020 19:30:08 +0200 Subject: Make assert strings consistent --- src/core/hle/service/ldr/ldr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 5b372b7db..20f268ec0 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -50,7 +50,7 @@ struct NRRCertification { std::array public_key; // Also known as modulus std::array signature; }; -static_assert(sizeof(NRRCertification) == 0x220, "Certification has invalid size!"); +static_assert(sizeof(NRRCertification) == 0x220, "Certification has invalid size."); using SHA256Hash = std::array; @@ -70,7 +70,7 @@ struct NRRHeader { u64_le reserved_3; }; #pragma pack() -static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size!"); +static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size."); #pragma pack(1) struct SegmentHeader { @@ -78,7 +78,7 @@ struct SegmentHeader { u32_le memory_size; }; #pragma pack() -static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size!"); +static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size."); #pragma pack(1) struct NROHeader { -- cgit v1.2.3 From 1520d7865d0cd0afde690f99de8bf34400671556 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sun, 14 Jun 2020 19:34:58 +0200 Subject: Clang-format --- src/core/hle/service/ldr/ldr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 20f268ec0..dd0bdde38 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -643,7 +643,8 @@ private: Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); return valid_magic && valid_nro_size && valid_bss_size && valid_ro_offset && - valid_rw_offset && valid_nro_calculated_size && text_aligned && ro_aligned && rw_aligned; + valid_rw_offset && valid_nro_calculated_size && text_aligned && ro_aligned && + rw_aligned; } Core::System& system; }; -- cgit v1.2.3 From 198b0fa7901da3a9ab71680351919c41b349e453 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sun, 14 Jun 2020 19:37:44 +0200 Subject: Use consistent variable names --- src/core/hle/service/ldr/ldr.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index dd0bdde38..d4c6879ac 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -626,7 +626,7 @@ private: header.segment_headers[TEXT_INDEX].memory_offset + header.segment_headers[TEXT_INDEX].memory_size; - const bool valid_rw_offset = header.segment_headers[DATA_INDEX].memory_offset == + const bool valid_data_offset = header.segment_headers[DATA_INDEX].memory_offset == header.segment_headers[RO_INDEX].memory_offset + header.segment_headers[RO_INDEX].memory_size; @@ -639,12 +639,12 @@ private: const bool ro_aligned = Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size); - const bool rw_aligned = + const bool data_aligned = Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); return valid_magic && valid_nro_size && valid_bss_size && valid_ro_offset && - valid_rw_offset && valid_nro_calculated_size && text_aligned && ro_aligned && - rw_aligned; + valid_data_offset && valid_nro_calculated_size && text_aligned && ro_aligned && + data_aligned; } Core::System& system; }; -- cgit v1.2.3 From 39213b1c593828147b4c2c0738e3fc72221c8e6e Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sun, 14 Jun 2020 19:41:28 +0200 Subject: Clang-format again --- src/core/hle/service/ldr/ldr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index d4c6879ac..09c17f41f 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -627,8 +627,8 @@ private: header.segment_headers[TEXT_INDEX].memory_size; const bool valid_data_offset = header.segment_headers[DATA_INDEX].memory_offset == - header.segment_headers[RO_INDEX].memory_offset + - header.segment_headers[RO_INDEX].memory_size; + header.segment_headers[RO_INDEX].memory_offset + + header.segment_headers[RO_INDEX].memory_size; const bool valid_nro_calculated_size = nro_size == header.segment_headers[DATA_INDEX].memory_offset + -- cgit v1.2.3 From 4b71bf654d54210c18e77abda1b3ca20c0e43a63 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Tue, 16 Jun 2020 15:57:02 +0200 Subject: Update assert string --- src/core/hle/service/ldr/ldr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 09c17f41f..6daea3408 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -50,7 +50,7 @@ struct NRRCertification { std::array public_key; // Also known as modulus std::array signature; }; -static_assert(sizeof(NRRCertification) == 0x220, "Certification has invalid size."); +static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid size."); using SHA256Hash = std::array; -- cgit v1.2.3 From c0d61620506ef4d70b1aa60bc9961f08ce9a939f Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Tue, 16 Jun 2020 20:24:58 +0200 Subject: Revert IsValidNRO refactor but make it more readable --- src/core/hle/service/ldr/ldr.cpp | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 6daea3408..ca53a9923 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -615,36 +615,23 @@ private: } static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { + return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && + header.nro_size == nro_size && header.bss_size == bss_size && - const bool valid_magic = header.magic == Common::MakeMagic('N', 'R', 'O', '0'); + header.segment_headers[RO_INDEX].memory_offset == + header.segment_headers[TEXT_INDEX].memory_offset + + header.segment_headers[TEXT_INDEX].memory_size && - const bool valid_nro_size = header.nro_size == nro_size; + header.segment_headers[DATA_INDEX].memory_offset == + header.segment_headers[RO_INDEX].memory_offset + + header.segment_headers[RO_INDEX].memory_size && - const bool valid_bss_size = header.bss_size == bss_size; + nro_size == header.segment_headers[DATA_INDEX].memory_offset + + header.segment_headers[DATA_INDEX].memory_size && - const bool valid_ro_offset = header.segment_headers[RO_INDEX].memory_offset == - header.segment_headers[TEXT_INDEX].memory_offset + - header.segment_headers[TEXT_INDEX].memory_size; - - const bool valid_data_offset = header.segment_headers[DATA_INDEX].memory_offset == - header.segment_headers[RO_INDEX].memory_offset + - header.segment_headers[RO_INDEX].memory_size; - - const bool valid_nro_calculated_size = - nro_size == header.segment_headers[DATA_INDEX].memory_offset + - header.segment_headers[DATA_INDEX].memory_size; - - const bool text_aligned = - Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size); - - const bool ro_aligned = Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size); - - const bool data_aligned = - Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); - - return valid_magic && valid_nro_size && valid_bss_size && valid_ro_offset && - valid_data_offset && valid_nro_calculated_size && text_aligned && ro_aligned && - data_aligned; + Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size) && + Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) && + Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); } Core::System& system; }; -- cgit v1.2.3 From bd9495c9ab5c1b452c700c54c2bbacf290306741 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Tue, 16 Jun 2020 20:28:44 +0200 Subject: Remove unnecessary pragmas --- src/core/hle/service/ldr/ldr.cpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index ca53a9923..9ce2db191 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -54,7 +54,6 @@ static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid s using SHA256Hash = std::array; -#pragma pack(1) struct NRRHeader { u32_le magic; u32_le certification_signature_key_generation; // 9.0.0+ @@ -69,18 +68,14 @@ struct NRRHeader { u32_le hash_count; u64_le reserved_3; }; -#pragma pack() static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size."); -#pragma pack(1) struct SegmentHeader { u32_le memory_offset; u32_le memory_size; }; -#pragma pack() static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size."); -#pragma pack(1) struct NROHeader { // Switchbrew calls this "Start" (0x10) u32_le unused; @@ -102,10 +97,8 @@ struct NROHeader { // .apiInfo, .dynstr, .dynsym std::array segment_headers_2; }; -#pragma pack() static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); -#pragma pack(1) struct NROInfo { SHA256Hash hash{}; VAddr nro_address{}; @@ -117,7 +110,6 @@ struct NROInfo { std::size_t data_size{}; VAddr src_addr{}; }; -#pragma pack() static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size."); class DebugMonitor final : public ServiceFramework { -- cgit v1.2.3 From 684dfbf20906c4476a7bc28273be9ebd53ab196d Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Thu, 18 Jun 2020 15:45:47 +0200 Subject: Move SHA256Hash to its original position It's not needed to have it in its previous position anymore--- src/core/hle/service/ldr/ldr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 9ce2db191..9f376657c 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -52,8 +52,6 @@ struct NRRCertification { }; static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid size."); -using SHA256Hash = std::array; - struct NRRHeader { u32_le magic; u32_le certification_signature_key_generation; // 9.0.0+ @@ -99,6 +97,8 @@ struct NROHeader { }; static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); +using SHA256Hash = std::array; + struct NROInfo { SHA256Hash hash{}; VAddr nro_address{}; -- cgit v1.2.3 From a5ed0c3df7218f922f98d4bd1fed1214ec728869 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 20 Jun 2020 01:06:05 -0400 Subject: software_keyboard: Eliminate trivial redundant copies We can just make use of moves here to get rid of two redundant copies --- src/core/hle/service/am/applets/software_keyboard.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 54e63c138..d14076b02 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -30,7 +30,7 @@ static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( config.sub_text.size()); params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(), config.guide_text.size()); - params.initial_text = initial_text; + params.initial_text = std::move(initial_text); params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit; params.password = static_cast(config.is_password); params.cursor_at_beginning = static_cast(config.initial_cursor_position); @@ -109,7 +109,7 @@ void SoftwareKeyboard::Execute() { const auto parameters = ConvertToFrontendParameters(config, initial_text); - frontend.RequestText([this](std::optional text) { WriteText(text); }, + frontend.RequestText([this](std::optional text) { WriteText(std::move(text)); }, parameters); } -- cgit v1.2.3 From 0235915baaca8c0928a54fae1df60595e451e223 Mon Sep 17 00:00:00 2001 From: Morph Date: Sun, 21 Jun 2020 15:48:02 -0400 Subject: hid: Implement Get/ResetGyroscopeZeroDriftMode - Used by Captain Toad Treasure Tracker --- src/core/hle/service/hid/controllers/npad.cpp | 8 +++++ src/core/hle/service/hid/controllers/npad.h | 10 ++++++- src/core/hle/service/hid/hid.cpp | 42 +++++++++++++++++++++++---- src/core/hle/service/hid/hid.h | 2 ++ 4 files changed, 56 insertions(+), 6 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index c55d900e2..6fbee7efa 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -566,6 +566,14 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) { connected_controllers[NPadIdToIndex(npad_id)].is_connected = false; } +void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { + gyroscope_zero_drift_mode = drift_mode; +} + +Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const { + return gyroscope_zero_drift_mode; +} + void Controller_NPad::StartLRAssignmentMode() { // Nothing internally is used for lr assignment mode. Since we have the ability to set the // controller types from boot, it doesn't really matter about showing a selection screen diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 931f03430..5d4c58a43 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -58,6 +58,12 @@ public: }; static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size"); + enum class GyroscopeZeroDriftMode : u32 { + Loose = 0, + Standard = 1, + Tight = 2, + }; + enum class NpadHoldType : u64 { Vertical = 0, Horizontal = 1, @@ -117,6 +123,8 @@ public: void ConnectNPad(u32 npad_id); void DisconnectNPad(u32 npad_id); + void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); + GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; LedPattern GetLedPattern(u32 npad_id); void SetVibrationEnabled(bool can_vibrate); bool IsVibrationEnabled() const; @@ -324,8 +332,8 @@ private: std::array styleset_changed_events; Vibration last_processed_vibration{}; std::array connected_controllers{}; + GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; bool can_controllers_vibrate{true}; - std::array npad_pad_states{}; bool is_in_lr_assignment_mode{false}; Core::System& system; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 72a050de2..415c2829e 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -185,8 +185,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {77, nullptr, "GetAccelerometerPlayMode"}, {78, nullptr, "ResetAccelerometerPlayMode"}, {79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"}, - {80, nullptr, "GetGyroscopeZeroDriftMode"}, - {81, nullptr, "ResetGyroscopeZeroDriftMode"}, + {80, &Hid::GetGyroscopeZeroDriftMode, "GetGyroscopeZeroDriftMode"}, + {81, &Hid::ResetGyroscopeZeroDriftMode, "ResetGyroscopeZeroDriftMode"}, {82, &Hid::IsSixAxisSensorAtRest, "IsSixAxisSensorAtRest"}, {83, nullptr, "IsFirmwareUpdateAvailableForSixAxisSensor"}, {91, &Hid::ActivateGesture, "ActivateGesture"}, @@ -419,9 +419,41 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { const auto drift_mode{rp.Pop()}; const auto applet_resource_user_id{rp.Pop()}; - LOG_WARNING(Service_HID, - "(STUBBED) called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, - drift_mode, applet_resource_user_id); + applet_resource->GetController(HidController::NPad) + .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode{drift_mode}); + + LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, + drift_mode, applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop()}; + const auto applet_resource_user_id{rp.Pop()}; + + LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push( + static_cast(applet_resource->GetController(HidController::NPad) + .GetGyroscopeZeroDriftMode())); +} + +void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop()}; + const auto applet_resource_user_id{rp.Pop()}; + + applet_resource->GetController(HidController::NPad) + .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); + + LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index d481a75f8..41b330fa9 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -95,6 +95,8 @@ private: void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); void StartSixAxisSensor(Kernel::HLERequestContext& ctx); void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); + void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); + void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); -- cgit v1.2.3 From e193aa3f53a09850606145466d6caa9abd3fb856 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Mon, 22 Jun 2020 22:03:26 +0200 Subject: account: Update function tables and add missing classes (#4145) * account: Update function tables and add missing classes * clang-format * Add missing "public" * Add missing public again * Add missing final--- src/core/hle/service/acc/acc.cpp | 341 ++++++++++++++++++++++++++++++++++++ src/core/hle/service/acc/acc_aa.cpp | 4 +- src/core/hle/service/acc/acc_su.cpp | 34 ++-- src/core/hle/service/acc/acc_u0.cpp | 18 +- src/core/hle/service/acc/acc_u1.cpp | 29 +-- 5 files changed, 384 insertions(+), 42 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 630a8b048..94d8c1fc6 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -44,6 +44,218 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) { return static_cast(std::min(size, max_jpeg_image_size)); } +class IManagerForSystemService final : public ServiceFramework { +public: + explicit IManagerForSystemService(Common::UUID user_id) + : ServiceFramework("IManagerForSystemService") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CheckAvailability"}, + {1, nullptr, "GetAccountId"}, + {2, nullptr, "EnsureIdTokenCacheAsync"}, + {3, nullptr, "LoadIdTokenCache"}, + {100, nullptr, "SetSystemProgramIdentification"}, + {101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+ + {110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+ + {111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+ + {112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0 + {113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+ + {120, nullptr, "GetNintendoAccountId"}, + {121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+ + {130, nullptr, "GetNintendoAccountUserResourceCache"}, + {131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"}, + {132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"}, + {133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+ + {134, nullptr, "RefreshNintendoAccountVerificationUrlCache"}, // 9.0.0+ + {135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+ + {140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+ + {141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+ + {142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+ + {150, nullptr, "CreateAuthorizationRequest"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +// 3.0.0+ +class IFloatingRegistrationRequest final : public ServiceFramework { +public: + explicit IFloatingRegistrationRequest(Common::UUID user_id) + : ServiceFramework("IFloatingRegistrationRequest") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetSessionId"}, + {12, nullptr, "GetAccountId"}, + {13, nullptr, "GetLinkedNintendoAccountId"}, + {14, nullptr, "GetNickname"}, + {15, nullptr, "GetProfileImage"}, + {21, nullptr, "LoadIdTokenCache"}, + {100, nullptr, "RegisterUser"}, // [1.0.0-3.0.2] RegisterAsync + {101, nullptr, "RegisterUserWithUid"}, // [1.0.0-3.0.2] RegisterWithUidAsync + {102, nullptr, "RegisterNetworkServiceAccountAsync"}, // 4.0.0+ + {103, nullptr, "RegisterNetworkServiceAccountWithUidAsync"}, // 4.0.0+ + {110, nullptr, "SetSystemProgramIdentification"}, + {111, nullptr, "EnsureIdTokenCacheAsync"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IAdministrator final : public ServiceFramework { +public: + explicit IAdministrator(Common::UUID user_id) : ServiceFramework("IAdministrator") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "CheckAvailability"}, + {1, nullptr, "GetAccountId"}, + {2, nullptr, "EnsureIdTokenCacheAsync"}, + {3, nullptr, "LoadIdTokenCache"}, + {100, nullptr, "SetSystemProgramIdentification"}, + {101, nullptr, "RefreshNotificationTokenAsync"}, // 7.0.0+ + {110, nullptr, "GetServiceEntryRequirementCache"}, // 4.0.0+ + {111, nullptr, "InvalidateServiceEntryRequirementCache"}, // 4.0.0+ + {112, nullptr, "InvalidateTokenCache"}, // 4.0.0 - 6.2.0 + {113, nullptr, "GetServiceEntryRequirementCacheForOnlinePlay"}, // 6.1.0+ + {120, nullptr, "GetNintendoAccountId"}, + {121, nullptr, "CalculateNintendoAccountAuthenticationFingerprint"}, // 9.0.0+ + {130, nullptr, "GetNintendoAccountUserResourceCache"}, + {131, nullptr, "RefreshNintendoAccountUserResourceCacheAsync"}, + {132, nullptr, "RefreshNintendoAccountUserResourceCacheAsyncIfSecondsElapsed"}, + {133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+ + {134, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsync"}, // 9.0.0+ + {135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+ + {140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+ + {141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+ + {142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+ + {150, nullptr, "CreateAuthorizationRequest"}, + {200, nullptr, "IsRegistered"}, + {201, nullptr, "RegisterAsync"}, + {202, nullptr, "UnregisterAsync"}, + {203, nullptr, "DeleteRegistrationInfoLocally"}, + {220, nullptr, "SynchronizeProfileAsync"}, + {221, nullptr, "UploadProfileAsync"}, + {222, nullptr, "SynchronizaProfileAsyncIfSecondsElapsed"}, + {250, nullptr, "IsLinkedWithNintendoAccount"}, + {251, nullptr, "CreateProcedureToLinkWithNintendoAccount"}, + {252, nullptr, "ResumeProcedureToLinkWithNintendoAccount"}, + {255, nullptr, "CreateProcedureToUpdateLinkageStateOfNintendoAccount"}, + {256, nullptr, "ResumeProcedureToUpdateLinkageStateOfNintendoAccount"}, + {260, nullptr, "CreateProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+ + {261, nullptr, "ResumeProcedureToLinkNnidWithNintendoAccount"}, // 3.0.0+ + {280, nullptr, "ProxyProcedureToAcquireApplicationAuthorizationForNintendoAccount"}, + {290, nullptr, "GetRequestForNintendoAccountUserResourceView"}, // 8.0.0+ + {300, nullptr, "TryRecoverNintendoAccountUserStateAsync"}, // 6.0.0+ + {400, nullptr, "IsServiceEntryRequirementCacheRefreshRequiredForOnlinePlay"}, // 6.1.0+ + {401, nullptr, "RefreshServiceEntryRequirementCacheForOnlinePlayAsync"}, // 6.1.0+ + {900, nullptr, "GetAuthenticationInfoForWin"}, // 9.0.0+ + {901, nullptr, "ImportAsyncForWin"}, // 9.0.0+ + {997, nullptr, "DebugUnlinkNintendoAccountAsync"}, + {998, nullptr, "DebugSetAvailabilityErrorDetail"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IAuthorizationRequest final : public ServiceFramework { +public: + explicit IAuthorizationRequest(Common::UUID user_id) + : ServiceFramework("IAuthorizationRequest") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetSessionId"}, + {10, nullptr, "InvokeWithoutInteractionAsync"}, + {19, nullptr, "IsAuthorized"}, + {20, nullptr, "GetAuthorizationCode"}, + {21, nullptr, "GetIdToken"}, + {22, nullptr, "GetState"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IOAuthProcedure final : public ServiceFramework { +public: + explicit IOAuthProcedure(Common::UUID user_id) : ServiceFramework("IOAuthProcedure") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "PrepareAsync"}, + {1, nullptr, "GetRequest"}, + {2, nullptr, "ApplyResponse"}, + {3, nullptr, "ApplyResponseAsync"}, + {10, nullptr, "Suspend"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +// 3.0.0+ +class IOAuthProcedureForExternalNsa final : public ServiceFramework { +public: + explicit IOAuthProcedureForExternalNsa(Common::UUID user_id) + : ServiceFramework("IOAuthProcedureForExternalNsa") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "PrepareAsync"}, + {1, nullptr, "GetRequest"}, + {2, nullptr, "ApplyResponse"}, + {3, nullptr, "ApplyResponseAsync"}, + {10, nullptr, "Suspend"}, + {100, nullptr, "GetAccountId"}, + {101, nullptr, "GetLinkedNintendoAccountId"}, + {102, nullptr, "GetNickname"}, + {103, nullptr, "GetProfileImage"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IOAuthProcedureForNintendoAccountLinkage final + : public ServiceFramework { +public: + explicit IOAuthProcedureForNintendoAccountLinkage(Common::UUID user_id) + : ServiceFramework("IOAuthProcedureForNintendoAccountLinkage") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "PrepareAsync"}, + {1, nullptr, "GetRequest"}, + {2, nullptr, "ApplyResponse"}, + {3, nullptr, "ApplyResponseAsync"}, + {10, nullptr, "Suspend"}, + {100, nullptr, "GetRequestWithTheme"}, + {101, nullptr, "IsNetworkServiceAccountReplaced"}, + {199, nullptr, "GetUrlForIntroductionOfExtraMembership"}, // 2.0.0 - 5.1.0 + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class INotifier final : public ServiceFramework { +public: + explicit INotifier(Common::UUID user_id) : ServiceFramework("INotifier") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetSystemEvent"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + class IProfileCommon : public ServiceFramework { public: explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id, @@ -226,6 +438,54 @@ public: : IProfileCommon("IProfileEditor", true, user_id, profile_manager) {} }; +class IAsyncContext final : public ServiceFramework { +public: + explicit IAsyncContext(Common::UUID user_id) : ServiceFramework("IAsyncContext") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetSystemEvent"}, + {1, nullptr, "Cancel"}, + {2, nullptr, "HasDone"}, + {3, nullptr, "GetResult"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class ISessionObject final : public ServiceFramework { +public: + explicit ISessionObject(Common::UUID user_id) : ServiceFramework("ISessionObject") { + // clang-format off + static const FunctionInfo functions[] = { + {999, nullptr, "Dummy"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class IGuestLoginRequest final : public ServiceFramework { +public: + explicit IGuestLoginRequest(Common::UUID) : ServiceFramework("IGuestLoginRequest") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetSessionId"}, + {11, nullptr, "Unknown"}, // 1.0.0 - 2.3.0 (the name is blank on Switchbrew) + {12, nullptr, "GetAccountId"}, + {13, nullptr, "GetLinkedNintendoAccountId"}, + {14, nullptr, "GetNickname"}, + {15, nullptr, "GetProfileImage"}, + {21, nullptr, "LoadIdTokenCache"}, // 3.0.0+ + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + class IManagerForApplication final : public ServiceFramework { public: explicit IManagerForApplication(Common::UUID user_id) @@ -265,6 +525,87 @@ private: Common::UUID user_id; }; +// 6.0.0+ +class IAsyncNetworkServiceLicenseKindContext final + : public ServiceFramework { +public: + explicit IAsyncNetworkServiceLicenseKindContext(Common::UUID user_id) + : ServiceFramework("IAsyncNetworkServiceLicenseKindContext") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetSystemEvent"}, + {1, nullptr, "Cancel"}, + {2, nullptr, "HasDone"}, + {3, nullptr, "GetResult"}, + {4, nullptr, "GetNetworkServiceLicenseKind"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +// 8.0.0+ +class IOAuthProcedureForUserRegistration final + : public ServiceFramework { +public: + explicit IOAuthProcedureForUserRegistration(Common::UUID user_id) + : ServiceFramework("IOAuthProcedureForUserRegistration") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "PrepareAsync"}, + {1, nullptr, "GetRequest"}, + {2, nullptr, "ApplyResponse"}, + {3, nullptr, "ApplyResponseAsync"}, + {10, nullptr, "Suspend"}, + {100, nullptr, "GetAccountId"}, + {101, nullptr, "GetLinkedNintendoAccountId"}, + {102, nullptr, "GetNickname"}, + {103, nullptr, "GetProfileImage"}, + {110, nullptr, "RegisterUserAsync"}, + {111, nullptr, "GetUid"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +class DAUTH_O final : public ServiceFramework { +public: + explicit DAUTH_O(Common::UUID) : ServiceFramework("dauth:o") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "EnsureAuthenticationTokenCacheAsync"}, // [5.0.0-5.1.0] GeneratePostData + {1, nullptr, "LoadAuthenticationTokenCache"}, // 6.0.0+ + {2, nullptr, "InvalidateAuthenticationTokenCache"}, // 6.0.0+ + {10, nullptr, "EnsureEdgeTokenCacheAsync"}, // 6.0.0+ + {11, nullptr, "LoadEdgeTokenCache"}, // 6.0.0+ + {12, nullptr, "InvalidateEdgeTokenCache"}, // 6.0.0+ + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + +// 6.0.0+ +class IAsyncResult final : public ServiceFramework { +public: + explicit IAsyncResult(Common::UUID user_id) : ServiceFramework("IAsyncResult") { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "GetResult"}, + {1, nullptr, "Cancel"}, + {2, nullptr, "IsAvailable"}, + {3, nullptr, "GetSystemEvent"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "called"); IPC::ResponseBuilder rb{ctx, 3}; diff --git a/src/core/hle/service/acc/acc_aa.cpp b/src/core/hle/service/acc/acc_aa.cpp index 3bac6bcd1..51f119b12 100644 --- a/src/core/hle/service/acc/acc_aa.cpp +++ b/src/core/hle/service/acc/acc_aa.cpp @@ -13,8 +13,8 @@ ACC_AA::ACC_AA(std::shared_ptr module, std::shared_ptr p {0, nullptr, "EnsureCacheAsync"}, {1, nullptr, "LoadCache"}, {2, nullptr, "GetDeviceAccountId"}, - {50, nullptr, "RegisterNotificationTokenAsync"}, - {51, nullptr, "UnregisterNotificationTokenAsync"}, + {50, nullptr, "RegisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0 + {51, nullptr, "UnregisterNotificationTokenAsync"}, // 1.0.0 - 6.2.0 }; RegisterHandlers(functions); } diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 2eefc6df5..85620bde3 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -17,28 +17,28 @@ ACC_SU::ACC_SU(std::shared_ptr module, std::shared_ptr p {3, &ACC_SU::ListOpenUsers, "ListOpenUsers"}, {4, &ACC_SU::GetLastOpenedUser, "GetLastOpenedUser"}, {5, &ACC_SU::GetProfile, "GetProfile"}, - {6, nullptr, "GetProfileDigest"}, + {6, nullptr, "GetProfileDigest"}, // 3.0.0+ {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, - {60, nullptr, "ListOpenContextStoredUsers"}, - {99, nullptr, "DebugActivateOpenContextRetention"}, + {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 + {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ {100, nullptr, "GetUserRegistrationNotifier"}, {101, nullptr, "GetUserStateChangeNotifier"}, {102, nullptr, "GetBaasAccountManagerForSystemService"}, {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, {104, nullptr, "GetProfileUpdateNotifier"}, - {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, - {106, nullptr, "GetProfileSyncNotifier"}, + {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ + {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ {110, nullptr, "StoreSaveDataThumbnail"}, {111, nullptr, "ClearSaveDataThumbnail"}, {112, nullptr, "LoadSaveDataThumbnail"}, - {113, nullptr, "GetSaveDataThumbnailExistence"}, - {120, nullptr, "ListOpenUsersInApplication"}, - {130, nullptr, "ActivateOpenContextRetention"}, - {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, - {150, nullptr, "AuthenticateApplicationAsync"}, - {190, nullptr, "GetUserLastOpenedApplication"}, - {191, nullptr, "ActivateOpenContextHolder"}, + {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ + {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+ + {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+ + {140, &ACC_SU::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ + {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+ + {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0 + {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+ {200, nullptr, "BeginUserRegistration"}, {201, nullptr, "CompleteUserRegistration"}, {202, nullptr, "CancelUserRegistration"}, @@ -46,15 +46,15 @@ ACC_SU::ACC_SU(std::shared_ptr module, std::shared_ptr p {204, nullptr, "SetUserPosition"}, {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"}, {206, nullptr, "CompleteUserRegistrationForcibly"}, - {210, nullptr, "CreateFloatingRegistrationRequest"}, - {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"}, - {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"}, + {210, nullptr, "CreateFloatingRegistrationRequest"}, // 3.0.0+ + {211, nullptr, "CreateProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+ + {212, nullptr, "ResumeProcedureToRegisterUserWithNintendoAccount"}, // 8.0.0+ {230, nullptr, "AuthenticateServiceAsync"}, {250, nullptr, "GetBaasAccountAdministrator"}, {290, nullptr, "ProxyProcedureForGuestLoginWithNintendoAccount"}, - {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"}, + {291, nullptr, "ProxyProcedureForFloatingRegistrationWithNintendoAccount"}, // 3.0.0+ {299, nullptr, "SuspendBackgroundDaemon"}, - {997, nullptr, "DebugInvalidateTokenCacheForUser"}, + {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+ {998, nullptr, "DebugSetUserStateClose"}, {999, nullptr, "DebugSetUserStateOpen"}, }; diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index fb4e7e772..49f6e20f1 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -17,23 +17,23 @@ ACC_U0::ACC_U0(std::shared_ptr module, std::shared_ptr p {3, &ACC_U0::ListOpenUsers, "ListOpenUsers"}, {4, &ACC_U0::GetLastOpenedUser, "GetLastOpenedUser"}, {5, &ACC_U0::GetProfile, "GetProfile"}, - {6, nullptr, "GetProfileDigest"}, + {6, nullptr, "GetProfileDigest"}, // 3.0.0+ {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, - {60, nullptr, "ListOpenContextStoredUsers"}, - {99, nullptr, "DebugActivateOpenContextRetention"}, + {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 + {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, {102, nullptr, "AuthenticateApplicationAsync"}, - {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, + {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ {110, nullptr, "StoreSaveDataThumbnail"}, {111, nullptr, "ClearSaveDataThumbnail"}, {120, nullptr, "CreateGuestLoginRequest"}, - {130, nullptr, "LoadOpenContext"}, - {131, nullptr, "ListOpenContextStoredUsers"}, - {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, - {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, - {150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, + {130, nullptr, "LoadOpenContext"}, // 5.0.0+ + {131, nullptr, "ListOpenContextStoredUsers"}, // 6.0.0+ + {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ + {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ + {150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, // 6.0.0+ }; // clang-format on diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index 9f29cdc82..f47004f84 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -17,28 +17,29 @@ ACC_U1::ACC_U1(std::shared_ptr module, std::shared_ptr p {3, &ACC_U1::ListOpenUsers, "ListOpenUsers"}, {4, &ACC_U1::GetLastOpenedUser, "GetLastOpenedUser"}, {5, &ACC_U1::GetProfile, "GetProfile"}, - {6, nullptr, "GetProfileDigest"}, + {6, nullptr, "GetProfileDigest"}, // 3.0.0+ {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, - {60, nullptr, "ListOpenContextStoredUsers"}, - {99, nullptr, "DebugActivateOpenContextRetention"}, + {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 + {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ {100, nullptr, "GetUserRegistrationNotifier"}, {101, nullptr, "GetUserStateChangeNotifier"}, {102, nullptr, "GetBaasAccountManagerForSystemService"}, - {103, nullptr, "GetProfileUpdateNotifier"}, - {104, nullptr, "CheckNetworkServiceAvailabilityAsync"}, - {105, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, - {106, nullptr, "GetProfileSyncNotifier"}, + {103, nullptr, "GetBaasUserAvailabilityChangeNotifier"}, + {104, nullptr, "GetProfileUpdateNotifier"}, + {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+ + {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+ {110, nullptr, "StoreSaveDataThumbnail"}, {111, nullptr, "ClearSaveDataThumbnail"}, {112, nullptr, "LoadSaveDataThumbnail"}, - {113, nullptr, "GetSaveDataThumbnailExistence"}, - {130, nullptr, "ActivateOpenContextRetention"}, - {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, - {150, nullptr, "AuthenticateApplicationAsync"}, - {190, nullptr, "GetUserLastOpenedApplication"}, - {191, nullptr, "ActivateOpenContextHolder"}, - {997, nullptr, "DebugInvalidateTokenCacheForUser"}, + {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+ + {120, nullptr, "ListOpenUsersInApplication"}, // 10.0.0+ + {130, nullptr, "ActivateOpenContextRetention"}, // 6.0.0+ + {140, &ACC_U1::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ + {150, nullptr, "AuthenticateApplicationAsync"}, // 10.0.0+ + {190, nullptr, "GetUserLastOpenedApplication"}, // 1.0.0 - 9.2.0 + {191, nullptr, "ActivateOpenContextHolder"}, // 7.0.0+ + {997, nullptr, "DebugInvalidateTokenCacheForUser"}, // 3.0.0+ {998, nullptr, "DebugSetUserStateClose"}, {999, nullptr, "DebugSetUserStateOpen"}, }; -- cgit v1.2.3 From 45dac6bc5cce693cf7affdfaffff433be8acd67f Mon Sep 17 00:00:00 2001 From: Morph Date: Mon, 22 Jun 2020 22:53:31 -0400 Subject: lm: Silence no return value warning --- src/core/hle/service/lm/manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/lm/manager.cpp b/src/core/hle/service/lm/manager.cpp index b67081b86..3ee2374e7 100644 --- a/src/core/hle/service/lm/manager.cpp +++ b/src/core/hle/service/lm/manager.cpp @@ -86,7 +86,8 @@ std::string FormatField(Field type, const std::vector& data) { return Common::StringFromFixedZeroTerminatedBuffer( reinterpret_cast(data.data()), data.size()); default: - UNIMPLEMENTED(); + UNIMPLEMENTED_MSG("Unimplemented field type={}", type); + return ""; } } -- cgit v1.2.3 From 5226610a15cc3bc90d2f3d8a755f3cff05717c56 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Wed, 13 May 2020 14:50:43 +1000 Subject: Implement GetKeyCodeMap & GetKeyCodeMap2 Closes #3919 --- src/core/hle/service/set/set.cpp | 72 ++++++++++++++++++++++++++++++++++++++-- src/core/hle/service/set/set.h | 2 ++ 2 files changed, 72 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index f3b4b286c..bb0685eed 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" @@ -31,6 +32,44 @@ constexpr std::array available_language_codes = {{ LanguageCode::ZH_HANT, }}; +enum class KeyboardLayout : u64 { + Japanese = 0, + EnglishUs = 1, + EnglishUsInternational = 2, + EnglishUk = 3, + French = 4, + FrenchCa = 5, + Spanish = 6, + SpanishLatin = 7, + German = 8, + Italian = 9, + Portuguese = 10, + Russian = 11, + Korean = 12, + ChineseSimplified = 13, + ChineseTraditional = 14, +}; + +constexpr std::array, 17> language_to_layout{{ + {LanguageCode::JA, KeyboardLayout::Japanese}, + {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, + {LanguageCode::FR, KeyboardLayout::French}, + {LanguageCode::DE, KeyboardLayout::German}, + {LanguageCode::IT, KeyboardLayout::Italian}, + {LanguageCode::ES, KeyboardLayout::Spanish}, + {LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified}, + {LanguageCode::KO, KeyboardLayout::Korean}, + {LanguageCode::NL, KeyboardLayout::EnglishUsInternational}, + {LanguageCode::PT, KeyboardLayout::Portuguese}, + {LanguageCode::RU, KeyboardLayout::Russian}, + {LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional}, + {LanguageCode::EN_GB, KeyboardLayout::EnglishUk}, + {LanguageCode::FR_CA, KeyboardLayout::FrenchCa}, + {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, + {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, + {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, +}}; + constexpr std::size_t pre4_0_0_max_entries = 15; constexpr std::size_t post4_0_0_max_entries = 17; @@ -120,6 +159,35 @@ void SET::GetRegionCode(Kernel::HLERequestContext& ctx) { rb.Push(Settings::values.region_index); } +void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) { + const auto language_code = available_language_codes[Settings::values.language_index]; + const auto key_code = + std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), + [=](const auto& element) { return element.first == language_code; }); + KeyboardLayout layout = KeyboardLayout::EnglishUs; + if (key_code == language_to_layout.cend()) { + LOG_ERROR(Service_SET, + "Could not find keyboard layout for language index {} defaulting to english us", + Settings::values.language_index); + } else { + layout = key_code->second; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + ctx.WriteBuffer(&layout, sizeof(KeyboardLayout)); +} + +void SET::GetKeyCodeMap(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); + GetKeyCodeMapImpl(ctx); +} + +void SET::GetKeyCodeMap2(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); + GetKeyCodeMapImpl(ctx); +} + SET::SET() : ServiceFramework("set") { // clang-format off static const FunctionInfo functions[] = { @@ -130,9 +198,9 @@ SET::SET() : ServiceFramework("set") { {4, &SET::GetRegionCode, "GetRegionCode"}, {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, - {7, nullptr, "GetKeyCodeMap"}, + {7, &SET::GetKeyCodeMap, "GetKeyCodeMap"}, {8, &SET::GetQuestFlag, "GetQuestFlag"}, - {9, nullptr, "GetKeyCodeMap2"}, + {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, {10, nullptr, "GetFirmwareVersionForDebug"}, }; // clang-format on diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 6084b345d..8ac9c169d 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -44,6 +44,8 @@ private: void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); void GetQuestFlag(Kernel::HLERequestContext& ctx); void GetRegionCode(Kernel::HLERequestContext& ctx); + void GetKeyCodeMap(Kernel::HLERequestContext& ctx); + void GetKeyCodeMap2(Kernel::HLERequestContext& ctx); }; } // namespace Service::Set -- cgit v1.2.3 From e3d2b646e09cd144f7dfc624dceb441327fb1c95 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Wed, 24 Jun 2020 12:07:41 +1000 Subject: Fixed logging output --- src/core/hle/service/set/set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index bb0685eed..7daf980ac 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -167,7 +167,7 @@ void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) { KeyboardLayout layout = KeyboardLayout::EnglishUs; if (key_code == language_to_layout.cend()) { LOG_ERROR(Service_SET, - "Could not find keyboard layout for language index {} defaulting to english us", + "Could not find keyboard layout for language index {}, defaulting to English us", Settings::values.language_index); } else { layout = key_code->second; -- cgit v1.2.3 From 380fbd8cb785aed3594bdcb3f17f9f6d28baa624 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Wed, 24 Jun 2020 13:05:08 +1000 Subject: Move GetKeyCodeMapImpl to an anonymous namespace --- src/core/hle/service/set/set.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 7daf980ac..e5cfd2101 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -89,6 +89,25 @@ void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t m ctx.WriteBuffer(available_language_codes.data(), copy_size); PushResponseLanguageCode(ctx, copy_amount); } + +void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) { + const auto language_code = available_language_codes[Settings::values.language_index]; + const auto key_code = + std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), + [=](const auto& element) { return element.first == language_code; }); + KeyboardLayout layout = KeyboardLayout::EnglishUs; + if (key_code == language_to_layout.cend()) { + LOG_ERROR(Service_SET, + "Could not find keyboard layout for language index {}, defaulting to English us", + Settings::values.language_index); + } else { + layout = key_code->second; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + ctx.WriteBuffer(&layout, sizeof(KeyboardLayout)); +} } // Anonymous namespace LanguageCode GetLanguageCodeFromIndex(std::size_t index) { @@ -159,25 +178,6 @@ void SET::GetRegionCode(Kernel::HLERequestContext& ctx) { rb.Push(Settings::values.region_index); } -void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) { - const auto language_code = available_language_codes[Settings::values.language_index]; - const auto key_code = - std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), - [=](const auto& element) { return element.first == language_code; }); - KeyboardLayout layout = KeyboardLayout::EnglishUs; - if (key_code == language_to_layout.cend()) { - LOG_ERROR(Service_SET, - "Could not find keyboard layout for language index {}, defaulting to English us", - Settings::values.language_index); - } else { - layout = key_code->second; - } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - ctx.WriteBuffer(&layout, sizeof(KeyboardLayout)); -} - void SET::GetKeyCodeMap(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); GetKeyCodeMapImpl(ctx); -- cgit v1.2.3 From 82ecdd0104802c917a1f321f48576aba6964438c Mon Sep 17 00:00:00 2001 From: David Marcec Date: Wed, 24 Jun 2020 22:50:27 +1000 Subject: Mark invalid IPC buffers as ASSERT_OR_EXECUTE_MSG Previously if applications would send faulty buffers(example homebrew) it would lead to us returning uninitalized data. Switching from ASSERT_MSG to ASSERT_OR_EXECUTE_MSG allows us to have a fail safe to prevent crashes but also continue execution without introducing undefined behavior --- src/core/hle/kernel/hle_ipc.cpp | 47 +++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ba0eac4c2..0d01a7047 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -282,18 +282,18 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { } std::vector HLERequestContext::ReadBuffer(std::size_t buffer_index) const { - std::vector buffer; + std::vector buffer{}; const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && BufferDescriptorA()[buffer_index].Size()}; if (is_buffer_a) { - ASSERT_MSG(BufferDescriptorA().size() > buffer_index, - "BufferDescriptorA invalid buffer_index {}", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return buffer; }, + "BufferDescriptorA invalid buffer_index {}", buffer_index); buffer.resize(BufferDescriptorA()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); } else { - ASSERT_MSG(BufferDescriptorX().size() > buffer_index, - "BufferDescriptorX invalid buffer_index {}", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return buffer; }, + "BufferDescriptorX invalid buffer_index {}", buffer_index); buffer.resize(BufferDescriptorX()[buffer_index].Size()); memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); } @@ -318,16 +318,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size, } if (is_buffer_b) { - ASSERT_MSG(BufferDescriptorB().size() > buffer_index, - "BufferDescriptorB invalid buffer_index {}", buffer_index); - ASSERT_MSG(BufferDescriptorB()[buffer_index].Size() >= size, - "BufferDescriptorB buffer_index {} is not large enough", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index && + BufferDescriptorB()[buffer_index].Size() >= size, + { return 0; }, "BufferDescriptorB is invalid, index={}, size={}", + buffer_index, size); memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); } else { - ASSERT_MSG(BufferDescriptorC().size() > buffer_index, - "BufferDescriptorC invalid buffer_index {}", buffer_index); - ASSERT_MSG(BufferDescriptorC()[buffer_index].Size() >= size, - "BufferDescriptorC buffer_index {} is not large enough", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index && + BufferDescriptorC()[buffer_index].Size() >= size, + { return 0; }, "BufferDescriptorC is invalid, index={}, size={}", + buffer_index, size); memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); } @@ -338,16 +338,12 @@ std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && BufferDescriptorA()[buffer_index].Size()}; if (is_buffer_a) { - ASSERT_MSG(BufferDescriptorA().size() > buffer_index, - "BufferDescriptorA invalid buffer_index {}", buffer_index); - ASSERT_MSG(BufferDescriptorA()[buffer_index].Size() > 0, - "BufferDescriptorA buffer_index {} is empty", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return 0; }, + "BufferDescriptorA invalid buffer_index {}", buffer_index); return BufferDescriptorA()[buffer_index].Size(); } else { - ASSERT_MSG(BufferDescriptorX().size() > buffer_index, - "BufferDescriptorX invalid buffer_index {}", buffer_index); - ASSERT_MSG(BufferDescriptorX()[buffer_index].Size() > 0, - "BufferDescriptorX buffer_index {} is empty", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return 0; }, + "BufferDescriptorX invalid buffer_index {}", buffer_index); return BufferDescriptorX()[buffer_index].Size(); } } @@ -356,14 +352,15 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && BufferDescriptorB()[buffer_index].Size()}; if (is_buffer_b) { - ASSERT_MSG(BufferDescriptorB().size() > buffer_index, - "BufferDescriptorB invalid buffer_index {}", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index, { return 0; }, + "BufferDescriptorB invalid buffer_index {}", buffer_index); return BufferDescriptorB()[buffer_index].Size(); } else { - ASSERT_MSG(BufferDescriptorC().size() > buffer_index, - "BufferDescriptorC invalid buffer_index {}", buffer_index); + ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index, { return 0; }, + "BufferDescriptorC invalid buffer_index {}", buffer_index); return BufferDescriptorC()[buffer_index].Size(); } + return 0; } std::string HLERequestContext::Description() const { -- cgit v1.2.3 From 2f0b322e721625def489f1dfaf9eb061e2eedb9a Mon Sep 17 00:00:00 2001 From: David Marcec Date: Wed, 24 Jun 2020 23:01:00 +1000 Subject: prepo: : Don't read extra buffer from report unless passed Prepo doesn't always pass a secondary buffer, we assume it always does which leads to a bad read. --- src/core/hle/service/prepo/prepo.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 14309c679..67833d9af 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -75,8 +75,13 @@ private: const auto user_id = rp.PopRaw(); const auto process_id = rp.PopRaw(); std::vector> data{ctx.ReadBuffer(0)}; + if constexpr (Type == Core::Reporter::PlayReportType::Old2) { - data.emplace_back(ctx.ReadBuffer(1)); + const auto read_buffer_count = + ctx.BufferDescriptorX().size() + ctx.BufferDescriptorA().size(); + if (read_buffer_count > 1) { + data.emplace_back(ctx.ReadBuffer(1)); + } } LOG_DEBUG( -- cgit v1.2.3 From 510838759f2315f21b0dcb8b27f840b489e1f63c Mon Sep 17 00:00:00 2001 From: David Marcec Date: Thu, 25 Jun 2020 00:25:15 +1000 Subject: Prevent nullptr dereference on swkbd error case --- src/core/hle/service/am/applets/software_keyboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index d14076b02..fbe3686ae 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp @@ -60,7 +60,7 @@ void SoftwareKeyboard::Initialize() { std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); const auto work_buffer_storage = broker.PopNormalDataToApplet(); - ASSERT(work_buffer_storage != nullptr); + ASSERT_OR_EXECUTE(work_buffer_storage != nullptr, { return; }); const auto& work_buffer = work_buffer_storage->GetData(); if (config.initial_string_size == 0) -- cgit v1.2.3 From 2c9308954c0a7cc7e8f9b12508ff28f570ffe3e9 Mon Sep 17 00:00:00 2001 From: Morph Date: Mon, 22 Jun 2020 05:37:46 -0400 Subject: hid: Stub a series of "SevenSixAxisSensor" service commands - Used by Captain Toad: Treasure Tracker Update 1.3.0 While we're at it, fix the input parameters for SetIsPalmaAllConnectable and SetPalmaBoostMode --- src/core/hle/service/hid/hid.cpp | 93 ++++++++++++++++++++++++++++++++-------- src/core/hle/service/hid/hid.h | 13 ++++-- 2 files changed, 85 insertions(+), 21 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 72a050de2..1ee99bfeb 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -230,15 +230,15 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { {211, nullptr, "IsVibrationDeviceMounted"}, {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, - {302, nullptr, "StopConsoleSixAxisSensor"}, - {303, nullptr, "ActivateSevenSixAxisSensor"}, - {304, nullptr, "StartSevenSixAxisSensor"}, + {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, + {303, &Hid::ActivateSevenSixAxisSensor, "ActivateSevenSixAxisSensor"}, + {304, &Hid::StartSevenSixAxisSensor, "StartSevenSixAxisSensor"}, {305, &Hid::StopSevenSixAxisSensor, "StopSevenSixAxisSensor"}, {306, &Hid::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"}, - {307, nullptr, "FinalizeSevenSixAxisSensor"}, + {307, &Hid::FinalizeSevenSixAxisSensor, "FinalizeSevenSixAxisSensor"}, {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, - {310, nullptr, "ResetSevenSixAxisSensorTimestamp"}, + {310, &Hid::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"}, {400, nullptr, "IsUsbFullKeyControllerEnabled"}, {401, nullptr, "EnableUsbFullKeyController"}, {402, nullptr, "IsUsbFullKeyControllerConnected"}, @@ -374,6 +374,15 @@ void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } +void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto flags{rp.Pop()}; + LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto unknown{rp.Pop()}; @@ -413,6 +422,18 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } +void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto handle{rp.Pop()}; + const auto applet_resource_user_id{rp.Pop()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto handle{rp.Pop()}; @@ -832,33 +853,35 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { +void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto handle{rp.Pop()}; + const auto applet_resource_user_id{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called, handle={}", handle); + LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { +void Hid::ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop()}; - const auto unknown{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}, unknown={}", - applet_resource_user_id, unknown); + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } -void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { +void Hid::StartSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto unknown{rp.Pop()}; + const auto applet_resource_user_id{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}", unknown); + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); @@ -882,10 +905,46 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { +void Hid::FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto flags{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); + const auto applet_resource_user_id{rp.Pop()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop()}; + const auto is_palma_all_connectable{rp.Pop()}; + + LOG_WARNING(Service_HID, + "(STUBBED) called, applet_resource_user_id={}, is_palma_all_connectable={}", + applet_resource_user_id, is_palma_all_connectable); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + +void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto palma_boost_mode{rp.Pop()}; + + LOG_WARNING(Service_HID, "(STUBBED) called, palma_boost_mode={}", palma_boost_mode); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index d481a75f8..ffce5ba45 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -91,9 +91,11 @@ private: void ActivateTouchScreen(Kernel::HLERequestContext& ctx); void ActivateMouse(Kernel::HLERequestContext& ctx); void ActivateKeyboard(Kernel::HLERequestContext& ctx); + void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); void ActivateGesture(Kernel::HLERequestContext& ctx); void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); void StartSixAxisSensor(Kernel::HLERequestContext& ctx); + void StopSixAxisSensor(Kernel::HLERequestContext& ctx); void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); @@ -126,12 +128,15 @@ private: void IsVibrationPermitted(Kernel::HLERequestContext& ctx); void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); - void StopSixAxisSensor(Kernel::HLERequestContext& ctx); - void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); - void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); + void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); + void ActivateSevenSixAxisSensor(Kernel::HLERequestContext& ctx); + void StartSevenSixAxisSensor(Kernel::HLERequestContext& ctx); void StopSevenSixAxisSensor(Kernel::HLERequestContext& ctx); void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx); - void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); + void FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx); + void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx); + void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); + void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); std::shared_ptr applet_resource; Core::System& system; -- cgit v1.2.3 From 38868e575090887f3c652c86ad2d08e5fbc8f891 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Thu, 25 Jun 2020 16:35:58 +1000 Subject: memory_manager: Remove useless assertion num_pages is an std::size_t. It will always be >= 0 --- src/core/hle/kernel/memory/memory_manager.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/memory/memory_manager.cpp index 616148190..acf13585c 100644 --- a/src/core/hle/kernel/memory/memory_manager.cpp +++ b/src/core/hle/kernel/memory/memory_manager.cpp @@ -139,7 +139,6 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa } // Only succeed if we allocated as many pages as we wanted - ASSERT(num_pages >= 0); if (num_pages) { return ERR_OUT_OF_MEMORY; } -- cgit v1.2.3 From 02a33feef44cac4b5f60d3fb5c33ad0deff189be Mon Sep 17 00:00:00 2001 From: Morph Date: Thu, 25 Jun 2020 01:58:13 -0400 Subject: caps: Update copyright headers Updated to "yuzu Emulator Project" --- src/core/hle/service/caps/caps.cpp | 2 +- src/core/hle/service/caps/caps.h | 2 +- src/core/hle/service/caps/caps_a.cpp | 2 +- src/core/hle/service/caps/caps_a.h | 2 +- src/core/hle/service/caps/caps_c.cpp | 2 +- src/core/hle/service/caps/caps_c.h | 2 +- src/core/hle/service/caps/caps_sc.cpp | 2 +- src/core/hle/service/caps/caps_sc.h | 2 +- src/core/hle/service/caps/caps_ss.cpp | 2 +- src/core/hle/service/caps/caps_ss.h | 2 +- src/core/hle/service/caps/caps_su.cpp | 2 +- src/core/hle/service/caps/caps_su.h | 2 +- src/core/hle/service/caps/caps_u.cpp | 2 +- src/core/hle/service/caps/caps_u.h | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp index 26c8a7081..ba5749b84 100644 --- a/src/core/hle/service/caps/caps.cpp +++ b/src/core/hle/service/caps/caps.cpp @@ -1,4 +1,4 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2018 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h index fc70a4c27..e01b47349 100644 --- a/src/core/hle/service/caps/caps.h +++ b/src/core/hle/service/caps/caps.h @@ -1,4 +1,4 @@ -// Copyright 2018 yuzu emulator team +// Copyright 2018 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp index 88a3fdc05..a0a3b2ae3 100644 --- a/src/core/hle/service/caps/caps_a.cpp +++ b/src/core/hle/service/caps/caps_a.cpp @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h index 8de832491..cb93aad5b 100644 --- a/src/core/hle/service/caps/caps_a.h +++ b/src/core/hle/service/caps/caps_a.h @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp index ea6452ffa..ab17a187e 100644 --- a/src/core/hle/service/caps/caps_c.cpp +++ b/src/core/hle/service/caps/caps_c.cpp @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h index d07cdb441..a9d028689 100644 --- a/src/core/hle/service/caps/caps_c.h +++ b/src/core/hle/service/caps/caps_c.h @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_sc.cpp b/src/core/hle/service/caps/caps_sc.cpp index d01a8a58e..822ee96c8 100644 --- a/src/core/hle/service/caps/caps_sc.cpp +++ b/src/core/hle/service/caps/caps_sc.cpp @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_sc.h b/src/core/hle/service/caps/caps_sc.h index 9ba372f7a..ac3e929ca 100644 --- a/src/core/hle/service/caps/caps_sc.h +++ b/src/core/hle/service/caps/caps_sc.h @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp index eaa3a7494..24dc716e7 100644 --- a/src/core/hle/service/caps/caps_ss.cpp +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h index e258a6925..450686e4f 100644 --- a/src/core/hle/service/caps/caps_ss.h +++ b/src/core/hle/service/caps/caps_ss.h @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index e8b0698e8..fffb2ecf9 100644 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h index c494d7c84..62c9603a9 100644 --- a/src/core/hle/service/caps/caps_su.h +++ b/src/core/hle/service/caps/caps_su.h @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp index 78bab6ed8..34f7f3881 100644 --- a/src/core/hle/service/caps/caps_u.cpp +++ b/src/core/hle/service/caps/caps_u.cpp @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h index e6e0716ff..689364de4 100644 --- a/src/core/hle/service/caps/caps_u.h +++ b/src/core/hle/service/caps/caps_u.h @@ -1,4 +1,4 @@ -// Copyright 2020 yuzu emulator team +// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -- cgit v1.2.3 From 3017be7855c3d4d9711b39fd5d0f41b652721348 Mon Sep 17 00:00:00 2001 From: Morph Date: Thu, 25 Jun 2020 01:59:16 -0400 Subject: caps: Use enum classes and check struct sizes on compile time --- src/core/hle/service/caps/caps.h | 74 ++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 34 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h index e01b47349..b8c67b6e2 100644 --- a/src/core/hle/service/caps/caps.h +++ b/src/core/hle/service/caps/caps.h @@ -12,73 +12,79 @@ class ServiceManager; namespace Service::Capture { -enum AlbumImageOrientation { +enum class AlbumImageOrientation { Orientation0 = 0, Orientation1 = 1, Orientation2 = 2, Orientation3 = 3, }; -enum AlbumReportOption { +enum class AlbumReportOption { Disable = 0, Enable = 1, }; -enum ContentType : u8 { +enum class ContentType : u8 { Screenshot = 0, Movie = 1, ExtraMovie = 3, }; -enum AlbumStorage : u8 { +enum class AlbumStorage : u8 { NAND = 0, SD = 1, }; struct AlbumFileDateTime { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 minute; - u8 second; - u8 uid; + s16 year{}; + s8 month{}; + s8 day{}; + s8 hour{}; + s8 minute{}; + s8 second{}; + s8 uid{}; }; +static_assert(sizeof(AlbumFileDateTime) == 0x8, "AlbumFileDateTime has incorrect size."); struct AlbumEntry { - u64 size; - u64 application_id; - AlbumFileDateTime datetime; - AlbumStorage storage; - ContentType content; - u8 padding[6]; + u64 size{}; + u64 application_id{}; + AlbumFileDateTime datetime{}; + AlbumStorage storage{}; + ContentType content{}; + INSERT_PADDING_BYTES(6); }; +static_assert(sizeof(AlbumEntry) == 0x20, "AlbumEntry has incorrect size."); struct AlbumFileEntry { - u64 size; - u64 hash; - AlbumFileDateTime datetime; - AlbumStorage storage; - ContentType content; - u8 padding[5]; - u8 unknown; + u64 size{}; // Size of the entry + u64 hash{}; // AES256 with hardcoded key over AlbumEntry + AlbumFileDateTime datetime{}; + AlbumStorage storage{}; + ContentType content{}; + INSERT_PADDING_BYTES(5); + u8 unknown{1}; // Set to 1 on official SW }; +static_assert(sizeof(AlbumFileEntry) == 0x20, "AlbumFileEntry has incorrect size."); struct ApplicationAlbumEntry { - u64 size; - u64 hash; - AlbumFileDateTime datetime; - AlbumStorage storage; - ContentType content; - u8 padding[5]; - u8 unknown; + u64 size{}; // Size of the entry + u64 hash{}; // AES256 with hardcoded key over AlbumEntry + AlbumFileDateTime datetime{}; + AlbumStorage storage{}; + ContentType content{}; + INSERT_PADDING_BYTES(5); + u8 unknown{1}; // Set to 1 on official SW }; +static_assert(sizeof(ApplicationAlbumEntry) == 0x20, "ApplicationAlbumEntry has incorrect size."); struct ApplicationAlbumFileEntry { - ApplicationAlbumEntry entry; - AlbumFileDateTime datetime; - u64 unknown; + ApplicationAlbumEntry entry{}; + AlbumFileDateTime datetime{}; + u64 unknown{}; }; +static_assert(sizeof(ApplicationAlbumFileEntry) == 0x30, + "ApplicationAlbumFileEntry has incorrect size."); /// Registers all Capture services with the specified service manager. void InstallInterfaces(SM::ServiceManager& sm); -- cgit v1.2.3 From 72f14ae21f93663c74aec7e12f23d6dc52a7350c Mon Sep 17 00:00:00 2001 From: Morph Date: Thu, 25 Jun 2020 02:00:25 -0400 Subject: caps_u: Fix GetAlbumContentsFileListForApplication stub --- src/core/hle/service/caps/caps_u.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp index 34f7f3881..f36d8de2d 100644 --- a/src/core/hle/service/caps/caps_u.cpp +++ b/src/core/hle/service/caps/caps_u.cpp @@ -58,19 +58,25 @@ void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& c // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total // output entries (which is copied to a s32 by official SW). IPC::RequestParser rp{ctx}; - [[maybe_unused]] const auto application_album_file_entries = rp.PopRaw>(); - const auto pid = rp.Pop(); - const auto content_type = rp.PopRaw(); - [[maybe_unused]] const auto start_datetime = rp.PopRaw(); - [[maybe_unused]] const auto end_datetime = rp.PopRaw(); - const auto applet_resource_user_id = rp.Pop(); + const auto pid{rp.Pop()}; + const auto content_type{rp.PopEnum()}; + const auto start_posix_time{rp.Pop()}; + const auto end_posix_time{rp.Pop()}; + const auto applet_resource_user_id{rp.Pop()}; + + // TODO: Update this when we implement the album. + // Currently we do not have a method of accessing album entries, set this to 0 for now. + constexpr s32 total_entries{0}; + LOG_WARNING(Service_Capture, - "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid, - content_type, applet_resource_user_id); + "(STUBBED) called. pid={}, content_type={}, start_posix_time={}, " + "end_posix_time={}, applet_resource_user_id={}, total_entries={}", + pid, content_type, start_posix_time, end_posix_time, applet_resource_user_id, + total_entries); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - rb.Push(0); + rb.Push(total_entries); } } // namespace Service::Capture -- cgit v1.2.3 From d3e9b45ce0327d6497884f796410682f4f1ed708 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 01:57:48 +0200 Subject: btm: Update function tables This was based on Switchbrew page: https://switchbrew.org/wiki/BTM_services "No comment" edition--- src/core/hle/service/btm/btm.cpp | 147 ++++++++++++++++++++------------------- 1 file changed, 76 insertions(+), 71 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index 251b3c9df..f6539a7a4 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -132,66 +132,71 @@ public: explicit BTM() : ServiceFramework{"btm"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "Unknown1"}, - {1, nullptr, "Unknown2"}, - {2, nullptr, "RegisterSystemEventForConnectedDeviceCondition"}, - {3, nullptr, "Unknown3"}, - {4, nullptr, "Unknown4"}, - {5, nullptr, "Unknown5"}, - {6, nullptr, "Unknown6"}, - {7, nullptr, "Unknown7"}, - {8, nullptr, "RegisterSystemEventForRegisteredDeviceInfo"}, - {9, nullptr, "Unknown8"}, - {10, nullptr, "Unknown9"}, - {11, nullptr, "Unknown10"}, - {12, nullptr, "Unknown11"}, - {13, nullptr, "Unknown12"}, + {0, nullptr, "GetState"}, + {1, nullptr, "GetHostDeviceProperty"}, + {2, nullptr, "AcquireDeviceConditionEvent"}, + {3, nullptr, "GetDeviceCondition"}, + {4, nullptr, "SetBurstMode"}, + {5, nullptr, "SetSlotMode"}, + {6, nullptr, "SetBluetoothMode"}, + {7, nullptr, "SetWlanMode"}, + {8, nullptr, "AcquireDeviceInfoEvent"}, + {9, nullptr, "GetDeviceInfo"}, + {10, nullptr, "AddDeviceInfo"}, + {11, nullptr, "RemoveDeviceInfo"}, + {12, nullptr, "IncreaseDeviceInfoOrder"}, + {13, nullptr, "LlrNotify"}, {14, nullptr, "EnableRadio"}, {15, nullptr, "DisableRadio"}, - {16, nullptr, "Unknown13"}, - {17, nullptr, "Unknown14"}, - {18, nullptr, "Unknown15"}, - {19, nullptr, "Unknown16"}, - {20, nullptr, "Unknown17"}, - {21, nullptr, "Unknown18"}, - {22, nullptr, "Unknown19"}, - {23, nullptr, "Unknown20"}, - {24, nullptr, "Unknown21"}, - {25, nullptr, "Unknown22"}, - {26, nullptr, "Unknown23"}, - {27, nullptr, "Unknown24"}, - {28, nullptr, "Unknown25"}, - {29, nullptr, "Unknown26"}, - {30, nullptr, "Unknown27"}, - {31, nullptr, "Unknown28"}, - {32, nullptr, "Unknown29"}, - {33, nullptr, "Unknown30"}, - {34, nullptr, "Unknown31"}, - {35, nullptr, "Unknown32"}, - {36, nullptr, "Unknown33"}, - {37, nullptr, "Unknown34"}, - {38, nullptr, "Unknown35"}, - {39, nullptr, "Unknown36"}, - {40, nullptr, "Unknown37"}, - {41, nullptr, "Unknown38"}, - {42, nullptr, "Unknown39"}, - {43, nullptr, "Unknown40"}, - {44, nullptr, "Unknown41"}, - {45, nullptr, "Unknown42"}, - {46, nullptr, "Unknown43"}, - {47, nullptr, "Unknown44"}, - {48, nullptr, "Unknown45"}, - {49, nullptr, "Unknown46"}, - {50, nullptr, "Unknown47"}, - {51, nullptr, "Unknown48"}, - {52, nullptr, "Unknown49"}, - {53, nullptr, "Unknown50"}, - {54, nullptr, "Unknown51"}, - {55, nullptr, "Unknown52"}, - {56, nullptr, "Unknown53"}, - {57, nullptr, "Unknown54"}, - {58, nullptr, "Unknown55"}, - {59, nullptr, "Unknown56"}, + {16, nullptr, "HidDisconnect"}, + {17, nullptr, "HidSetRetransmissionMode"}, + {18, nullptr, "AcquireAwakeReqEvent"}, + {19, nullptr, "AcquireLlrStateEvent"}, + {20, nullptr, "IsLlrStarted"}, + {21, nullptr, "EnableSlotSaving"}, + {22, nullptr, "ProtectDeviceInfo"}, + {23, nullptr, "AcquireBleScanEvent"}, + {24, nullptr, "GetBleScanParameterGeneral"}, + {25, nullptr, "GetBleScanParameterSmartDevice"}, + {26, nullptr, "StartBleScanForGeneral"}, + {27, nullptr, "StopBleScanForGeneral"}, + {28, nullptr, "GetBleScanResultsForGeneral"}, + {29, nullptr, "StartBleScanForPairedDevice"}, + {30, nullptr, "StopBleScanForPairedDevice"}, + {31, nullptr, "StartBleScanForSmartDevice"}, + {32, nullptr, "StopBleScanForSmartDevice"}, + {33, nullptr, "GetBleScanResultsForSmartDevice"}, + {34, nullptr, "AcquireBleConnectionEvent"}, + {35, nullptr, "BleConnect"}, + {36, nullptr, "BleOverrideConnection"}, + {37, nullptr, "BleDisconnect"}, + {38, nullptr, "BleGetConnectionState"}, + {39, nullptr, "BleGetGattClientConditionList"}, + {40, nullptr, "AcquireBlePairingEvent"}, + {41, nullptr, "BlePairDevice"}, + {42, nullptr, "BleUnpairDeviceOnBoth"}, + {43, nullptr, "BleUnpairDevice"}, + {44, nullptr, "BleGetPairedAddresses"}, + {45, nullptr, "AcquireBleServiceDiscoveryEvent"}, + {46, nullptr, "GetGattServices"}, + {47, nullptr, "GetGattService"}, + {48, nullptr, "GetGattIncludedServices"}, + {49, nullptr, "GetBelongingService"}, + {50, nullptr, "GetGattCharacteristics"}, + {51, nullptr, "GetGattDescriptors"}, + {52, nullptr, "AcquireBleMtuConfigEvent"}, + {53, nullptr, "ConfigureBleMtu"}, + {54, nullptr, "GetBleMtu"}, + {55, nullptr, "RegisterBleGattDataPath"}, + {56, nullptr, "UnregisterBleGattDataPath"}, + {57, nullptr, "RegisterAppletResourceUserId"}, + {58, nullptr, "UnregisterAppletResourceUserId"}, + {59, nullptr, "SetAppletResourceUserId"}, + {60, nullptr, "Unknown"}, + {61, nullptr, "Unknown2"}, + {62, nullptr, "Unknown3"}, + {63, nullptr, "Unknown4"}, + {64, nullptr, "Unknown5"}, }; // clang-format on @@ -204,19 +209,19 @@ public: explicit BTM_DBG() : ServiceFramework{"btm:dbg"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "RegisterSystemEventForDiscovery"}, - {1, nullptr, "Unknown1"}, - {2, nullptr, "Unknown2"}, - {3, nullptr, "Unknown3"}, - {4, nullptr, "Unknown4"}, - {5, nullptr, "Unknown5"}, - {6, nullptr, "Unknown6"}, - {7, nullptr, "Unknown7"}, - {8, nullptr, "Unknown8"}, - {9, nullptr, "Unknown9"}, - {10, nullptr, "Unknown10"}, - {11, nullptr, "Unknown11"}, - {12, nullptr, "Unknown11"}, + {0, nullptr, "AcquireDiscoveryEvent"}, + {1, nullptr, "StartDiscovery"}, + {2, nullptr, "CancelDiscovery"}, + {3, nullptr, "GetDeviceProperty"}, + {4, nullptr, "CreateBond"}, + {5, nullptr, "CancelBond"}, + {6, nullptr, "SetTsiMode"}, + {7, nullptr, "GeneralTest"}, + {8, nullptr, "HidConnect"}, + {9, nullptr, "GeneralGet"}, + {10, nullptr, "GetGattClientDisconnectionReason"}, + {11, nullptr, "GetBleConnectionParameter"}, + {12, nullptr, "GetBleConnectionParameterRequest"}, }; // clang-format on -- cgit v1.2.3 From 3828aa4927d604804f09bd2b8a307f3e50a8c986 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:17:51 +0200 Subject: es: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/ETicket_services--- src/core/hle/service/es/es.cpp | 43 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index f8e9df4b1..593772ee2 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -27,8 +27,8 @@ public: {8, &ETicket::GetTitleKey, "GetTitleKey"}, {9, &ETicket::CountCommonTicket, "CountCommonTicket"}, {10, &ETicket::CountPersonalizedTicket, "CountPersonalizedTicket"}, - {11, &ETicket::ListCommonTicket, "ListCommonTicket"}, - {12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicket"}, + {11, &ETicket::ListCommonTicket, "ListCommonTicketRightsIds"}, + {12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicketRightsIds"}, {13, nullptr, "ListMissingPersonalizedTicket"}, {14, &ETicket::GetCommonTicketSize, "GetCommonTicketSize"}, {15, &ETicket::GetPersonalizedTicketSize, "GetPersonalizedTicketSize"}, @@ -55,7 +55,46 @@ public: {36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"}, {37, nullptr, "OwnTicket2"}, {38, nullptr, "OwnTicket3"}, + {501, nullptr, "Unknown"}, + {502, nullptr, "Unknown2"}, {503, nullptr, "GetTitleKey"}, + {504, nullptr, "Unknown3"}, + {508, nullptr, "Unknown4"}, + {509, nullptr, "Unknown5"}, + {510, nullptr, "Unknown6"}, + {511, nullptr, "Unknown7"}, + {1001, nullptr, "Unknown8"}, + {1002, nullptr, "Unknown9"}, + {1003, nullptr, "Unknown10"}, + {1004, nullptr, "Unknown11"}, + {1005, nullptr, "Unknown12"}, + {1006, nullptr, "Unknown13"}, + {1007, nullptr, "Unknown14"}, + {1009, nullptr, "Unknown15"}, + {1010, nullptr, "Unknown16"}, + {1011, nullptr, "Unknown17"}, + {1012, nullptr, "Unknown18"}, + {1013, nullptr, "Unknown19"}, + {1014, nullptr, "Unknown20"}, + {1015, nullptr, "Unknown21"}, + {1016, nullptr, "Unknown22"}, + {1017, nullptr, "Unknown23"}, + {1018, nullptr, "Unknown24"}, + {1019, nullptr, "Unknown25"}, + {1020, nullptr, "Unknown26"}, + {1021, nullptr, "Unknown27"}, + {1501, nullptr, "Unknown28"}, + {1502, nullptr, "Unknown29"}, + {1503, nullptr, "Unknown30"}, + {1504, nullptr, "Unknown31"}, + {1505, nullptr, "Unknown32"}, + {2000, nullptr, "Unknown33"}, + {2001, nullptr, "Unknown34"}, + {2100, nullptr, "Unknown35"}, + {2501, nullptr, "Unknown36"}, + {2502, nullptr, "Unknown37"}, + {3001, nullptr, "Unknown38"}, + {3002, nullptr, "Unknown39"}, }; // clang-format on RegisterHandlers(functions); -- cgit v1.2.3 From 0f4a611129fd5b76ebdafd4f8c614b1257decae3 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:25:04 +0200 Subject: eupld: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/Error_Upload_services--- src/core/hle/service/eupld/eupld.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/eupld/eupld.cpp b/src/core/hle/service/eupld/eupld.cpp index 2df30acee..0d6d244f4 100644 --- a/src/core/hle/service/eupld/eupld.cpp +++ b/src/core/hle/service/eupld/eupld.cpp @@ -19,6 +19,7 @@ public: {1, nullptr, "ImportCrt"}, {2, nullptr, "ImportPki"}, {3, nullptr, "SetAutoUpload"}, + {4, nullptr, "GetAutoUpload"}, }; // clang-format on -- cgit v1.2.3 From b5d54619cc8cc3a4860f783c1a82255b2d87d7ee Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:31:44 +0200 Subject: aoc: Update function table (#4170) * aoc: Update function table * Remove comments--- src/core/hle/service/aoc/aoc_u.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 4227a4adf..8e79f707b 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp @@ -60,6 +60,7 @@ AOC_U::AOC_U(Core::System& system) {6, nullptr, "PrepareAddOnContentByApplicationId"}, {7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"}, {8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"}, + {9, nullptr, "GetAddOnContentLostErrorCode"}, {100, nullptr, "CreateEcPurchasedEventManager"}, {101, nullptr, "CreatePermanentEcPurchasedEventManager"}, }; -- cgit v1.2.3 From ca25a3845eed214ac3bd76d37c47739dfbd56865 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:32:26 +0200 Subject: am: Update function tables and add missing classes (#4169) * am: Update function tables and add missing classes * Remove comments (1/5) * Remove comments (2/5) * Remove comments (3/5) * Remove comments (4/5) * Remove comments (5/5) * Remove unused classes (1/2) * Remove unused classes (2/2)--- src/core/hle/service/am/am.cpp | 18 ++++++++++-------- src/core/hle/service/am/am.h | 2 +- src/core/hle/service/am/spsm.cpp | 16 ++++++++-------- 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 4df74c4f9..20f366635 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -68,6 +68,7 @@ IWindowController::IWindowController(Core::System& system_) static const FunctionInfo functions[] = { {0, nullptr, "CreateWindow"}, {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, + {2, nullptr, "GetAppletResourceUserIdOfCallerApplet"}, {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, {11, nullptr, "ReleaseForegroundRights"}, {12, nullptr, "RejectToChangeIntoBackground"}, @@ -189,8 +190,8 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController" {5, nullptr, "GetLastForegroundCaptureImageEx"}, {6, nullptr, "GetLastApplicationCaptureImageEx"}, {7, nullptr, "GetCallerAppletCaptureImageEx"}, - {8, nullptr, "TakeScreenShotOfOwnLayer"}, // 2.0.0+ - {9, nullptr, "CopyBetweenCaptureBuffers"}, // 5.0.0+ + {8, nullptr, "TakeScreenShotOfOwnLayer"}, + {9, nullptr, "CopyBetweenCaptureBuffers"}, {10, nullptr, "AcquireLastApplicationCaptureBuffer"}, {11, nullptr, "ReleaseLastApplicationCaptureBuffer"}, {12, nullptr, "AcquireLastForegroundCaptureBuffer"}, @@ -200,17 +201,14 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController" {16, nullptr, "AcquireLastApplicationCaptureBufferEx"}, {17, nullptr, "AcquireLastForegroundCaptureBufferEx"}, {18, nullptr, "AcquireCallerAppletCaptureBufferEx"}, - // 2.0.0+ {20, nullptr, "ClearCaptureBuffer"}, {21, nullptr, "ClearAppletTransitionBuffer"}, - // 4.0.0+ {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"}, {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"}, {24, nullptr, "AcquireLastForegroundCaptureSharedBuffer"}, {25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"}, {26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"}, {27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"}, - // 6.0.0+ {28, nullptr, "TakeScreenShotOfOwnLayerEx"}, }; // clang-format on @@ -225,7 +223,7 @@ IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} { static const FunctionInfo functions[] = { {0, nullptr, "NotifyMessageToHomeMenuForDebug"}, {1, nullptr, "OpenMainApplication"}, - {10, nullptr, "EmulateButtonEvent"}, + {10, nullptr, "PerformSystemButtonPressing"}, {20, nullptr, "InvalidateTransitionLayer"}, {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"}, {40, nullptr, "GetAppletResourceUsageInfo"}, @@ -267,7 +265,7 @@ ISelfController::ISelfController(Core::System& system, {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, {17, nullptr, "SetControllerFirmwareUpdateSection"}, {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, - {19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"}, + {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"}, {20, nullptr, "SetDesirableKeyboardLayout"}, {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, {41, nullptr, "IsSystemBufferSharingEnabled"}, @@ -443,7 +441,7 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& rb.Push(RESULT_SUCCESS); } -void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { +void ISelfController::SetAlbumImageOrientation(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; @@ -607,6 +605,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system, {20, nullptr, "PushToGeneralChannel"}, {30, nullptr, "GetHomeButtonReaderLockAccessor"}, {31, nullptr, "GetReaderLockAccessorEx"}, + {32, nullptr, "GetWriterLockAccessorEx"}, {40, nullptr, "GetCradleFwVersion"}, {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, @@ -1132,6 +1131,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {24, nullptr, "GetLaunchStorageInfoForDebug"}, {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"}, {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"}, + {27, nullptr, "CreateCacheStorage"}, {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"}, {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"}, {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, @@ -1157,6 +1157,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_) {120, nullptr, "ExecuteProgram"}, {121, nullptr, "ClearUserChannel"}, {122, nullptr, "UnpopToUserChannel"}, + {123, nullptr, "GetPreviousProgramIndex"}, + {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"}, {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"}, {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"}, {141, nullptr, "TryPopFromFriendInvitationStorageChannel"}, diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 469f7f814..2f69466ec 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -138,7 +138,7 @@ private: void SetFocusHandlingMode(Kernel::HLERequestContext& ctx); void SetRestartMessageEnabled(Kernel::HLERequestContext& ctx); void SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx); - void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx); + void SetAlbumImageOrientation(Kernel::HLERequestContext& ctx); void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/am/spsm.cpp b/src/core/hle/service/am/spsm.cpp index 003ee8667..f27729ce7 100644 --- a/src/core/hle/service/am/spsm.cpp +++ b/src/core/hle/service/am/spsm.cpp @@ -10,17 +10,17 @@ SPSM::SPSM() : ServiceFramework{"spsm"} { // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "GetState"}, - {1, nullptr, "SleepSystemAndWaitAwake"}, - {2, nullptr, "Unknown1"}, - {3, nullptr, "Unknown2"}, + {1, nullptr, "EnterSleep"}, + {2, nullptr, "GetLastWakeReason"}, + {3, nullptr, "Shutdown"}, {4, nullptr, "GetNotificationMessageEventHandle"}, - {5, nullptr, "Unknown3"}, - {6, nullptr, "Unknown4"}, - {7, nullptr, "Unknown5"}, + {5, nullptr, "ReceiveNotificationMessage"}, + {6, nullptr, "AnalyzeLogForLastSleepWakeSequence"}, + {7, nullptr, "ResetEventLog"}, {8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"}, {9, nullptr, "ChangeHomeButtonLongPressingTime"}, - {10, nullptr, "Unknown6"}, - {11, nullptr, "Unknown7"}, + {10, nullptr, "PutErrorState"}, + {11, nullptr, "InvalidateCurrentHomeButtonPressing"}, }; // clang-format on -- cgit v1.2.3 From e6fee39ae74ccc0d21ee7fedc2d9e47196aea74e Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:33:25 +0200 Subject: bcat: Update function tables and add missing classes (#4172) * bcat: Update function tables and add missing classes--- src/core/hle/service/bcat/bcat.cpp | 2 ++ src/core/hle/service/bcat/module.cpp | 3 +++ 2 files changed, 5 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/bcat/bcat.cpp b/src/core/hle/service/bcat/bcat.cpp index 8bb2528c9..b31766212 100644 --- a/src/core/hle/service/bcat/bcat.cpp +++ b/src/core/hle/service/bcat/bcat.cpp @@ -14,6 +14,8 @@ BCAT::BCAT(Core::System& system, std::shared_ptr module, {0, &BCAT::CreateBcatService, "CreateBcatService"}, {1, &BCAT::CreateDeliveryCacheStorageService, "CreateDeliveryCacheStorageService"}, {2, &BCAT::CreateDeliveryCacheStorageServiceWithApplicationId, "CreateDeliveryCacheStorageServiceWithApplicationId"}, + {3, nullptr, "CreateDeliveryCacheProgressService"}, + {4, nullptr, "CreateDeliveryCacheProgressServiceWithApplicationId"}, }; // clang-format on RegisterHandlers(functions); diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 34aba7a27..603b64d4f 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp @@ -143,10 +143,13 @@ public: {20401, nullptr, "UnregisterSystemApplicationDeliveryTask"}, {20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"}, {30100, &IBcatService::SetPassphrase, "SetPassphrase"}, + {30101, nullptr, "Unknown"}, + {30102, nullptr, "Unknown2"}, {30200, nullptr, "RegisterBackgroundDeliveryTask"}, {30201, nullptr, "UnregisterBackgroundDeliveryTask"}, {30202, nullptr, "BlockDeliveryTask"}, {30203, nullptr, "UnblockDeliveryTask"}, + {30210, nullptr, "SetDeliveryTaskTimer"}, {30300, nullptr, "RegisterSystemApplicationDeliveryTasks"}, {90100, nullptr, "EnumerateBackgroundDeliveryTask"}, {90200, nullptr, "GetDeliveryList"}, -- cgit v1.2.3 From 6e14edbcc22c33bf32702011eb27412b1807cfe2 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:33:55 +0200 Subject: bpc: Update function tables (#4173) * bpc: Update function tables This was based on Switchbrew page: https://switchbrew.org/wiki/PCV_services--- src/core/hle/service/bpc/bpc.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/bpc/bpc.cpp b/src/core/hle/service/bpc/bpc.cpp index 1c1ecdb60..fac6b2f9c 100644 --- a/src/core/hle/service/bpc/bpc.cpp +++ b/src/core/hle/service/bpc/bpc.cpp @@ -23,9 +23,14 @@ public: {5, nullptr, "GetBoardPowerControlEvent"}, {6, nullptr, "GetSleepButtonState"}, {7, nullptr, "GetPowerEvent"}, - {8, nullptr, "Unknown1"}, - {9, nullptr, "Unknown2"}, - {10, nullptr, "Unknown3"}, + {8, nullptr, "CreateWakeupTimer"}, + {9, nullptr, "CancelWakeupTimer"}, + {10, nullptr, "EnableWakeupTimerOnDevice"}, + {11, nullptr, "CreateWakeupTimerEx"}, + {12, nullptr, "GetLastEnabledWakeupTimerType"}, + {13, nullptr, "CleanAllWakeupTimers"}, + {14, nullptr, "Unknown"}, + {15, nullptr, "Unknown2"}, }; // clang-format on @@ -38,10 +43,11 @@ public: explicit BPC_R() : ServiceFramework{"bpc:r"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "GetExternalRtcValue"}, - {1, nullptr, "SetExternalRtcValue"}, - {2, nullptr, "ReadExternalRtcResetFlag"}, - {3, nullptr, "ClearExternalRtcResetFlag"}, + {0, nullptr, "GetRtcTime"}, + {1, nullptr, "SetRtcTime"}, + {2, nullptr, "GetRtcResetDetected"}, + {3, nullptr, "ClearRtcResetDetected"}, + {4, nullptr, "SetUpRtcResetOnShutdown"}, }; // clang-format on -- cgit v1.2.3 From 032b7d490dfc456c271696997ca11b9572867600 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:34:29 +0200 Subject: btdrv: Update function table (#4174) * btdrv: Update function table--- src/core/hle/service/btdrv/btdrv.cpp | 167 ++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 83 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index 40a06c9fd..f311afa2f 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp @@ -58,102 +58,103 @@ public: {1, nullptr, "InitializeBluetooth"}, {2, nullptr, "EnableBluetooth"}, {3, nullptr, "DisableBluetooth"}, - {4, nullptr, "CleanupBluetooth"}, + {4, nullptr, "FinalizeBluetooth"}, {5, nullptr, "GetAdapterProperties"}, {6, nullptr, "GetAdapterProperty"}, {7, nullptr, "SetAdapterProperty"}, - {8, nullptr, "StartDiscovery"}, - {9, nullptr, "CancelDiscovery"}, + {8, nullptr, "StartInquiry"}, + {9, nullptr, "StopInquiry"}, {10, nullptr, "CreateBond"}, {11, nullptr, "RemoveBond"}, {12, nullptr, "CancelBond"}, - {13, nullptr, "PinReply"}, - {14, nullptr, "SspReply"}, + {13, nullptr, "RespondToPinRequest"}, + {14, nullptr, "RespondToSspRequest"}, {15, nullptr, "GetEventInfo"}, {16, nullptr, "InitializeHid"}, - {17, nullptr, "HidConnect"}, - {18, nullptr, "HidDisconnect"}, - {19, nullptr, "HidSendData"}, - {20, nullptr, "HidSendData2"}, - {21, nullptr, "HidSetReport"}, - {22, nullptr, "HidGetReport"}, - {23, nullptr, "HidWakeController"}, - {24, nullptr, "HidAddPairedDevice"}, - {25, nullptr, "HidGetPairedDevice"}, - {26, nullptr, "CleanupHid"}, - {27, nullptr, "HidGetEventInfo"}, - {28, nullptr, "ExtSetTsi"}, - {29, nullptr, "ExtSetBurstMode"}, - {30, nullptr, "ExtSetZeroRetran"}, - {31, nullptr, "ExtSetMcMode"}, - {32, nullptr, "ExtStartLlrMode"}, - {33, nullptr, "ExtExitLlrMode"}, - {34, nullptr, "ExtSetRadio"}, - {35, nullptr, "ExtSetVisibility"}, - {36, nullptr, "ExtSetTbfcScan"}, + {17, nullptr, "OpenHidConnection"}, + {18, nullptr, "CloseHidConnection"}, + {19, nullptr, "WriteHidData"}, + {20, nullptr, "WriteHidData2"}, + {21, nullptr, "SetHidReport"}, + {22, nullptr, "GetHidReport"}, + {23, nullptr, "TriggerConnection"}, + {24, nullptr, "AddPairedDeviceInfo"}, + {25, nullptr, "GetPairedDeviceInfo"}, + {26, nullptr, "FinalizeHid"}, + {27, nullptr, "GetHidEventInfo"}, + {28, nullptr, "SetTsi"}, + {29, nullptr, "EnableBurstMode"}, + {30, nullptr, "SetZeroRetransmission"}, + {31, nullptr, "EnableMcMode"}, + {32, nullptr, "EnableLlrScan"}, + {33, nullptr, "DisableLlrScan"}, + {34, nullptr, "EnableRadio"}, + {35, nullptr, "SetVisibility"}, + {36, nullptr, "EnableTbfcScan"}, {37, nullptr, "RegisterHidReportEvent"}, - {38, nullptr, "HidGetReportEventInfo"}, + {38, nullptr, "GetHidReportEventInfo"}, {39, nullptr, "GetLatestPlr"}, - {40, nullptr, "ExtGetPendingConnections"}, + {40, nullptr, "GetPendingConnections"}, {41, nullptr, "GetChannelMap"}, - {42, nullptr, "EnableBluetoothBoostSetting"}, - {43, nullptr, "IsBluetoothBoostSettingEnabled"}, - {44, nullptr, "EnableBluetoothAfhSetting"}, - {45, nullptr, "IsBluetoothAfhSettingEnabled"}, - {46, nullptr, "InitializeBluetoothLe"}, - {47, nullptr, "EnableBluetoothLe"}, - {48, nullptr, "DisableBluetoothLe"}, - {49, nullptr, "CleanupBluetoothLe"}, - {50, nullptr, "SetLeVisibility"}, - {51, nullptr, "SetLeConnectionParameter"}, - {52, nullptr, "SetLeDefaultConnectionParameter"}, - {53, nullptr, "SetLeAdvertiseData"}, - {54, nullptr, "SetLeAdvertiseParameter"}, - {55, nullptr, "StartLeScan"}, - {56, nullptr, "StopLeScan"}, - {57, nullptr, "AddLeScanFilterCondition"}, - {58, nullptr, "DeleteLeScanFilterCondition"}, - {59, nullptr, "DeleteLeScanFilter"}, - {60, nullptr, "ClearLeScanFilters"}, - {61, nullptr, "EnableLeScanFilter"}, - {62, nullptr, "RegisterLeClient"}, - {63, nullptr, "UnregisterLeClient"}, - {64, nullptr, "UnregisterLeClientAll"}, - {65, nullptr, "LeClientConnect"}, - {66, nullptr, "LeClientCancelConnection"}, - {67, nullptr, "LeClientDisconnect"}, - {68, nullptr, "LeClientGetAttributes"}, - {69, nullptr, "LeClientDiscoverService"}, - {70, nullptr, "LeClientConfigureMtu"}, - {71, nullptr, "RegisterLeServer"}, - {72, nullptr, "UnregisterLeServer"}, - {73, nullptr, "LeServerConnect"}, - {74, nullptr, "LeServerDisconnect"}, - {75, nullptr, "CreateLeService"}, - {76, nullptr, "StartLeService"}, - {77, nullptr, "AddLeCharacteristic"}, - {78, nullptr, "AddLeDescriptor"}, - {79, nullptr, "GetLeCoreEventInfo"}, - {80, nullptr, "LeGetFirstCharacteristic"}, - {81, nullptr, "LeGetNextCharacteristic"}, - {82, nullptr, "LeGetFirstDescriptor"}, - {83, nullptr, "LeGetNextDescriptor"}, - {84, nullptr, "RegisterLeCoreDataPath"}, - {85, nullptr, "UnregisterLeCoreDataPath"}, - {86, nullptr, "RegisterLeHidDataPath"}, - {87, nullptr, "UnregisterLeHidDataPath"}, - {88, nullptr, "RegisterLeDataPath"}, - {89, nullptr, "UnregisterLeDataPath"}, - {90, nullptr, "LeClientReadCharacteristic"}, - {91, nullptr, "LeClientReadDescriptor"}, - {92, nullptr, "LeClientWriteCharacteristic"}, - {93, nullptr, "LeClientWriteDescriptor"}, - {94, nullptr, "LeClientRegisterNotification"}, - {95, nullptr, "LeClientDeregisterNotification"}, + {42, nullptr, "EnableTxPowerBoostSetting"}, + {43, nullptr, "IsTxPowerBoostSettingEnabled"}, + {44, nullptr, "EnableAfhSetting"}, + {45, nullptr, "IsAfhSettingEnabled"}, + {46, nullptr, "InitializeBle"}, + {47, nullptr, "EnableBle"}, + {48, nullptr, "DisableBle"}, + {49, nullptr, "FinalizeBle"}, + {50, nullptr, "SetBleVisibility"}, + {51, nullptr, "SetBleConnectionParameter"}, + {52, nullptr, "SetBleDefaultConnectionParameter"}, + {53, nullptr, "SetBleAdvertiseData"}, + {54, nullptr, "SetBleAdvertiseParameter"}, + {55, nullptr, "StartBleScan"}, + {56, nullptr, "StopBleScan"}, + {57, nullptr, "AddBleScanFilterCondition"}, + {58, nullptr, "DeleteBleScanFilterCondition"}, + {59, nullptr, "DeleteBleScanFilter"}, + {60, nullptr, "ClearBleScanFilters"}, + {61, nullptr, "EnableBleScanFilter"}, + {62, nullptr, "RegisterGattClient"}, + {63, nullptr, "UnregisterGattClient"}, + {64, nullptr, "UnregisterAllGattClients"}, + {65, nullptr, "ConnectGattServer"}, + {66, nullptr, "CancelConnectGattServer"}, + {67, nullptr, "DisconnectGattServer"}, + {68, nullptr, "GetGattAttribute"}, + {69, nullptr, "GetGattService"}, + {70, nullptr, "ConfigureAttMtu"}, + {71, nullptr, "RegisterGattServer"}, + {72, nullptr, "UnregisterGattServer"}, + {73, nullptr, "ConnectGattClient"}, + {74, nullptr, "DisconnectGattClient"}, + {75, nullptr, "AddGattService"}, + {76, nullptr, "EnableGattService"}, + {77, nullptr, "AddGattCharacteristic"}, + {78, nullptr, "AddGattDescriptor"}, + {79, nullptr, "GetBleManagedEventInfo"}, + {80, nullptr, "GetGattFirstCharacteristic"}, + {81, nullptr, "GetGattNextCharacteristic"}, + {82, nullptr, "GetGattFirstDescriptor"}, + {83, nullptr, "GetGattNextDescriptor"}, + {84, nullptr, "RegisterGattManagedDataPath"}, + {85, nullptr, "UnregisterGattManagedDataPath"}, + {86, nullptr, "RegisterGattHidDataPath"}, + {87, nullptr, "UnregisterGattHidDataPath"}, + {88, nullptr, "RegisterGattDataPath"}, + {89, nullptr, "UnregisterGattDataPath"}, + {90, nullptr, "ReadGattCharacteristic"}, + {91, nullptr, "ReadGattDescriptor"}, + {92, nullptr, "WriteGattCharacteristic"}, + {93, nullptr, "WriteGattDescriptor"}, + {94, nullptr, "RegisterGattNotification"}, + {95, nullptr, "UnregisterGattNotification"}, {96, nullptr, "GetLeHidEventInfo"}, {97, nullptr, "RegisterBleHidEvent"}, - {98, nullptr, "SetLeScanParameter"}, - {256, nullptr, "GetIsManufacturingMode"}, + {98, nullptr, "SetBleScanParameter"}, + {99, nullptr, "MoveToSecondaryPiconet"}, + {256, nullptr, "IsManufacturingMode"}, {257, nullptr, "EmulateBluetoothCrash"}, {258, nullptr, "GetBleChannelMap"}, }; -- cgit v1.2.3 From 0b23ce6ef2e97196c1388f90843b3970d51568fb Mon Sep 17 00:00:00 2001 From: David Marcec Date: Sat, 27 Jun 2020 10:42:46 +1000 Subject: btm: Give better names for unknown functions --- src/core/hle/service/btm/btm.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index f6539a7a4..0d251c6d0 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp @@ -192,11 +192,11 @@ public: {57, nullptr, "RegisterAppletResourceUserId"}, {58, nullptr, "UnregisterAppletResourceUserId"}, {59, nullptr, "SetAppletResourceUserId"}, - {60, nullptr, "Unknown"}, - {61, nullptr, "Unknown2"}, - {62, nullptr, "Unknown3"}, - {63, nullptr, "Unknown4"}, - {64, nullptr, "Unknown5"}, + {60, nullptr, "Unknown60"}, + {61, nullptr, "Unknown61"}, + {62, nullptr, "Unknown62"}, + {63, nullptr, "Unknown63"}, + {64, nullptr, "Unknown64"}, }; // clang-format on -- cgit v1.2.3 From bc51a9365ba20303452792429a4ae611938f8d9c Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:43:22 +0200 Subject: Update function names --- src/core/hle/service/es/es.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index 593772ee2..884c818da 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -27,8 +27,8 @@ public: {8, &ETicket::GetTitleKey, "GetTitleKey"}, {9, &ETicket::CountCommonTicket, "CountCommonTicket"}, {10, &ETicket::CountPersonalizedTicket, "CountPersonalizedTicket"}, - {11, &ETicket::ListCommonTicket, "ListCommonTicketRightsIds"}, - {12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicketRightsIds"}, + {11, &ETicket::ListCommonTicketRightsIds, "ListCommonTicketRightsIds"}, + {12, &ETicket::ListPersonalizedTicketRightsIds, "ListPersonalizedTicketRightsIds"}, {13, nullptr, "ListMissingPersonalizedTicket"}, {14, &ETicket::GetCommonTicketSize, "GetCommonTicketSize"}, {15, &ETicket::GetPersonalizedTicketSize, "GetPersonalizedTicketSize"}, @@ -186,7 +186,7 @@ private: rb.Push(count); } - void ListCommonTicket(Kernel::HLERequestContext& ctx) { + void ListCommonTicketRightsIds(Kernel::HLERequestContext& ctx) { u32 out_entries; if (keys.GetCommonTickets().empty()) out_entries = 0; @@ -209,7 +209,7 @@ private: rb.Push(out_entries); } - void ListPersonalizedTicket(Kernel::HLERequestContext& ctx) { + void ListPersonalizedTicketRightsIds(Kernel::HLERequestContext& ctx) { u32 out_entries; if (keys.GetPersonalizedTickets().empty()) out_entries = 0; -- cgit v1.2.3 From 2d82b7f1a1eb43e3f0c9a1695a8ada3db2728462 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 02:48:29 +0200 Subject: Use better names for "Unknown"s --- src/core/hle/service/es/es.cpp | 78 +++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index 884c818da..9365f27e1 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -55,46 +55,46 @@ public: {36, nullptr, "DeleteAllInactiveELicenseRequiredPersonalizedTicket"}, {37, nullptr, "OwnTicket2"}, {38, nullptr, "OwnTicket3"}, - {501, nullptr, "Unknown"}, - {502, nullptr, "Unknown2"}, + {501, nullptr, "Unknown501"}, + {502, nullptr, "Unknown502"}, {503, nullptr, "GetTitleKey"}, - {504, nullptr, "Unknown3"}, - {508, nullptr, "Unknown4"}, - {509, nullptr, "Unknown5"}, - {510, nullptr, "Unknown6"}, - {511, nullptr, "Unknown7"}, - {1001, nullptr, "Unknown8"}, - {1002, nullptr, "Unknown9"}, - {1003, nullptr, "Unknown10"}, - {1004, nullptr, "Unknown11"}, - {1005, nullptr, "Unknown12"}, - {1006, nullptr, "Unknown13"}, - {1007, nullptr, "Unknown14"}, - {1009, nullptr, "Unknown15"}, - {1010, nullptr, "Unknown16"}, - {1011, nullptr, "Unknown17"}, - {1012, nullptr, "Unknown18"}, - {1013, nullptr, "Unknown19"}, - {1014, nullptr, "Unknown20"}, - {1015, nullptr, "Unknown21"}, - {1016, nullptr, "Unknown22"}, - {1017, nullptr, "Unknown23"}, - {1018, nullptr, "Unknown24"}, - {1019, nullptr, "Unknown25"}, - {1020, nullptr, "Unknown26"}, - {1021, nullptr, "Unknown27"}, - {1501, nullptr, "Unknown28"}, - {1502, nullptr, "Unknown29"}, - {1503, nullptr, "Unknown30"}, - {1504, nullptr, "Unknown31"}, - {1505, nullptr, "Unknown32"}, - {2000, nullptr, "Unknown33"}, - {2001, nullptr, "Unknown34"}, - {2100, nullptr, "Unknown35"}, - {2501, nullptr, "Unknown36"}, - {2502, nullptr, "Unknown37"}, - {3001, nullptr, "Unknown38"}, - {3002, nullptr, "Unknown39"}, + {504, nullptr, "Unknown504"}, + {508, nullptr, "Unknown508"}, + {509, nullptr, "Unknown509"}, + {510, nullptr, "Unknown510"}, + {511, nullptr, "Unknown511"}, + {1001, nullptr, "Unknown1001"}, + {1002, nullptr, "Unknown1001"}, + {1003, nullptr, "Unknown1003"}, + {1004, nullptr, "Unknown1004"}, + {1005, nullptr, "Unknown1005"}, + {1006, nullptr, "Unknown1006"}, + {1007, nullptr, "Unknown1007"}, + {1009, nullptr, "Unknown1009"}, + {1010, nullptr, "Unknown1010"}, + {1011, nullptr, "Unknown1011"}, + {1012, nullptr, "Unknown1012"}, + {1013, nullptr, "Unknown1013"}, + {1014, nullptr, "Unknown1014"}, + {1015, nullptr, "Unknown1015"}, + {1016, nullptr, "Unknown1016"}, + {1017, nullptr, "Unknown1017"}, + {1018, nullptr, "Unknown1018"}, + {1019, nullptr, "Unknown1019"}, + {1020, nullptr, "Unknown1020"}, + {1021, nullptr, "Unknown1021"}, + {1501, nullptr, "Unknown1501"}, + {1502, nullptr, "Unknown1502"}, + {1503, nullptr, "Unknown1503"}, + {1504, nullptr, "Unknown1504"}, + {1505, nullptr, "Unknown1505"}, + {2000, nullptr, "Unknown2000"}, + {2001, nullptr, "Unknown2001"}, + {2100, nullptr, "Unknown2100"}, + {2501, nullptr, "Unknown2501"}, + {2502, nullptr, "Unknown2502"}, + {3001, nullptr, "Unknown3001"}, + {3002, nullptr, "Unknown3002"}, }; // clang-format on RegisterHandlers(functions); -- cgit v1.2.3 From af88767508fd9e5f522a63eda5f4e55ba67d67a2 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 12:39:10 +0200 Subject: friend: Update function table --- src/core/hle/service/friend/friend.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 68f259b70..b7adaffc7 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -25,9 +25,13 @@ public: {10101, &IFriendService::GetFriendList, "GetFriendList"}, {10102, nullptr, "UpdateFriendInfo"}, {10110, nullptr, "GetFriendProfileImage"}, + {10120, nullptr, "Unknown10120"}, + {10121, nullptr, "Unknown10121"}, {10200, nullptr, "SendFriendRequestForApplication"}, {10211, nullptr, "AddFacedFriendRequestForApplication"}, {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"}, + {10420, nullptr, "Unknown10420"}, + {10421, nullptr, "Unknown10421"}, {10500, nullptr, "GetProfileList"}, {10600, nullptr, "DeclareOpenOnlinePlaySession"}, {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, @@ -97,6 +101,8 @@ public: {30900, nullptr, "SendFriendInvitation"}, {30910, nullptr, "ReadFriendInvitation"}, {30911, nullptr, "ReadAllFriendInvitations"}, + {40100, nullptr, "Unknown40100"}, + {40400, nullptr, "Unknown40400"}, {49900, nullptr, "DeleteNetworkServiceAccountCache"}, }; // clang-format on -- cgit v1.2.3 From 64fa9b9f57a05914aa8ce4bd51f645ed772aecda Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 12:41:21 +0200 Subject: grc: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/GRC_services--- src/core/hle/service/grc/grc.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp index 24910ac6c..fd9471e3c 100644 --- a/src/core/hle/service/grc/grc.cpp +++ b/src/core/hle/service/grc/grc.cpp @@ -17,6 +17,9 @@ public: static const FunctionInfo functions[] = { {1, nullptr, "OpenContinuousRecorder"}, {2, nullptr, "OpenGameMovieTrimmer"}, + {3, nullptr, "OpenOffscreenRecorder"}, + {101, nullptr, "CreateMovieMaker"}, + {9903, nullptr, "SetOffscreenRecordingMaker"} }; // clang-format on -- cgit v1.2.3 From 73b035d2e272efe12cfb53c9b2f18074d856cd00 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 12:43:33 +0200 Subject: lbl: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/Backlight_services--- src/core/hle/service/lbl/lbl.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp index e8f9f2d29..17350b403 100644 --- a/src/core/hle/service/lbl/lbl.cpp +++ b/src/core/hle/service/lbl/lbl.cpp @@ -47,6 +47,7 @@ public: {26, &LBL::EnableVrMode, "EnableVrMode"}, {27, &LBL::DisableVrMode, "DisableVrMode"}, {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"}, + {29, nullptr, "IsAutoBrightnessControlSupported"}, }; // clang-format on -- cgit v1.2.3 From a8d17adb7c4a6caed17b2204a6090ffb0f062f63 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 12:45:42 +0200 Subject: Oops (fix typo) --- src/core/hle/service/grc/grc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/grc/grc.cpp b/src/core/hle/service/grc/grc.cpp index fd9471e3c..401e0b208 100644 --- a/src/core/hle/service/grc/grc.cpp +++ b/src/core/hle/service/grc/grc.cpp @@ -19,7 +19,7 @@ public: {2, nullptr, "OpenGameMovieTrimmer"}, {3, nullptr, "OpenOffscreenRecorder"}, {101, nullptr, "CreateMovieMaker"}, - {9903, nullptr, "SetOffscreenRecordingMaker"} + {9903, nullptr, "SetOffscreenRecordingMarker"} }; // clang-format on -- cgit v1.2.3 From b9be484a51df4e0c666501d516fb822bed699723 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 12:50:56 +0200 Subject: ldn: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/LDN_services--- src/core/hle/service/ldn/ldn.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 92adde6d4..49972cd69 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -69,6 +69,7 @@ public: {101, nullptr, "GetNetworkInfoLatestUpdate"}, {102, nullptr, "Scan"}, {103, nullptr, "ScanPrivate"}, + {104, nullptr, "SetWirelessControllerRestriction"}, {200, nullptr, "OpenAccessPoint"}, {201, nullptr, "CloseAccessPoint"}, {202, nullptr, "CreateNetwork"}, -- cgit v1.2.3 From 521942422609b76a575efd93feb06788ae957c21 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 12:53:59 +0200 Subject: mig: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/Migration_services--- src/core/hle/service/mig/mig.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/mig/mig.cpp b/src/core/hle/service/mig/mig.cpp index d16367f2c..113a4665c 100644 --- a/src/core/hle/service/mig/mig.cpp +++ b/src/core/hle/service/mig/mig.cpp @@ -20,6 +20,12 @@ public: {101, nullptr, "ResumeServer"}, {200, nullptr, "CreateClient"}, {201, nullptr, "ResumeClient"}, + {1001, nullptr, "Unknown1001"}, + {1010, nullptr, "Unknown1010"}, + {1100, nullptr, "Unknown1100"}, + {1101, nullptr, "Unknown1101"}, + {1200, nullptr, "Unknown1200"}, + {1201, nullptr, "Unknown1201"} }; // clang-format on -- cgit v1.2.3 From b8296439469e91aa533ad29aac79cdb88cb2e306 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 12:59:01 +0200 Subject: mm: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/Display_services--- src/core/hle/service/mm/mm_u.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index def63dc8a..25c24e537 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp @@ -14,14 +14,14 @@ public: explicit MM_U() : ServiceFramework{"mm:u"} { // clang-format off static const FunctionInfo functions[] = { - {0, &MM_U::Initialize, "Initialize"}, - {1, &MM_U::Finalize, "Finalize"}, - {2, &MM_U::SetAndWait, "SetAndWait"}, - {3, &MM_U::Get, "Get"}, - {4, &MM_U::InitializeWithId, "InitializeWithId"}, - {5, &MM_U::FinalizeWithId, "FinalizeWithId"}, - {6, &MM_U::SetAndWaitWithId, "SetAndWaitWithId"}, - {7, &MM_U::GetWithId, "GetWithId"}, + {0, &MM_U::InitializeOld, "InitializeOld"}, + {1, &MM_U::FinalizeOld, "FinalizeOld"}, + {2, &MM_U::SetAndWaitOld, "SetAndWaitOld"}, + {3, &MM_U::GetOld, "GetOld"}, + {4, &MM_U::Initialize, "Initialize"}, + {5, &MM_U::Finalize, "Finalize"}, + {6, &MM_U::SetAndWait, "SetAndWait"}, + {7, &MM_U::Get, "Get"}, }; // clang-format on @@ -29,21 +29,21 @@ public: } private: - void Initialize(Kernel::HLERequestContext& ctx) { + void InitializeOld(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } - void Finalize(Kernel::HLERequestContext& ctx) { + void FinalizeOld(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } - void SetAndWait(Kernel::HLERequestContext& ctx) { + void SetAndWaitOld(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; min = rp.Pop(); max = rp.Pop(); @@ -54,7 +54,7 @@ private: rb.Push(RESULT_SUCCESS); } - void Get(Kernel::HLERequestContext& ctx) { + void GetOld(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; @@ -62,7 +62,7 @@ private: rb.Push(current); } - void InitializeWithId(Kernel::HLERequestContext& ctx) { + void Initialize(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; @@ -70,14 +70,14 @@ private: rb.Push(id); // Any non zero value } - void FinalizeWithId(Kernel::HLERequestContext& ctx) { + void Finalize(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } - void SetAndWaitWithId(Kernel::HLERequestContext& ctx) { + void SetAndWait(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; u32 input_id = rp.Pop(); min = rp.Pop(); @@ -90,7 +90,7 @@ private: rb.Push(RESULT_SUCCESS); } - void GetWithId(Kernel::HLERequestContext& ctx) { + void Get(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; -- cgit v1.2.3 From c56414b80d945b286b6e98bc689146211615cd5a Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 13:05:22 +0200 Subject: ncm: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/NCM_services ILocationResolver's 16, 17, 18 and 19 have unofficial names--- src/core/hle/service/ncm/ncm.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ncm/ncm.cpp b/src/core/hle/service/ncm/ncm.cpp index ec9aae04a..e38dea1f4 100644 --- a/src/core/hle/service/ncm/ncm.cpp +++ b/src/core/hle/service/ncm/ncm.cpp @@ -28,16 +28,16 @@ public: {7, nullptr, "ResolveApplicationLegalInformationPath"}, {8, nullptr, "RedirectApplicationLegalInformationPath"}, {9, nullptr, "Refresh"}, - {10, nullptr, "RedirectProgramPath2"}, - {11, nullptr, "Refresh2"}, - {12, nullptr, "DeleteProgramPath"}, - {13, nullptr, "DeleteApplicationControlPath"}, - {14, nullptr, "DeleteApplicationHtmlDocumentPath"}, - {15, nullptr, "DeleteApplicationLegalInformationPath"}, - {16, nullptr, ""}, - {17, nullptr, ""}, - {18, nullptr, ""}, - {19, nullptr, ""}, + {10, nullptr, "RedirectApplicationProgramPath"}, + {11, nullptr, "ClearApplicationRedirection"}, + {12, nullptr, "EraseProgramRedirection"}, + {13, nullptr, "EraseApplicationControlRedirection"}, + {14, nullptr, "EraseApplicationHtmlDocumentRedirection"}, + {15, nullptr, "EraseApplicationLegalInformationRedirection"}, + {16, nullptr, "ResolveProgramPathForDebug"}, + {17, nullptr, "RedirectProgramPathForDebug"}, + {18, nullptr, "RedirectApplicationProgramPathForDebug"}, + {19, nullptr, "EraseProgramRedirectionForDebug"}, }; // clang-format on -- cgit v1.2.3 From 23515e0cccf4dd4ce71bbbfcb8620a5437b19fb3 Mon Sep 17 00:00:00 2001 From: VolcaEM Date: Sat, 27 Jun 2020 13:09:36 +0200 Subject: nfc: Update function table This was based on Switchbrew page: https://switchbrew.org/wiki/NFC_services--- src/core/hle/service/nfc/nfc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index b7b34ce7e..780ea30fe 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -198,9 +198,9 @@ public: static const FunctionInfo functions[] = { {0, nullptr, "Initialize"}, {1, nullptr, "Finalize"}, - {2, nullptr, "GetState"}, - {3, nullptr, "IsNfcEnabled"}, - {100, nullptr, "SetNfcEnabled"}, + {2, nullptr, "GetStateOld"}, + {3, nullptr, "IsNfcEnabledOld"}, + {100, nullptr, "SetNfcEnabledOld"}, {400, nullptr, "InitializeSystem"}, {401, nullptr, "FinalizeSystem"}, {402, nullptr, "GetState"}, -- cgit v1.2.3 From e31425df3877636c098ec7426ebd2067920715cb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 24 Feb 2020 22:04:12 -0400 Subject: General: Recover Prometheus project from harddrive failure This commit: Implements CPU Interrupts, Replaces Cycle Timing for Host Timing, Reworks the Kernel's Scheduler, Introduce Idle State and Suspended State, Recreates the bootmanager, Initializes Multicore system. --- src/core/hle/kernel/kernel.cpp | 84 ++++- src/core/hle/kernel/kernel.h | 19 + src/core/hle/kernel/physical_core.cpp | 37 +- src/core/hle/kernel/physical_core.h | 21 ++ src/core/hle/kernel/process.cpp | 17 +- src/core/hle/kernel/scheduler.cpp | 415 +++++++++++++++------ src/core/hle/kernel/scheduler.h | 94 +++-- src/core/hle/kernel/svc.cpp | 21 +- src/core/hle/kernel/thread.cpp | 232 +++++------- src/core/hle/kernel/thread.h | 81 +++- src/core/hle/kernel/time_manager.cpp | 2 +- src/core/hle/service/hid/controllers/debug_pad.cpp | 2 +- src/core/hle/service/hid/controllers/gesture.cpp | 2 +- src/core/hle/service/hid/controllers/keyboard.cpp | 2 +- src/core/hle/service/hid/controllers/mouse.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 2 +- src/core/hle/service/hid/controllers/stubbed.cpp | 2 +- .../hle/service/hid/controllers/touchscreen.cpp | 4 +- src/core/hle/service/hid/controllers/xpad.cpp | 2 +- src/core/hle/service/hid/hid.cpp | 16 +- src/core/hle/service/hid/irs.cpp | 2 +- .../hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 3 +- src/core/hle/service/nvflinger/nvflinger.cpp | 13 +- .../service/time/standard_steady_clock_core.cpp | 5 +- .../service/time/tick_based_steady_clock_core.cpp | 5 +- src/core/hle/service/time/time.cpp | 5 +- src/core/hle/service/time/time_sharedmemory.cpp | 3 +- 27 files changed, 710 insertions(+), 383 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 7655382fa..ba051a7d8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -13,11 +13,13 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/thread.h" #include "core/arm/arm_interface.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/cpu_manager.h" #include "core/device_memory.h" #include "core/hardware_properties.h" #include "core/hle/kernel/client_port.h" @@ -117,7 +119,9 @@ struct KernelCore::Impl { InitializeSystemResourceLimit(kernel); InitializeMemoryLayout(); InitializeThreads(); - InitializePreemption(); + InitializePreemption(kernel); + InitializeSchedulers(); + InitializeSuspendThreads(); } void Shutdown() { @@ -155,6 +159,12 @@ struct KernelCore::Impl { } } + void InitializeSchedulers() { + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + cores[i].Scheduler().Initialize(); + } + } + // Creates the default system resource limit void InitializeSystemResourceLimit(KernelCore& kernel) { system_resource_limit = ResourceLimit::Create(kernel); @@ -178,10 +188,13 @@ struct KernelCore::Impl { Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); } - void InitializePreemption() { - preemption_event = - Core::Timing::CreateEvent("PreemptionCallback", [this](u64 userdata, s64 cycles_late) { - global_scheduler.PreemptThreads(); + void InitializePreemption(KernelCore& kernel) { + preemption_event = Core::Timing::CreateEvent( + "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { + { + SchedulerLock lock(kernel); + global_scheduler.PreemptThreads(); + } s64 time_interval = Core::Timing::msToCycles(std::chrono::milliseconds(10)); system.CoreTiming().ScheduleEvent(time_interval, preemption_event); }); @@ -190,6 +203,20 @@ struct KernelCore::Impl { system.CoreTiming().ScheduleEvent(time_interval, preemption_event); } + void InitializeSuspendThreads() { + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + std::string name = "Suspend Thread Id:" + std::to_string(i); + std::function init_func = + system.GetCpuManager().GetSuspendThreadStartFunc(); + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + ThreadType type = + static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_SUSPEND); + auto thread_res = Thread::Create(system, type, name, 0, 0, 0, static_cast(i), 0, + nullptr, std::move(init_func), init_func_parameter); + suspend_threads[i] = std::move(thread_res).Unwrap(); + } + } + void MakeCurrentProcess(Process* process) { current_process = process; @@ -201,7 +228,10 @@ struct KernelCore::Impl { core.SetIs64Bit(process->Is64BitProcess()); } - system.Memory().SetCurrentPageTable(*process); + u32 core_id = GetCurrentHostThreadID(); + if (core_id < Core::Hardware::NUM_CPU_CORES) { + system.Memory().SetCurrentPageTable(*process, core_id); + } } void RegisterCoreThread(std::size_t core_id) { @@ -219,7 +249,9 @@ struct KernelCore::Impl { std::unique_lock lock{register_thread_mutex}; const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); - ASSERT(it == host_thread_ids.end()); + if (it != host_thread_ids.end()) { + return; + } host_thread_ids[this_id] = registered_thread_ids++; } @@ -343,6 +375,8 @@ struct KernelCore::Impl { std::shared_ptr irs_shared_mem; std::shared_ptr time_shared_mem; + std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + // System context Core::System& system; }; @@ -412,6 +446,26 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { return impl->cores[id]; } +Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return impl->cores[core_id]; +} + +const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return impl->cores[core_id]; +} + +Kernel::Scheduler& KernelCore::CurrentScheduler() { + return CurrentPhysicalCore().Scheduler(); +} + +const Kernel::Scheduler& KernelCore::CurrentScheduler() const { + return CurrentPhysicalCore().Scheduler(); +} + Kernel::Synchronization& KernelCore::Synchronization() { return impl->synchronization; } @@ -557,4 +611,20 @@ const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const { return *impl->time_shared_mem; } +void KernelCore::Suspend(bool in_suspention) { + const bool should_suspend = exception_exited || in_suspention; + { + SchedulerLock lock(*this); + ThreadStatus status = should_suspend ? ThreadStatus::Ready : ThreadStatus::WaitSleep; + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + impl->suspend_threads[i]->SetStatus(status); + } + } +} + +void KernelCore::ExceptionalExit() { + exception_exited = true; + Suspend(true); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 83de1f542..5d32a8329 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -110,6 +110,18 @@ public: /// Gets the an instance of the respective physical CPU core. const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; + /// Gets the sole instance of the Scheduler at the current running core. + Kernel::Scheduler& CurrentScheduler(); + + /// Gets the sole instance of the Scheduler at the current running core. + const Kernel::Scheduler& CurrentScheduler() const; + + /// Gets the an instance of the current physical CPU core. + Kernel::PhysicalCore& CurrentPhysicalCore(); + + /// Gets the an instance of the current physical CPU core. + const Kernel::PhysicalCore& CurrentPhysicalCore() const; + /// Gets the an instance of the Synchronization Interface. Kernel::Synchronization& Synchronization(); @@ -191,6 +203,12 @@ public: /// Gets the shared memory object for Time services. const Kernel::SharedMemory& GetTimeSharedMem() const; + /// Suspend/unsuspend the OS. + void Suspend(bool in_suspention); + + /// Exceptional exit the OS. + void ExceptionalExit(); + private: friend class Object; friend class Process; @@ -219,6 +237,7 @@ private: struct Impl; std::unique_ptr impl; + bool exception_exited{}; }; } // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index a15011076..69202540b 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -2,12 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/assert.h" #include "common/logging/log.h" +#include "common/spin_lock.h" #include "core/arm/arm_interface.h" #ifdef ARCHITECTURE_x86_64 #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" #endif +#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" @@ -19,21 +22,23 @@ namespace Kernel { PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor) - : core_index{id} { + : interrupt_handler{}, core_index{id} { #ifdef ARCHITECTURE_x86_64 - arm_interface_32 = - std::make_unique(system, exclusive_monitor, core_index); - arm_interface_64 = - std::make_unique(system, exclusive_monitor, core_index); - + arm_interface_32 = std::make_unique(system, interrupt_handler, + exclusive_monitor, core_index); + arm_interface_64 = std::make_unique(system, interrupt_handler, + exclusive_monitor, core_index); #else using Core::ARM_Unicorn; - arm_interface_32 = std::make_unique(system, ARM_Unicorn::Arch::AArch32); - arm_interface_64 = std::make_unique(system, ARM_Unicorn::Arch::AArch64); + arm_interface_32 = + std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch32); + arm_interface_64 = + std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch64); LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); #endif scheduler = std::make_unique(system, core_index); + guard = std::make_unique(); } PhysicalCore::~PhysicalCore() = default; @@ -47,6 +52,10 @@ void PhysicalCore::Step() { arm_interface->Step(); } +void PhysicalCore::Idle() { + interrupt_handler.AwaitInterrupt(); +} + void PhysicalCore::Stop() { arm_interface->PrepareReschedule(); } @@ -63,4 +72,16 @@ void PhysicalCore::SetIs64Bit(bool is_64_bit) { } } +void PhysicalCore::Interrupt() { + guard->lock(); + interrupt_handler.SetInterrupt(true); + guard->unlock(); +} + +void PhysicalCore::ClearInterrupt() { + guard->lock(); + interrupt_handler.SetInterrupt(false); + guard->unlock(); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 3269166be..c3da30b72 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -7,6 +7,12 @@ #include #include +#include "core/arm/cpu_interrupt_handler.h" + +namespace Common { + class SpinLock; +} + namespace Kernel { class Scheduler; } // namespace Kernel @@ -32,11 +38,24 @@ public: /// Execute current jit state void Run(); + /// Set this core in IdleState. + void Idle(); /// Execute a single instruction in current jit. void Step(); /// Stop JIT execution/exit void Stop(); + /// Interrupt this physical core. + void Interrupt(); + + /// Clear this core's interrupt + void ClearInterrupt(); + + /// Check if this core is interrupted + bool IsInterrupted() const { + return interrupt_handler.IsInterrupted(); + } + // Shutdown this physical core. void Shutdown(); @@ -71,11 +90,13 @@ public: void SetIs64Bit(bool is_64_bit); private: + Core::CPUInterruptHandler interrupt_handler; std::size_t core_index; std::unique_ptr arm_interface_32; std::unique_ptr arm_interface_64; std::unique_ptr scheduler; Core::ARM_Interface* arm_interface{}; + std::unique_ptr guard; }; } // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c4c5199b1..7e26a54f4 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -30,14 +30,15 @@ namespace { /** * Sets up the primary application thread * + * @param system The system instance to create the main thread under. * @param owner_process The parent process for the main thread - * @param kernel The kernel instance to create the main thread under. * @param priority The priority to give the main thread */ -void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority, VAddr stack_top) { +void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); - auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, - owner_process.GetIdealCore(), stack_top, owner_process); + ThreadType type = THREADTYPE_USER; + auto thread_res = Thread::Create(system, type, "main", entry_point, priority, 0, + owner_process.GetIdealCore(), stack_top, &owner_process); std::shared_ptr thread = std::move(thread_res).Unwrap(); @@ -48,8 +49,12 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority, V thread->GetContext32().cpu_registers[1] = thread_handle; thread->GetContext64().cpu_registers[1] = thread_handle; + auto& kernel = system.Kernel(); // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires - thread->ResumeFromWait(); + { + SchedulerLock lock{kernel}; + thread->SetStatus(ThreadStatus::Ready); + } } } // Anonymous namespace @@ -294,7 +299,7 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { ChangeStatus(ProcessStatus::Running); - SetupMainThread(*this, kernel, main_thread_priority, main_thread_stack_top); + SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); resource_limit->Reserve(ResourceType::Threads, 1); resource_limit->Reserve(ResourceType::PhysicalMemory, main_thread_stack_size); } diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 1140c72a3..5166020a0 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -11,11 +11,15 @@ #include #include "common/assert.h" +#include "common/bit_util.h" +#include "common/fiber.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/cpu_manager.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/time_manager.h" @@ -27,78 +31,108 @@ GlobalScheduler::GlobalScheduler(KernelCore& kernel) : kernel{kernel} {} GlobalScheduler::~GlobalScheduler() = default; void GlobalScheduler::AddThread(std::shared_ptr thread) { + global_list_guard.lock(); thread_list.push_back(std::move(thread)); + global_list_guard.unlock(); } void GlobalScheduler::RemoveThread(std::shared_ptr thread) { + global_list_guard.lock(); thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), thread_list.end()); + global_list_guard.unlock(); } -void GlobalScheduler::UnloadThread(std::size_t core) { - Scheduler& sched = kernel.Scheduler(core); - sched.UnloadThread(); -} - -void GlobalScheduler::SelectThread(std::size_t core) { +u32 GlobalScheduler::SelectThreads() { const auto update_thread = [](Thread* thread, Scheduler& sched) { + sched.guard.lock(); if (thread != sched.selected_thread.get()) { if (thread == nullptr) { ++sched.idle_selection_count; } sched.selected_thread = SharedFrom(thread); } - sched.is_context_switch_pending = sched.selected_thread != sched.current_thread; + const bool reschedule_pending = sched.selected_thread != sched.current_thread; + sched.is_context_switch_pending = reschedule_pending; std::atomic_thread_fence(std::memory_order_seq_cst); + sched.guard.unlock(); + return reschedule_pending; }; - Scheduler& sched = kernel.Scheduler(core); - Thread* current_thread = nullptr; - // Step 1: Get top thread in schedule queue. - current_thread = scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); - if (current_thread) { - update_thread(current_thread, sched); - return; + if (!is_reselection_pending.load()) { + return 0; } - // Step 2: Try selecting a suggested thread. - Thread* winner = nullptr; - std::set sug_cores; - for (auto thread : suggested_queue[core]) { - s32 this_core = thread->GetProcessorID(); - Thread* thread_on_core = nullptr; - if (this_core >= 0) { - thread_on_core = scheduled_queue[this_core].front(); - } - if (this_core < 0 || thread != thread_on_core) { - winner = thread; - break; + std::array top_threads{}; + + u32 idle_cores{}; + + // Step 1: Get top thread in schedule queue. + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + Thread* top_thread = + scheduled_queue[core].empty() ? nullptr : scheduled_queue[core].front(); + if (top_thread != nullptr) { + // TODO(Blinkhawk): Implement Thread Pinning + } else { + idle_cores |= (1ul << core); } - sug_cores.insert(this_core); + top_threads[core] = top_thread; } - // if we got a suggested thread, select it, else do a second pass. - if (winner && winner->GetPriority() > 2) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); + + while (idle_cores != 0) { + u32 core_id = Common::CountTrailingZeroes32(idle_cores); + + if (!suggested_queue[core_id].empty()) { + std::array migration_candidates{}; + std::size_t num_candidates = 0; + auto iter = suggested_queue[core_id].begin(); + Thread* suggested = nullptr; + // Step 2: Try selecting a suggested thread. + while (iter != suggested_queue[core_id].end()) { + suggested = *iter; + iter++; + s32 suggested_core_id = suggested->GetProcessorID(); + Thread* top_thread = + suggested_core_id > 0 ? top_threads[suggested_core_id] : nullptr; + if (top_thread != suggested) { + if (top_thread != nullptr && + top_thread->GetPriority() < THREADPRIO_MAX_CORE_MIGRATION) { + suggested = nullptr; + break; + // There's a too high thread to do core migration, cancel + } + TransferToCore(suggested->GetPriority(), static_cast(core_id), suggested); + break; + } + migration_candidates[num_candidates++] = suggested_core_id; + } + // Step 3: Select a suggested thread from another core + if (suggested == nullptr) { + for (std::size_t i = 0; i < num_candidates; i++) { + s32 candidate_core = migration_candidates[i]; + suggested = top_threads[candidate_core]; + auto it = scheduled_queue[candidate_core].begin(); + it++; + Thread* next = it != scheduled_queue[candidate_core].end() ? *it : nullptr; + if (next != nullptr) { + TransferToCore(suggested->GetPriority(), static_cast(core_id), + suggested); + top_threads[candidate_core] = next; + break; + } + } + } + top_threads[core_id] = suggested; } - TransferToCore(winner->GetPriority(), static_cast(core), winner); - update_thread(winner, sched); - return; + + idle_cores &= ~(1ul << core_id); } - // Step 3: Select a suggested thread from another core - for (auto& src_core : sug_cores) { - auto it = scheduled_queue[src_core].begin(); - it++; - if (it != scheduled_queue[src_core].end()) { - Thread* thread_on_core = scheduled_queue[src_core].front(); - Thread* to_change = *it; - if (thread_on_core->IsRunning() || to_change->IsRunning()) { - UnloadThread(static_cast(src_core)); - } - TransferToCore(thread_on_core->GetPriority(), static_cast(core), thread_on_core); - current_thread = thread_on_core; - break; + u32 cores_needing_context_switch{}; + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + Scheduler& sched = kernel.Scheduler(core); + if (update_thread(top_threads[core], sched)) { + cores_needing_context_switch |= (1ul << core); } } - update_thread(current_thread, sched); + return cores_needing_context_switch; } bool GlobalScheduler::YieldThread(Thread* yielding_thread) { @@ -153,9 +187,6 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { if (winner != nullptr) { if (winner != yielding_thread) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), s32(core_id), winner); } } else { @@ -195,9 +226,6 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } if (winner != nullptr) { if (winner != yielding_thread) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), static_cast(core_id), winner); } } else { @@ -213,7 +241,9 @@ void GlobalScheduler::PreemptThreads() { const u32 priority = preemption_priorities[core_id]; if (scheduled_queue[core_id].size(priority) > 0) { - scheduled_queue[core_id].front(priority)->IncrementYieldCount(); + if (scheduled_queue[core_id].size(priority) > 1) { + scheduled_queue[core_id].front(priority)->IncrementYieldCount(); + } scheduled_queue[core_id].yield(priority); if (scheduled_queue[core_id].size(priority) > 1) { scheduled_queue[core_id].front(priority)->IncrementYieldCount(); @@ -247,9 +277,6 @@ void GlobalScheduler::PreemptThreads() { } if (winner != nullptr) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = winner->GetPriority() <= current_thread->GetPriority() ? winner : current_thread; @@ -280,9 +307,6 @@ void GlobalScheduler::PreemptThreads() { } if (winner != nullptr) { - if (winner->IsRunning()) { - UnloadThread(static_cast(winner->GetProcessorID())); - } TransferToCore(winner->GetPriority(), s32(core_id), winner); current_thread = winner; } @@ -292,6 +316,28 @@ void GlobalScheduler::PreemptThreads() { } } +void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, + Core::EmuThreadHandle global_thread) { + u32 current_core = global_thread.host_handle; + bool must_context_switch = global_thread.guest_handle != InvalidHandle && + (current_core < Core::Hardware::NUM_CPU_CORES); + while (cores_pending_reschedule != 0) { + u32 core = Common::CountTrailingZeroes32(cores_pending_reschedule); + ASSERT(core < Core::Hardware::NUM_CPU_CORES); + if (!must_context_switch || core != current_core) { + auto& phys_core = kernel.PhysicalCore(core); + phys_core.Interrupt(); + } else { + must_context_switch = true; + } + cores_pending_reschedule &= ~(1ul << core); + } + if (must_context_switch) { + auto& core_scheduler = kernel.CurrentScheduler(); + core_scheduler.TryDoContextSwitch(); + } +} + void GlobalScheduler::Suggest(u32 priority, std::size_t core, Thread* thread) { suggested_queue[core].add(thread, priority); } @@ -349,6 +395,108 @@ bool GlobalScheduler::AskForReselectionOrMarkRedundant(Thread* current_thread, } } +void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { + if (old_flags == thread->scheduling_state) { + return; + } + + if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == + ThreadSchedStatus::Runnable) { + // In this case the thread was running, now it's pausing/exitting + if (thread->processor_id >= 0) { + Unschedule(thread->current_priority, static_cast(thread->processor_id), thread); + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Unsuggest(thread->current_priority, core, thread); + } + } + } else if (thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable) { + // The thread is now set to running from being stopped + if (thread->processor_id >= 0) { + Schedule(thread->current_priority, static_cast(thread->processor_id), thread); + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Suggest(thread->current_priority, core, thread); + } + } + } + + SetReselectionPending(); +} + +void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priority) { + if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + return; + } + if (thread->processor_id >= 0) { + Unschedule(old_priority, static_cast(thread->processor_id), thread); + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Unsuggest(old_priority, core, thread); + } + } + + if (thread->processor_id >= 0) { + // TODO(Blinkhawk): compare it with current thread running on current core, instead of + // checking running + if (thread->IsRunning()) { + SchedulePrepend(thread->current_priority, static_cast(thread->processor_id), + thread); + } else { + Schedule(thread->current_priority, static_cast(thread->processor_id), thread); + } + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (core != static_cast(thread->processor_id) && + ((thread->affinity_mask >> core) & 1) != 0) { + Suggest(thread->current_priority, core, thread); + } + } + thread->IncrementYieldCount(); + SetReselectionPending(); +} + +void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, + s32 old_core) { + if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable || + thread->current_priority >= THREADPRIO_COUNT) { + return; + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (((old_affinity_mask >> core) & 1) != 0) { + if (core == static_cast(old_core)) { + Unschedule(thread->current_priority, core, thread); + } else { + Unsuggest(thread->current_priority, core, thread); + } + } + } + + for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + if (((thread->affinity_mask >> core) & 1) != 0) { + if (core == static_cast(thread->processor_id)) { + Schedule(thread->current_priority, core, thread); + } else { + Suggest(thread->current_priority, core, thread); + } + } + } + + thread->IncrementYieldCount(); + SetReselectionPending(); +} + void GlobalScheduler::Shutdown() { for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { scheduled_queue[core].clear(); @@ -374,13 +522,12 @@ void GlobalScheduler::Unlock() { ASSERT(scope_lock > 0); return; } - for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - SelectThread(i); - } + u32 cores_pending_reschedule = SelectThreads(); + Core::EmuThreadHandle leaving_thread = current_owner; current_owner = Core::EmuThreadHandle::InvalidHandle(); scope_lock = 1; inner_lock.unlock(); - // TODO(Blinkhawk): Setup the interrupts and change context on current core. + EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); } Scheduler::Scheduler(Core::System& system, std::size_t core_id) @@ -393,56 +540,83 @@ bool Scheduler::HaveReadyThreads() const { } Thread* Scheduler::GetCurrentThread() const { - return current_thread.get(); + if (current_thread) { + return current_thread.get(); + } + return idle_thread.get(); } Thread* Scheduler::GetSelectedThread() const { return selected_thread.get(); } -void Scheduler::SelectThreads() { - system.GlobalScheduler().SelectThread(core_id); -} - u64 Scheduler::GetLastContextSwitchTicks() const { return last_context_switch_time; } void Scheduler::TryDoContextSwitch() { + auto& phys_core = system.Kernel().CurrentPhysicalCore(); + if (phys_core.IsInterrupted()) { + phys_core.ClearInterrupt(); + } + guard.lock(); if (is_context_switch_pending) { SwitchContext(); + } else { + guard.unlock(); } } -void Scheduler::UnloadThread() { - Thread* const previous_thread = GetCurrentThread(); - Process* const previous_process = system.Kernel().CurrentProcess(); +void Scheduler::OnThreadStart() { + SwitchContextStep2(); +} - UpdateLastContextSwitchTime(previous_thread, previous_process); +void Scheduler::SwitchContextStep2() { + Thread* previous_thread = current_thread.get(); + Thread* new_thread = selected_thread.get(); - // Save context for previous thread - if (previous_thread) { - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32()); - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64()); - // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0()); + // Load context of new thread + Process* const previous_process = + previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; - if (previous_thread->GetStatus() == ThreadStatus::Running) { - // This is only the case when a reschedule is triggered without the current thread - // yielding execution (i.e. an event triggered, system core time-sliced, etc) - previous_thread->SetStatus(ThreadStatus::Ready); + if (new_thread) { + new_thread->context_guard.lock(); + ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), + "Thread must be assigned to this core."); + ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, + "Thread must be ready to become running."); + + // Cancel any outstanding wakeup events for this thread + current_thread = SharedFrom(new_thread); + new_thread->SetStatus(ThreadStatus::Running); + new_thread->SetIsRunning(true); + + auto* const thread_owner_process = current_thread->GetOwnerProcess(); + if (previous_process != thread_owner_process && thread_owner_process != nullptr) { + system.Kernel().MakeCurrentProcess(thread_owner_process); } - previous_thread->SetIsRunning(false); + if (!new_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.LoadContext(new_thread->GetContext32()); + cpu_core.LoadContext(new_thread->GetContext64()); + cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); + cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + } + } else { + current_thread = nullptr; + // Note: We do not reset the current process and current page table when idling because + // technically we haven't changed processes, our threads are just paused. } - current_thread = nullptr; + guard.unlock(); } void Scheduler::SwitchContext() { - Thread* const previous_thread = GetCurrentThread(); - Thread* const new_thread = GetSelectedThread(); + Thread* previous_thread = current_thread.get(); + Thread* new_thread = selected_thread.get(); is_context_switch_pending = false; if (new_thread == previous_thread) { + guard.unlock(); return; } @@ -452,51 +626,44 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext32()); - system.ArmInterface(core_id).SaveContext(previous_thread->GetContext64()); - // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(system.ArmInterface(core_id).GetTPIDR_EL0()); + if (!previous_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.SaveContext(previous_thread->GetContext32()); + cpu_core.SaveContext(previous_thread->GetContext64()); + // Save the TPIDR_EL0 system register in case it was modified. + previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + } if (previous_thread->GetStatus() == ThreadStatus::Running) { - // This is only the case when a reschedule is triggered without the current thread - // yielding execution (i.e. an event triggered, system core time-sliced, etc) previous_thread->SetStatus(ThreadStatus::Ready); } previous_thread->SetIsRunning(false); + previous_thread->context_guard.unlock(); } - // Load context of new thread - if (new_thread) { - ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), - "Thread must be assigned to this core."); - ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, - "Thread must be ready to become running."); - - // Cancel any outstanding wakeup events for this thread - new_thread->CancelWakeupTimer(); - current_thread = SharedFrom(new_thread); - new_thread->SetStatus(ThreadStatus::Running); - new_thread->SetIsRunning(true); - - auto* const thread_owner_process = current_thread->GetOwnerProcess(); - if (previous_process != thread_owner_process) { - system.Kernel().MakeCurrentProcess(thread_owner_process); - } + std::shared_ptr old_context; + if (previous_thread != nullptr) { + old_context = previous_thread->GetHostContext(); + } else { + old_context = idle_thread->GetHostContext(); + } - system.ArmInterface(core_id).LoadContext(new_thread->GetContext32()); - system.ArmInterface(core_id).LoadContext(new_thread->GetContext64()); - system.ArmInterface(core_id).SetTlsAddress(new_thread->GetTLSAddress()); - system.ArmInterface(core_id).SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + std::shared_ptr next_context; + if (new_thread != nullptr) { + next_context = new_thread->GetHostContext(); } else { - current_thread = nullptr; - // Note: We do not reset the current process and current page table when idling because - // technically we haven't changed processes, our threads are just paused. + next_context = idle_thread->GetHostContext(); } + + Common::Fiber::YieldTo(old_context, next_context); + /// When a thread wakes up, the scheduler may have changed to other in another core. + auto& next_scheduler = system.Kernel().CurrentScheduler(); + next_scheduler.SwitchContextStep2(); } void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { const u64 prev_switch_ticks = last_context_switch_time; - const u64 most_recent_switch_ticks = system.CoreTiming().GetTicks(); + const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); const u64 update_ticks = most_recent_switch_ticks - prev_switch_ticks; if (thread != nullptr) { @@ -510,6 +677,16 @@ void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { last_context_switch_time = most_recent_switch_ticks; } +void Scheduler::Initialize() { + std::string name = "Idle Thread Id:" + std::to_string(core_id); + std::function init_func = system.GetCpuManager().GetIdleThreadStartFunc(); + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + ThreadType type = static_cast(THREADTYPE_KERNEL | THREADTYPE_HLE | THREADTYPE_IDLE); + auto thread_res = Thread::Create(system, type, name, 0, 64, 0, static_cast(core_id), 0, + nullptr, std::move(init_func), init_func_parameter); + idle_thread = std::move(thread_res).Unwrap(); +} + void Scheduler::Shutdown() { current_thread = nullptr; selected_thread = nullptr; diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 07df33f9c..16655b03f 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -11,6 +11,7 @@ #include "common/common_types.h" #include "common/multi_level_queue.h" +#include "common/spin_lock.h" #include "core/hardware_properties.h" #include "core/hle/kernel/thread.h" @@ -41,41 +42,17 @@ public: return thread_list; } - /** - * Add a thread to the suggested queue of a cpu core. Suggested threads may be - * picked if no thread is scheduled to run on the core. - */ - void Suggest(u32 priority, std::size_t core, Thread* thread); - - /** - * Remove a thread to the suggested queue of a cpu core. Suggested threads may be - * picked if no thread is scheduled to run on the core. - */ - void Unsuggest(u32 priority, std::size_t core, Thread* thread); - - /** - * Add a thread to the scheduling queue of a cpu core. The thread is added at the - * back the queue in its priority level. - */ - void Schedule(u32 priority, std::size_t core, Thread* thread); + /// Notify the scheduler a thread's status has changed. + void AdjustSchedulingOnStatus(Thread* thread, u32 old_flags); - /** - * Add a thread to the scheduling queue of a cpu core. The thread is added at the - * front the queue in its priority level. - */ - void SchedulePrepend(u32 priority, std::size_t core, Thread* thread); + /// Notify the scheduler a thread's priority has changed. + void AdjustSchedulingOnPriority(Thread* thread, u32 old_priority); - /// Reschedule an already scheduled thread based on a new priority - void Reschedule(u32 priority, std::size_t core, Thread* thread); - - /// Unschedules a thread. - void Unschedule(u32 priority, std::size_t core, Thread* thread); - - /// Selects a core and forces it to unload its current thread's context - void UnloadThread(std::size_t core); + /// Notify the scheduler a thread's core and/or affinity mask has changed. + void AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, s32 old_core); /** - * Takes care of selecting the new scheduled thread in three steps: + * Takes care of selecting the new scheduled threads in three steps: * * 1. First a thread is selected from the top of the priority queue. If no thread * is obtained then we move to step two, else we are done. @@ -85,8 +62,10 @@ public: * * 3. Third is no suggested thread is found, we do a second pass and pick a running * thread in another core and swap it with its current thread. + * + * returns the cores needing scheduling. */ - void SelectThread(std::size_t core); + u32 SelectThreads(); bool HaveReadyThreads(std::size_t core_id) const { return !scheduled_queue[core_id].empty(); @@ -149,6 +128,39 @@ private: /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling /// and reschedules current core if needed. void Unlock(); + + void EnableInterruptAndSchedule(u32 cores_pending_reschedule, Core::EmuThreadHandle global_thread); + + /** + * Add a thread to the suggested queue of a cpu core. Suggested threads may be + * picked if no thread is scheduled to run on the core. + */ + void Suggest(u32 priority, std::size_t core, Thread* thread); + + /** + * Remove a thread to the suggested queue of a cpu core. Suggested threads may be + * picked if no thread is scheduled to run on the core. + */ + void Unsuggest(u32 priority, std::size_t core, Thread* thread); + + /** + * Add a thread to the scheduling queue of a cpu core. The thread is added at the + * back the queue in its priority level. + */ + void Schedule(u32 priority, std::size_t core, Thread* thread); + + /** + * Add a thread to the scheduling queue of a cpu core. The thread is added at the + * front the queue in its priority level. + */ + void SchedulePrepend(u32 priority, std::size_t core, Thread* thread); + + /// Reschedule an already scheduled thread based on a new priority + void Reschedule(u32 priority, std::size_t core, Thread* thread); + + /// Unschedules a thread. + void Unschedule(u32 priority, std::size_t core, Thread* thread); + /** * Transfers a thread into an specific core. If the destination_core is -1 * it will be unscheduled from its source code and added into its suggested @@ -174,6 +186,8 @@ private: std::atomic scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; + Common::SpinLock global_list_guard{}; + /// Lists all thread ids that aren't deleted/etc. std::vector> thread_list; KernelCore& kernel; @@ -190,12 +204,6 @@ public: /// Reschedules to the next available thread (call after current thread is suspended) void TryDoContextSwitch(); - /// Unloads currently running thread - void UnloadThread(); - - /// Select the threads in top of the scheduling multilist. - void SelectThreads(); - /// Gets the current running thread Thread* GetCurrentThread() const; @@ -209,15 +217,22 @@ public: return is_context_switch_pending; } + void Initialize(); + /// Shutdowns the scheduler. void Shutdown(); + void OnThreadStart(); + private: friend class GlobalScheduler; /// Switches the CPU's active thread context to that of the specified thread void SwitchContext(); + /// When a thread wakes up, it must run this through it's new scheduler + void SwitchContextStep2(); + /** * Called on every context switch to update the internal timestamp * This also updates the running time ticks for the given thread and @@ -233,12 +248,15 @@ private: std::shared_ptr current_thread = nullptr; std::shared_ptr selected_thread = nullptr; + std::shared_ptr idle_thread = nullptr; Core::System& system; u64 last_context_switch_time = 0; u64 idle_selection_count = 0; const std::size_t core_id; + Common::SpinLock guard{}; + bool is_context_switch_pending = false; }; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4ae4529f5..d7f0dcabd 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -863,9 +863,9 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { const u64 thread_ticks = current_thread->GetTotalCPUTimeTicks(); - out_ticks = thread_ticks + (core_timing.GetTicks() - prev_ctx_ticks); + out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); } else if (same_thread && info_sub_id == system.CurrentCoreIndex()) { - out_ticks = core_timing.GetTicks() - prev_ctx_ticks; + out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; } *result = out_ticks; @@ -1428,9 +1428,10 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(ResourceType::Threads, 1)); + ThreadType type = THREADTYPE_USER; CASCADE_RESULT(std::shared_ptr thread, - Thread::Create(kernel, "", entry_point, priority, arg, processor_id, stack_top, - *current_process)); + Thread::Create(system, type, "", entry_point, priority, arg, processor_id, stack_top, + current_process)); const auto new_thread_handle = current_process->GetHandleTable().Create(thread); if (new_thread_handle.Failed()) { @@ -1513,13 +1514,6 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } else { current_thread->Sleep(nanoseconds); } - - if (is_redundant) { - // If it's redundant, the core is pretty much idle. Some games keep idling - // a core while it's doing nothing, we advance timing to avoid costly continuous - // calls. - system.CoreTiming().AddTicks(2000); - } system.PrepareReschedule(current_thread->GetProcessorID()); } @@ -1725,10 +1719,7 @@ static u64 GetSystemTick(Core::System& system) { auto& core_timing = system.CoreTiming(); // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) - const u64 result{Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks())}; - - // Advance time to defeat dumb games that busy-wait for the frame to end. - core_timing.AddTicks(400); + const u64 result{system.CoreTiming().GetClockTicks()}; return result; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index db7f379ac..8cb3593db 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -9,12 +9,14 @@ #include "common/assert.h" #include "common/common_types.h" +#include "common/fiber.h" #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/cpu_manager.h" #include "core/hardware_properties.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" @@ -23,6 +25,7 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" #include "core/memory.h" @@ -44,6 +47,7 @@ Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} Thread::~Thread() = default; void Thread::Stop() { + SchedulerLock lock(kernel); // Cancel any outstanding wakeup events for this thread Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), global_handle); @@ -71,9 +75,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { // This function might be called from any thread so we have to be cautious and use the // thread-safe version of ScheduleEvent. - const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); Core::System::GetInstance().CoreTiming().ScheduleEvent( - cycles, kernel.ThreadWakeupCallbackEventType(), global_handle); + nanoseconds, kernel.ThreadWakeupCallbackEventType(), global_handle); } void Thread::CancelWakeupTimer() { @@ -125,6 +128,16 @@ void Thread::ResumeFromWait() { SetStatus(ThreadStatus::Ready); } +void Thread::OnWakeUp() { + SchedulerLock lock(kernel); + if (activity == ThreadActivity::Paused) { + SetStatus(ThreadStatus::Paused); + return; + } + + SetStatus(ThreadStatus::Ready); +} + void Thread::CancelWait() { if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { is_sync_cancelled = true; @@ -153,12 +166,29 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, context.fpcr = 0; } -ResultVal> Thread::Create(KernelCore& kernel, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process& owner_process) { +std::shared_ptr Thread::GetHostContext() const { + return host_context; +} + +ResultVal> Thread::Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, u32 priority, + u64 arg, s32 processor_id, VAddr stack_top, + Process* owner_process) { + std::function init_func = system.GetCpuManager().GetGuestThreadStartFunc(); + void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater(); + return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top, + owner_process, std::move(init_func), init_func_parameter); +} + +ResultVal> Thread::Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, u32 priority, + u64 arg, s32 processor_id, VAddr stack_top, + Process* owner_process, + std::function&& thread_start_func, + void* thread_start_parameter) { + auto& kernel = system.Kernel(); // Check if priority is in ranged. Lowest priority -> highest priority id. - if (priority > THREADPRIO_LOWEST) { + if (priority > THREADPRIO_LOWEST && (type_flags & THREADTYPE_IDLE == 0)) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); return ERR_INVALID_THREAD_PRIORITY; } @@ -168,11 +198,12 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin return ERR_INVALID_PROCESSOR_ID; } - auto& system = Core::System::GetInstance(); - if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) { - LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); - // TODO (bunnei): Find the correct error code to use here - return RESULT_UNKNOWN; + if (owner_process) { + if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) { + LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); + // TODO (bunnei): Find the correct error code to use here + return RESULT_UNKNOWN; + } } std::shared_ptr thread = std::make_shared(kernel); @@ -183,7 +214,7 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin thread->stack_top = stack_top; thread->tpidr_el0 = 0; thread->nominal_priority = thread->current_priority = priority; - thread->last_running_ticks = system.CoreTiming().GetTicks(); + thread->last_running_ticks = 0; thread->processor_id = processor_id; thread->ideal_core = processor_id; thread->affinity_mask = 1ULL << processor_id; @@ -193,16 +224,27 @@ ResultVal> Thread::Create(KernelCore& kernel, std::strin thread->wait_handle = 0; thread->name = std::move(name); thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); - thread->owner_process = &owner_process; - auto& scheduler = kernel.GlobalScheduler(); - scheduler.AddThread(thread); - thread->tls_address = thread->owner_process->CreateTLSRegion(); - - thread->owner_process->RegisterThread(thread.get()); - - ResetThreadContext32(thread->context_32, static_cast(stack_top), - static_cast(entry_point), static_cast(arg)); - ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); + thread->owner_process = owner_process; + thread->type = type_flags; + if ((type_flags & THREADTYPE_IDLE) == 0) { + auto& scheduler = kernel.GlobalScheduler(); + scheduler.AddThread(thread); + } + if (owner_process) { + thread->tls_address = thread->owner_process->CreateTLSRegion(); + thread->owner_process->RegisterThread(thread.get()); + } else { + thread->tls_address = 0; + } + // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used + // to initialize the context + if ((type_flags & THREADTYPE_HLE) == 0) { + ResetThreadContext32(thread->context_32, static_cast(stack_top), + static_cast(entry_point), static_cast(arg)); + ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); + } + thread->host_context = + std::make_shared(std::move(thread_start_func), thread_start_parameter); return MakeResult>(std::move(thread)); } @@ -258,7 +300,7 @@ void Thread::SetStatus(ThreadStatus new_status) { } if (status == ThreadStatus::Running) { - last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); + last_running_ticks = Core::System::GetInstance().CoreTiming().GetCPUTicks(); } status = new_status; @@ -375,38 +417,55 @@ void Thread::SetActivity(ThreadActivity value) { } void Thread::Sleep(s64 nanoseconds) { - // Sleep current thread and check for next thread to schedule - SetStatus(ThreadStatus::WaitSleep); + Handle event_handle{}; + { + SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); + SetStatus(ThreadStatus::WaitSleep); + } - // Create an event to wake the thread up after the specified nanosecond delay has passed - WakeAfterDelay(nanoseconds); + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); + } } bool Thread::YieldSimple() { - auto& scheduler = kernel.GlobalScheduler(); - return scheduler.YieldThread(this); + bool result{}; + { + SchedulerLock lock(kernel); + result = kernel.GlobalScheduler().YieldThread(this); + } + return result; } bool Thread::YieldAndBalanceLoad() { - auto& scheduler = kernel.GlobalScheduler(); - return scheduler.YieldThreadAndBalanceLoad(this); + bool result{}; + { + SchedulerLock lock(kernel); + result = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); + } + return result; } bool Thread::YieldAndWaitForLoadBalancing() { - auto& scheduler = kernel.GlobalScheduler(); - return scheduler.YieldThreadAndWaitForLoadBalancing(this); + bool result{}; + { + SchedulerLock lock(kernel); + result = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); + } + return result; } void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { const u32 old_flags = scheduling_state; scheduling_state = (scheduling_state & static_cast(ThreadSchedMasks::HighMask)) | static_cast(new_status); - AdjustSchedulingOnStatus(old_flags); + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_flags); } void Thread::SetCurrentPriority(u32 new_priority) { const u32 old_priority = std::exchange(current_priority, new_priority); - AdjustSchedulingOnPriority(old_priority); + kernel.GlobalScheduler().AdjustSchedulingOnPriority(this, old_priority); } ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { @@ -443,111 +502,12 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { processor_id = ideal_core; } } - AdjustSchedulingOnAffinity(old_affinity_mask, old_core); + kernel.GlobalScheduler().AdjustSchedulingOnAffinity(this, old_affinity_mask, old_core); } } return RESULT_SUCCESS; } -void Thread::AdjustSchedulingOnStatus(u32 old_flags) { - if (old_flags == scheduling_state) { - return; - } - - auto& scheduler = kernel.GlobalScheduler(); - if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == - ThreadSchedStatus::Runnable) { - // In this case the thread was running, now it's pausing/exitting - if (processor_id >= 0) { - scheduler.Unschedule(current_priority, static_cast(processor_id), this); - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Unsuggest(current_priority, core, this); - } - } - } else if (GetSchedulingStatus() == ThreadSchedStatus::Runnable) { - // The thread is now set to running from being stopped - if (processor_id >= 0) { - scheduler.Schedule(current_priority, static_cast(processor_id), this); - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Suggest(current_priority, core, this); - } - } - } - - scheduler.SetReselectionPending(); -} - -void Thread::AdjustSchedulingOnPriority(u32 old_priority) { - if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) { - return; - } - auto& scheduler = kernel.GlobalScheduler(); - if (processor_id >= 0) { - scheduler.Unschedule(old_priority, static_cast(processor_id), this); - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Unsuggest(old_priority, core, this); - } - } - - // Add thread to the new priority queues. - Thread* current_thread = GetCurrentThread(); - - if (processor_id >= 0) { - if (current_thread == this) { - scheduler.SchedulePrepend(current_priority, static_cast(processor_id), this); - } else { - scheduler.Schedule(current_priority, static_cast(processor_id), this); - } - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (core != static_cast(processor_id) && ((affinity_mask >> core) & 1) != 0) { - scheduler.Suggest(current_priority, core, this); - } - } - - scheduler.SetReselectionPending(); -} - -void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) { - auto& scheduler = kernel.GlobalScheduler(); - if (GetSchedulingStatus() != ThreadSchedStatus::Runnable || - current_priority >= THREADPRIO_COUNT) { - return; - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (((old_affinity_mask >> core) & 1) != 0) { - if (core == static_cast(old_core)) { - scheduler.Unschedule(current_priority, core, this); - } else { - scheduler.Unsuggest(current_priority, core, this); - } - } - } - - for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - if (((affinity_mask >> core) & 1) != 0) { - if (core == static_cast(processor_id)) { - scheduler.Schedule(current_priority, core, this); - } else { - scheduler.Suggest(current_priority, core, this); - } - } - } - - scheduler.SetReselectionPending(); -} - //////////////////////////////////////////////////////////////////////////////////////////////////// /** diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 23fdef8a4..33d340b47 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -9,23 +9,42 @@ #include #include "common/common_types.h" +#include "common/spin_lock.h" #include "core/arm/arm_interface.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/synchronization_object.h" #include "core/hle/result.h" +namespace Common { +class Fiber; +} + +namespace Core { +class System; +} + namespace Kernel { +class GlobalScheduler; class KernelCore; class Process; class Scheduler; enum ThreadPriority : u32 { - THREADPRIO_HIGHEST = 0, ///< Highest thread priority - THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps - THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps - THREADPRIO_LOWEST = 63, ///< Lowest thread priority - THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. + THREADPRIO_HIGHEST = 0, ///< Highest thread priority + THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration + THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps + THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps + THREADPRIO_LOWEST = 63, ///< Lowest thread priority + THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. +}; + +enum ThreadType : u32 { + THREADTYPE_USER = 0x1, + THREADTYPE_KERNEL = 0x2, + THREADTYPE_HLE = 0x4, + THREADTYPE_IDLE = 0x8, + THREADTYPE_SUSPEND = 0x10, }; enum ThreadProcessorId : s32 { @@ -111,22 +130,43 @@ public: std::function thread, std::shared_ptr object, std::size_t index)>; + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param system The instance of the whole system + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @return A shared pointer to the newly created thread + */ + static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, + VAddr entry_point, u32 priority, u64 arg, + s32 processor_id, VAddr stack_top, + Process* owner_process); + /** * Creates and returns a new thread. The new thread is immediately scheduled - * @param kernel The kernel instance this thread will be created under. + * @param system The instance of the whole system * @param name The friendly name desired for the thread * @param entry_point The address at which the thread should start execution * @param priority The thread's priority * @param arg User data to pass to the thread * @param processor_id The ID(s) of the processors on which the thread is desired to be run * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @param thread_start_func The function where the host context will start. + * @param thread_start_parameter The parameter which will passed to host context on init * @return A shared pointer to the newly created thread */ - static ResultVal> Create(KernelCore& kernel, std::string name, + static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, VAddr entry_point, u32 priority, u64 arg, s32 processor_id, VAddr stack_top, - Process& owner_process); + Process* owner_process, + std::function&& thread_start_func, + void* thread_start_parameter); std::string GetName() const override { return name; @@ -192,7 +232,9 @@ public: } /// Resumes a thread from waiting - void ResumeFromWait(); + void /* deprecated */ ResumeFromWait(); + + void OnWakeUp(); /// Cancels a waiting operation that this thread may or may not be within. /// @@ -206,10 +248,10 @@ public: * Schedules an event to wake up the specified thread after the specified delay * @param nanoseconds The time this thread will be allowed to sleep for */ - void WakeAfterDelay(s64 nanoseconds); + void /* deprecated */ WakeAfterDelay(s64 nanoseconds); /// Cancel any outstanding wakeup events for this thread - void CancelWakeupTimer(); + void /* deprecated */ CancelWakeupTimer(); /** * Sets the result after the thread awakens (from svcWaitSynchronization) @@ -290,6 +332,12 @@ public: return context_64; } + bool IsHLEThread() const { + return (type & THREADTYPE_HLE) != 0; + } + + std::shared_ptr GetHostContext() const; + ThreadStatus GetStatus() const { return status; } @@ -467,16 +515,19 @@ public: } private: + friend class GlobalScheduler; + friend class Scheduler; + void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); - void AdjustSchedulingOnStatus(u32 old_flags); - void AdjustSchedulingOnPriority(u32 old_priority); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); ThreadContext32 context_32{}; ThreadContext64 context_64{}; + Common::SpinLock context_guard{}; + std::shared_ptr host_context{}; u64 thread_id = 0; @@ -485,6 +536,8 @@ private: VAddr entry_point = 0; VAddr stack_top = 0; + ThreadType type; + /// Nominal thread priority, as set by the emulated application. /// The nominal priority is the thread priority without priority /// inheritance taken into account. diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 21b290468..0b8f0d993 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -19,7 +19,7 @@ TimeManager::TimeManager(Core::System& system) : system{system} { Handle proper_handle = static_cast(thread_handle); std::shared_ptr thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); - thread->ResumeFromWait(); + thread->OnWakeUp(); }); } diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 1f2131ec8..cb35919e9 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -23,7 +23,7 @@ void Controller_DebugPad::OnRelease() {} void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetTicks(); + shared_memory.header.timestamp = core_timing.GetCPUTicks(); shared_memory.header.total_entry_count = 17; if (!IsControllerActivated()) { diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 6e990dd00..b7b7bfeae 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -19,7 +19,7 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetTicks(); + shared_memory.header.timestamp = core_timing.GetCPUTicks(); shared_memory.header.total_entry_count = 17; if (!IsControllerActivated()) { diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 9a8d354ba..feae89525 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -21,7 +21,7 @@ void Controller_Keyboard::OnRelease() {} void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetTicks(); + shared_memory.header.timestamp = core_timing.GetCPUTicks(); shared_memory.header.total_entry_count = 17; if (!IsControllerActivated()) { diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 93d88ea50..ac40989c5 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -19,7 +19,7 @@ void Controller_Mouse::OnRelease() {} void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetTicks(); + shared_memory.header.timestamp = core_timing.GetCPUTicks(); shared_memory.header.total_entry_count = 17; if (!IsControllerActivated()) { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 6fbee7efa..ef67ad690 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -328,7 +328,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* const auto& last_entry = main_controller->npad[main_controller->common.last_entry_index]; - main_controller->common.timestamp = core_timing.GetTicks(); + main_controller->common.timestamp = core_timing.GetCPUTicks(); main_controller->common.last_entry_index = (main_controller->common.last_entry_index + 1) % 17; diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 9e527d176..e7483bfa2 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -23,7 +23,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u } CommonHeader header{}; - header.timestamp = core_timing.GetTicks(); + header.timestamp = core_timing.GetCPUTicks(); header.total_entry_count = 17; header.entry_count = 0; header.last_entry_index = 0; diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 1c6e55566..e326f8f5c 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -22,7 +22,7 @@ void Controller_Touchscreen::OnRelease() {} void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - shared_memory.header.timestamp = core_timing.GetTicks(); + shared_memory.header.timestamp = core_timing.GetCPUTicks(); shared_memory.header.total_entry_count = 17; if (!IsControllerActivated()) { @@ -49,7 +49,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; - const u64 tick = core_timing.GetTicks(); + const u64 tick = core_timing.GetCPUTicks(); touch_entry.delta_time = tick - last_touch; last_touch = tick; touch_entry.finger = Settings::values.touchscreen.finger; diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index 27511b27b..2503ef241 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -20,7 +20,7 @@ void Controller_XPad::OnRelease() {} void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { for (auto& xpad_entry : shared_memory.shared_memory_entries) { - xpad_entry.header.timestamp = core_timing.GetTicks(); + xpad_entry.header.timestamp = core_timing.GetCPUTicks(); xpad_entry.header.total_entry_count = 17; if (!IsControllerActivated()) { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 57d5edea7..e9020e0dc 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -39,11 +39,9 @@ namespace Service::HID { // Updating period for each HID device. // TODO(ogniK): Find actual polling rate of hid -constexpr s64 pad_update_ticks = static_cast(Core::Hardware::BASE_CLOCK_RATE / 66); -[[maybe_unused]] constexpr s64 accelerometer_update_ticks = - static_cast(Core::Hardware::BASE_CLOCK_RATE / 100); -[[maybe_unused]] constexpr s64 gyroscope_update_ticks = - static_cast(Core::Hardware::BASE_CLOCK_RATE / 100); +constexpr s64 pad_update_ticks = static_cast(1000000000 / 66); +[[maybe_unused]] constexpr s64 accelerometer_update_ticks = static_cast(1000000000 / 100); +[[maybe_unused]] constexpr s64 gyroscope_update_ticks = static_cast(1000000000 / 100); constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system) @@ -78,8 +76,8 @@ IAppletResource::IAppletResource(Core::System& system) // Register update callbacks pad_update_event = - Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 cycles_late) { - UpdateControllers(userdata, cycles_late); + Core::Timing::CreateEvent("HID::UpdatePadCallback", [this](u64 userdata, s64 ns_late) { + UpdateControllers(userdata, ns_late); }); // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) @@ -109,7 +107,7 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { rb.PushCopyObjects(shared_mem); } -void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) { +void IAppletResource::UpdateControllers(u64 userdata, s64 ns_late) { auto& core_timing = system.CoreTiming(); const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); @@ -120,7 +118,7 @@ void IAppletResource::UpdateControllers(u64 userdata, s64 cycles_late) { controller->OnUpdate(core_timing, shared_mem->GetPointer(), SHARED_MEMORY_SIZE); } - core_timing.ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event); + core_timing.ScheduleEvent(pad_update_ticks - ns_late, pad_update_event); } class IActiveVibrationDeviceList final : public ServiceFramework { diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 36ed6f7da..e82fd031b 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -98,7 +98,7 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 5}; rb.Push(RESULT_SUCCESS); - rb.PushRaw(system.CoreTiming().GetTicks()); + rb.PushRaw(system.CoreTiming().GetCPUTicks()); rb.PushRaw(0); } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 0d913334e..fba89e7a6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -200,8 +200,7 @@ u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector& input, std::vector& o IoctlGetGpuTime params{}; std::memcpy(¶ms, input.data(), input.size()); - const auto ns = Core::Timing::CyclesToNs(system.CoreTiming().GetTicks()); - params.gpu_time = static_cast(ns.count()); + params.gpu_time = static_cast(system.CoreTiming().GetGlobalTimeNs().count()); std::memcpy(output.data(), ¶ms, output.size()); return 0; } diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 437bc5dee..aaf28995d 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -27,8 +27,8 @@ namespace Service::NVFlinger { -constexpr s64 frame_ticks = static_cast(Core::Hardware::BASE_CLOCK_RATE / 60); -constexpr s64 frame_ticks_30fps = static_cast(Core::Hardware::BASE_CLOCK_RATE / 30); +constexpr s64 frame_ticks = static_cast(1000000000 / 60); +constexpr s64 frame_ticks_30fps = static_cast(1000000000 / 30); NVFlinger::NVFlinger(Core::System& system) : system(system) { displays.emplace_back(0, "Default", system); @@ -39,11 +39,10 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { // Schedule the screen composition events composition_event = - Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 cycles_late) { + Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 ns_late) { Compose(); - const auto ticks = - Settings::values.force_30fps_mode ? frame_ticks_30fps : GetNextTicks(); - this->system.CoreTiming().ScheduleEvent(std::max(0LL, ticks - cycles_late), + const auto ticks = GetNextTicks(); + this->system.CoreTiming().ScheduleEvent(std::max(0LL, ticks - ns_late), composition_event); }); @@ -223,7 +222,7 @@ void NVFlinger::Compose() { s64 NVFlinger::GetNextTicks() const { constexpr s64 max_hertz = 120LL; - return (Core::Hardware::BASE_CLOCK_RATE * (1LL << swap_interval)) / max_hertz; + return (1000000000 * (1LL << swap_interval)) / max_hertz; } } // namespace Service::NVFlinger diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp index 1575f0b49..59a272f4a 100644 --- a/src/core/hle/service/time/standard_steady_clock_core.cpp +++ b/src/core/hle/service/time/standard_steady_clock_core.cpp @@ -11,9 +11,8 @@ namespace Service::Time::Clock { TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { - const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( - Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Hardware::CNTFREQ)}; + const TimeSpanType ticks_time_span{ + TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp index 44d5bc651..8baaa2a6a 100644 --- a/src/core/hle/service/time/tick_based_steady_clock_core.cpp +++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp @@ -11,9 +11,8 @@ namespace Service::Time::Clock { SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { - const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( - Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Hardware::CNTFREQ)}; + const TimeSpanType ticks_time_span{ + TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; return {ticks_time_span.ToSeconds(), GetClockSourceId()}; } diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 67f1bbcf3..4cf58a61a 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -234,9 +234,8 @@ void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERe const auto current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { - const auto ticks{Clock::TimeSpanType::FromTicks( - Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Hardware::CNTFREQ)}; + const auto ticks{Clock::TimeSpanType::FromTicks(system.CoreTiming().GetClockTicks(), + Core::Hardware::CNTFREQ)}; const s64 base_time_point{context.offset + current_time_point.time_point - ticks.ToSeconds()}; IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index 999ec1e51..e0ae9f874 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -30,8 +30,7 @@ void SharedMemory::SetupStandardSteadyClock(Core::System& system, const Common::UUID& clock_source_id, Clock::TimeSpanType current_time_point) { const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( - Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), - Core::Hardware::CNTFREQ)}; + system.CoreTiming().GetClockTicks(), Core::Hardware::CNTFREQ)}; const Clock::SteadyClockContext context{ static_cast(current_time_point.nanoseconds - ticks_time_span.nanoseconds), clock_source_id}; -- cgit v1.2.3 From 49ba56399563a87f29b4d89eb04b1178a571eb61 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 12:40:33 -0400 Subject: SVC: Correct CreateThread, StartThread, ExitThread, SleepThread. --- src/core/hle/kernel/svc.cpp | 18 +++++------------- src/core/hle/kernel/thread.cpp | 38 ++++++++++++++++++-------------------- src/core/hle/kernel/thread.h | 12 ++++++++---- 3 files changed, 31 insertions(+), 37 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d7f0dcabd..dfb032b4b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1464,13 +1464,7 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { ASSERT(thread->GetStatus() == ThreadStatus::Dormant); - thread->ResumeFromWait(); - - if (thread->GetStatus() == ThreadStatus::Ready) { - system.PrepareReschedule(thread->GetProcessorID()); - } - - return RESULT_SUCCESS; + return thread->Start(); } /// Called when a thread exits @@ -1478,9 +1472,8 @@ static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); auto* const current_thread = system.CurrentScheduler().GetCurrentThread(); - current_thread->Stop(); system.GlobalScheduler().RemoveThread(SharedFrom(current_thread)); - system.PrepareReschedule(); + current_thread->Stop(); } /// Sleep the current thread @@ -1500,13 +1493,13 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (nanoseconds <= 0) { switch (static_cast(nanoseconds)) { case SleepType::YieldWithoutLoadBalancing: - is_redundant = current_thread->YieldSimple(); + current_thread->YieldSimple(); break; case SleepType::YieldWithLoadBalancing: - is_redundant = current_thread->YieldAndBalanceLoad(); + current_thread->YieldAndBalanceLoad(); break; case SleepType::YieldAndWaitForLoadBalancing: - is_redundant = current_thread->YieldAndWaitForLoadBalancing(); + current_thread->YieldAndWaitForLoadBalancing(); break; default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); @@ -1514,7 +1507,6 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } else { current_thread->Sleep(nanoseconds); } - system.PrepareReschedule(current_thread->GetProcessorID()); } /// Wait process wide key atomic diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8cb3593db..d9e610272 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -56,12 +56,6 @@ void Thread::Stop() { SetStatus(ThreadStatus::Dead); Signal(); - // Clean up any dangling references in objects that this thread was waiting for - for (auto& wait_object : wait_objects) { - wait_object->RemoveWaitingThread(SharedFrom(this)); - } - wait_objects.clear(); - owner_process->UnregisterThread(this); // Mark the TLS slot in the thread's page as free. @@ -138,6 +132,12 @@ void Thread::OnWakeUp() { SetStatus(ThreadStatus::Ready); } +ResultCode Thread::Start() { + SchedulerLock lock(kernel); + SetStatus(ThreadStatus::Ready); + return RESULT_SUCCESS; +} + void Thread::CancelWait() { if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { is_sync_cancelled = true; @@ -188,7 +188,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy void* thread_start_parameter) { auto& kernel = system.Kernel(); // Check if priority is in ranged. Lowest priority -> highest priority id. - if (priority > THREADPRIO_LOWEST && (type_flags & THREADTYPE_IDLE == 0)) { + if (priority > THREADPRIO_LOWEST && ((type_flags & THREADTYPE_IDLE) == 0)) { LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); return ERR_INVALID_THREAD_PRIORITY; } @@ -416,7 +416,7 @@ void Thread::SetActivity(ThreadActivity value) { } } -void Thread::Sleep(s64 nanoseconds) { +ResultCode Thread::Sleep(s64 nanoseconds) { Handle event_handle{}; { SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); @@ -427,33 +427,31 @@ void Thread::Sleep(s64 nanoseconds) { auto& time_manager = kernel.TimeManager(); time_manager.UnscheduleTimeEvent(event_handle); } + return RESULT_SUCCESS; } -bool Thread::YieldSimple() { - bool result{}; +ResultCode Thread::YieldSimple() { { SchedulerLock lock(kernel); - result = kernel.GlobalScheduler().YieldThread(this); + kernel.GlobalScheduler().YieldThread(this); } - return result; + return RESULT_SUCCESS; } -bool Thread::YieldAndBalanceLoad() { - bool result{}; +ResultCode Thread::YieldAndBalanceLoad() { { SchedulerLock lock(kernel); - result = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); + kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); } - return result; + return RESULT_SUCCESS; } -bool Thread::YieldAndWaitForLoadBalancing() { - bool result{}; +ResultCode Thread::YieldAndWaitForLoadBalancing() { { SchedulerLock lock(kernel); - result = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); + kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); } - return result; + return RESULT_SUCCESS; } void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 33d340b47..78a4357b0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -236,6 +236,8 @@ public: void OnWakeUp(); + ResultCode Start(); + /// Cancels a waiting operation that this thread may or may not be within. /// /// When the thread is within a waiting state, this will set the thread's @@ -470,16 +472,16 @@ public: void SetActivity(ThreadActivity value); /// Sleeps this thread for the given amount of nanoseconds. - void Sleep(s64 nanoseconds); + ResultCode Sleep(s64 nanoseconds); /// Yields this thread without rebalancing loads. - bool YieldSimple(); + ResultCode YieldSimple(); /// Yields this thread and does a load rebalancing. - bool YieldAndBalanceLoad(); + ResultCode YieldAndBalanceLoad(); /// Yields this thread and if the core is left idle, loads are rebalanced - bool YieldAndWaitForLoadBalancing(); + ResultCode YieldAndWaitForLoadBalancing(); void IncrementYieldCount() { yield_count++; @@ -603,6 +605,8 @@ private: bool is_running = false; bool is_sync_cancelled = false; + bool will_be_terminated{}; + std::string name; }; -- cgit v1.2.3 From 589f9cf108d306e8265ff4856b522cd32fbc121f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 13:22:11 -0400 Subject: SVC: Correct GetThreadPriority, SetThreadPriority, GetThreadCoreMask, SetThreadCoreMask, GetCurrentProcessorNumber --- src/core/hle/kernel/svc.cpp | 17 ++++++++--------- src/core/hle/kernel/thread.cpp | 6 ++---- src/core/hle/kernel/thread.h | 3 +-- 3 files changed, 11 insertions(+), 15 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dfb032b4b..2a218e294 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -27,6 +27,7 @@ #include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/resource_limit.h" @@ -1071,6 +1072,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr thread = handle_table.Get(handle); if (!thread) { + *priority = 0; LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; } @@ -1105,14 +1107,13 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri thread->SetPriority(priority); - system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } /// Get which CPU core is executing the current thread static u32 GetCurrentProcessorNumber(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); - return system.CurrentScheduler().GetCurrentThread()->GetProcessorID(); + return static_cast(system.CurrentPhysicalCore().CoreIndex()); } static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, @@ -1430,8 +1431,8 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e ThreadType type = THREADTYPE_USER; CASCADE_RESULT(std::shared_ptr thread, - Thread::Create(system, type, "", entry_point, priority, arg, processor_id, stack_top, - current_process)); + Thread::Create(system, type, "", entry_point, priority, arg, processor_id, + stack_top, current_process)); const auto new_thread_handle = current_process->GetHandleTable().Create(thread); if (new_thread_handle.Failed()) { @@ -1804,6 +1805,8 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); + *core = 0; + *mask = 0; return ERR_INVALID_HANDLE; } @@ -1866,11 +1869,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_HANDLE; } - system.PrepareReschedule(thread->GetProcessorID()); - thread->ChangeCore(core, affinity_mask); - system.PrepareReschedule(thread->GetProcessorID()); - - return RESULT_SUCCESS; + return thread->SetCoreAndAffinityMask(core, affinity_mask); } static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d9e610272..e6bb7c666 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -250,6 +250,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy } void Thread::SetPriority(u32 priority) { + SchedulerLock lock(kernel); ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, "Invalid priority value."); nominal_priority = priority; @@ -383,10 +384,6 @@ void Thread::UpdatePriority() { lock_owner->UpdatePriority(); } -void Thread::ChangeCore(u32 core, u64 mask) { - SetCoreAndAffinityMask(core, mask); -} - bool Thread::AllSynchronizationObjectsReady() const { return std::none_of(wait_objects.begin(), wait_objects.end(), [this](const std::shared_ptr& object) { @@ -467,6 +464,7 @@ void Thread::SetCurrentPriority(u32 new_priority) { } ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { + SchedulerLock lock(kernel); const auto HighestSetCore = [](u64 mask, u32 max_cores) { for (s32 core = static_cast(max_cores - 1); core >= 0; core--) { if (((mask >> core) & 1) != 0) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 78a4357b0..29fe5483b 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -221,7 +221,7 @@ public: void UpdatePriority(); /// Changes the core that the thread is running or scheduled to run on. - void ChangeCore(u32 core, u64 mask); + ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); /** * Gets the thread's thread ID @@ -522,7 +522,6 @@ private: void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); - ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); -- cgit v1.2.3 From ef4afa9760f07bc218256cdb044529ad3a7c08b5 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 13:24:29 -0400 Subject: SVC: Remove global HLE Lock. --- src/core/hle/kernel/svc.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 2a218e294..a071b0c09 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2410,9 +2410,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); - // Lock the global kernel mutex when we enter the kernel HLE. - std::lock_guard lock{HLE::g_hle_lock}; - const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { -- cgit v1.2.3 From 3b5b950c895a2db217a3e5c8105cec4498a2534e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 16:38:33 -0400 Subject: SVC: Correct SignalEvent, ClearEvent, ResetSignal, WaitSynchronization, CancelSynchronization, ArbitrateLock --- src/core/hle/kernel/mutex.cpp | 65 +++++++++------ src/core/hle/kernel/process.cpp | 1 + src/core/hle/kernel/readable_event.cpp | 3 + src/core/hle/kernel/svc.cpp | 1 - src/core/hle/kernel/synchronization.cpp | 118 +++++++++++++++------------ src/core/hle/kernel/synchronization_object.h | 5 +- src/core/hle/kernel/thread.cpp | 14 ++-- src/core/hle/kernel/thread.h | 17 +++- 8 files changed, 134 insertions(+), 90 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 7869eb32b..3520c5e49 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -72,42 +72,55 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, return ERR_INVALID_ADDRESS; } - const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); + auto& kernel = system.Kernel(); std::shared_ptr current_thread = - SharedFrom(system.CurrentScheduler().GetCurrentThread()); - std::shared_ptr holding_thread = handle_table.Get(holding_thread_handle); - std::shared_ptr requesting_thread = handle_table.Get(requesting_thread_handle); + SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); + { + SchedulerLock lock(kernel); + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + return ERR_INVALID_ADDRESS; + } - // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another - // thread. - ASSERT(requesting_thread == current_thread); + const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); + std::shared_ptr holding_thread = handle_table.Get(holding_thread_handle); + std::shared_ptr requesting_thread = handle_table.Get(requesting_thread_handle); - const u32 addr_value = system.Memory().Read32(address); + // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another + // thread. + ASSERT(requesting_thread == current_thread); - // If the mutex isn't being held, just return success. - if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { - return RESULT_SUCCESS; - } + current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); - if (holding_thread == nullptr) { - LOG_ERROR(Kernel, "Holding thread does not exist! thread_handle={:08X}", - holding_thread_handle); - return ERR_INVALID_HANDLE; - } + const u32 addr_value = system.Memory().Read32(address); - // Wait until the mutex is released - current_thread->SetMutexWaitAddress(address); - current_thread->SetWaitHandle(requesting_thread_handle); + // If the mutex isn't being held, just return success. + if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { + return RESULT_SUCCESS; + } - current_thread->SetStatus(ThreadStatus::WaitMutex); - current_thread->InvalidateWakeupCallback(); + if (holding_thread == nullptr) { + return ERR_INVALID_HANDLE; + } - // Update the lock holder thread's priority to prevent priority inversion. - holding_thread->AddMutexWaiter(current_thread); + // Wait until the mutex is released + current_thread->SetMutexWaitAddress(address); + current_thread->SetWaitHandle(requesting_thread_handle); - system.PrepareReschedule(); + current_thread->SetStatus(ThreadStatus::WaitMutex); - return RESULT_SUCCESS; + // Update the lock holder thread's priority to prevent priority inversion. + holding_thread->AddMutexWaiter(current_thread); + } + + { + SchedulerLock lock(kernel); + auto* owner = current_thread->GetLockOwner(); + if (owner != nullptr) { + owner->RemoveMutexWaiter(current_thread); + } + } + return current_thread->GetSignalingResult(); } ResultCode Mutex::Release(VAddr address) { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 7e26a54f4..cd4b0aa60 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -212,6 +212,7 @@ void Process::UnregisterThread(const Thread* thread) { } ResultCode Process::ClearSignalState() { + SchedulerLock lock(system.Kernel()); if (status == ProcessStatus::Exited) { LOG_ERROR(Kernel, "called on a terminated process instance."); return ERR_INVALID_STATE; diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp index ef5e19e63..6e286419e 100644 --- a/src/core/hle/kernel/readable_event.cpp +++ b/src/core/hle/kernel/readable_event.cpp @@ -6,8 +6,10 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/hle/kernel/errors.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" namespace Kernel { @@ -37,6 +39,7 @@ void ReadableEvent::Clear() { } ResultCode ReadableEvent::Reset() { + SchedulerLock lock(kernel); if (!is_signaled) { LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", GetObjectId(), GetTypeName(), GetName()); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a071b0c09..0d905c0ca 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -448,7 +448,6 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand } thread->CancelWait(); - system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index dc37fad1a..b36e550a0 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -10,78 +10,88 @@ #include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/synchronization_object.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" namespace Kernel { -/// Default thread wakeup callback for WaitSynchronization -static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); - - if (reason == ThreadWakeupReason::Timeout) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return true; - } - - ASSERT(reason == ThreadWakeupReason::Signal); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - thread->SetWaitSynchronizationOutput(static_cast(index)); - return true; -} - Synchronization::Synchronization(Core::System& system) : system{system} {} void Synchronization::SignalObject(SynchronizationObject& obj) const { + SchedulerLock lock(system.Kernel()); if (obj.IsSignaled()) { - obj.WakeupAllWaitingThreads(); + for (auto thread : obj.GetWaitingThreads()) { + if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { + thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); + thread->ResumeFromWait(); + } + } } } std::pair Synchronization::WaitFor( std::vector>& sync_objects, s64 nano_seconds) { + auto& kernel = system.Kernel(); auto* const thread = system.CurrentScheduler().GetCurrentThread(); - // Find the first object that is acquirable in the provided list of objects - const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), - [thread](const std::shared_ptr& object) { - return object->IsSignaled(); - }); - - if (itr != sync_objects.end()) { - // We found a ready object, acquire it and set the result value - SynchronizationObject* object = itr->get(); - object->Acquire(thread); - const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); - return {RESULT_SUCCESS, index}; + Handle event_handle = InvalidHandle; + { + SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds); + const auto itr = + std::find_if(sync_objects.begin(), sync_objects.end(), + [thread](const std::shared_ptr& object) { + return object->IsSignaled(); + }); + + if (itr != sync_objects.end()) { + // We found a ready object, acquire it and set the result value + SynchronizationObject* object = itr->get(); + object->Acquire(thread); + const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); + lock.CancelSleep(); + return {RESULT_SUCCESS, index}; + } + + if (nano_seconds == 0) { + lock.CancelSleep(); + return {RESULT_TIMEOUT, InvalidHandle}; + } + + /// TODO(Blinkhawk): Check for termination pending + + if (thread->IsSyncCancelled()) { + thread->SetSyncCancelled(false); + lock.CancelSleep(); + return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; + } + + for (auto& object : sync_objects) { + object->AddWaitingThread(SharedFrom(thread)); + } + thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + thread->SetStatus(ThreadStatus::WaitSynch); } - // No objects were ready to be acquired, prepare to suspend the thread. - - // If a timeout value of 0 was provided, just return the Timeout error code instead of - // suspending the thread. - if (nano_seconds == 0) { - return {RESULT_TIMEOUT, InvalidHandle}; + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); } - if (thread->IsSyncCancelled()) { - thread->SetSyncCancelled(false); - return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; + { + SchedulerLock lock(kernel); + ResultCode signaling_result = thread->GetSignalingResult(); + SynchronizationObject* signaling_object = thread->GetSignalingObject(); + if (signaling_result == RESULT_SUCCESS) { + const auto itr = std::find_if( + sync_objects.begin(), sync_objects.end(), + [signaling_object](const std::shared_ptr& object) { + return object.get() == signaling_object; + }); + ASSERT(itr != sync_objects.end()); + signaling_object->Acquire(thread); + const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); + return {RESULT_SUCCESS, index}; + } + return {signaling_result, -1}; } - - for (auto& object : sync_objects) { - object->AddWaitingThread(SharedFrom(thread)); - } - - thread->SetSynchronizationObjects(std::move(sync_objects)); - thread->SetStatus(ThreadStatus::WaitSynch); - - // Create an event to wake the thread up after the specified nanosecond delay has passed - thread->WakeAfterDelay(nano_seconds); - thread->SetWakeupCallback(DefaultThreadWakeupCallback); - - system.PrepareReschedule(thread->GetProcessorID()); - - return {RESULT_TIMEOUT, InvalidHandle}; } } // namespace Kernel diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index 741c31faf..0a0d069e0 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -12,6 +12,7 @@ namespace Kernel { class KernelCore; +class Synchronization; class Thread; /// Class that represents a Kernel object that a thread can be waiting on @@ -53,7 +54,7 @@ public: * Wake up all threads waiting on this object that can be awoken, in priority order, * and set the synchronization result and output of the thread. */ - void WakeupAllWaitingThreads(); + void /* deprecated */ WakeupAllWaitingThreads(); /** * Wakes up a single thread waiting on this object. @@ -62,7 +63,7 @@ public: void WakeupWaitingThread(std::shared_ptr thread); /// Obtains the highest priority thread that is ready to run from this object's waiting list. - std::shared_ptr GetHighestPriorityReadyThread() const; + std::shared_ptr /* deprecated */ GetHighestPriorityReadyThread() const; /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e6bb7c666..5fef3945b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -139,12 +139,13 @@ ResultCode Thread::Start() { } void Thread::CancelWait() { + SchedulerLock lock(kernel); if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { is_sync_cancelled = true; return; } is_sync_cancelled = false; - SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); + SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); ResumeFromWait(); } @@ -258,13 +259,16 @@ void Thread::SetPriority(u32 priority) { } void Thread::SetWaitSynchronizationResult(ResultCode result) { - context_32.cpu_registers[0] = result.raw; - context_64.cpu_registers[0] = result.raw; + UNREACHABLE(); } void Thread::SetWaitSynchronizationOutput(s32 output) { - context_32.cpu_registers[1] = output; - context_64.cpu_registers[1] = output; + UNREACHABLE(); +} + +void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { + signaling_object = object; + signaling_result = result; } s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr object) const { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 29fe5483b..a8ae1a66f 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -259,13 +259,23 @@ public: * Sets the result after the thread awakens (from svcWaitSynchronization) * @param result Value to set to the returned result */ - void SetWaitSynchronizationResult(ResultCode result); + void /*deprecated*/ SetWaitSynchronizationResult(ResultCode result); /** * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) * @param output Value to set to the output parameter */ - void SetWaitSynchronizationOutput(s32 output); + void /*deprecated*/ SetWaitSynchronizationOutput(s32 output); + + void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); + + SynchronizationObject* GetSignalingObject() const { + return signaling_object; + } + + ResultCode GetSignalingResult() const { + return signaling_result; + } /** * Retrieves the index that this particular object occupies in the list of objects @@ -565,6 +575,9 @@ private: /// passed to WaitSynchronization. ThreadSynchronizationObjects wait_objects; + SynchronizationObject* signaling_object; + ResultCode signaling_result{RESULT_SUCCESS}; + /// List of threads that are waiting for a mutex that is held by this thread. MutexWaitingThreads wait_mutex_threads; -- cgit v1.2.3 From 203e706302c24f278eec7d0bd2362ce73b0e2612 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 17:37:12 -0400 Subject: SVC: Correct ArbitrateUnlock --- src/core/hle/kernel/mutex.cpp | 65 +++++++++++++++++++++--------------------- src/core/hle/kernel/mutex.h | 3 ++ src/core/hle/kernel/thread.cpp | 2 +- 3 files changed, 37 insertions(+), 33 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 3520c5e49..18325db57 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -84,10 +84,11 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, const auto& handle_table = kernel.CurrentProcess()->GetHandleTable(); std::shared_ptr holding_thread = handle_table.Get(holding_thread_handle); - std::shared_ptr requesting_thread = handle_table.Get(requesting_thread_handle); + std::shared_ptr requesting_thread = + handle_table.Get(requesting_thread_handle); - // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another - // thread. + // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of + // another thread. ASSERT(requesting_thread == current_thread); current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); @@ -123,47 +124,47 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, return current_thread->GetSignalingResult(); } -ResultCode Mutex::Release(VAddr address) { - // The mutex address must be 4-byte aligned - if ((address % sizeof(u32)) != 0) { - LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); - return ERR_INVALID_ADDRESS; - } - - std::shared_ptr current_thread = - SharedFrom(system.CurrentScheduler().GetCurrentThread()); - auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address); +std::pair> Mutex::Unlock(std::shared_ptr owner, + VAddr address) { + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); + return {ERR_INVALID_ADDRESS, nullptr}; + } - // There are no more threads waiting for the mutex, release it completely. - if (thread == nullptr) { + auto [new_owner, num_waiters] = GetHighestPriorityMutexWaitingThread(owner, address); + if (new_owner == nullptr) { system.Memory().Write32(address, 0); - return RESULT_SUCCESS; + return {RESULT_SUCCESS, nullptr}; } - // Transfer the ownership of the mutex from the previous owner to the new one. - TransferMutexOwnership(address, current_thread, thread); - - u32 mutex_value = thread->GetWaitHandle(); - + TransferMutexOwnership(address, owner, new_owner); + u32 mutex_value = new_owner->GetWaitHandle(); if (num_waiters >= 2) { // Notify the guest that there are still some threads waiting for the mutex mutex_value |= Mutex::MutexHasWaitersFlag; } - - // Grant the mutex to the next waiting thread and resume it. + new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS); + new_owner->ResumeFromWait(); + new_owner->SetLockOwner(nullptr); system.Memory().Write32(address, mutex_value); + return {RESULT_SUCCESS, new_owner}; +} + +ResultCode Mutex::Release(VAddr address) { + auto& kernel = system.Kernel(); + SchedulerLock lock(kernel); - ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); - thread->ResumeFromWait(); + std::shared_ptr current_thread = + SharedFrom(kernel.CurrentScheduler().GetCurrentThread()); - thread->SetLockOwner(nullptr); - thread->SetCondVarWaitAddress(0); - thread->SetMutexWaitAddress(0); - thread->SetWaitHandle(0); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + auto [result, new_owner] = Unlock(current_thread, address); - system.PrepareReschedule(); + if (result != RESULT_SUCCESS && new_owner != nullptr) { + new_owner->SetSynchronizationResults(nullptr, result); + } - return RESULT_SUCCESS; + return result; } + } // namespace Kernel diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index b904de2e8..bce06ecea 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -28,6 +28,9 @@ public: ResultCode TryAcquire(VAddr address, Handle holding_thread_handle, Handle requesting_thread_handle); + /// Unlocks a mutex for owner at address + std::pair> Unlock(std::shared_ptr owner, VAddr address); + /// Releases the mutex at the specified address. ResultCode Release(VAddr address); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 5fef3945b..f100ffc70 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -80,7 +80,7 @@ void Thread::CancelWakeupTimer() { void Thread::ResumeFromWait() { ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); - + SchedulerLock lock(kernel); switch (status) { case ThreadStatus::Paused: case ThreadStatus::WaitSynch: -- cgit v1.2.3 From 15a79eb0d7abe752a9a55d0cfa7ea220e17318b7 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 19:43:28 -0400 Subject: SVC: Correct SendSyncRequest. --- src/core/hle/kernel/hle_ipc.cpp | 24 +++++----- src/core/hle/kernel/scheduler.cpp | 9 ++++ src/core/hle/kernel/scheduler.h | 2 + src/core/hle/kernel/server_session.cpp | 15 ++++--- src/core/hle/kernel/svc.cpp | 21 +++++++-- src/core/hle/kernel/thread.cpp | 14 ++++-- src/core/hle/kernel/thread.h | 82 ++++++++++++++++++++++------------ 7 files changed, 115 insertions(+), 52 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 0d01a7047..955d5fe1c 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -14,6 +14,7 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" @@ -21,7 +22,9 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/writable_event.h" #include "core/memory.h" @@ -46,11 +49,10 @@ std::shared_ptr HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, std::shared_ptr writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetWakeupCallback( + thread->SetHLECallback( [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index) mutable -> bool { - ASSERT(thread->GetStatus() == ThreadStatus::WaitHLEEvent); callback(thread, context, reason); context.WriteToOutgoingCommandBuffer(*thread); return true; @@ -62,14 +64,16 @@ std::shared_ptr HLERequestContext::SleepClientThread( writable_event = pair.writable; } - const auto readable_event{writable_event->GetReadableEvent()}; - writable_event->Clear(); - thread->SetStatus(ThreadStatus::WaitHLEEvent); - thread->SetSynchronizationObjects({readable_event}); - readable_event->AddWaitingThread(thread); - - if (timeout > 0) { - thread->WakeAfterDelay(timeout); + { + Handle event_handle = InvalidHandle; + SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout); + const auto readable_event{writable_event->GetReadableEvent()}; + writable_event->Clear(); + thread->SetStatus(ThreadStatus::WaitHLEEvent); + thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + readable_event->AddWaitingThread(thread); + lock.Release(); + thread->SetHLETimeEvent(event_handle); } is_thread_waiting = true; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 5166020a0..0e85ee69e 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -715,4 +715,13 @@ SchedulerLockAndSleep::~SchedulerLockAndSleep() { time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); } +void SchedulerLockAndSleep::Release() { + if (sleep_cancelled) { + return; + } + auto& time_manager = kernel.TimeManager(); + time_manager.ScheduleTimeEvent(event_handle, time_task, nanoseconds); + sleep_cancelled = true; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 16655b03f..f5f64338f 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -279,6 +279,8 @@ public: sleep_cancelled = true; } + void Release(); + private: Handle& event_handle; Thread* time_task; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 25438b86b..05516a453 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -19,6 +19,7 @@ #include "core/hle/kernel/process.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/memory.h" @@ -168,9 +169,12 @@ ResultCode ServerSession::CompleteSyncRequest() { } // Some service requests require the thread to block - if (!context.IsThreadWaiting()) { - context.GetThread().ResumeFromWait(); - context.GetThread().SetWaitSynchronizationResult(result); + { + SchedulerLock lock(kernel); + if (!context.IsThreadWaiting()) { + context.GetThread().ResumeFromWait(); + context.GetThread().SetSynchronizationResults(nullptr, result); + } } request_queue.Pop(); @@ -180,8 +184,9 @@ ResultCode ServerSession::CompleteSyncRequest() { ResultCode ServerSession::HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory) { - Core::System::GetInstance().CoreTiming().ScheduleEvent(20000, request_event, {}); - return QueueSyncRequest(std::move(thread), memory); + ResultCode result = QueueSyncRequest(std::move(thread), memory); + Core::System::GetInstance().CoreTiming().ScheduleEvent(0, request_event, {}); + return result; } } // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 0d905c0ca..768d72b92 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -38,6 +38,7 @@ #include "core/hle/kernel/svc_wrap.h" #include "core/hle/kernel/synchronization.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/kernel/writable_event.h" #include "core/hle/lock.h" @@ -318,11 +319,23 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}({})", handle, session->GetName()); auto thread = system.CurrentScheduler().GetCurrentThread(); - thread->InvalidateWakeupCallback(); - thread->SetStatus(ThreadStatus::WaitIPC); - system.PrepareReschedule(thread->GetProcessorID()); + { + SchedulerLock lock(system.Kernel()); + thread->InvalidateHLECallback(); + thread->SetStatus(ThreadStatus::WaitIPC); + session->SendSyncRequest(SharedFrom(thread), system.Memory()); + } + ResultCode result = thread->GetSignalingResult(); + if (thread->HasHLECallback()) { + Handle event_handle = thread->GetHLETimeEvent(); + if (event_handle != InvalidHandle) { + auto& time_manager = system.Kernel().TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); + } + thread->InvokeHLECallback(ThreadWakeupReason::Timeout, SharedFrom(thread), nullptr, 0); + } - return session->SendSyncRequest(SharedFrom(thread), system.Memory()); + return result; } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f100ffc70..fb97535a3 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -96,7 +96,7 @@ void Thread::ResumeFromWait() { case ThreadStatus::Ready: // The thread's wakeup callback must have already been cleared when the thread was first // awoken. - ASSERT(wakeup_callback == nullptr); + ASSERT(hle_callback == nullptr); // If the thread is waiting on multiple wait objects, it might be awoken more than once // before actually resuming. We can ignore subsequent wakeups if the thread status has // already been set to ThreadStatus::Ready. @@ -112,7 +112,7 @@ void Thread::ResumeFromWait() { return; } - wakeup_callback = nullptr; + hle_callback = nullptr; if (activity == ThreadActivity::Paused) { SetStatus(ThreadStatus::Paused); @@ -398,8 +398,14 @@ bool Thread::AllSynchronizationObjectsReady() const { bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index) { - ASSERT(wakeup_callback); - return wakeup_callback(reason, std::move(thread), std::move(object), index); + ASSERT(hle_callback); + return hle_callback(reason, std::move(thread), std::move(object), index); +} + +bool Thread::InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object, std::size_t index) { + ASSERT(hle_callback); + return hle_callback(reason, std::move(thread), std::move(object), index); } void Thread::SetActivity(ThreadActivity value) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index a8ae1a66f..04496f96e 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -31,12 +31,12 @@ class Process; class Scheduler; enum ThreadPriority : u32 { - THREADPRIO_HIGHEST = 0, ///< Highest thread priority - THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration - THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps - THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps - THREADPRIO_LOWEST = 63, ///< Lowest thread priority - THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. + THREADPRIO_HIGHEST = 0, ///< Highest thread priority + THREADPRIO_MAX_CORE_MIGRATION = 2, ///< Highest priority for a core migration + THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps + THREADPRIO_DEFAULT = 44, ///< Default thread priority for userland apps + THREADPRIO_LOWEST = 63, ///< Lowest thread priority + THREADPRIO_COUNT = 64, ///< Total number of possible thread priorities. }; enum ThreadType : u32 { @@ -129,23 +129,24 @@ public: using WakeupCallback = std::function thread, std::shared_ptr object, std::size_t index)>; + using HLECallback = std::function thread)>; - /** - * Creates and returns a new thread. The new thread is immediately scheduled - * @param system The instance of the whole system - * @param name The friendly name desired for the thread - * @param entry_point The address at which the thread should start execution - * @param priority The thread's priority - * @param arg User data to pass to the thread - * @param processor_id The ID(s) of the processors on which the thread is desired to be run - * @param stack_top The address of the thread's stack top - * @param owner_process The parent process for the thread, if null, it's a kernel thread - * @return A shared pointer to the newly created thread - */ - static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process* owner_process); + /** + * Creates and returns a new thread. The new thread is immediately scheduled + * @param system The instance of the whole system + * @param name The friendly name desired for the thread + * @param entry_point The address at which the thread should start execution + * @param priority The thread's priority + * @param arg User data to pass to the thread + * @param processor_id The ID(s) of the processors on which the thread is desired to be run + * @param stack_top The address of the thread's stack top + * @param owner_process The parent process for the thread, if null, it's a kernel thread + * @return A shared pointer to the newly created thread + */ + static ResultVal> Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, + VAddr stack_top, Process* owner_process); /** * Creates and returns a new thread. The new thread is immediately scheduled @@ -161,10 +162,10 @@ public: * @param thread_start_parameter The parameter which will passed to host context on init * @return A shared pointer to the newly created thread */ - static ResultVal> Create(Core::System& system, ThreadType type_flags, std::string name, - VAddr entry_point, u32 priority, u64 arg, - s32 processor_id, VAddr stack_top, - Process* owner_process, + static ResultVal> Create(Core::System& system, ThreadType type_flags, + std::string name, VAddr entry_point, + u32 priority, u64 arg, s32 processor_id, + VAddr stack_top, Process* owner_process, std::function&& thread_start_func, void* thread_start_parameter); @@ -447,17 +448,37 @@ public: } bool HasWakeupCallback() const { - return wakeup_callback != nullptr; + return hle_callback != nullptr; + } + + bool HasHLECallback() const { + return hle_callback != nullptr; } void SetWakeupCallback(WakeupCallback callback) { - wakeup_callback = std::move(callback); + hle_callback = std::move(callback); + } + + void SetHLECallback(WakeupCallback callback) { + hle_callback = std::move(callback); + } + + void SetHLETimeEvent(Handle time_event) { + hle_time_event = time_event; + } + + Handle GetHLETimeEvent() const { + return hle_time_event; } void InvalidateWakeupCallback() { SetWakeupCallback(nullptr); } + void InvalidateHLECallback() { + SetHLECallback(nullptr); + } + /** * Invokes the thread's wakeup callback. * @@ -466,6 +487,8 @@ public: */ bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index); + bool InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, + std::shared_ptr object, std::size_t index); u32 GetIdealCore() const { return ideal_core; @@ -600,7 +623,8 @@ private: /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread /// was waiting via WaitSynchronization then the object will be the last object that became /// available. In case of a timeout, the object will be nullptr. - WakeupCallback wakeup_callback; + WakeupCallback hle_callback; + Handle hle_time_event; Scheduler* scheduler = nullptr; -- cgit v1.2.3 From 3d9fbb8226e9bf7dce99568f6e616e7361d43c41 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 26 Feb 2020 10:44:21 -0400 Subject: CPU_Manager: Reconfigre guest threads for dynamrmic downsides --- src/core/hle/kernel/physical_core.cpp | 3 +++ src/core/hle/kernel/physical_core.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 69202540b..ff14fcb42 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -45,6 +45,9 @@ PhysicalCore::~PhysicalCore() = default; void PhysicalCore::Run() { arm_interface->Run(); +} + +void PhysicalCore::ClearExclusive() { arm_interface->ClearExclusiveState(); } diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index c3da30b72..cd2e42fc3 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -38,6 +38,8 @@ public: /// Execute current jit state void Run(); + /// Clear Exclusive state. + void ClearExclusive(); /// Set this core in IdleState. void Idle(); /// Execute a single instruction in current jit. -- cgit v1.2.3 From 5b6a67f849d0d78d6f71ccb7d93f48a97760a901 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 26 Feb 2020 18:55:11 -0400 Subject: SVC: Cleanup old methods. --- src/core/hle/kernel/svc.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 768d72b92..8634d3feb 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -622,7 +622,6 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { // Kill the current thread current_thread->Stop(); - system.PrepareReschedule(); } } @@ -1004,6 +1003,7 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); + UNIMPLEMENTED(); if (activity > static_cast(ThreadActivity::Paused)) { return ERR_INVALID_ENUM_VALUE; } @@ -1032,7 +1032,6 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act thread->SetActivity(static_cast(activity)); - system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1385,6 +1384,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha /// Exits the current process static void ExitProcess(Core::System& system) { auto* current_process = system.Kernel().CurrentProcess(); + UNIMPLEMENTED(); LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running, @@ -1394,8 +1394,6 @@ static void ExitProcess(Core::System& system) { // Kill the current thread system.CurrentScheduler().GetCurrentThread()->Stop(); - - system.PrepareReschedule(); } /// Creates a new thread @@ -1458,8 +1456,6 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e thread->SetName( fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); - system.PrepareReschedule(thread->GetProcessorID()); - return RESULT_SUCCESS; } @@ -1545,6 +1541,8 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return ERR_INVALID_ADDRESS; } + UNIMPLEMENTED(); + ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); auto* const current_process = system.Kernel().CurrentProcess(); @@ -1569,7 +1567,6 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add // Note: Deliberately don't attempt to inherit the lock owner's priority. - system.PrepareReschedule(current_thread->GetProcessorID()); return RESULT_SUCCESS; } @@ -1580,6 +1577,8 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); + UNIMPLEMENTED(); + // Retrieve a list of all threads that are waiting for this condition variable. auto* const current_process = system.Kernel().CurrentProcess(); std::vector> waiting_threads = @@ -1634,7 +1633,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ thread->SetMutexWaitAddress(0); thread->SetWaitHandle(0); thread->SetWaitSynchronizationResult(RESULT_SUCCESS); - system.PrepareReschedule(thread->GetProcessorID()); } else { // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast(mutex_val & Mutex::MutexOwnerMask); @@ -1646,7 +1644,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ thread->SetStatus(ThreadStatus::WaitMutex); owner->AddMutexWaiter(thread); - system.PrepareReschedule(thread->GetProcessorID()); } } } @@ -1661,6 +1658,7 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address, type, value, timeout); + UNIMPLEMENTED(); // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); @@ -1677,9 +1675,6 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, auto& address_arbiter = system.Kernel().CurrentProcess()->GetAddressArbiter(); const ResultCode result = address_arbiter.WaitForAddress(address, arbitration_type, value, timeout); - if (result == RESULT_SUCCESS) { - system.PrepareReschedule(); - } return result; } @@ -1689,6 +1684,8 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address, type, value, num_to_wake); + UNIMPLEMENTED(); + // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); @@ -1945,7 +1942,6 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) { } writable_event->Signal(); - system.PrepareReschedule(); return RESULT_SUCCESS; } -- cgit v1.2.3 From d4ebb510a05d29befde6556e632413e5b35b9ab5 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 26 Feb 2020 22:26:53 -0400 Subject: SVC: Correct WaitSynchronization, WaitProcessWideKey, SignalProcessWideKey. --- src/core/hle/kernel/process.cpp | 1 - src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/svc.cpp | 75 ++++++++++++++++---------- src/core/hle/kernel/synchronization.cpp | 8 ++- src/core/hle/kernel/synchronization_object.cpp | 4 ++ src/core/hle/kernel/synchronization_object.h | 2 + src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/time_manager.cpp | 18 ++++++- src/core/hle/kernel/time_manager.h | 5 ++ 9 files changed, 84 insertions(+), 33 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index cd4b0aa60..ea5fe5b29 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -187,7 +187,6 @@ void Process::RemoveConditionVariableThread(std::shared_ptr thread) { } ++it; } - UNREACHABLE(); } std::vector> Process::GetConditionVariableThreads( diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 0e85ee69e..758fa8188 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -632,7 +632,7 @@ void Scheduler::SwitchContext() { cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); - + cpu_core.ClearExclusiveState(); } if (previous_thread->GetStatus() == ThreadStatus::Running) { previous_thread->SetStatus(ThreadStatus::Ready); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 8634d3feb..a5193063b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1541,33 +1541,50 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return ERR_INVALID_ADDRESS; } - UNIMPLEMENTED(); - ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); - + auto& kernel = system.Kernel(); + Handle event_handle; + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); auto* const current_process = system.Kernel().CurrentProcess(); - const auto& handle_table = current_process->GetHandleTable(); - std::shared_ptr thread = handle_table.Get(thread_handle); - ASSERT(thread); + { + SchedulerLockAndSleep lock(kernel, event_handle, current_thread, nano_seconds); + const auto& handle_table = current_process->GetHandleTable(); + std::shared_ptr thread = handle_table.Get(thread_handle); + ASSERT(thread); + + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + + const auto release_result = current_process->GetMutex().Release(mutex_addr); + if (release_result.IsError()) { + lock.CancelSleep(); + return release_result; + } - const auto release_result = current_process->GetMutex().Release(mutex_addr); - if (release_result.IsError()) { - return release_result; + if (nano_seconds == 0) { + lock.CancelSleep(); + return RESULT_TIMEOUT; + } + + current_thread->SetCondVarWaitAddress(condition_variable_addr); + current_thread->SetMutexWaitAddress(mutex_addr); + current_thread->SetWaitHandle(thread_handle); + current_thread->SetStatus(ThreadStatus::WaitCondVar); + current_process->InsertConditionVariableThread(SharedFrom(current_thread)); } - Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - current_thread->SetCondVarWaitAddress(condition_variable_addr); - current_thread->SetMutexWaitAddress(mutex_addr); - current_thread->SetWaitHandle(thread_handle); - current_thread->SetStatus(ThreadStatus::WaitCondVar); - current_thread->InvalidateWakeupCallback(); - current_process->InsertConditionVariableThread(SharedFrom(current_thread)); + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); + } - current_thread->WakeAfterDelay(nano_seconds); + { + SchedulerLock lock(kernel); + current_process->RemoveConditionVariableThread(SharedFrom(current_thread)); + } // Note: Deliberately don't attempt to inherit the lock owner's priority. - return RESULT_SUCCESS; + return current_thread->GetSignalingResult(); } /// Signal process wide key @@ -1577,10 +1594,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ ASSERT(condition_variable_addr == Common::AlignDown(condition_variable_addr, 4)); - UNIMPLEMENTED(); - // Retrieve a list of all threads that are waiting for this condition variable. - auto* const current_process = system.Kernel().CurrentProcess(); + auto& kernel = system.Kernel(); + SchedulerLock lock(kernel); + auto* const current_process = kernel.CurrentProcess(); std::vector> waiting_threads = current_process->GetConditionVariableThreads(condition_variable_addr); @@ -1589,10 +1606,18 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ std::size_t last = waiting_threads.size(); if (target > 0) last = std::min(waiting_threads.size(), static_cast(target)); - + auto& time_manager = kernel.TimeManager(); for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; + if (thread->GetStatus() != ThreadStatus::WaitCondVar) { + last++; + last = std::min(waiting_threads.size(), last); + continue; + } + + time_manager.CancelTimeEvent(thread.get()); + ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); // liberate Cond Var Thread. @@ -1630,17 +1655,13 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ } thread->SetLockOwner(nullptr); - thread->SetMutexWaitAddress(0); - thread->SetWaitHandle(0); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); } else { // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast(mutex_val & Mutex::MutexOwnerMask); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto owner = handle_table.Get(owner_handle); ASSERT(owner); - ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); - thread->InvalidateWakeupCallback(); thread->SetStatus(ThreadStatus::WaitMutex); owner->AddMutexWaiter(thread); diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index b36e550a0..c60c5bb42 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -17,12 +17,15 @@ namespace Kernel { Synchronization::Synchronization(Core::System& system) : system{system} {} void Synchronization::SignalObject(SynchronizationObject& obj) const { - SchedulerLock lock(system.Kernel()); + auto& kernel = system.Kernel(); + SchedulerLock lock(kernel); + auto& time_manager = kernel.TimeManager(); if (obj.IsSignaled()) { for (auto thread : obj.GetWaitingThreads()) { if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); thread->ResumeFromWait(); + time_manager.CancelTimeEvent(thread.get()); } } } @@ -79,6 +82,9 @@ std::pair Synchronization::WaitFor( SchedulerLock lock(kernel); ResultCode signaling_result = thread->GetSignalingResult(); SynchronizationObject* signaling_object = thread->GetSignalingObject(); + for (auto& obj : sync_objects) { + obj->RemoveWaitingThread(SharedFrom(thread)); + } if (signaling_result == RESULT_SUCCESS) { const auto itr = std::find_if( sync_objects.begin(), sync_objects.end(), diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index 43f3eef18..be9e09106 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -102,6 +102,10 @@ void SynchronizationObject::WakeupAllWaitingThreads() { } } +void SynchronizationObject::ClearWaitingThreads() { + waiting_threads.clear(); +} + const std::vector>& SynchronizationObject::GetWaitingThreads() const { return waiting_threads; } diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index 0a0d069e0..a35544ac1 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -68,6 +68,8 @@ public: /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; + void ClearWaitingThreads(); + protected: bool is_signaled{}; // Tells if this sync object is signalled; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fb97535a3..a645ee3a2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -49,12 +49,12 @@ Thread::~Thread() = default; void Thread::Stop() { SchedulerLock lock(kernel); // Cancel any outstanding wakeup events for this thread + Signal(); Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), global_handle); kernel.GlobalHandleTable().Close(global_handle); global_handle = 0; SetStatus(ThreadStatus::Dead); - Signal(); owner_process->UnregisterThread(this); diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 0b8f0d993..dab5fc4c6 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -8,15 +8,21 @@ #include "core/core_timing_util.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" namespace Kernel { -TimeManager::TimeManager(Core::System& system) : system{system} { +TimeManager::TimeManager(Core::System& system_) : system{system_} { time_manager_event_type = Core::Timing::CreateEvent( "Kernel::TimeManagerCallback", [this](u64 thread_handle, [[maybe_unused]] s64 cycles_late) { + SchedulerLock lock(system.Kernel()); Handle proper_handle = static_cast(thread_handle); + if (cancelled_events[proper_handle]) { + return; + } + event_fired[proper_handle] = true; std::shared_ptr thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); thread->OnWakeUp(); @@ -24,14 +30,16 @@ TimeManager::TimeManager(Core::System& system) : system{system} { } void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 nanoseconds) { + event_handle = timetask->GetGlobalHandle(); if (nanoseconds > 0) { ASSERT(timetask); - event_handle = timetask->GetGlobalHandle(); const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle); } else { event_handle = InvalidHandle; } + cancelled_events[event_handle] = false; + event_fired[event_handle] = false; } void TimeManager::UnscheduleTimeEvent(Handle event_handle) { @@ -39,6 +47,12 @@ void TimeManager::UnscheduleTimeEvent(Handle event_handle) { return; } system.CoreTiming().UnscheduleEvent(time_manager_event_type, event_handle); + cancelled_events[event_handle] = true; +} + +void TimeManager::CancelTimeEvent(Thread* time_task) { + Handle event_handle = time_task->GetGlobalHandle(); + UnscheduleTimeEvent(event_handle); } } // namespace Kernel diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index eaec486d1..3080ac838 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include "core/hle/kernel/object.h" @@ -35,9 +36,13 @@ public: /// Unschedule an existing time event void UnscheduleTimeEvent(Handle event_handle); + void CancelTimeEvent(Thread* time_task); + private: Core::System& system; std::shared_ptr time_manager_event_type; + std::unordered_map cancelled_events; + std::unordered_map event_fired; }; } // namespace Kernel -- cgit v1.2.3 From 3902067008abed4ca748e2f6d4ad582748f9ed52 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 10:28:44 -0400 Subject: SVC: Add locks to the memory management. --- src/core/hle/kernel/svc.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index a5193063b..279fe5888 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -135,6 +135,7 @@ enum class ResourceLimitValueType { ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, u32 resource_type, ResourceLimitValueType value_type) { + std::lock_guard lock{HLE::g_hle_lock}; const auto type = static_cast(resource_type); if (!IsValidResourceType(type)) { LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); @@ -162,6 +163,7 @@ ResultVal RetrieveResourceLimitValue(Core::System& system, Handle resource_ /// Set the process heap to a given Size. It can both extend and shrink the heap. static ResultCode SetHeapSize(Core::System& system, VAddr* heap_addr, u64 heap_size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB. @@ -192,6 +194,7 @@ static ResultCode SetHeapSize32(Core::System& system, u32* heap_addr, u32 heap_s static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 size, u32 mask, u32 attribute) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address, size, mask, attribute); @@ -230,6 +233,7 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si /// Maps a memory range into a different range. static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); @@ -245,6 +249,7 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr /// Unmaps a region that was previously mapped with svcMapMemory static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); @@ -261,6 +266,7 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { + std::lock_guard lock{HLE::g_hle_lock}; auto& memory = system.Memory(); if (!memory.IsValidVirtualAddress(port_name_address)) { @@ -309,6 +315,7 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { + std::lock_guard lock{HLE::g_hle_lock}; const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); std::shared_ptr session = handle_table.Get(handle); if (!session) { @@ -639,6 +646,7 @@ static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr addre /// Gets system/memory information for the current process static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 handle, u64 info_sub_id) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, info_sub_id, handle); @@ -904,6 +912,7 @@ static ResultCode GetInfo32(Core::System& system, u32* result_low, u32* result_h /// Maps memory at a desired address static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); if (!Common::Is4KBAligned(addr)) { @@ -953,6 +962,7 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) /// Unmaps memory previously mapped via MapPhysicalMemory static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called, addr=0x{:016X}, size=0x{:X}", addr, size); if (!Common::Is4KBAligned(addr)) { @@ -1129,6 +1139,7 @@ static u32 GetCurrentProcessorNumber(Core::System& system) { static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, u64 size, u32 permissions) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called, shared_memory_handle=0x{:X}, addr=0x{:X}, size=0x{:X}, permissions=0x{:08X}", shared_memory_handle, addr, size, permissions); @@ -1202,6 +1213,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_TRACE(Kernel_SVC, "called process=0x{:08X} address={:X}", process_handle, address); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); std::shared_ptr process = handle_table.Get(process_handle); @@ -1782,6 +1794,7 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, u32 permissions) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, permissions); @@ -1993,6 +2006,7 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_ } static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) { + std::lock_guard lock{HLE::g_hle_lock}; LOG_DEBUG(Kernel_SVC, "called"); auto& kernel = system.Kernel(); @@ -2439,6 +2453,13 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); + auto& physical_core = system.CurrentPhysicalCore(); + if (physical_core.IsInterrupted()) { + auto& sched = physical_core.Scheduler(); + sched.TryDoContextSwitch(); + } + physical_core.ClearExclusive(); + const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { -- cgit v1.2.3 From cc3aa959265480e1990b10ee37ebf1c0ade3da64 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 10:47:02 -0400 Subject: NVFlinger: Lock race condition between CPU, Host Timing, VSync. --- src/core/hle/service/nvflinger/nvflinger.cpp | 2 ++ src/core/hle/service/nvflinger/nvflinger.h | 7 +++++++ src/core/hle/service/vi/vi.cpp | 2 ++ 3 files changed, 11 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index aaf28995d..b97f71350 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -36,10 +36,12 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { displays.emplace_back(2, "Edid", system); displays.emplace_back(3, "Internal", system); displays.emplace_back(4, "Null", system); + guard = std::make_shared(); // Schedule the screen composition events composition_event = Core::Timing::CreateEvent("ScreenComposition", [this](u64 userdata, s64 ns_late) { + Lock(); Compose(); const auto ticks = GetNextTicks(); this->system.CoreTiming().ScheduleEvent(std::max(0LL, ticks - ns_late), diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 57a21f33b..02c081494 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include #include @@ -79,6 +80,10 @@ public: s64 GetNextTicks() const; + std::unique_lock Lock() { + return std::unique_lock{*guard}; + } + private: /// Finds the display identified by the specified ID. VI::Display* FindDisplay(u64 display_id); @@ -108,6 +113,8 @@ private: /// Event that handles screen composition. std::shared_ptr composition_event; + std::shared_ptr guard; + Core::System& system; }; diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 46e14c2a3..157092074 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -511,6 +511,7 @@ private: LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, static_cast(transaction), flags); + nv_flinger->Lock(); auto& buffer_queue = nv_flinger->FindBufferQueue(id); switch (transaction) { @@ -550,6 +551,7 @@ private: [=](std::shared_ptr thread, Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { // Repeat TransactParcel DequeueBuffer when a buffer is available + nv_flinger->Lock(); auto& buffer_queue = nv_flinger->FindBufferQueue(id); auto result = buffer_queue.DequeueBuffer(width, height); ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); -- cgit v1.2.3 From bd36eaf15d88c3875aba7032fe5124fbb150bd5d Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 11:25:42 -0400 Subject: SVC: Correct races on physical core switching. --- src/core/hle/kernel/svc.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 279fe5888..1e6c60d78 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2454,11 +2454,6 @@ void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); auto& physical_core = system.CurrentPhysicalCore(); - if (physical_core.IsInterrupted()) { - auto& sched = physical_core.Scheduler(); - sched.TryDoContextSwitch(); - } - physical_core.ClearExclusive(); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); @@ -2471,6 +2466,10 @@ void Call(Core::System& system, u32 immediate) { } else { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } + auto& physical_core_2 = system.CurrentPhysicalCore(); + if (physical_core.CoreIndex() != physical_core_2.CoreIndex()) { + physical_core.Stop(); + } } } // namespace Kernel::Svc -- cgit v1.2.3 From 04e0f8776c26930d7dc8015e53914b11bf1929c1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 27 Feb 2020 19:12:41 -0400 Subject: General: Add better safety for JIT use. --- src/core/hle/kernel/scheduler.cpp | 3 +++ src/core/hle/kernel/svc.cpp | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 758fa8188..727d2e6cc 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -581,6 +581,7 @@ void Scheduler::SwitchContextStep2() { if (new_thread) { new_thread->context_guard.lock(); + cpu_core.Lock(); ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), "Thread must be assigned to this core."); ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, @@ -601,6 +602,7 @@ void Scheduler::SwitchContextStep2() { cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); } } else { current_thread = nullptr; @@ -639,6 +641,7 @@ void Scheduler::SwitchContext() { } previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); + cpu_core.Unlock(); } std::shared_ptr old_context; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1e6c60d78..b535593c7 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -10,6 +10,7 @@ #include "common/alignment.h" #include "common/assert.h" +#include "common/fiber.h" #include "common/logging/log.h" #include "common/microprofile.h" #include "common/string_util.h" @@ -2468,7 +2469,10 @@ void Call(Core::System& system, u32 immediate) { } auto& physical_core_2 = system.CurrentPhysicalCore(); if (physical_core.CoreIndex() != physical_core_2.CoreIndex()) { - physical_core.Stop(); + LOG_CRITICAL(Kernel_SVC, "Rewinding"); + auto* thread = physical_core_2.Scheduler().GetCurrentThread(); + auto* host_context = thread->GetHostContext().get(); + host_context->Rewind(); } } -- cgit v1.2.3 From 2a8837ff51a9cf5a0123489dba5f7ab48373c2d3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 28 Feb 2020 09:42:06 -0400 Subject: General: Add Asserts --- src/core/hle/kernel/scheduler.cpp | 18 ++++++++++++++++++ src/core/hle/kernel/scheduler.h | 1 + src/core/hle/kernel/svc.cpp | 1 + 3 files changed, 20 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 727d2e6cc..d67d3c5cd 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -44,6 +44,7 @@ void GlobalScheduler::RemoveThread(std::shared_ptr thread) { } u32 GlobalScheduler::SelectThreads() { + ASSERT(is_locked); const auto update_thread = [](Thread* thread, Scheduler& sched) { sched.guard.lock(); if (thread != sched.selected_thread.get()) { @@ -136,6 +137,7 @@ u32 GlobalScheduler::SelectThreads() { } bool GlobalScheduler::YieldThread(Thread* yielding_thread) { + ASSERT(is_locked); // Note: caller should use critical section, etc. const u32 core_id = static_cast(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); @@ -149,6 +151,7 @@ bool GlobalScheduler::YieldThread(Thread* yielding_thread) { } bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { + ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. const u32 core_id = static_cast(yielding_thread->GetProcessorID()); @@ -197,6 +200,7 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { } bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread) { + ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. Thread* winner = nullptr; @@ -237,6 +241,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } void GlobalScheduler::PreemptThreads() { + ASSERT(is_locked); for (std::size_t core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { const u32 priority = preemption_priorities[core_id]; @@ -339,33 +344,40 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, } void GlobalScheduler::Suggest(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); suggested_queue[core].add(thread, priority); } void GlobalScheduler::Unsuggest(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); suggested_queue[core].remove(thread, priority); } void GlobalScheduler::Schedule(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority); } void GlobalScheduler::SchedulePrepend(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); ASSERT_MSG(thread->GetProcessorID() == s32(core), "Thread must be assigned to this core."); scheduled_queue[core].add(thread, priority, false); } void GlobalScheduler::Reschedule(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); scheduled_queue[core].remove(thread, priority); scheduled_queue[core].add(thread, priority); } void GlobalScheduler::Unschedule(u32 priority, std::size_t core, Thread* thread) { + ASSERT(is_locked); scheduled_queue[core].remove(thread, priority); } void GlobalScheduler::TransferToCore(u32 priority, s32 destination_core, Thread* thread) { + ASSERT(is_locked); const bool schedulable = thread->GetPriority() < THREADPRIO_COUNT; const s32 source_core = thread->GetProcessorID(); if (source_core == destination_core || !schedulable) { @@ -399,6 +411,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { if (old_flags == thread->scheduling_state) { return; } + ASSERT(is_locked); if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == ThreadSchedStatus::Runnable) { @@ -434,6 +447,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { return; } + ASSERT(is_locked); if (thread->processor_id >= 0) { Unschedule(old_priority, static_cast(thread->processor_id), thread); } @@ -472,6 +486,7 @@ void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinit thread->current_priority >= THREADPRIO_COUNT) { return; } + ASSERT(is_locked); for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (((old_affinity_mask >> core) & 1) != 0) { @@ -507,10 +522,12 @@ void GlobalScheduler::Shutdown() { void GlobalScheduler::Lock() { Core::EmuThreadHandle current_thread = kernel.GetCurrentEmuThreadID(); + ASSERT(!current_thread.IsInvalid()); if (current_thread == current_owner) { ++scope_lock; } else { inner_lock.lock(); + is_locked = true; current_owner = current_thread; ASSERT(current_owner != Core::EmuThreadHandle::InvalidHandle()); scope_lock = 1; @@ -526,6 +543,7 @@ void GlobalScheduler::Unlock() { Core::EmuThreadHandle leaving_thread = current_owner; current_owner = Core::EmuThreadHandle::InvalidHandle(); scope_lock = 1; + is_locked = false; inner_lock.unlock(); EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f5f64338f..f26a554f5 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -182,6 +182,7 @@ private: std::array preemption_priorities = {59, 59, 59, 62}; /// Scheduler lock mechanisms. + bool is_locked{}; std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock std::atomic scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b535593c7..4c1040a3b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1657,6 +1657,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ update_val = thread->GetWaitHandle(); } } while (!monitor.ExclusiveWrite32(current_core, mutex_address, update_val)); + monitor.ClearExclusive(); if (mutex_val == 0) { // We were able to acquire the mutex, resume this thread. ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); -- cgit v1.2.3 From de5b521c0900bbd4d7012ffa3dfd63cc8f3d4371 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 11:04:37 -0400 Subject: Process: Protect TLS region and Modules. --- src/core/hle/kernel/process.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index ea5fe5b29..f9d7c024d 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -22,6 +22,7 @@ #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/lock.h" #include "core/memory.h" #include "core/settings.h" @@ -345,6 +346,7 @@ static auto FindTLSPageWithAvailableSlots(std::vector& tls_pages) { } VAddr Process::CreateTLSRegion() { + SchedulerLock lock(system.Kernel()); if (auto tls_page_iter{FindTLSPageWithAvailableSlots(tls_pages)}; tls_page_iter != tls_pages.cend()) { return *tls_page_iter->ReserveSlot(); @@ -375,6 +377,7 @@ VAddr Process::CreateTLSRegion() { } void Process::FreeTLSRegion(VAddr tls_address) { + SchedulerLock lock(system.Kernel()); const VAddr aligned_address = Common::AlignDown(tls_address, Core::Memory::PAGE_SIZE); auto iter = std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { @@ -389,6 +392,7 @@ void Process::FreeTLSRegion(VAddr tls_address) { } void Process::LoadModule(CodeSet code_set, VAddr base_addr) { + std::lock_guard lock{HLE::g_hle_lock}; const auto ReprotectSegment = [&](const CodeSet::Segment& segment, Memory::MemoryPermission permission) { page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); -- cgit v1.2.3 From 75e10578f12cf64bd734388ba80b5f5a46ca6133 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 13:02:50 -0400 Subject: Core: Correct HLE Event Callbacks and other issues. --- src/core/hle/kernel/hle_ipc.cpp | 19 +++++++++--------- src/core/hle/kernel/svc.cpp | 5 ++--- src/core/hle/kernel/synchronization.cpp | 1 + src/core/hle/kernel/thread.cpp | 35 ++++++++++++++++----------------- src/core/hle/kernel/thread.h | 16 ++++++++------- 5 files changed, 39 insertions(+), 37 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 955d5fe1c..e74d91670 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -21,8 +21,8 @@ #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/thread.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/kernel/writable_event.h" @@ -49,14 +49,6 @@ std::shared_ptr HLERequestContext::SleepClientThread( const std::string& reason, u64 timeout, WakeupCallback&& callback, std::shared_ptr writable_event) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->SetHLECallback( - [context = *this, callback](ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) mutable -> bool { - callback(thread, context, reason); - context.WriteToOutgoingCommandBuffer(*thread); - return true; - }); if (!writable_event) { // Create event if not provided @@ -67,6 +59,15 @@ std::shared_ptr HLERequestContext::SleepClientThread( { Handle event_handle = InvalidHandle; SchedulerLockAndSleep lock(kernel, event_handle, thread.get(), timeout); + thread->SetHLECallback( + [context = *this, callback](std::shared_ptr thread) mutable -> bool { + ThreadWakeupReason reason = thread->GetSignalingResult() == RESULT_TIMEOUT + ? ThreadWakeupReason::Timeout + : ThreadWakeupReason::Signal; + callback(thread, context, reason); + context.WriteToOutgoingCommandBuffer(*thread); + return true; + }); const auto readable_event{writable_event->GetReadableEvent()}; writable_event->Clear(); thread->SetStatus(ThreadStatus::WaitHLEEvent); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4c1040a3b..9f46a1758 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -333,17 +333,16 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { thread->SetStatus(ThreadStatus::WaitIPC); session->SendSyncRequest(SharedFrom(thread), system.Memory()); } - ResultCode result = thread->GetSignalingResult(); if (thread->HasHLECallback()) { Handle event_handle = thread->GetHLETimeEvent(); if (event_handle != InvalidHandle) { auto& time_manager = system.Kernel().TimeManager(); time_manager.UnscheduleTimeEvent(event_handle); } - thread->InvokeHLECallback(ThreadWakeupReason::Timeout, SharedFrom(thread), nullptr, 0); + thread->InvokeHLECallback(SharedFrom(thread)); } - return result; + return RESULT_SUCCESS; } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index c60c5bb42..4ee7ad93c 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -28,6 +28,7 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const { time_manager.CancelTimeEvent(thread.get()); } } + obj.ClearWaitingThreads(); } } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index a645ee3a2..16babe71a 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -47,19 +47,21 @@ Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {} Thread::~Thread() = default; void Thread::Stop() { - SchedulerLock lock(kernel); - // Cancel any outstanding wakeup events for this thread - Signal(); - Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - global_handle); - kernel.GlobalHandleTable().Close(global_handle); - global_handle = 0; - SetStatus(ThreadStatus::Dead); + { + SchedulerLock lock(kernel); + // Cancel any outstanding wakeup events for this thread + Signal(); + Core::System::GetInstance().CoreTiming().UnscheduleEvent( + kernel.ThreadWakeupCallbackEventType(), global_handle); + kernel.GlobalHandleTable().Close(global_handle); + SetStatus(ThreadStatus::Dead); - owner_process->UnregisterThread(this); + owner_process->UnregisterThread(this); - // Mark the TLS slot in the thread's page as free. - owner_process->FreeTLSRegion(tls_address); + // Mark the TLS slot in the thread's page as free. + owner_process->FreeTLSRegion(tls_address); + } + global_handle = 0; } void Thread::WakeAfterDelay(s64 nanoseconds) { @@ -112,8 +114,6 @@ void Thread::ResumeFromWait() { return; } - hle_callback = nullptr; - if (activity == ThreadActivity::Paused) { SetStatus(ThreadStatus::Paused); return; @@ -398,14 +398,13 @@ bool Thread::AllSynchronizationObjectsReady() const { bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index) { - ASSERT(hle_callback); - return hle_callback(reason, std::move(thread), std::move(object), index); + ASSERT(wakeup_callback); + return wakeup_callback(reason, std::move(thread), std::move(object), index); } -bool Thread::InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index) { +bool Thread::InvokeHLECallback(std::shared_ptr thread) { ASSERT(hle_callback); - return hle_callback(reason, std::move(thread), std::move(object), index); + return hle_callback(std::move(thread)); } void Thread::SetActivity(ThreadActivity value) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 04496f96e..c4c9d69ec 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -448,7 +448,7 @@ public: } bool HasWakeupCallback() const { - return hle_callback != nullptr; + return wakeup_callback != nullptr; } bool HasHLECallback() const { @@ -456,10 +456,10 @@ public: } void SetWakeupCallback(WakeupCallback callback) { - hle_callback = std::move(callback); + wakeup_callback = std::move(callback); } - void SetHLECallback(WakeupCallback callback) { + void SetHLECallback(HLECallback callback) { hle_callback = std::move(callback); } @@ -487,8 +487,7 @@ public: */ bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, std::shared_ptr object, std::size_t index); - bool InvokeHLECallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index); + bool InvokeHLECallback(std::shared_ptr thread); u32 GetIdealCore() const { return ideal_core; @@ -622,8 +621,11 @@ private: /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread /// was waiting via WaitSynchronization then the object will be the last object that became - /// available. In case of a timeout, the object will be nullptr. - WakeupCallback hle_callback; + /// available. In case of a timeout, the object will be nullptr. DEPRECATED + WakeupCallback wakeup_callback; + + /// Callback for HLE Events + HLECallback hle_callback; Handle hle_time_event; Scheduler* scheduler = nullptr; -- cgit v1.2.3 From b4dc01f16affe4baa9a7ab5ac4b240e03c03ae67 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 13:37:11 -0400 Subject: Kernel: Correct Signal on Thread Death and Setup Sync Objects on Thread for Debugging --- src/core/hle/kernel/synchronization.cpp | 3 +++ src/core/hle/kernel/thread.cpp | 15 +++++++-------- src/core/hle/kernel/thread.h | 14 +++++++------- 3 files changed, 17 insertions(+), 15 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 4ee7ad93c..ac43a7094 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -70,6 +70,8 @@ std::pair Synchronization::WaitFor( for (auto& object : sync_objects) { object->AddWaitingThread(SharedFrom(thread)); } + + thread->SetSynchronizationObjects(&sync_objects); thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); thread->SetStatus(ThreadStatus::WaitSynch); } @@ -83,6 +85,7 @@ std::pair Synchronization::WaitFor( SchedulerLock lock(kernel); ResultCode signaling_result = thread->GetSignalingResult(); SynchronizationObject* signaling_object = thread->GetSignalingObject(); + thread->SetSynchronizationObjects(nullptr); for (auto& obj : sync_objects) { obj->RemoveWaitingThread(SharedFrom(thread)); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 16babe71a..fb1751860 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -50,11 +50,11 @@ void Thread::Stop() { { SchedulerLock lock(kernel); // Cancel any outstanding wakeup events for this thread - Signal(); Core::System::GetInstance().CoreTiming().UnscheduleEvent( kernel.ThreadWakeupCallbackEventType(), global_handle); - kernel.GlobalHandleTable().Close(global_handle); SetStatus(ThreadStatus::Dead); + Signal(); + kernel.GlobalHandleTable().Close(global_handle); owner_process->UnregisterThread(this); @@ -81,7 +81,6 @@ void Thread::CancelWakeupTimer() { } void Thread::ResumeFromWait() { - ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); SchedulerLock lock(kernel); switch (status) { case ThreadStatus::Paused: @@ -219,7 +218,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy thread->processor_id = processor_id; thread->ideal_core = processor_id; thread->affinity_mask = 1ULL << processor_id; - thread->wait_objects.clear(); + thread->wait_objects = nullptr; thread->mutex_wait_address = 0; thread->condvar_wait_address = 0; thread->wait_handle = 0; @@ -272,9 +271,9 @@ void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode } s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr object) const { - ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything"); - const auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object); - return static_cast(std::distance(match, wait_objects.rend()) - 1); + ASSERT_MSG(!wait_objects->empty(), "Thread is not waiting for anything"); + const auto match = std::find(wait_objects->rbegin(), wait_objects->rend(), object); + return static_cast(std::distance(match, wait_objects->rend()) - 1); } VAddr Thread::GetCommandBufferAddress() const { @@ -389,7 +388,7 @@ void Thread::UpdatePriority() { } bool Thread::AllSynchronizationObjectsReady() const { - return std::none_of(wait_objects.begin(), wait_objects.end(), + return std::none_of(wait_objects->begin(), wait_objects->end(), [this](const std::shared_ptr& object) { return object->ShouldWait(this); }); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c4c9d69ec..7b6d1b4ec 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -21,7 +21,7 @@ class Fiber; namespace Core { class System; -} +} // namespace Core namespace Kernel { @@ -386,18 +386,18 @@ public: } const ThreadSynchronizationObjects& GetSynchronizationObjects() const { - return wait_objects; + return *wait_objects; } - void SetSynchronizationObjects(ThreadSynchronizationObjects objects) { - wait_objects = std::move(objects); + void SetSynchronizationObjects(ThreadSynchronizationObjects* objects) { + wait_objects = objects; } void ClearSynchronizationObjects() { - for (const auto& waiting_object : wait_objects) { + for (const auto& waiting_object : *wait_objects) { waiting_object->RemoveWaitingThread(SharedFrom(this)); } - wait_objects.clear(); + wait_objects->clear(); } /// Determines whether all the objects this thread is waiting on are ready. @@ -595,7 +595,7 @@ private: /// Objects that the thread is waiting on, in the same order as they were /// passed to WaitSynchronization. - ThreadSynchronizationObjects wait_objects; + ThreadSynchronizationObjects* wait_objects; SynchronizationObject* signaling_object; ResultCode signaling_result{RESULT_SUCCESS}; -- cgit v1.2.3 From 07993ac8c8c66bbf638dddc7750106f6dfb0e09b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 15:50:38 -0400 Subject: Kernel: Corrections to Scheduling. --- src/core/hle/kernel/scheduler.cpp | 26 +++++++++++++------------- src/core/hle/kernel/scheduler.h | 2 ++ src/core/hle/kernel/svc.cpp | 1 - 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d67d3c5cd..da77967dd 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -47,13 +47,13 @@ u32 GlobalScheduler::SelectThreads() { ASSERT(is_locked); const auto update_thread = [](Thread* thread, Scheduler& sched) { sched.guard.lock(); - if (thread != sched.selected_thread.get()) { + if (thread != sched.selected_thread_set.get()) { if (thread == nullptr) { ++sched.idle_selection_count; } - sched.selected_thread = SharedFrom(thread); + sched.selected_thread_set = SharedFrom(thread); } - const bool reschedule_pending = sched.selected_thread != sched.current_thread; + const bool reschedule_pending = sched.selected_thread_set != sched.current_thread; sched.is_context_switch_pending = reschedule_pending; std::atomic_thread_fence(std::memory_order_seq_cst); sched.guard.unlock(); @@ -118,6 +118,8 @@ u32 GlobalScheduler::SelectThreads() { suggested); top_threads[candidate_core] = next; break; + } else { + suggested = nullptr; } } } @@ -590,7 +592,7 @@ void Scheduler::OnThreadStart() { } void Scheduler::SwitchContextStep2() { - Thread* previous_thread = current_thread.get(); + Thread* previous_thread = current_thread_prev.get(); Thread* new_thread = selected_thread.get(); // Load context of new thread @@ -606,8 +608,6 @@ void Scheduler::SwitchContextStep2() { "Thread must be ready to become running."); // Cancel any outstanding wakeup events for this thread - current_thread = SharedFrom(new_thread); - new_thread->SetStatus(ThreadStatus::Running); new_thread->SetIsRunning(true); auto* const thread_owner_process = current_thread->GetOwnerProcess(); @@ -622,21 +622,21 @@ void Scheduler::SwitchContextStep2() { cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } - } else { - current_thread = nullptr; - // Note: We do not reset the current process and current page table when idling because - // technically we haven't changed processes, our threads are just paused. } - guard.unlock(); + + TryDoContextSwitch(); } void Scheduler::SwitchContext() { - Thread* previous_thread = current_thread.get(); + current_thread_prev = current_thread; + selected_thread = selected_thread_set; + Thread* previous_thread = current_thread_prev.get(); Thread* new_thread = selected_thread.get(); + current_thread = selected_thread; is_context_switch_pending = false; + guard.unlock(); if (new_thread == previous_thread) { - guard.unlock(); return; } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f26a554f5..f73ca777e 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -249,6 +249,8 @@ private: std::shared_ptr current_thread = nullptr; std::shared_ptr selected_thread = nullptr; + std::shared_ptr current_thread_prev = nullptr; + std::shared_ptr selected_thread_set = nullptr; std::shared_ptr idle_thread = nullptr; Core::System& system; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9f46a1758..5e9dd43bf 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -316,7 +316,6 @@ static ResultCode ConnectToNamedPort32(Core::System& system, Handle* out_handle, /// Makes a blocking IPC call to an OS service. static ResultCode SendSyncRequest(Core::System& system, Handle handle) { - std::lock_guard lock{HLE::g_hle_lock}; const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); std::shared_ptr session = handle_table.Get(handle); if (!session) { -- cgit v1.2.3 From 1e987dbe8d9b5fbe778637c0b35cbc51b1a0956b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 15:59:09 -0400 Subject: Scheduler: Correct Select Threads Step 2. --- src/core/hle/kernel/scheduler.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index da77967dd..9329202c6 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -103,6 +103,7 @@ u32 GlobalScheduler::SelectThreads() { TransferToCore(suggested->GetPriority(), static_cast(core_id), suggested); break; } + suggested = nullptr; migration_candidates[num_candidates++] = suggested_core_id; } // Step 3: Select a suggested thread from another core -- cgit v1.2.3 From e4b175ade205095e7cc89e0f60c902c708d7d767 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 3 Mar 2020 17:19:44 -0400 Subject: SVC: Correct svcWaitForAddress and svcSignalToAddress. --- src/core/hle/kernel/address_arbiter.cpp | 214 +++++++++++++++++++++++--------- src/core/hle/kernel/address_arbiter.h | 3 - src/core/hle/kernel/svc.cpp | 3 - src/core/hle/kernel/thread.h | 9 ++ 4 files changed, 161 insertions(+), 68 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 8475b698c..ebabde921 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -7,11 +7,15 @@ #include "common/assert.h" #include "common/common_types.h" +#include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/errors.h" +#include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/time_manager.h" #include "core/hle/result.h" #include "core/memory.h" @@ -20,6 +24,7 @@ namespace Kernel { // Wake up num_to_wake (or all) threads in a vector. void AddressArbiter::WakeThreads(const std::vector>& waiting_threads, s32 num_to_wake) { + auto& time_manager = system.Kernel().TimeManager(); // Only process up to 'target' threads, unless 'target' is <= 0, in which case process // them all. std::size_t last = waiting_threads.size(); @@ -29,12 +34,20 @@ void AddressArbiter::WakeThreads(const std::vector>& wai // Signal the waiting threads. for (std::size_t i = 0; i < last; i++) { + if (waiting_threads[i]->GetStatus() != ThreadStatus::WaitArb) { + last++; + last = std::min(waiting_threads.size(), last); + continue; + } + + time_manager.CancelTimeEvent(waiting_threads[i].get()); + ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb); - waiting_threads[i]->SetWaitSynchronizationResult(RESULT_SUCCESS); + waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS); RemoveThread(waiting_threads[i]); + waiting_threads[i]->WaitForArbitration(false); waiting_threads[i]->SetArbiterWaitAddress(0); waiting_threads[i]->ResumeFromWait(); - system.PrepareReschedule(waiting_threads[i]->GetProcessorID()); } } @@ -56,6 +69,7 @@ ResultCode AddressArbiter::SignalToAddress(VAddr address, SignalType type, s32 v } ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { + SchedulerLock lock(system.Kernel()); const std::vector> waiting_threads = GetThreadsWaitingOnAddress(address); WakeThreads(waiting_threads, num_to_wake); @@ -64,6 +78,7 @@ ResultCode AddressArbiter::SignalToAddressOnly(VAddr address, s32 num_to_wake) { ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + SchedulerLock lock(system.Kernel()); auto& memory = system.Memory(); // Ensure that we can write to the address. @@ -71,16 +86,25 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 return ERR_INVALID_ADDRESS_STATE; } - if (static_cast(memory.Read32(address)) != value) { - return ERR_INVALID_STATE; - } + const std::size_t current_core = system.CurrentCoreIndex(); + auto& monitor = system.Monitor(); + u32 current_value; + do { + monitor.SetExclusive(current_core, address); + current_value = memory.Read32(address); + + if (current_value != value) { + return ERR_INVALID_STATE; + } + current_value++; + } while (!monitor.ExclusiveWrite32(current_core, address, current_value)); - memory.Write32(address, static_cast(value + 1)); return SignalToAddressOnly(address, num_to_wake); } ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr address, s32 value, s32 num_to_wake) { + SchedulerLock lock(system.Kernel()); auto& memory = system.Memory(); // Ensure that we can write to the address. @@ -92,29 +116,34 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a const std::vector> waiting_threads = GetThreadsWaitingOnAddress(address); - // Determine the modified value depending on the waiting count. + const std::size_t current_core = system.CurrentCoreIndex(); + auto& monitor = system.Monitor(); s32 updated_value; - if (num_to_wake <= 0) { - if (waiting_threads.empty()) { - updated_value = value + 1; - } else { - updated_value = value - 1; + do { + monitor.SetExclusive(current_core, address); + updated_value = memory.Read32(address); + + if (updated_value != value) { + return ERR_INVALID_STATE; } - } else { - if (waiting_threads.empty()) { - updated_value = value + 1; - } else if (waiting_threads.size() <= static_cast(num_to_wake)) { - updated_value = value - 1; + // Determine the modified value depending on the waiting count. + if (num_to_wake <= 0) { + if (waiting_threads.empty()) { + updated_value = value + 1; + } else { + updated_value = value - 1; + } } else { - updated_value = value; + if (waiting_threads.empty()) { + updated_value = value + 1; + } else if (waiting_threads.size() <= static_cast(num_to_wake)) { + updated_value = value - 1; + } else { + updated_value = value; + } } - } + } while (!monitor.ExclusiveWrite32(current_core, address, updated_value)); - if (static_cast(memory.Read32(address)) != value) { - return ERR_INVALID_STATE; - } - - memory.Write32(address, static_cast(updated_value)); WakeThreads(waiting_threads, num_to_wake); return RESULT_SUCCESS; } @@ -136,60 +165,121 @@ ResultCode AddressArbiter::WaitForAddress(VAddr address, ArbitrationType type, s ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s64 timeout, bool should_decrement) { auto& memory = system.Memory(); + auto& kernel = system.Kernel(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - // Ensure that we can read the address. - if (!memory.IsValidVirtualAddress(address)) { - return ERR_INVALID_ADDRESS_STATE; - } + Handle event_handle = InvalidHandle; + { + SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + + // Ensure that we can read the address. + if (!memory.IsValidVirtualAddress(address)) { + lock.CancelSleep(); + return ERR_INVALID_ADDRESS_STATE; + } + + /// TODO(Blinkhawk): Check termination pending. + + s32 current_value = static_cast(memory.Read32(address)); + if (current_value >= value) { + lock.CancelSleep(); + return ERR_INVALID_STATE; + } - const s32 cur_value = static_cast(memory.Read32(address)); - if (cur_value >= value) { - return ERR_INVALID_STATE; + s32 decrement_value; + + const std::size_t current_core = system.CurrentCoreIndex(); + auto& monitor = system.Monitor(); + do { + monitor.SetExclusive(current_core, address); + current_value = static_cast(memory.Read32(address)); + if (should_decrement) { + decrement_value = current_value - 1; + } else { + decrement_value = current_value; + } + } while ( + !monitor.ExclusiveWrite32(current_core, address, static_cast(decrement_value))); + + // Short-circuit without rescheduling, if timeout is zero. + if (timeout == 0) { + lock.CancelSleep(); + return RESULT_TIMEOUT; + } + + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + current_thread->SetArbiterWaitAddress(address); + InsertThread(SharedFrom(current_thread)); + current_thread->SetStatus(ThreadStatus::WaitArb); + current_thread->WaitForArbitration(true); } - if (should_decrement) { - memory.Write32(address, static_cast(cur_value - 1)); + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); } - // Short-circuit without rescheduling, if timeout is zero. - if (timeout == 0) { - return RESULT_TIMEOUT; + { + SchedulerLock lock(kernel); + if (current_thread->IsWaitingForArbitration()) { + RemoveThread(SharedFrom(current_thread)); + current_thread->WaitForArbitration(false); + } } - return WaitForAddressImpl(address, timeout); + return current_thread->GetSignalingResult(); } ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout) { auto& memory = system.Memory(); + auto& kernel = system.Kernel(); + Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - // Ensure that we can read the address. - if (!memory.IsValidVirtualAddress(address)) { - return ERR_INVALID_ADDRESS_STATE; - } + Handle event_handle = InvalidHandle; + { + SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + + // Ensure that we can read the address. + if (!memory.IsValidVirtualAddress(address)) { + lock.CancelSleep(); + return ERR_INVALID_ADDRESS_STATE; + } + + /// TODO(Blinkhawk): Check termination pending. - // Only wait for the address if equal. - if (static_cast(memory.Read32(address)) != value) { - return ERR_INVALID_STATE; + s32 current_value = static_cast(memory.Read32(address)); + if (current_value != value) { + lock.CancelSleep(); + return ERR_INVALID_STATE; + } + + // Short-circuit without rescheduling, if timeout is zero. + if (timeout == 0) { + lock.CancelSleep(); + return RESULT_TIMEOUT; + } + + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + current_thread->SetArbiterWaitAddress(address); + InsertThread(SharedFrom(current_thread)); + current_thread->SetStatus(ThreadStatus::WaitArb); + current_thread->WaitForArbitration(true); } - // Short-circuit without rescheduling if timeout is zero. - if (timeout == 0) { - return RESULT_TIMEOUT; + if (event_handle != InvalidHandle) { + auto& time_manager = kernel.TimeManager(); + time_manager.UnscheduleTimeEvent(event_handle); } - return WaitForAddressImpl(address, timeout); -} + { + SchedulerLock lock(kernel); + if (current_thread->IsWaitingForArbitration()) { + RemoveThread(SharedFrom(current_thread)); + current_thread->WaitForArbitration(false); + } + } -ResultCode AddressArbiter::WaitForAddressImpl(VAddr address, s64 timeout) { - Thread* current_thread = system.CurrentScheduler().GetCurrentThread(); - current_thread->SetArbiterWaitAddress(address); - InsertThread(SharedFrom(current_thread)); - current_thread->SetStatus(ThreadStatus::WaitArb); - current_thread->InvalidateWakeupCallback(); - current_thread->WakeAfterDelay(timeout); - - system.PrepareReschedule(current_thread->GetProcessorID()); - return RESULT_TIMEOUT; + return current_thread->GetSignalingResult(); } void AddressArbiter::HandleWakeupThread(std::shared_ptr thread) { @@ -221,9 +311,9 @@ void AddressArbiter::RemoveThread(std::shared_ptr thread) { const auto iter = std::find_if(thread_list.cbegin(), thread_list.cend(), [&thread](const auto& entry) { return thread == entry; }); - ASSERT(iter != thread_list.cend()); - - thread_list.erase(iter); + if (iter != thread_list.cend()) { + thread_list.erase(iter); + } } std::vector> AddressArbiter::GetThreadsWaitingOnAddress( diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index f958eee5a..0b05d533c 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h @@ -73,9 +73,6 @@ private: /// Waits on an address if the value passed is equal to the argument value. ResultCode WaitForAddressIfEqual(VAddr address, s32 value, s64 timeout); - // Waits on the given address with a timeout in nanoseconds - ResultCode WaitForAddressImpl(VAddr address, s64 timeout); - /// Wake up num_to_wake (or all) threads in a vector. void WakeThreads(const std::vector>& waiting_threads, s32 num_to_wake); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5e9dd43bf..718462b2b 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1691,7 +1691,6 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, timeout={}", address, type, value, timeout); - UNIMPLEMENTED(); // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); @@ -1717,8 +1716,6 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, LOG_TRACE(Kernel_SVC, "called, address=0x{:X}, type=0x{:X}, value=0x{:X}, num_to_wake=0x{:X}", address, type, value, num_to_wake); - UNIMPLEMENTED(); - // If the passed address is a kernel virtual address, return invalid memory state. if (Core::Memory::IsKernelVirtualAddress(address)) { LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 7b6d1b4ec..e8355bbd1 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -548,6 +548,14 @@ public: return global_handle; } + bool IsWaitingForArbitration() const { + return waiting_for_arbitration; + } + + void WaitForArbitration(bool set) { + waiting_for_arbitration = set; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -615,6 +623,7 @@ private: /// If waiting for an AddressArbiter, this is the address being waited on. VAddr arb_wait_address{0}; + bool waiting_for_arbitration{}; /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle global_handle = 0; -- cgit v1.2.3 From a6bce296ad3fa8e7da66df3d32cd148448ac0abb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 4 Mar 2020 22:46:22 -0400 Subject: Mutex: Correct Result writting to clear exclusivity. --- src/core/hle/kernel/mutex.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 18325db57..ebe3f6050 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -9,6 +9,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/arm/exclusive_monitor.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -133,8 +134,12 @@ std::pair> Mutex::Unlock(std::shared_ptr> Mutex::Unlock(std::shared_ptrSetSynchronizationResults(nullptr, RESULT_SUCCESS); - new_owner->ResumeFromWait(); new_owner->SetLockOwner(nullptr); - system.Memory().Write32(address, mutex_value); + new_owner->ResumeFromWait(); + + do { + monitor.SetExclusive(current_core, address); + } while (!monitor.ExclusiveWrite32(current_core, address, mutex_value)); return {RESULT_SUCCESS, new_owner}; } -- cgit v1.2.3 From c43e55973425be2dfca06804a85493fc6f9c07d1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 09:31:03 -0400 Subject: NVDRV: Remove frame limiting as Host Timing already takes care. --- src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 3f7b8e670..19df0dca7 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -41,7 +41,6 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 system.GetPerfStats().EndGameFrame(); system.GetPerfStats().EndSystemFrame(); system.GPU().SwapBuffers(&framebuffer); - system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs()); system.GetPerfStats().BeginSystemFrame(); } -- cgit v1.2.3 From 1c672128c421ea3141a74f9c6695ecc83231ca30 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 09:52:24 -0400 Subject: Scheduler: Release old thread fiber before trying to switch to the next thread fiber. --- src/core/hle/kernel/scheduler.cpp | 37 ++++++++++++++++++++++++++----------- src/core/hle/kernel/scheduler.h | 9 +++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 9329202c6..aa1f1a305 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -53,7 +53,8 @@ u32 GlobalScheduler::SelectThreads() { } sched.selected_thread_set = SharedFrom(thread); } - const bool reschedule_pending = sched.selected_thread_set != sched.current_thread; + const bool reschedule_pending = + sched.is_context_switch_pending || (sched.selected_thread_set != sched.current_thread); sched.is_context_switch_pending = reschedule_pending; std::atomic_thread_fence(std::memory_order_seq_cst); sched.guard.unlock(); @@ -552,7 +553,9 @@ void GlobalScheduler::Unlock() { } Scheduler::Scheduler(Core::System& system, std::size_t core_id) - : system{system}, core_id{core_id} {} + : system(system), core_id(core_id) { + switch_fiber = std::make_shared(std::function(OnSwitch), this); +} Scheduler::~Scheduler() = default; @@ -636,8 +639,9 @@ void Scheduler::SwitchContext() { current_thread = selected_thread; is_context_switch_pending = false; - guard.unlock(); + if (new_thread == previous_thread) { + guard.unlock(); return; } @@ -669,20 +673,31 @@ void Scheduler::SwitchContext() { } else { old_context = idle_thread->GetHostContext(); } + guard.unlock(); - std::shared_ptr next_context; - if (new_thread != nullptr) { - next_context = new_thread->GetHostContext(); - } else { - next_context = idle_thread->GetHostContext(); - } - - Common::Fiber::YieldTo(old_context, next_context); + Common::Fiber::YieldTo(old_context, switch_fiber); /// When a thread wakes up, the scheduler may have changed to other in another core. auto& next_scheduler = system.Kernel().CurrentScheduler(); next_scheduler.SwitchContextStep2(); } +void Scheduler::OnSwitch(void* this_scheduler) { + Scheduler* sched = static_cast(this_scheduler); + sched->SwitchToCurrent(); +} + +void Scheduler::SwitchToCurrent() { + while (true) { + std::shared_ptr next_context; + if (current_thread != nullptr) { + next_context = current_thread->GetHostContext(); + } else { + next_context = idle_thread->GetHostContext(); + } + Common::Fiber::YieldTo(switch_fiber, next_context); + } +} + void Scheduler::UpdateLastContextSwitchTime(Thread* thread, Process* process) { const u64 prev_switch_ticks = last_context_switch_time; const u64 most_recent_switch_ticks = system.CoreTiming().GetCPUTicks(); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f73ca777e..728cca802 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -15,6 +15,10 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/thread.h" +namespace Common { + class Fiber; +} + namespace Core { class ARM_Interface; class System; @@ -247,12 +251,17 @@ private: */ void UpdateLastContextSwitchTime(Thread* thread, Process* process); + static void OnSwitch(void* this_scheduler); + void SwitchToCurrent(); + std::shared_ptr current_thread = nullptr; std::shared_ptr selected_thread = nullptr; std::shared_ptr current_thread_prev = nullptr; std::shared_ptr selected_thread_set = nullptr; std::shared_ptr idle_thread = nullptr; + std::shared_ptr switch_fiber = nullptr; + Core::System& system; u64 last_context_switch_time = 0; u64 idle_selection_count = 0; -- cgit v1.2.3 From a33fbaddec5d516328d7cd179114dcf0b93cfb69 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 14:56:05 -0400 Subject: Core: Correct rebase. --- src/core/hle/kernel/scheduler.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index aa1f1a305..ae89e908f 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -552,8 +552,7 @@ void GlobalScheduler::Unlock() { EnableInterruptAndSchedule(cores_pending_reschedule, leaving_thread); } -Scheduler::Scheduler(Core::System& system, std::size_t core_id) - : system(system), core_id(core_id) { +Scheduler::Scheduler(Core::System& system, std::size_t core_id) : system(system), core_id(core_id) { switch_fiber = std::make_shared(std::function(OnSwitch), this); } @@ -601,9 +600,10 @@ void Scheduler::SwitchContextStep2() { // Load context of new thread Process* const previous_process = - previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; + previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; if (new_thread) { + auto& cpu_core = system.ArmInterface(core_id); new_thread->context_guard.lock(); cpu_core.Lock(); ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), @@ -619,7 +619,6 @@ void Scheduler::SwitchContextStep2() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); @@ -651,12 +650,12 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + auto& cpu_core = system.ArmInterface(core_id); if (!previous_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. - previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } if (previous_thread->GetStatus() == ThreadStatus::Running) { -- cgit v1.2.3 From 19847d4d42e061a24086fe90d62382a1ff198322 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 19:30:37 -0400 Subject: Scheduler: Correct assert. --- src/core/hle/kernel/scheduler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index ae89e908f..4e2a5adf3 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -606,10 +606,8 @@ void Scheduler::SwitchContextStep2() { auto& cpu_core = system.ArmInterface(core_id); new_thread->context_guard.lock(); cpu_core.Lock(); - ASSERT_MSG(new_thread->GetProcessorID() == s32(this->core_id), - "Thread must be assigned to this core."); - ASSERT_MSG(new_thread->GetStatus() == ThreadStatus::Ready, - "Thread must be ready to become running."); + ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, + "Thread must be runnable."); // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); -- cgit v1.2.3 From 3de33348e41ab824eb13f202eccc29d5be2a6d42 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 20:20:36 -0400 Subject: Scheduler: Protect on closed threads. --- src/core/hle/kernel/scheduler.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 4e2a5adf3..74d3731fc 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -604,7 +604,6 @@ void Scheduler::SwitchContextStep2() { if (new_thread) { auto& cpu_core = system.ArmInterface(core_id); - new_thread->context_guard.lock(); cpu_core.Lock(); ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, "Thread must be runnable."); @@ -685,13 +684,24 @@ void Scheduler::OnSwitch(void* this_scheduler) { void Scheduler::SwitchToCurrent() { while (true) { - std::shared_ptr next_context; - if (current_thread != nullptr) { - next_context = current_thread->GetHostContext(); - } else { - next_context = idle_thread->GetHostContext(); + guard.lock(); + selected_thread = selected_thread_set; + current_thread = selected_thread; + guard.unlock(); + while (!is_context_switch_pending) { + current_thread->context_guard.lock(); + if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + current_thread->context_guard.unlock(); + break; + } + std::shared_ptr next_context; + if (current_thread != nullptr) { + next_context = current_thread->GetHostContext(); + } else { + next_context = idle_thread->GetHostContext(); + } + Common::Fiber::YieldTo(switch_fiber, next_context); } - Common::Fiber::YieldTo(switch_fiber, next_context); } } -- cgit v1.2.3 From 6ed28e15fa9f4c727cf24990c35b13a35547d943 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 20:36:05 -0400 Subject: Scheduler: Fix HLE Threads on guard --- src/core/hle/kernel/scheduler.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 74d3731fc..d7529360c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -689,10 +689,12 @@ void Scheduler::SwitchToCurrent() { current_thread = selected_thread; guard.unlock(); while (!is_context_switch_pending) { - current_thread->context_guard.lock(); - if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { - current_thread->context_guard.unlock(); - break; + if (current_thread != nullptr) { + current_thread->context_guard.lock(); + if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + current_thread->context_guard.unlock(); + break; + } } std::shared_ptr next_context; if (current_thread != nullptr) { -- cgit v1.2.3 From 44cb9997b3bf3b1e16b05c2b115c7c4ad5e37dd1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 6 Mar 2020 22:58:56 -0400 Subject: Scheduler: Correct locking for hle threads. --- src/core/hle/kernel/scheduler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d7529360c..f020438fb 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -687,9 +687,10 @@ void Scheduler::SwitchToCurrent() { guard.lock(); selected_thread = selected_thread_set; current_thread = selected_thread; + is_context_switch_pending = false; guard.unlock(); while (!is_context_switch_pending) { - if (current_thread != nullptr) { + if (current_thread != nullptr && !current_thread->IsHLEThread()) { current_thread->context_guard.lock(); if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { current_thread->context_guard.unlock(); -- cgit v1.2.3 From a66c61ca2de61e3a46fa857cf8afea359b2fb8eb Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 10:24:46 -0400 Subject: SCC: Small corrections to CancelSynchronization --- src/core/hle/kernel/synchronization.cpp | 2 ++ src/core/hle/kernel/thread.cpp | 5 +++-- src/core/hle/kernel/thread.h | 9 +++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index ac43a7094..a7e3fbe92 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -74,7 +74,9 @@ std::pair Synchronization::WaitFor( thread->SetSynchronizationObjects(&sync_objects); thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); thread->SetStatus(ThreadStatus::WaitSynch); + thread->SetWaitingSync(true); } + thread->SetWaitingSync(false); if (event_handle != InvalidHandle) { auto& time_manager = kernel.TimeManager(); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fb1751860..e8962a0d8 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -139,13 +139,14 @@ ResultCode Thread::Start() { void Thread::CancelWait() { SchedulerLock lock(kernel); - if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { + if (GetSchedulingStatus() != ThreadSchedStatus::Paused || !is_waiting_on_sync) { is_sync_cancelled = true; return; } + //TODO(Blinkhawk): Implement cancel of server session is_sync_cancelled = false; SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); - ResumeFromWait(); + SetStatus(ThreadStatus::Ready); } static void ResetThreadContext32(Core::ARM_Interface::ThreadContext32& context, u32 stack_top, diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index e8355bbd1..d8a983200 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -556,6 +556,14 @@ public: waiting_for_arbitration = set; } + bool IsWaitingSync() const { + return is_waiting_on_sync; + } + + void SetWaitingSync(bool is_waiting) { + is_waiting_on_sync = is_waiting; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -650,6 +658,7 @@ private: u32 scheduling_state = 0; bool is_running = false; + bool is_waiting_on_sync = false; bool is_sync_cancelled = false; bool will_be_terminated{}; -- cgit v1.2.3 From 83c7ba1ef700eff17f30b6c2782db77710dc322e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 12:44:35 -0400 Subject: SVC: Correct SetThreadActivity. --- src/core/hle/kernel/scheduler.cpp | 9 +++--- src/core/hle/kernel/svc.cpp | 5 +--- src/core/hle/kernel/thread.cpp | 61 +++++++++++++++++++++++++-------------- src/core/hle/kernel/thread.h | 22 +++++++++----- 4 files changed, 59 insertions(+), 38 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index f020438fb..a37b992ec 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -417,8 +417,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { } ASSERT(is_locked); - if (static_cast(old_flags & static_cast(ThreadSchedMasks::LowMask)) == - ThreadSchedStatus::Runnable) { + if (old_flags == static_cast(ThreadSchedStatus::Runnable)) { // In this case the thread was running, now it's pausing/exitting if (thread->processor_id >= 0) { Unschedule(thread->current_priority, static_cast(thread->processor_id), thread); @@ -430,7 +429,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { Unsuggest(thread->current_priority, core, thread); } } - } else if (thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable) { + } else if (thread->scheduling_state == static_cast(ThreadSchedStatus::Runnable)) { // The thread is now set to running from being stopped if (thread->processor_id >= 0) { Schedule(thread->current_priority, static_cast(thread->processor_id), thread); @@ -448,7 +447,7 @@ void GlobalScheduler::AdjustSchedulingOnStatus(Thread* thread, u32 old_flags) { } void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priority) { - if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + if (thread->scheduling_state != static_cast(ThreadSchedStatus::Runnable)) { return; } ASSERT(is_locked); @@ -486,7 +485,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit void GlobalScheduler::AdjustSchedulingOnAffinity(Thread* thread, u64 old_affinity_mask, s32 old_core) { - if (thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable || + if (thread->scheduling_state != static_cast(ThreadSchedStatus::Runnable) || thread->current_priority >= THREADPRIO_COUNT) { return; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 718462b2b..da2f90a1d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1012,7 +1012,6 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); - UNIMPLEMENTED(); if (activity > static_cast(ThreadActivity::Paused)) { return ERR_INVALID_ENUM_VALUE; } @@ -1039,9 +1038,7 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return ERR_BUSY; } - thread->SetActivity(static_cast(activity)); - - return RESULT_SUCCESS; + return thread->SetActivity(static_cast(activity)); } /// Gets the thread context diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e8962a0d8..b99e3b7a5 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -113,20 +113,11 @@ void Thread::ResumeFromWait() { return; } - if (activity == ThreadActivity::Paused) { - SetStatus(ThreadStatus::Paused); - return; - } - SetStatus(ThreadStatus::Ready); } void Thread::OnWakeUp() { SchedulerLock lock(kernel); - if (activity == ThreadActivity::Paused) { - SetStatus(ThreadStatus::Paused); - return; - } SetStatus(ThreadStatus::Ready); } @@ -143,7 +134,7 @@ void Thread::CancelWait() { is_sync_cancelled = true; return; } - //TODO(Blinkhawk): Implement cancel of server session + // TODO(Blinkhawk): Implement cancel of server session is_sync_cancelled = false; SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED); SetStatus(ThreadStatus::Ready); @@ -407,19 +398,31 @@ bool Thread::InvokeHLECallback(std::shared_ptr thread) { return hle_callback(std::move(thread)); } -void Thread::SetActivity(ThreadActivity value) { - activity = value; +ResultCode Thread::SetActivity(ThreadActivity value) { + SchedulerLock lock(kernel); + + auto sched_status = GetSchedulingStatus(); + + if (sched_status != ThreadSchedStatus::Runnable && sched_status != ThreadSchedStatus::Paused) { + return ERR_INVALID_STATE; + } + + if (IsPendingTermination()) { + return RESULT_SUCCESS; + } if (value == ThreadActivity::Paused) { - // Set status if not waiting - if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { - SetStatus(ThreadStatus::Paused); - kernel.PrepareReschedule(processor_id); + if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) != 0) { + return ERR_INVALID_STATE; } - } else if (status == ThreadStatus::Paused) { - // Ready to reschedule - ResumeFromWait(); + AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); + } else { + if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) == 0) { + return ERR_INVALID_STATE; + } + RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); } + return RESULT_SUCCESS; } ResultCode Thread::Sleep(s64 nanoseconds) { @@ -460,11 +463,27 @@ ResultCode Thread::YieldAndWaitForLoadBalancing() { return RESULT_SUCCESS; } +void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { + const u32 old_state = scheduling_state; + pausing_state |= static_cast(flag); + const u32 base_scheduling = static_cast(GetSchedulingStatus()); + scheduling_state = base_scheduling | pausing_state; + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); +} + +void Thread::RemoveSchedulingFlag(ThreadSchedFlags flag) { + const u32 old_state = scheduling_state; + pausing_state &= ~static_cast(flag); + const u32 base_scheduling = static_cast(GetSchedulingStatus()); + scheduling_state = base_scheduling | pausing_state; + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); +} + void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { - const u32 old_flags = scheduling_state; + const u32 old_state = scheduling_state; scheduling_state = (scheduling_state & static_cast(ThreadSchedMasks::HighMask)) | static_cast(new_status); - kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_flags); + kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_state); } void Thread::SetCurrentPriority(u32 new_priority) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index d8a983200..0a8f7bb65 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -497,11 +497,7 @@ public: return affinity_mask; } - ThreadActivity GetActivity() const { - return activity; - } - - void SetActivity(ThreadActivity value); + ResultCode SetActivity(ThreadActivity value); /// Sleeps this thread for the given amount of nanoseconds. ResultCode Sleep(s64 nanoseconds); @@ -564,11 +560,22 @@ public: is_waiting_on_sync = is_waiting; } + bool IsPendingTermination() const { + return will_be_terminated || GetSchedulingStatus() == ThreadSchedStatus::Exited; + } + + bool IsPaused() const { + return pausing_state != 0; + } + private: friend class GlobalScheduler; friend class Scheduler; void SetSchedulingStatus(ThreadSchedStatus new_status); + void AddSchedulingFlag(ThreadSchedFlags flag); + void RemoveSchedulingFlag(ThreadSchedFlags flag); + void SetCurrentPriority(u32 new_priority); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); @@ -650,18 +657,17 @@ private: u32 ideal_core{0xFFFFFFFF}; u64 affinity_mask{0x1}; - ThreadActivity activity = ThreadActivity::Normal; - s32 ideal_core_override = -1; u64 affinity_mask_override = 0x1; u32 affinity_override_count = 0; u32 scheduling_state = 0; + u32 pausing_state = 0; bool is_running = false; bool is_waiting_on_sync = false; bool is_sync_cancelled = false; - bool will_be_terminated{}; + bool will_be_terminated = false; std::string name; }; -- cgit v1.2.3 From 725bac14044b2645b9ce912d1b1e2c9c2a96818b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 13:27:27 -0400 Subject: Scheduler: Remove arm_interface lock and a few corrections. --- src/core/hle/kernel/scheduler.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index a37b992ec..affc2fbed 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -463,9 +463,7 @@ void GlobalScheduler::AdjustSchedulingOnPriority(Thread* thread, u32 old_priorit } if (thread->processor_id >= 0) { - // TODO(Blinkhawk): compare it with current thread running on current core, instead of - // checking running - if (thread->IsRunning()) { + if (thread == kernel.CurrentScheduler().GetCurrentThread()) { SchedulePrepend(thread->current_priority, static_cast(thread->processor_id), thread); } else { @@ -602,8 +600,6 @@ void Scheduler::SwitchContextStep2() { previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; if (new_thread) { - auto& cpu_core = system.ArmInterface(core_id); - cpu_core.Lock(); ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, "Thread must be runnable."); @@ -615,6 +611,7 @@ void Scheduler::SwitchContextStep2() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); @@ -646,8 +643,8 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { - auto& cpu_core = system.ArmInterface(core_id); if (!previous_thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. @@ -659,7 +656,6 @@ void Scheduler::SwitchContext() { } previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); - cpu_core.Unlock(); } std::shared_ptr old_context; -- cgit v1.2.3 From 535c542d84ea56b5710bf84af3fba6272913f48e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 13:37:47 -0400 Subject: SVC: WaitSynchronization add Termination Pending Result. --- src/core/hle/kernel/errors.h | 1 + src/core/hle/kernel/synchronization.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index 29bfa3621..d4e5d88cf 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -12,6 +12,7 @@ namespace Kernel { constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7}; constexpr ResultCode ERR_INVALID_CAPABILITY_DESCRIPTOR{ErrorModule::Kernel, 14}; +constexpr ResultCode ERR_THREAD_TERMINATING{ErrorModule::Kernel, 59}; constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101}; constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102}; constexpr ResultCode ERR_OUT_OF_RESOURCES{ErrorModule::Kernel, 103}; diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index a7e3fbe92..4323fc120 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -59,7 +59,10 @@ std::pair Synchronization::WaitFor( return {RESULT_TIMEOUT, InvalidHandle}; } - /// TODO(Blinkhawk): Check for termination pending + if (thread->IsPendingTermination()) { + lock.CancelSleep(); + return {ERR_THREAD_TERMINATING, InvalidHandle}; + } if (thread->IsSyncCancelled()) { thread->SetSyncCancelled(false); -- cgit v1.2.3 From cd1c38be8d15d3caf52f566a9e8dc20504c61068 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 18:59:42 -0400 Subject: ARM/Memory: Correct Exclusive Monitor and Implement Exclusive Memory Writes. --- src/core/hle/kernel/address_arbiter.cpp | 6 +++--- src/core/hle/kernel/mutex.cpp | 5 +++-- src/core/hle/kernel/svc.cpp | 2 +- src/core/hle/kernel/thread.cpp | 6 +++--- 4 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index ebabde921..07acabc1d 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -90,7 +90,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 auto& monitor = system.Monitor(); u32 current_value; do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); current_value = memory.Read32(address); if (current_value != value) { @@ -120,7 +120,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a auto& monitor = system.Monitor(); s32 updated_value; do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); updated_value = memory.Read32(address); if (updated_value != value) { @@ -191,7 +191,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); current_value = static_cast(memory.Read32(address)); if (should_decrement) { decrement_value = current_value - 1; diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index ebe3f6050..16c95782a 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -10,6 +10,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/arm/exclusive_monitor.h" +#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -138,7 +139,7 @@ std::pair> Mutex::Unlock(std::shared_ptr> Mutex::Unlock(std::shared_ptrResumeFromWait(); do { - monitor.SetExclusive(current_core, address); + monitor.SetExclusive32(current_core, address); } while (!monitor.ExclusiveWrite32(current_core, address, mutex_value)); return {RESULT_SUCCESS, new_owner}; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index da2f90a1d..371beed0d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1641,7 +1641,7 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ u32 update_val = 0; const VAddr mutex_address = thread->GetMutexWaitAddress(); do { - monitor.SetExclusive(current_core, mutex_address); + monitor.SetExclusive32(current_core, mutex_address); // If the mutex is not yet acquired, acquire it. mutex_val = memory.Read32(mutex_address); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index b99e3b7a5..51cc5dcca 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -236,7 +236,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); } thread->host_context = - std::make_shared(std::move(thread_start_func), thread_start_parameter); + std::make_shared(std::move(thread_start_func), thread_start_parameter); return MakeResult>(std::move(thread)); } @@ -412,12 +412,12 @@ ResultCode Thread::SetActivity(ThreadActivity value) { } if (value == ThreadActivity::Paused) { - if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) != 0) { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) != 0) { return ERR_INVALID_STATE; } AddSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); } else { - if (pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag) == 0) { + if ((pausing_state & static_cast(ThreadSchedFlags::ThreadPauseFlag)) == 0) { return ERR_INVALID_STATE; } RemoveSchedulingFlag(ThreadSchedFlags::ThreadPauseFlag); -- cgit v1.2.3 From 445b4342b3db8ab447aaa9e5422d2a7a3a45e5ac Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 19:04:02 -0400 Subject: Mutex: Revert workaround due to poor exclusive memory. --- src/core/hle/kernel/mutex.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 16c95782a..5a96d5e90 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -9,7 +9,6 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" @@ -135,12 +134,8 @@ std::pair> Mutex::Unlock(std::shared_ptr> Mutex::Unlock(std::shared_ptrSetLockOwner(nullptr); new_owner->ResumeFromWait(); - do { - monitor.SetExclusive32(current_core, address); - } while (!monitor.ExclusiveWrite32(current_core, address, mutex_value)); + system.Memory().Write32(address, mutex_value); return {RESULT_SUCCESS, new_owner}; } -- cgit v1.2.3 From 4217e58a103049675df27f404171f73fa0be8537 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 11:25:50 -0400 Subject: Scheduler: Correct yields. --- src/core/hle/kernel/scheduler.cpp | 28 +++++++++++++++++++++------- src/core/hle/kernel/thread.h | 4 ++++ 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index affc2fbed..ab17204bb 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -147,9 +147,11 @@ bool GlobalScheduler::YieldThread(Thread* yielding_thread) { const u32 priority = yielding_thread->GetPriority(); // Yield the thread - const Thread* const winner = scheduled_queue[core_id].front(priority); - ASSERT_MSG(yielding_thread == winner, "Thread yielding without being in front"); - scheduled_queue[core_id].yield(priority); + Reschedule(priority, core_id, yielding_thread); + const Thread* const winner = scheduled_queue[core_id].front(); + if (kernel.GetCurrentHostThreadID() != core_id) { + is_reselection_pending.store(true, std::memory_order_release); + } return AskForReselectionOrMarkRedundant(yielding_thread, winner); } @@ -162,9 +164,7 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { const u32 priority = yielding_thread->GetPriority(); // Yield the thread - ASSERT_MSG(yielding_thread == scheduled_queue[core_id].front(priority), - "Thread yielding without being in front"); - scheduled_queue[core_id].yield(priority); + Reschedule(priority, core_id, yielding_thread); std::array current_threads; for (std::size_t i = 0; i < current_threads.size(); i++) { @@ -200,6 +200,10 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { winner = next_thread; } + if (kernel.GetCurrentHostThreadID() != core_id) { + is_reselection_pending.store(true, std::memory_order_release); + } + return AskForReselectionOrMarkRedundant(yielding_thread, winner); } @@ -239,6 +243,12 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread } else { winner = yielding_thread; } + } else { + winner = scheduled_queue[i].front(); + } + + if (kernel.GetCurrentHostThreadID() != core_id) { + is_reselection_pending.store(true, std::memory_order_release); } return AskForReselectionOrMarkRedundant(yielding_thread, winner); @@ -687,7 +697,11 @@ void Scheduler::SwitchToCurrent() { while (!is_context_switch_pending) { if (current_thread != nullptr && !current_thread->IsHLEThread()) { current_thread->context_guard.lock(); - if (current_thread->GetSchedulingStatus() != ThreadSchedStatus::Runnable) { + if (!current_thread->IsRunnable()) { + current_thread->context_guard.unlock(); + break; + } + if (current_thread->GetProcessorID() != core_id) { current_thread->context_guard.unlock(); break; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0a8f7bb65..953b023b5 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -524,6 +524,10 @@ public: static_cast(ThreadSchedMasks::LowMask)); } + bool IsRunnable() const { + return scheduling_state == static_cast(ThreadSchedStatus::Runnable); + } + bool IsRunning() const { return is_running; } -- cgit v1.2.3 From 6515c6e8c699584528486341579cf3a8dde3eea4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 12:51:24 -0400 Subject: Kernel: Fixes, corrections and asserts to scheduler and different svcs. --- src/core/hle/kernel/address_arbiter.cpp | 27 ++++++++++++--------------- src/core/hle/kernel/kernel.cpp | 1 + src/core/hle/kernel/scheduler.cpp | 3 ++- src/core/hle/kernel/scheduler.h | 5 +++-- src/core/hle/kernel/svc.cpp | 27 ++++++++++++++------------- src/core/hle/kernel/synchronization.cpp | 10 ++++++---- src/core/hle/kernel/time_manager.cpp | 2 -- src/core/hle/kernel/time_manager.h | 1 - 8 files changed, 38 insertions(+), 38 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 07acabc1d..e8f22b598 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -34,19 +34,9 @@ void AddressArbiter::WakeThreads(const std::vector>& wai // Signal the waiting threads. for (std::size_t i = 0; i < last; i++) { - if (waiting_threads[i]->GetStatus() != ThreadStatus::WaitArb) { - last++; - last = std::min(waiting_threads.size(), last); - continue; - } - - time_manager.CancelTimeEvent(waiting_threads[i].get()); - - ASSERT(waiting_threads[i]->GetStatus() == ThreadStatus::WaitArb); waiting_threads[i]->SetSynchronizationResults(nullptr, RESULT_SUCCESS); RemoveThread(waiting_threads[i]); waiting_threads[i]->WaitForArbitration(false); - waiting_threads[i]->SetArbiterWaitAddress(0); waiting_threads[i]->ResumeFromWait(); } } @@ -172,20 +162,25 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 { SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + if (current_thread->IsPendingTermination()) { + lock.CancelSleep(); + return ERR_THREAD_TERMINATING; + } + // Ensure that we can read the address. if (!memory.IsValidVirtualAddress(address)) { lock.CancelSleep(); return ERR_INVALID_ADDRESS_STATE; } - /// TODO(Blinkhawk): Check termination pending. - s32 current_value = static_cast(memory.Read32(address)); if (current_value >= value) { lock.CancelSleep(); return ERR_INVALID_STATE; } + current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + s32 decrement_value; const std::size_t current_core = system.CurrentCoreIndex(); @@ -207,7 +202,6 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 return RESULT_TIMEOUT; } - current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); current_thread->SetArbiterWaitAddress(address); InsertThread(SharedFrom(current_thread)); current_thread->SetStatus(ThreadStatus::WaitArb); @@ -239,14 +233,17 @@ ResultCode AddressArbiter::WaitForAddressIfEqual(VAddr address, s32 value, s64 t { SchedulerLockAndSleep lock(kernel, event_handle, current_thread, timeout); + if (current_thread->IsPendingTermination()) { + lock.CancelSleep(); + return ERR_THREAD_TERMINATING; + } + // Ensure that we can read the address. if (!memory.IsValidVirtualAddress(address)) { lock.CancelSleep(); return ERR_INVALID_ADDRESS_STATE; } - /// TODO(Blinkhawk): Check termination pending. - s32 current_value = static_cast(memory.Read32(address)); if (current_value != value) { lock.CancelSleep(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index ba051a7d8..721ab1e70 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -49,6 +49,7 @@ namespace Kernel { * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time */ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) { + UNREACHABLE(); const auto proper_handle = static_cast(thread_handle); const auto& system = Core::System::GetInstance(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index ab17204bb..5322f0aae 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -133,6 +133,7 @@ u32 GlobalScheduler::SelectThreads() { u32 cores_needing_context_switch{}; for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { Scheduler& sched = kernel.Scheduler(core); + ASSERT(top_threads[core] == nullptr || top_threads[core]->GetProcessorID() == core); if (update_thread(top_threads[core], sched)) { cores_needing_context_switch |= (1ul << core); } @@ -244,7 +245,7 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread winner = yielding_thread; } } else { - winner = scheduled_queue[i].front(); + winner = scheduled_queue[core_id].front(); } if (kernel.GetCurrentHostThreadID() != core_id) { diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 728cca802..5e062bf59 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -16,7 +16,7 @@ #include "core/hle/kernel/thread.h" namespace Common { - class Fiber; +class Fiber; } namespace Core { @@ -133,7 +133,8 @@ private: /// and reschedules current core if needed. void Unlock(); - void EnableInterruptAndSchedule(u32 cores_pending_reschedule, Core::EmuThreadHandle global_thread); + void EnableInterruptAndSchedule(u32 cores_pending_reschedule, + Core::EmuThreadHandle global_thread); /** * Add a thread to the suggested queue of a cpu core. Suggested threads may be diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 371beed0d..aad2ac549 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1562,6 +1562,11 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add current_thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); + if (thread->IsPendingTermination()) { + lock.CancelSleep(); + return ERR_THREAD_TERMINATING; + } + const auto release_result = current_process->GetMutex().Release(mutex_addr); if (release_result.IsError()) { lock.CancelSleep(); @@ -1588,6 +1593,11 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add { SchedulerLock lock(kernel); + auto* owner = current_thread->GetLockOwner(); + if (owner != nullptr) { + owner->RemoveMutexWaiter(SharedFrom(current_thread)); + } + current_process->RemoveConditionVariableThread(SharedFrom(current_thread)); } // Note: Deliberately don't attempt to inherit the lock owner's priority. @@ -1618,19 +1628,10 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ for (std::size_t index = 0; index < last; ++index) { auto& thread = waiting_threads[index]; - if (thread->GetStatus() != ThreadStatus::WaitCondVar) { - last++; - last = std::min(waiting_threads.size(), last); - continue; - } - - time_manager.CancelTimeEvent(thread.get()); - ASSERT(thread->GetCondVarWaitAddress() == condition_variable_addr); // liberate Cond Var Thread. current_process->RemoveConditionVariableThread(thread); - thread->SetCondVarWaitAddress(0); const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); @@ -1655,9 +1656,6 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ monitor.ClearExclusive(); if (mutex_val == 0) { // We were able to acquire the mutex, resume this thread. - ASSERT(thread->GetStatus() == ThreadStatus::WaitCondVar); - thread->ResumeFromWait(); - auto* const lock_owner = thread->GetLockOwner(); if (lock_owner != nullptr) { lock_owner->RemoveMutexWaiter(thread); @@ -1665,13 +1663,16 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ thread->SetLockOwner(nullptr); thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS); + thread->ResumeFromWait(); } else { // The mutex is already owned by some other thread, make this thread wait on it. const Handle owner_handle = static_cast(mutex_val & Mutex::MutexOwnerMask); const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); auto owner = handle_table.Get(owner_handle); ASSERT(owner); - thread->SetStatus(ThreadStatus::WaitMutex); + if (thread->GetStatus() == ThreadStatus::WaitCondVar) { + thread->SetStatus(ThreadStatus::WaitMutex); + } owner->AddMutexWaiter(thread); } diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 4323fc120..275bf11cc 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -23,9 +23,10 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const { if (obj.IsSignaled()) { for (auto thread : obj.GetWaitingThreads()) { if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); + ASSERT(thread->IsWaitingSync()); thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); thread->ResumeFromWait(); - time_manager.CancelTimeEvent(thread.get()); } } obj.ClearWaitingThreads(); @@ -91,10 +92,11 @@ std::pair Synchronization::WaitFor( ResultCode signaling_result = thread->GetSignalingResult(); SynchronizationObject* signaling_object = thread->GetSignalingObject(); thread->SetSynchronizationObjects(nullptr); + auto shared_thread = SharedFrom(thread); for (auto& obj : sync_objects) { - obj->RemoveWaitingThread(SharedFrom(thread)); + obj->RemoveWaitingThread(shared_thread); } - if (signaling_result == RESULT_SUCCESS) { + if (signaling_object != nullptr) { const auto itr = std::find_if( sync_objects.begin(), sync_objects.end(), [signaling_object](const std::shared_ptr& object) { @@ -103,7 +105,7 @@ std::pair Synchronization::WaitFor( ASSERT(itr != sync_objects.end()); signaling_object->Acquire(thread); const u32 index = static_cast(std::distance(sync_objects.begin(), itr)); - return {RESULT_SUCCESS, index}; + return {signaling_result, index}; } return {signaling_result, -1}; } diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index dab5fc4c6..cc228f5f7 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -22,7 +22,6 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { if (cancelled_events[proper_handle]) { return; } - event_fired[proper_handle] = true; std::shared_ptr thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); thread->OnWakeUp(); @@ -39,7 +38,6 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 event_handle = InvalidHandle; } cancelled_events[event_handle] = false; - event_fired[event_handle] = false; } void TimeManager::UnscheduleTimeEvent(Handle event_handle) { diff --git a/src/core/hle/kernel/time_manager.h b/src/core/hle/kernel/time_manager.h index 3080ac838..307a18765 100644 --- a/src/core/hle/kernel/time_manager.h +++ b/src/core/hle/kernel/time_manager.h @@ -42,7 +42,6 @@ private: Core::System& system; std::shared_ptr time_manager_event_type; std::unordered_map cancelled_events; - std::unordered_map event_fired; }; } // namespace Kernel -- cgit v1.2.3 From 9e9c287f8b24ce9a932490cc35b3d0b5f58bb7a3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 16:20:05 -0400 Subject: Kernel: Corrections to TimeManager, Scheduler and Mutex. --- src/core/hle/kernel/mutex.cpp | 3 +-- src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/time_manager.cpp | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 5a96d5e90..32dc1ffae 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -35,8 +35,6 @@ static std::pair, u32> GetHighestPriorityMutexWaitingThr if (thread->GetMutexWaitAddress() != mutex_addr) continue; - ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); - ++num_waiters; if (highest_priority_thread == nullptr || thread->GetPriority() < highest_priority_thread->GetPriority()) { @@ -50,6 +48,7 @@ static std::pair, u32> GetHighestPriorityMutexWaitingThr /// Update the mutex owner field of all threads waiting on the mutex to point to the new owner. static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr current_thread, std::shared_ptr new_owner) { + current_thread->RemoveMutexWaiter(new_owner); const auto threads = current_thread->GetMutexWaitingThreads(); for (const auto& thread : threads) { if (thread->GetMutexWaitAddress() != mutex_addr) diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 5322f0aae..98fbb8fe5 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -93,7 +93,7 @@ u32 GlobalScheduler::SelectThreads() { iter++; s32 suggested_core_id = suggested->GetProcessorID(); Thread* top_thread = - suggested_core_id > 0 ? top_threads[suggested_core_id] : nullptr; + suggested_core_id >= 0 ? top_threads[suggested_core_id] : nullptr; if (top_thread != suggested) { if (top_thread != nullptr && top_thread->GetPriority() < THREADPRIO_MAX_CORE_MIGRATION) { diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index cc228f5f7..941305e8e 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp @@ -32,8 +32,9 @@ void TimeManager::ScheduleTimeEvent(Handle& event_handle, Thread* timetask, s64 event_handle = timetask->GetGlobalHandle(); if (nanoseconds > 0) { ASSERT(timetask); - const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds}); - system.CoreTiming().ScheduleEvent(cycles, time_manager_event_type, event_handle); + ASSERT(timetask->GetStatus() != ThreadStatus::Ready); + ASSERT(timetask->GetStatus() != ThreadStatus::WaitMutex); + system.CoreTiming().ScheduleEvent(nanoseconds, time_manager_event_type, event_handle); } else { event_handle = InvalidHandle; } -- cgit v1.2.3 From 391f5f360d4144c21d65b998dd4e467b56533f78 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 21:13:18 -0400 Subject: Scheduler: Set last running time on thread. --- src/core/hle/kernel/scheduler.cpp | 2 ++ src/core/hle/kernel/thread.cpp | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 98fbb8fe5..d68d86cdf 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -616,6 +616,7 @@ void Scheduler::SwitchContextStep2() { // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); + new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process && thread_owner_process != nullptr) { @@ -654,6 +655,7 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { auto& cpu_core = system.ArmInterface(core_id); cpu_core.SaveContext(previous_thread->GetContext32()); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 51cc5dcca..fc6c0bc85 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -295,10 +295,6 @@ void Thread::SetStatus(ThreadStatus new_status) { break; } - if (status == ThreadStatus::Running) { - last_running_ticks = Core::System::GetInstance().CoreTiming().GetCPUTicks(); - } - status = new_status; } -- cgit v1.2.3 From ab9aae28bf5daa5fa7105bb4ef41b6d0b3c9cdc1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 22:39:41 -0400 Subject: General: Initial Setup for Single Core. --- src/core/hle/kernel/kernel.cpp | 19 +++++++++++++++++++ src/core/hle/kernel/kernel.h | 3 +++ 2 files changed, 22 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 721ab1e70..4a091ea38 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -113,6 +113,10 @@ struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} + void SetMulticore(bool is_multicore) { + this->is_multicore = is_multicore; + } + void Initialize(KernelCore& kernel) { Shutdown(); @@ -237,6 +241,9 @@ struct KernelCore::Impl { void RegisterCoreThread(std::size_t core_id) { std::unique_lock lock{register_thread_mutex}; + if (!is_multicore) { + single_core_thread_id = std::this_thread::get_id(); + } const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); @@ -258,6 +265,11 @@ struct KernelCore::Impl { u32 GetCurrentHostThreadID() const { const std::thread::id this_id = std::this_thread::get_id(); + if (!is_multicore) { + if (single_core_thread_id == this_id) { + return static_cast(system.GetCpuManager().CurrentCore()); + } + } const auto it = host_thread_ids.find(this_id); if (it == host_thread_ids.end()) { return Core::INVALID_HOST_THREAD_ID; @@ -378,6 +390,9 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + bool is_multicore{}; + std::thread::id single_core_thread_id{}; + // System context Core::System& system; }; @@ -387,6 +402,10 @@ KernelCore::~KernelCore() { Shutdown(); } +void KernelCore::SetMulticore(bool is_multicore) { + impl->SetMulticore(is_multicore); +} + void KernelCore::Initialize() { impl->Initialize(*this); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5d32a8329..162bbd2f8 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -65,6 +65,9 @@ public: KernelCore(KernelCore&&) = delete; KernelCore& operator=(KernelCore&&) = delete; + /// Sets if emulation is multicore or single core, must be set before Initialize + void SetMulticore(bool is_multicore); + /// Resets the kernel to a clean slate for use. void Initialize(); -- cgit v1.2.3 From 8a78fc25802b8f69d073b703728a3501c98bf5e8 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 9 Mar 2020 10:51:05 -0400 Subject: Synchronization: Correct wide Assertion. --- src/core/hle/kernel/synchronization.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp index 275bf11cc..851b702a5 100644 --- a/src/core/hle/kernel/synchronization.cpp +++ b/src/core/hle/kernel/synchronization.cpp @@ -23,8 +23,10 @@ void Synchronization::SignalObject(SynchronizationObject& obj) const { if (obj.IsSignaled()) { for (auto thread : obj.GetWaitingThreads()) { if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) { - ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); - ASSERT(thread->IsWaitingSync()); + if (thread->GetStatus() != ThreadStatus::WaitHLEEvent) { + ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch); + ASSERT(thread->IsWaitingSync()); + } thread->SetSynchronizationResults(&obj, RESULT_SUCCESS); thread->ResumeFromWait(); } -- cgit v1.2.3 From a439cdf22ea50f0e39cb51f6dff15fee3b495d16 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 11:50:33 -0400 Subject: CPU_Manager: Unload/Reload threads on preemption on SingleCore --- src/core/hle/kernel/scheduler.cpp | 42 +++++++++++++++++++++++++++++++++++++++ src/core/hle/kernel/scheduler.h | 10 ++++++++++ 2 files changed, 52 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d68d86cdf..00322d997 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -602,6 +602,48 @@ void Scheduler::OnThreadStart() { SwitchContextStep2(); } +void Scheduler::Unload() { + Thread* thread = current_thread.get(); + if (thread) { + thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + thread->SetIsRunning(false); + if (!thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.SaveContext(thread->GetContext32()); + cpu_core.SaveContext(thread->GetContext64()); + // Save the TPIDR_EL0 system register in case it was modified. + thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); + } + thread->context_guard.unlock(); + } +} + +void Scheduler::Reload() { + Thread* thread = current_thread.get(); + if (thread) { + ASSERT_MSG(thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable, + "Thread must be runnable."); + + // Cancel any outstanding wakeup events for this thread + thread->SetIsRunning(true); + thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + + auto* const thread_owner_process = thread->GetOwnerProcess(); + if (thread_owner_process != nullptr) { + system.Kernel().MakeCurrentProcess(thread_owner_process); + } + if (!thread->IsHLEThread()) { + auto& cpu_core = system.ArmInterface(core_id); + cpu_core.LoadContext(thread->GetContext32()); + cpu_core.LoadContext(thread->GetContext64()); + cpu_core.SetTlsAddress(thread->GetTLSAddress()); + cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); + cpu_core.ClearExclusiveState(); + } + } +} + void Scheduler::SwitchContextStep2() { Thread* previous_thread = current_thread_prev.get(); Thread* new_thread = selected_thread.get(); diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 5e062bf59..f63cc5085 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -210,6 +210,12 @@ public: /// Reschedules to the next available thread (call after current thread is suspended) void TryDoContextSwitch(); + /// The next two are for SingleCore Only. + /// Unload current thread before preempting core. + void Unload(); + /// Reload current thread after core preemption. + void Reload(); + /// Gets the current running thread Thread* GetCurrentThread() const; @@ -230,6 +236,10 @@ public: void OnThreadStart(); + std::shared_ptr ControlContext() { + return switch_fiber; + } + private: friend class GlobalScheduler; -- cgit v1.2.3 From d494b074e8afd3aff7b65afc7b977496be06ccc9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 13:13:39 -0400 Subject: Kernel: Preempt Single core on redudant yields. --- src/core/hle/kernel/kernel.cpp | 4 ++++ src/core/hle/kernel/kernel.h | 2 ++ src/core/hle/kernel/svc.cpp | 23 +++++++++++++++++------ src/core/hle/kernel/thread.cpp | 21 ++++++++++++--------- src/core/hle/kernel/thread.h | 9 +++++---- 5 files changed, 40 insertions(+), 19 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 4a091ea38..2a1b91752 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -642,6 +642,10 @@ void KernelCore::Suspend(bool in_suspention) { } } +bool KernelCore::IsMulticore() const { + return impl->is_multicore; +} + void KernelCore::ExceptionalExit() { exception_exited = true; Suspend(true); diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 162bbd2f8..50eeb50ec 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -212,6 +212,8 @@ public: /// Exceptional exit the OS. void ExceptionalExit(); + bool IsMulticore() const; + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index aad2ac549..eca92b356 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -19,6 +19,7 @@ #include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" +#include "core/cpu_manager.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" @@ -1509,21 +1510,31 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (nanoseconds <= 0) { switch (static_cast(nanoseconds)) { - case SleepType::YieldWithoutLoadBalancing: - current_thread->YieldSimple(); + case SleepType::YieldWithoutLoadBalancing: { + auto pair = current_thread->YieldSimple(); + is_redundant = pair.second; break; - case SleepType::YieldWithLoadBalancing: - current_thread->YieldAndBalanceLoad(); + } + case SleepType::YieldWithLoadBalancing: { + auto pair = current_thread->YieldAndBalanceLoad(); + is_redundant = pair.second; break; - case SleepType::YieldAndWaitForLoadBalancing: - current_thread->YieldAndWaitForLoadBalancing(); + } + case SleepType::YieldAndWaitForLoadBalancing: { + auto pair = current_thread->YieldAndWaitForLoadBalancing(); + is_redundant = pair.second; break; + } default: UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); } } else { current_thread->Sleep(nanoseconds); } + + if (is_redundant && !system.Kernel().IsMulticore()) { + system.GetCpuManager().PreemptSingleCore(); + } } /// Wait process wide key atomic diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fc6c0bc85..1c32552b1 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -435,28 +435,31 @@ ResultCode Thread::Sleep(s64 nanoseconds) { return RESULT_SUCCESS; } -ResultCode Thread::YieldSimple() { +std::pair Thread::YieldSimple() { + bool is_redundant = false; { SchedulerLock lock(kernel); - kernel.GlobalScheduler().YieldThread(this); + is_redundant = kernel.GlobalScheduler().YieldThread(this); } - return RESULT_SUCCESS; + return {RESULT_SUCCESS, is_redundant}; } -ResultCode Thread::YieldAndBalanceLoad() { +std::pair Thread::YieldAndBalanceLoad() { + bool is_redundant = false; { SchedulerLock lock(kernel); - kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); + is_redundant = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this); } - return RESULT_SUCCESS; + return {RESULT_SUCCESS, is_redundant}; } -ResultCode Thread::YieldAndWaitForLoadBalancing() { +std::pair Thread::YieldAndWaitForLoadBalancing() { + bool is_redundant = false; { SchedulerLock lock(kernel); - kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); + is_redundant = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this); } - return RESULT_SUCCESS; + return {RESULT_SUCCESS, is_redundant}; } void Thread::AddSchedulingFlag(ThreadSchedFlags flag) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 953b023b5..9a29875ac 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -6,6 +6,7 @@ #include #include +#include #include #include "common/common_types.h" @@ -503,13 +504,13 @@ public: ResultCode Sleep(s64 nanoseconds); /// Yields this thread without rebalancing loads. - ResultCode YieldSimple(); + std::pair YieldSimple(); /// Yields this thread and does a load rebalancing. - ResultCode YieldAndBalanceLoad(); + std::pair YieldAndBalanceLoad(); /// Yields this thread and if the core is left idle, loads are rebalanced - ResultCode YieldAndWaitForLoadBalancing(); + std::pair YieldAndWaitForLoadBalancing(); void IncrementYieldCount() { yield_count++; @@ -587,7 +588,7 @@ private: ThreadContext32 context_32{}; ThreadContext64 context_64{}; Common::SpinLock context_guard{}; - std::shared_ptr host_context{}; + std::shared_ptr host_context{}; u64 thread_id = 0; -- cgit v1.2.3 From f370de84b16f9d668b7d5dcc0fd851264e2e6144 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 18:41:11 -0400 Subject: Kernel: Rewind on SVC change. --- src/core/hle/kernel/scheduler.cpp | 2 ++ src/core/hle/kernel/svc.cpp | 9 ++++----- src/core/hle/kernel/thread.h | 10 ++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 00322d997..25fc8a3e8 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -605,6 +605,7 @@ void Scheduler::OnThreadStart() { void Scheduler::Unload() { Thread* thread = current_thread.get(); if (thread) { + thread->SetContinuousOnSVC(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); thread->SetIsRunning(false); if (!thread->IsHLEThread()) { @@ -697,6 +698,7 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { auto& cpu_core = system.ArmInterface(core_id); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index eca92b356..d3d4e7bf9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2459,7 +2459,8 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void Call(Core::System& system, u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); - auto& physical_core = system.CurrentPhysicalCore(); + auto* thread = system.CurrentScheduler().GetCurrentThread(); + thread->SetContinuousOnSVC(true); const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); @@ -2472,10 +2473,8 @@ void Call(Core::System& system, u32 immediate) { } else { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } - auto& physical_core_2 = system.CurrentPhysicalCore(); - if (physical_core.CoreIndex() != physical_core_2.CoreIndex()) { - LOG_CRITICAL(Kernel_SVC, "Rewinding"); - auto* thread = physical_core_2.Scheduler().GetCurrentThread(); + + if (!thread->IsContinuousOnSVC()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 9a29875ac..168828ab0 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -573,6 +573,14 @@ public: return pausing_state != 0; } + bool IsContinuousOnSVC() const { + return is_continuous_on_svc; + } + + void SetContinuousOnSVC(bool is_continuous) { + is_continuous_on_svc = is_continuous; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -672,6 +680,8 @@ private: bool is_waiting_on_sync = false; bool is_sync_cancelled = false; + bool is_continuous_on_svc = false; + bool will_be_terminated = false; std::string name; -- cgit v1.2.3 From e6f8bde74b9476dced103c6c54ab81616d34b97e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 11 Mar 2020 20:44:53 -0400 Subject: General: Fix Stop function --- src/core/hle/kernel/kernel.cpp | 15 +++++++++++++++ src/core/hle/kernel/thread.cpp | 8 +++++--- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 2a1b91752..24da4367e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -119,6 +119,7 @@ struct KernelCore::Impl { void Initialize(KernelCore& kernel) { Shutdown(); + RegisterHostThread(); InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); @@ -135,6 +136,19 @@ struct KernelCore::Impl { next_user_process_id = Process::ProcessIDMin; next_thread_id = 1; + for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + if (suspend_threads[i]) { + suspend_threads[i].reset(); + } + } + + for (std::size_t i = 0; i < cores.size(); i++) { + cores[i].Shutdown(); + } + cores.clear(); + + registered_core_threads.reset(); + process_list.clear(); current_process = nullptr; @@ -154,6 +168,7 @@ struct KernelCore::Impl { cores.clear(); exclusive_monitor.reset(); + host_thread_ids.clear(); } void InitializePhysicalCores() { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1c32552b1..6f8e7a070 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -56,10 +56,12 @@ void Thread::Stop() { Signal(); kernel.GlobalHandleTable().Close(global_handle); - owner_process->UnregisterThread(this); + if (owner_process) { + owner_process->UnregisterThread(this); - // Mark the TLS slot in the thread's page as free. - owner_process->FreeTLSRegion(tls_address); + // Mark the TLS slot in the thread's page as free. + owner_process->FreeTLSRegion(tls_address); + } } global_handle = 0; } -- cgit v1.2.3 From 7020d498c5aef7c1180bfc57031cdd7fbfecdf0f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 12 Mar 2020 16:48:43 -0400 Subject: General: Fix microprofile on dynarmic/svc, fix wait tree showing which threads were running. --- src/core/hle/kernel/kernel.cpp | 15 +++++++++++++++ src/core/hle/kernel/kernel.h | 4 ++++ src/core/hle/kernel/scheduler.cpp | 7 +++++++ src/core/hle/kernel/svc.cpp | 10 +++++++--- src/core/hle/kernel/thread.h | 18 ++++++++++++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 24da4367e..d2f5f9bf2 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -13,6 +13,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/microprofile.h" #include "common/thread.h" #include "core/arm/arm_interface.h" #include "core/arm/exclusive_monitor.h" @@ -41,6 +42,8 @@ #include "core/hle/result.h" #include "core/memory.h" +MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); + namespace Kernel { /** @@ -408,6 +411,8 @@ struct KernelCore::Impl { bool is_multicore{}; std::thread::id single_core_thread_id{}; + std::array svc_ticks{}; + // System context Core::System& system; }; @@ -666,4 +671,14 @@ void KernelCore::ExceptionalExit() { Suspend(true); } +void KernelCore::EnterSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); +} + +void KernelCore::ExitSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 50eeb50ec..1eb6ede73 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -214,6 +214,10 @@ public: bool IsMulticore() const; + void EnterSVCProfile(); + + void ExitSVCProfile(); + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 25fc8a3e8..2ad380b17 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -354,7 +354,9 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, } if (must_context_switch) { auto& core_scheduler = kernel.CurrentScheduler(); + kernel.ExitSVCProfile(); core_scheduler.TryDoContextSwitch(); + kernel.EnterSVCProfile(); } } @@ -628,6 +630,7 @@ void Scheduler::Reload() { // Cancel any outstanding wakeup events for this thread thread->SetIsRunning(true); + thread->SetWasRunning(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); auto* const thread_owner_process = thread->GetOwnerProcess(); @@ -660,6 +663,7 @@ void Scheduler::SwitchContextStep2() { // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process && thread_owner_process != nullptr) { @@ -698,6 +702,9 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + if (new_thread != nullptr && new_thread->IsSuspendThread()) { + previous_thread->SetWasRunning(true); + } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d3d4e7bf9..9b9f9402e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2454,10 +2454,10 @@ static const FunctionDef* GetSVCInfo64(u32 func_num) { return &SVC_Table_64[func_num]; } -MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); - void Call(Core::System& system, u32 immediate) { - MICROPROFILE_SCOPE(Kernel_SVC); + system.ExitDynarmicProfile(); + auto& kernel = system.Kernel(); + kernel.EnterSVCProfile(); auto* thread = system.CurrentScheduler().GetCurrentThread(); thread->SetContinuousOnSVC(true); @@ -2474,10 +2474,14 @@ void Call(Core::System& system, u32 immediate) { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } + kernel.ExitSVCProfile(); + if (!thread->IsContinuousOnSVC()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } + + system.EnterDynarmicProfile(); } } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 168828ab0..f42d7bd13 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -350,6 +350,22 @@ public: return (type & THREADTYPE_HLE) != 0; } + bool IsSuspendThread() const { + return (type & THREADTYPE_SUSPEND) != 0; + } + + bool IsIdleThread() const { + return (type & THREADTYPE_IDLE) != 0; + } + + bool WasRunning() const { + return was_running; + } + + void SetWasRunning(bool value) { + was_running = value; + } + std::shared_ptr GetHostContext() const; ThreadStatus GetStatus() const { @@ -684,6 +700,8 @@ private: bool will_be_terminated = false; + bool was_running = false; + std::string name; }; -- cgit v1.2.3 From db68fba4a634ab6127ed485f55c41b5e1a05bc10 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 12 Mar 2020 19:53:54 -0400 Subject: Scheduler: Correct yielding interaction with SetThreadActivity. --- src/core/hle/kernel/scheduler.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 2ad380b17..8d56b49ce 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -144,6 +144,11 @@ u32 GlobalScheduler::SelectThreads() { bool GlobalScheduler::YieldThread(Thread* yielding_thread) { ASSERT(is_locked); // Note: caller should use critical section, etc. + if (!yielding_thread->IsRunnable()) { + // Normally this case shouldn't happen except for SetThreadActivity. + is_reselection_pending.store(true, std::memory_order_release); + return false; + } const u32 core_id = static_cast(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); @@ -161,6 +166,11 @@ bool GlobalScheduler::YieldThreadAndBalanceLoad(Thread* yielding_thread) { ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. + if (!yielding_thread->IsRunnable()) { + // Normally this case shouldn't happen except for SetThreadActivity. + is_reselection_pending.store(true, std::memory_order_release); + return false; + } const u32 core_id = static_cast(yielding_thread->GetProcessorID()); const u32 priority = yielding_thread->GetPriority(); @@ -212,6 +222,11 @@ bool GlobalScheduler::YieldThreadAndWaitForLoadBalancing(Thread* yielding_thread ASSERT(is_locked); // Note: caller should check if !thread.IsSchedulerOperationRedundant and use critical section, // etc. + if (!yielding_thread->IsRunnable()) { + // Normally this case shouldn't happen except for SetThreadActivity. + is_reselection_pending.store(true, std::memory_order_release); + return false; + } Thread* winner = nullptr; const u32 core_id = static_cast(yielding_thread->GetProcessorID()); -- cgit v1.2.3 From 25565dffd588006aace7530486e71ff318dc5550 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 15 Mar 2020 15:54:40 -0400 Subject: ARM: Addapt to new Exclusive Monitor Interface. --- src/core/hle/kernel/address_arbiter.cpp | 9 +++------ src/core/hle/kernel/svc.cpp | 4 +--- 2 files changed, 4 insertions(+), 9 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index e8f22b598..4d2a9b35d 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -80,8 +80,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32 auto& monitor = system.Monitor(); u32 current_value; do { - monitor.SetExclusive32(current_core, address); - current_value = memory.Read32(address); + current_value = monitor.ExclusiveRead32(current_core, address); if (current_value != value) { return ERR_INVALID_STATE; @@ -110,8 +109,7 @@ ResultCode AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(VAddr a auto& monitor = system.Monitor(); s32 updated_value; do { - monitor.SetExclusive32(current_core, address); - updated_value = memory.Read32(address); + updated_value = monitor.ExclusiveRead32(current_core, address); if (updated_value != value) { return ERR_INVALID_STATE; @@ -186,8 +184,7 @@ ResultCode AddressArbiter::WaitForAddressIfLessThan(VAddr address, s32 value, s6 const std::size_t current_core = system.CurrentCoreIndex(); auto& monitor = system.Monitor(); do { - monitor.SetExclusive32(current_core, address); - current_value = static_cast(memory.Read32(address)); + current_value = static_cast(monitor.ExclusiveRead32(current_core, address)); if (should_decrement) { decrement_value = current_value - 1; } else { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9b9f9402e..36e9c48f9 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1653,10 +1653,8 @@ static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_ u32 update_val = 0; const VAddr mutex_address = thread->GetMutexWaitAddress(); do { - monitor.SetExclusive32(current_core, mutex_address); - // If the mutex is not yet acquired, acquire it. - mutex_val = memory.Read32(mutex_address); + mutex_val = monitor.ExclusiveRead32(current_core, mutex_address); if (mutex_val != 0) { update_val = mutex_val | Mutex::MutexHasWaitersFlag; -- cgit v1.2.3 From f2ade343e2492c213ac93680a55e9bed712dac9a Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 19 Mar 2020 13:09:32 -0400 Subject: SingleCore: Move Host Timing from a sepparate thread to main cpu thread. --- src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/thread.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d2f5f9bf2..a19cd7a1f 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -303,7 +303,7 @@ struct KernelCore::Impl { } const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); const Kernel::Thread* current = sched.GetCurrentThread(); - if (current != nullptr) { + if (current != nullptr && !current->IsPhantomMode()) { result.guest_handle = current->GetGlobalHandle(); } else { result.guest_handle = InvalidHandle; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f42d7bd13..f998890c4 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -597,6 +597,14 @@ public: is_continuous_on_svc = is_continuous; } + bool IsPhantomMode() const { + return is_phantom_mode; + } + + void SetPhantomMode(bool phantom) { + is_phantom_mode = phantom; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -699,6 +707,7 @@ private: bool is_continuous_on_svc = false; bool will_be_terminated = false; + bool is_phantom_mode = false; bool was_running = false; -- cgit v1.2.3 From 87c49aa7be4b7277f8ae929058633827d339a052 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 20 Mar 2020 12:36:01 -0400 Subject: SVC/ARM: Correct svcSendSyncRequest and cache ticks on arm interface. --- src/core/hle/kernel/svc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 36e9c48f9..f08745226 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -342,7 +342,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { thread->InvokeHLECallback(SharedFrom(thread)); } - return RESULT_SUCCESS; + return thread->GetSignalingResult(); } static ResultCode SendSyncRequest32(Core::System& system, Handle handle) { -- cgit v1.2.3 From 1b82ccec2220a69711ba75cf51ee98cbcfe6a510 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 29 Feb 2020 13:58:50 -0400 Subject: Core: Refactor ARM Interface. --- src/core/hle/kernel/kernel.cpp | 28 +++++++++++++++++++++++++++- src/core/hle/kernel/physical_core.cpp | 25 ++++++++----------------- src/core/hle/kernel/physical_core.h | 14 ++++++++------ 3 files changed, 43 insertions(+), 24 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index a19cd7a1f..e33ef5323 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include #include @@ -16,7 +17,9 @@ #include "common/microprofile.h" #include "common/thread.h" #include "core/arm/arm_interface.h" +#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -42,6 +45,11 @@ #include "core/hle/result.h" #include "core/memory.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif + MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { @@ -178,7 +186,20 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { - cores.emplace_back(system, i, *exclusive_monitor); +#ifdef ARCHITECTURE_x86_64 + arm_interfaces_32[i] = + std::make_unique(system, interrupts, *exclusive_monitor, i); + arm_interfaces_64[i] = + std::make_unique(system, interrupts, *exclusive_monitor, i); +#else + arm_interfaces_32[i] = std::make_shared( + system, interrupts, ARM_Unicorn::Arch::AArch32, i); + arm_interfaces_64[i] = std::make_shared( + system, interrupts, ARM_Unicorn::Arch::AArch64, i); + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif + cores.emplace_back(system, i, *exclusive_monitor, interrupts[i], *arm_interfaces_32[i], + *arm_interfaces_64[i]); } } @@ -407,6 +428,11 @@ struct KernelCore::Impl { std::shared_ptr time_shared_mem; std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + std::array interrupts{}; + std::array, Core::Hardware::NUM_CPU_CORES> + arm_interfaces_32{}; + std::array, Core::Hardware::NUM_CPU_CORES> + arm_interfaces_64{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index ff14fcb42..9146b331d 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -21,21 +21,12 @@ namespace Kernel { PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, - Core::ExclusiveMonitor& exclusive_monitor) - : interrupt_handler{}, core_index{id} { -#ifdef ARCHITECTURE_x86_64 - arm_interface_32 = std::make_unique(system, interrupt_handler, - exclusive_monitor, core_index); - arm_interface_64 = std::make_unique(system, interrupt_handler, - exclusive_monitor, core_index); -#else - using Core::ARM_Unicorn; - arm_interface_32 = - std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch32); - arm_interface_64 = - std::make_unique(system, interrupt_handler, ARM_Unicorn::Arch::AArch64); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif + Core::ExclusiveMonitor& exclusive_monitor, + Core::CPUInterruptHandler& interrupt_handler, + Core::ARM_Interface& arm_interface32, + Core::ARM_Interface& arm_interface64) + : interrupt_handler{interrupt_handler}, core_index{id}, arm_interface_32{arm_interface32}, + arm_interface_64{arm_interface64} { scheduler = std::make_unique(system, core_index); guard = std::make_unique(); @@ -69,9 +60,9 @@ void PhysicalCore::Shutdown() { void PhysicalCore::SetIs64Bit(bool is_64_bit) { if (is_64_bit) { - arm_interface = arm_interface_64.get(); + arm_interface = &arm_interface_64; } else { - arm_interface = arm_interface_32.get(); + arm_interface = &arm_interface_32; } } diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index cd2e42fc3..2673d90f2 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { - class SpinLock; +class SpinLock; } namespace Kernel { @@ -27,7 +27,9 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor); + PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor, + Core::CPUInterruptHandler& interrupt_handler, Core::ARM_Interface& arm_interface32, + Core::ARM_Interface& arm_interface64); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; @@ -92,13 +94,13 @@ public: void SetIs64Bit(bool is_64_bit); private: - Core::CPUInterruptHandler interrupt_handler; + Core::CPUInterruptHandler& interrupt_handler; std::size_t core_index; - std::unique_ptr arm_interface_32; - std::unique_ptr arm_interface_64; + Core::ARM_Interface& arm_interface_32; + Core::ARM_Interface& arm_interface_64; std::unique_ptr scheduler; Core::ARM_Interface* arm_interface{}; - std::unique_ptr guard; + std::unique_ptr guard; }; } // namespace Kernel -- cgit v1.2.3 From 1567824d2da8e9b49b433f3d1d753d8ad84e65f9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 1 Mar 2020 12:14:17 -0400 Subject: General: Move ARM_Interface into Threads. --- src/core/hle/kernel/kernel.cpp | 59 +++++++++++++---------------------- src/core/hle/kernel/kernel.h | 8 ++++- src/core/hle/kernel/physical_core.cpp | 37 +++------------------- src/core/hle/kernel/physical_core.h | 37 +++++----------------- src/core/hle/kernel/scheduler.cpp | 12 +++---- src/core/hle/kernel/svc.cpp | 11 ++----- src/core/hle/kernel/thread.cpp | 35 +++++++++++++++++++++ src/core/hle/kernel/thread.h | 8 ++++- 8 files changed, 88 insertions(+), 119 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e33ef5323..3feddd9ad 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -19,7 +19,6 @@ #include "core/arm/arm_interface.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" -#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -45,11 +44,6 @@ #include "core/hle/result.h" #include "core/memory.h" -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#endif - MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { @@ -186,20 +180,8 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { -#ifdef ARCHITECTURE_x86_64 - arm_interfaces_32[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); - arm_interfaces_64[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); -#else - arm_interfaces_32[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch32, i); - arm_interfaces_64[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch64, i); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif - cores.emplace_back(system, i, *exclusive_monitor, interrupts[i], *arm_interfaces_32[i], - *arm_interfaces_64[i]); + schedulers[i] = std::make_unique(system, i); + cores.emplace_back(system, i, *schedulers[i], interrupts[i]); } } @@ -268,10 +250,6 @@ struct KernelCore::Impl { return; } - for (auto& core : cores) { - core.SetIs64Bit(process->Is64BitProcess()); - } - u32 core_id = GetCurrentHostThreadID(); if (core_id < Core::Hardware::NUM_CPU_CORES) { system.Memory().SetCurrentPageTable(*process, core_id); @@ -429,10 +407,7 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_32{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_64{}; + std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; @@ -497,11 +472,11 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { } Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { @@ -525,11 +500,23 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { } Kernel::Scheduler& KernelCore::CurrentScheduler() { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; } const Kernel::Scheduler& KernelCore::CurrentScheduler() const { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; +} + +std::array& KernelCore::Interrupts() { + return impl->interrupts; +} + +const std::array& KernelCore::Interrupts() const { + return impl->interrupts; } Kernel::Synchronization& KernelCore::Synchronization() { @@ -557,15 +544,11 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) { - PhysicalCore(i).ArmInterface().ClearInstructionCache(); - } + //TODO: Reimplement, this } void KernelCore::PrepareReschedule(std::size_t id) { - if (id < impl->global_scheduler.CpuCoresCount()) { - impl->cores[id].Stop(); - } + // TODO: Reimplement, this } void KernelCore::AddNamedPort(std::string name, std::shared_ptr port) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1eb6ede73..846056b85 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,15 +4,17 @@ #pragma once +#include #include #include #include #include +#include "core/hardware_properties.h" #include "core/hle/kernel/memory/memory_types.h" #include "core/hle/kernel/object.h" namespace Core { -struct EmuThreadHandle; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -144,6 +146,10 @@ public: const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + std::array& Interrupts(); + + const std::array& Interrupts() const; + void InvalidateAllInstructionCaches(); /// Adds a port to the named port table diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 9146b331d..c82c60a16 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -20,50 +20,21 @@ namespace Kernel { -PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, - Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, - Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64) - : interrupt_handler{interrupt_handler}, core_index{id}, arm_interface_32{arm_interface32}, - arm_interface_64{arm_interface64} { +PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler) + : interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { - scheduler = std::make_unique(system, core_index); guard = std::make_unique(); } PhysicalCore::~PhysicalCore() = default; -void PhysicalCore::Run() { - arm_interface->Run(); -} - -void PhysicalCore::ClearExclusive() { - arm_interface->ClearExclusiveState(); -} - -void PhysicalCore::Step() { - arm_interface->Step(); -} - void PhysicalCore::Idle() { interrupt_handler.AwaitInterrupt(); } -void PhysicalCore::Stop() { - arm_interface->PrepareReschedule(); -} - void PhysicalCore::Shutdown() { - scheduler->Shutdown(); -} - -void PhysicalCore::SetIs64Bit(bool is_64_bit) { - if (is_64_bit) { - arm_interface = &arm_interface_64; - } else { - arm_interface = &arm_interface_32; - } + scheduler.Shutdown(); } void PhysicalCore::Interrupt() { diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 2673d90f2..751b994a7 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { -class SpinLock; + class SpinLock; } namespace Kernel { @@ -27,9 +27,9 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64); + PhysicalCore(Core::System& system, std::size_t id, + Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; @@ -38,17 +38,7 @@ public: PhysicalCore(PhysicalCore&&) = default; PhysicalCore& operator=(PhysicalCore&&) = default; - /// Execute current jit state - void Run(); - /// Clear Exclusive state. - void ClearExclusive(); - /// Set this core in IdleState. void Idle(); - /// Execute a single instruction in current jit. - void Step(); - /// Stop JIT execution/exit - void Stop(); - /// Interrupt this physical core. void Interrupt(); @@ -63,14 +53,6 @@ public: // Shutdown this physical core. void Shutdown(); - Core::ARM_Interface& ArmInterface() { - return *arm_interface; - } - - const Core::ARM_Interface& ArmInterface() const { - return *arm_interface; - } - bool IsMainCore() const { return core_index == 0; } @@ -84,22 +66,17 @@ public: } Kernel::Scheduler& Scheduler() { - return *scheduler; + return scheduler; } const Kernel::Scheduler& Scheduler() const { - return *scheduler; + return scheduler; } - void SetIs64Bit(bool is_64_bit); - private: Core::CPUInterruptHandler& interrupt_handler; std::size_t core_index; - Core::ARM_Interface& arm_interface_32; - Core::ARM_Interface& arm_interface_64; - std::unique_ptr scheduler; - Core::ARM_Interface* arm_interface{}; + Kernel::Scheduler& scheduler; std::unique_ptr guard; }; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 8d56b49ce..a5083ae7c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -681,15 +681,16 @@ void Scheduler::SwitchContextStep2() { new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); - if (previous_process != thread_owner_process && thread_owner_process != nullptr) { + if (thread_owner_process != nullptr) { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = new_thread->ArmInterface(); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + cpu_core.ChangeProcessorId(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -722,18 +723,15 @@ void Scheduler::SwitchContext() { } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + previous_thread->SetIsRunning(false); if (!previous_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = previous_thread->ArmInterface(); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } - if (previous_thread->GetStatus() == ThreadStatus::Running) { - previous_thread->SetStatus(ThreadStatus::Ready); - } - previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f08745226..599972211 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1533,7 +1533,9 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } if (is_redundant && !system.Kernel().IsMulticore()) { + system.Kernel().ExitSVCProfile(); system.GetCpuManager().PreemptSingleCore(); + system.Kernel().EnterSVCProfile(); } } @@ -2457,9 +2459,6 @@ void Call(Core::System& system, u32 immediate) { auto& kernel = system.Kernel(); kernel.EnterSVCProfile(); - auto* thread = system.CurrentScheduler().GetCurrentThread(); - thread->SetContinuousOnSVC(true); - const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { @@ -2473,12 +2472,6 @@ void Call(Core::System& system, u32 immediate) { } kernel.ExitSVCProfile(); - - if (!thread->IsContinuousOnSVC()) { - auto* host_context = thread->GetHostContext().get(); - host_context->Rewind(); - } - system.EnterDynarmicProfile(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6f8e7a070..58b06aa9e 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,6 +13,13 @@ #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif +#include "core/arm/cpu_interrupt_handler.h" +#include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -232,7 +239,27 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy } // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context + thread->arm_interface.reset(); if ((type_flags & THREADTYPE_HLE) == 0) { +#ifdef ARCHITECTURE_x86_64 + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } else { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } + +#else + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); + } else { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); + } + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif ResetThreadContext32(thread->context_32, static_cast(stack_top), static_cast(entry_point), static_cast(arg)); ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); @@ -276,6 +303,14 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + command_header_offset; } +Core::ARM_Interface& Thread::ArmInterface() { + return *arm_interface; +} + +const Core::ARM_Interface& Thread::ArmInterface() const { + return *arm_interface; +} + void Thread::SetStatus(ThreadStatus new_status) { if (new_status == status) { return; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f998890c4..c08fc3a89 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -21,6 +21,7 @@ class Fiber; } namespace Core { +class ARM_Interface; class System; } // namespace Core @@ -271,6 +272,10 @@ public: void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); + Core::ARM_Interface& ArmInterface(); + + const Core::ARM_Interface& ArmInterface() const; + SynchronizationObject* GetSignalingObject() const { return signaling_object; } @@ -617,9 +622,10 @@ private: void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); + Common::SpinLock context_guard{}; ThreadContext32 context_32{}; ThreadContext64 context_64{}; - Common::SpinLock context_guard{}; + std::unique_ptr arm_interface{}; std::shared_ptr host_context{}; u64 thread_id = 0; -- cgit v1.2.3 From 5974e3ea33e12e7abd813704e5b895003ba83555 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 7 Mar 2020 14:16:25 -0400 Subject: Thread: Release the ARM Interface on exitting. --- src/core/hle/kernel/scheduler.cpp | 2 +- src/core/hle/kernel/thread.cpp | 2 ++ src/core/hle/kernel/thread.h | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index a5083ae7c..ce7e1986d 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -724,7 +724,7 @@ void Scheduler::SwitchContext() { previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); previous_thread->SetIsRunning(false); - if (!previous_thread->IsHLEThread()) { + if (!previous_thread->IsHLEThread() && !previous_thread->HasExited()) { Core::ARM_Interface& cpu_core = previous_thread->ArmInterface(); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 58b06aa9e..65fedfc9b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -69,6 +69,8 @@ void Thread::Stop() { // Mark the TLS slot in the thread's page as free. owner_process->FreeTLSRegion(tls_address); } + arm_interface.reset(); + has_exited = true; } global_handle = 0; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index c08fc3a89..f651d7822 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -610,6 +610,10 @@ public: is_phantom_mode = phantom; } + bool HasExited() const { + return has_exited; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -714,6 +718,7 @@ private: bool will_be_terminated = false; bool is_phantom_mode = false; + bool has_exited = false; bool was_running = false; -- cgit v1.2.3 From 9bde28d7b100fdcd1cc50c8f2a4b8c74704f5e34 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 10 Mar 2020 13:24:52 -0400 Subject: Scheduler: Correct Reload/Unload --- src/core/hle/kernel/kernel.cpp | 1 + src/core/hle/kernel/scheduler.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 3feddd9ad..739205eca 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -149,6 +149,7 @@ struct KernelCore::Impl { for (std::size_t i = 0; i < cores.size(); i++) { cores[i].Shutdown(); + schedulers[i].reset(); } cores.clear(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index ce7e1986d..43c924fa0 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -625,8 +625,8 @@ void Scheduler::Unload() { thread->SetContinuousOnSVC(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); thread->SetIsRunning(false); - if (!thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + if (!thread->IsHLEThread() && !thread->HasExited()) { + Core::ARM_Interface& cpu_core = thread->ArmInterface(); cpu_core.SaveContext(thread->GetContext32()); cpu_core.SaveContext(thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. @@ -653,11 +653,12 @@ void Scheduler::Reload() { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = thread->ArmInterface(); cpu_core.LoadContext(thread->GetContext32()); cpu_core.LoadContext(thread->GetContext64()); cpu_core.SetTlsAddress(thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); + cpu_core.ChangeProcessorId(this->core_id); cpu_core.ClearExclusiveState(); } } -- cgit v1.2.3 From f5e32935ca9d1727624c86ca78aff91027caf819 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 28 Mar 2020 15:23:28 -0400 Subject: SingleCore: Use Cycle Timing instead of Host Timing. --- src/core/hle/kernel/svc.cpp | 5 +++++ src/core/hle/kernel/thread.cpp | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 599972211..c47fa9167 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1534,6 +1534,7 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { if (is_redundant && !system.Kernel().IsMulticore()) { system.Kernel().ExitSVCProfile(); + system.CoreTiming().AddTicks(1000U); system.GetCpuManager().PreemptSingleCore(); system.Kernel().EnterSVCProfile(); } @@ -1762,6 +1763,10 @@ static u64 GetSystemTick(Core::System& system) { // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) const u64 result{system.CoreTiming().GetClockTicks()}; + if (!system.Kernel().IsMulticore()) { + core_timing.AddTicks(400U); + } + return result; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 65fedfc9b..d88039a16 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -246,19 +246,23 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy #ifdef ARCHITECTURE_x86_64 if (owner_process && !owner_process->Is64BitProcess()) { thread->arm_interface = std::make_unique( - system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), + processor_id); } else { thread->arm_interface = std::make_unique( - system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), + processor_id); } #else if (owner_process && !owner_process->Is64BitProcess()) { thread->arm_interface = std::make_shared( - system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32, + processor_id); } else { thread->arm_interface = std::make_shared( - system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); + system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64, + processor_id); } LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); #endif -- cgit v1.2.3 From a7ecd9e19cd2d46768c7c55e1aa7f5e4870d7c9e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 28 Mar 2020 15:40:57 -0400 Subject: FrameLimiting: Enable frame limiting for single core. --- src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/hle') diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index 19df0dca7..3f7b8e670 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -41,6 +41,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 system.GetPerfStats().EndGameFrame(); system.GetPerfStats().EndSystemFrame(); system.GPU().SwapBuffers(&framebuffer); + system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs()); system.GetPerfStats().BeginSystemFrame(); } -- cgit v1.2.3 From 7e2ce2f7f47e77b46d66dcefbd0c391e58421103 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 29 Mar 2020 17:06:46 -0400 Subject: SingleCore: Improve Cycle timing Behavior and replace mutex in global scheduler for spinlock. --- src/core/hle/kernel/scheduler.h | 2 +- src/core/hle/kernel/server_session.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index f63cc5085..10dc4b832 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -188,7 +188,7 @@ private: /// Scheduler lock mechanisms. bool is_locked{}; - std::mutex inner_lock{}; // TODO(Blinkhawk): Replace for a SpinLock + Common::SpinLock inner_lock{}; std::atomic scope_lock{}; Core::EmuThreadHandle current_owner{Core::EmuThreadHandle::InvalidHandle()}; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index 05516a453..e988a3f22 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -185,7 +185,8 @@ ResultCode ServerSession::CompleteSyncRequest() { ResultCode ServerSession::HandleSyncRequest(std::shared_ptr thread, Core::Memory::Memory& memory) { ResultCode result = QueueSyncRequest(std::move(thread), memory); - Core::System::GetInstance().CoreTiming().ScheduleEvent(0, request_event, {}); + const u64 delay = kernel.IsMulticore() ? 0U : 20000U; + Core::System::GetInstance().CoreTiming().ScheduleEvent(delay, request_event, {}); return result; } -- cgit v1.2.3 From 19165cd859dcbb1f7d5e2c74c831e5196c2d1c41 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 30 Mar 2020 21:50:05 -0400 Subject: HLE_IPC: Correct HLE Event behavior on timeout. --- src/core/hle/kernel/hle_ipc.cpp | 1 + src/core/hle/kernel/svc.cpp | 10 +++++++++- src/core/hle/kernel/thread.h | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index e74d91670..9277b5d08 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -70,6 +70,7 @@ std::shared_ptr HLERequestContext::SleepClientThread( }); const auto readable_event{writable_event->GetReadableEvent()}; writable_event->Clear(); + thread->SetHLESyncObject(readable_event.get()); thread->SetStatus(ThreadStatus::WaitHLEEvent); thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT); readable_event->AddWaitingThread(thread); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c47fa9167..37e893c84 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -333,13 +333,21 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { thread->SetStatus(ThreadStatus::WaitIPC); session->SendSyncRequest(SharedFrom(thread), system.Memory()); } + if (thread->HasHLECallback()) { Handle event_handle = thread->GetHLETimeEvent(); if (event_handle != InvalidHandle) { auto& time_manager = system.Kernel().TimeManager(); time_manager.UnscheduleTimeEvent(event_handle); } - thread->InvokeHLECallback(SharedFrom(thread)); + + { + SchedulerLock lock(system.Kernel()); + auto* sync_object = thread->GetHLESyncObject(); + sync_object->RemoveWaitingThread(SharedFrom(thread)); + + thread->InvokeHLECallback(SharedFrom(thread)); + } } return thread->GetSignalingResult(); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f651d7822..61963148d 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -489,10 +489,18 @@ public: hle_time_event = time_event; } + void SetHLESyncObject(SynchronizationObject* object) { + hle_object = object; + } + Handle GetHLETimeEvent() const { return hle_time_event; } + SynchronizationObject* GetHLESyncObject() const { + return hle_object; + } + void InvalidateWakeupCallback() { SetWakeupCallback(nullptr); } @@ -698,6 +706,7 @@ private: /// Callback for HLE Events HLECallback hle_callback; Handle hle_time_event; + SynchronizationObject* hle_object; Scheduler* scheduler = nullptr; -- cgit v1.2.3 From c8bf47dcfbd43f3e7835d2e45b4704e056d8e9ee Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 31 Mar 2020 15:12:41 -0400 Subject: Kernel/svcBreak: Implement CacheInvalidation for Singlecore and correct svcBreak. --- src/core/hle/kernel/kernel.cpp | 12 +++++++++++- src/core/hle/kernel/svc.cpp | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 739205eca..1f230fc4a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -545,7 +545,17 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - //TODO: Reimplement, this + if (!IsMulticore()) { + auto& threads = GlobalScheduler().GetThreadList(); + for (auto& thread : threads) { + if (!thread->IsHLEThread()) { + auto& arm_interface = thread->ArmInterface(); + arm_interface.ClearInstructionCache(); + } + } + } else { + UNIMPLEMENTED_MSG("Cache Invalidation unimplemented for multicore"); + } } void KernelCore::PrepareReschedule(std::size_t id) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 37e893c84..dbd35580e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -622,6 +622,7 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt); if (!break_reason.signal_debugger) { + SchedulerLock lock(system.Kernel()); LOG_CRITICAL( Debug_Emulated, "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", @@ -633,9 +634,8 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { const auto thread_processor_id = current_thread->GetProcessorID(); system.ArmInterface(static_cast(thread_processor_id)).LogBacktrace(); - system.Kernel().CurrentProcess()->PrepareForTermination(); - // Kill the current thread + system.Kernel().ExceptionalExit(); current_thread->Stop(); } } -- cgit v1.2.3 From 48fa3b7a0f2054a836b0a8061e6b082c246b5ae0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 1 Apr 2020 17:28:49 -0400 Subject: General: Cleanup legacy code. --- src/core/hle/kernel/client_port.cpp | 2 +- src/core/hle/kernel/kernel.cpp | 81 +------------------------- src/core/hle/kernel/kernel.h | 3 - src/core/hle/kernel/svc.cpp | 3 +- src/core/hle/kernel/synchronization_object.cpp | 64 -------------------- src/core/hle/kernel/synchronization_object.h | 15 ----- src/core/hle/kernel/thread.cpp | 34 ----------- src/core/hle/kernel/thread.h | 56 +----------------- src/core/hle/service/sm/sm.cpp | 2 +- 9 files changed, 6 insertions(+), 254 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 5498fd313..8aff2227a 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -34,7 +34,7 @@ ResultVal> ClientPort::Connect() { } // Wake the threads waiting on the ServerPort - server_port->WakeupAllWaitingThreads(); + server_port->Signal(); return MakeResult(std::move(client)); } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1f230fc4a..dbb75416d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -48,72 +48,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { -/** - * Callback that will wake up the thread it was scheduled for - * @param thread_handle The handle of the thread that's been awoken - * @param cycles_late The number of CPU cycles that have passed since the desired wakeup time - */ -static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] s64 cycles_late) { - UNREACHABLE(); - const auto proper_handle = static_cast(thread_handle); - const auto& system = Core::System::GetInstance(); - - // Lock the global kernel mutex when we enter the kernel HLE. - std::lock_guard lock{HLE::g_hle_lock}; - - std::shared_ptr thread = - system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle); - if (thread == nullptr) { - LOG_CRITICAL(Kernel, "Callback fired for invalid thread {:08X}", proper_handle); - return; - } - - bool resume = true; - - if (thread->GetStatus() == ThreadStatus::WaitSynch || - thread->GetStatus() == ThreadStatus::WaitHLEEvent) { - // Remove the thread from each of its waiting objects' waitlists - for (const auto& object : thread->GetSynchronizationObjects()) { - object->RemoveWaitingThread(thread); - } - thread->ClearSynchronizationObjects(); - - // Invoke the wakeup callback before clearing the wait objects - if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Timeout, thread, nullptr, 0); - } - } else if (thread->GetStatus() == ThreadStatus::WaitMutex || - thread->GetStatus() == ThreadStatus::WaitCondVar) { - thread->SetMutexWaitAddress(0); - thread->SetWaitHandle(0); - if (thread->GetStatus() == ThreadStatus::WaitCondVar) { - thread->GetOwnerProcess()->RemoveConditionVariableThread(thread); - thread->SetCondVarWaitAddress(0); - } - - auto* const lock_owner = thread->GetLockOwner(); - // Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance - // and don't have a lock owner unless SignalProcessWideKey was called first and the thread - // wasn't awakened due to the mutex already being acquired. - if (lock_owner != nullptr) { - lock_owner->RemoveMutexWaiter(thread); - } - } - - if (thread->GetStatus() == ThreadStatus::WaitArb) { - auto& address_arbiter = thread->GetOwnerProcess()->GetAddressArbiter(); - address_arbiter.HandleWakeupThread(thread); - } - - if (resume) { - if (thread->GetStatus() == ThreadStatus::WaitCondVar || - thread->GetStatus() == ThreadStatus::WaitArb) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - } - thread->ResumeFromWait(); - } -} - struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} @@ -129,7 +63,6 @@ struct KernelCore::Impl { InitializePhysicalCores(); InitializeSystemResourceLimit(kernel); InitializeMemoryLayout(); - InitializeThreads(); InitializePreemption(kernel); InitializeSchedulers(); InitializeSuspendThreads(); @@ -161,7 +94,6 @@ struct KernelCore::Impl { system_resource_limit = nullptr; global_handle_table.Clear(); - thread_wakeup_event_type = nullptr; preemption_event = nullptr; global_scheduler.Shutdown(); @@ -210,11 +142,6 @@ struct KernelCore::Impl { } } - void InitializeThreads() { - thread_wakeup_event_type = - Core::Timing::CreateEvent("ThreadWakeupCallback", ThreadWakeupCallback); - } - void InitializePreemption(KernelCore& kernel) { preemption_event = Core::Timing::CreateEvent( "PreemptionCallback", [this, &kernel](u64 userdata, s64 cycles_late) { @@ -376,7 +303,6 @@ struct KernelCore::Impl { std::shared_ptr system_resource_limit; - std::shared_ptr thread_wakeup_event_type; std::shared_ptr preemption_event; // This is the kernel's handle table or supervisor handle table which @@ -516,7 +442,8 @@ std::array& KernelCore return impl->interrupts; } -const std::array& KernelCore::Interrupts() const { +const std::array& KernelCore::Interrupts() + const { return impl->interrupts; } @@ -595,10 +522,6 @@ u64 KernelCore::CreateNewUserProcessID() { return impl->next_user_process_id++; } -const std::shared_ptr& KernelCore::ThreadWakeupCallbackEventType() const { - return impl->thread_wakeup_event_type; -} - Kernel::HandleTable& KernelCore::GlobalHandleTable() { return impl->global_handle_table; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 846056b85..49bd47e89 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -241,9 +241,6 @@ private: /// Creates a new thread ID, incrementing the internal thread ID counter. u64 CreateNewThreadID(); - /// Retrieves the event type used for thread wakeup callbacks. - const std::shared_ptr& ThreadWakeupCallbackEventType() const; - /// Provides a reference to the global handle table. Kernel::HandleTable& GlobalHandleTable(); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dbd35580e..781032cd1 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -16,7 +16,6 @@ #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" -#include "core/core_manager.h" #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/cpu_manager.h" @@ -1909,7 +1908,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_COMBINATION; } - if (core < Core::NUM_CPU_CORES) { + if (core < Core::Hardware::NUM_CPU_CORES) { if ((affinity_mask & (1ULL << core)) == 0) { LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}", core, diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp index be9e09106..ba4d39157 100644 --- a/src/core/hle/kernel/synchronization_object.cpp +++ b/src/core/hle/kernel/synchronization_object.cpp @@ -38,70 +38,6 @@ void SynchronizationObject::RemoveWaitingThread(std::shared_ptr thread) waiting_threads.erase(itr); } -std::shared_ptr SynchronizationObject::GetHighestPriorityReadyThread() const { - Thread* candidate = nullptr; - u32 candidate_priority = THREADPRIO_LOWEST + 1; - - for (const auto& thread : waiting_threads) { - const ThreadStatus thread_status = thread->GetStatus(); - - // The list of waiting threads must not contain threads that are not waiting to be awakened. - ASSERT_MSG(thread_status == ThreadStatus::WaitSynch || - thread_status == ThreadStatus::WaitHLEEvent, - "Inconsistent thread statuses in waiting_threads"); - - if (thread->GetPriority() >= candidate_priority) - continue; - - if (ShouldWait(thread.get())) - continue; - - candidate = thread.get(); - candidate_priority = thread->GetPriority(); - } - - return SharedFrom(candidate); -} - -void SynchronizationObject::WakeupWaitingThread(std::shared_ptr thread) { - ASSERT(!ShouldWait(thread.get())); - - if (!thread) { - return; - } - - if (thread->IsSleepingOnWait()) { - for (const auto& object : thread->GetSynchronizationObjects()) { - ASSERT(!object->ShouldWait(thread.get())); - object->Acquire(thread.get()); - } - } else { - Acquire(thread.get()); - } - - const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this)); - - thread->ClearSynchronizationObjects(); - - thread->CancelWakeupTimer(); - - bool resume = true; - if (thread->HasWakeupCallback()) { - resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this), - index); - } - if (resume) { - thread->ResumeFromWait(); - kernel.PrepareReschedule(thread->GetProcessorID()); - } -} - -void SynchronizationObject::WakeupAllWaitingThreads() { - while (auto thread = GetHighestPriorityReadyThread()) { - WakeupWaitingThread(thread); - } -} - void SynchronizationObject::ClearWaitingThreads() { waiting_threads.clear(); } diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h index a35544ac1..f89b24204 100644 --- a/src/core/hle/kernel/synchronization_object.h +++ b/src/core/hle/kernel/synchronization_object.h @@ -50,21 +50,6 @@ public: */ void RemoveWaitingThread(std::shared_ptr thread); - /** - * Wake up all threads waiting on this object that can be awoken, in priority order, - * and set the synchronization result and output of the thread. - */ - void /* deprecated */ WakeupAllWaitingThreads(); - - /** - * Wakes up a single thread waiting on this object. - * @param thread Thread that is waiting on this object to wakeup. - */ - void WakeupWaitingThread(std::shared_ptr thread); - - /// Obtains the highest priority thread that is ready to run from this object's waiting list. - std::shared_ptr /* deprecated */ GetHighestPriorityReadyThread() const; - /// Get a const reference to the waiting threads list for debug use const std::vector>& GetWaitingThreads() const; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d88039a16..fba2a9c85 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -56,9 +56,6 @@ Thread::~Thread() = default; void Thread::Stop() { { SchedulerLock lock(kernel); - // Cancel any outstanding wakeup events for this thread - Core::System::GetInstance().CoreTiming().UnscheduleEvent( - kernel.ThreadWakeupCallbackEventType(), global_handle); SetStatus(ThreadStatus::Dead); Signal(); kernel.GlobalHandleTable().Close(global_handle); @@ -75,22 +72,6 @@ void Thread::Stop() { global_handle = 0; } -void Thread::WakeAfterDelay(s64 nanoseconds) { - // Don't schedule a wakeup if the thread wants to wait forever - if (nanoseconds == -1) - return; - - // This function might be called from any thread so we have to be cautious and use the - // thread-safe version of ScheduleEvent. - Core::System::GetInstance().CoreTiming().ScheduleEvent( - nanoseconds, kernel.ThreadWakeupCallbackEventType(), global_handle); -} - -void Thread::CancelWakeupTimer() { - Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), - global_handle); -} - void Thread::ResumeFromWait() { SchedulerLock lock(kernel); switch (status) { @@ -284,14 +265,6 @@ void Thread::SetPriority(u32 priority) { UpdatePriority(); } -void Thread::SetWaitSynchronizationResult(ResultCode result) { - UNREACHABLE(); -} - -void Thread::SetWaitSynchronizationOutput(s32 output) { - UNREACHABLE(); -} - void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) { signaling_object = object; signaling_result = result; @@ -425,13 +398,6 @@ bool Thread::AllSynchronizationObjectsReady() const { }); } -bool Thread::InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, - std::size_t index) { - ASSERT(wakeup_callback); - return wakeup_callback(reason, std::move(thread), std::move(object), index); -} - bool Thread::InvokeHLECallback(std::shared_ptr thread) { ASSERT(hle_callback); return hle_callback(std::move(thread)); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 61963148d..3ae0df6ef 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -128,9 +128,6 @@ public: using ThreadSynchronizationObjects = std::vector>; - using WakeupCallback = - std::function thread, - std::shared_ptr object, std::size_t index)>; using HLECallback = std::function thread)>; /** @@ -235,7 +232,7 @@ public: } /// Resumes a thread from waiting - void /* deprecated */ ResumeFromWait(); + void ResumeFromWait(); void OnWakeUp(); @@ -249,27 +246,6 @@ public: /// void CancelWait(); - /** - * Schedules an event to wake up the specified thread after the specified delay - * @param nanoseconds The time this thread will be allowed to sleep for - */ - void /* deprecated */ WakeAfterDelay(s64 nanoseconds); - - /// Cancel any outstanding wakeup events for this thread - void /* deprecated */ CancelWakeupTimer(); - - /** - * Sets the result after the thread awakens (from svcWaitSynchronization) - * @param result Value to set to the returned result - */ - void /*deprecated*/ SetWaitSynchronizationResult(ResultCode result); - - /** - * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) - * @param output Value to set to the output parameter - */ - void /*deprecated*/ SetWaitSynchronizationOutput(s32 output); - void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); Core::ARM_Interface& ArmInterface(); @@ -330,11 +306,6 @@ public: */ VAddr GetCommandBufferAddress() const; - /// Returns whether this thread is waiting on objects from a WaitSynchronization call. - bool IsSleepingOnWait() const { - return status == ThreadStatus::WaitSynch; - } - ThreadContext32& GetContext32() { return context_32; } @@ -469,18 +440,10 @@ public: arb_wait_address = address; } - bool HasWakeupCallback() const { - return wakeup_callback != nullptr; - } - bool HasHLECallback() const { return hle_callback != nullptr; } - void SetWakeupCallback(WakeupCallback callback) { - wakeup_callback = std::move(callback); - } - void SetHLECallback(HLECallback callback) { hle_callback = std::move(callback); } @@ -501,22 +464,10 @@ public: return hle_object; } - void InvalidateWakeupCallback() { - SetWakeupCallback(nullptr); - } - void InvalidateHLECallback() { SetHLECallback(nullptr); } - /** - * Invokes the thread's wakeup callback. - * - * @pre A valid wakeup callback has been set. Violating this precondition - * will cause an assertion to trigger. - */ - bool InvokeWakeupCallback(ThreadWakeupReason reason, std::shared_ptr thread, - std::shared_ptr object, std::size_t index); bool InvokeHLECallback(std::shared_ptr thread); u32 GetIdealCore() const { @@ -698,11 +649,6 @@ private: /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle global_handle = 0; - /// Callback that will be invoked when the thread is resumed from a waiting state. If the thread - /// was waiting via WaitSynchronization then the object will be the last object that became - /// available. In case of a timeout, the object will be nullptr. DEPRECATED - WakeupCallback wakeup_callback; - /// Callback for HLE Events HLECallback hle_callback; Handle hle_time_event; diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 6ada13be4..d872de16c 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -142,7 +142,7 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { } // Wake the threads waiting on the ServerPort - server_port->WakeupAllWaitingThreads(); + server_port->Signal(); LOG_DEBUG(Service_SM, "called service={} -> session={}", name, client->GetObjectId()); IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; -- cgit v1.2.3 From 467d43570e10b98fa33067352d35fe62ceb3cb9e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 May 2020 18:53:13 -0400 Subject: Clang Format. --- src/core/hle/kernel/mutex.cpp | 11 +++++------ src/core/hle/kernel/mutex.h | 3 ++- src/core/hle/kernel/physical_core.h | 7 +++---- src/core/hle/kernel/server_session.cpp | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 32dc1ffae..8f6c944d1 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -9,7 +9,6 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/core.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/kernel.h" @@ -126,11 +125,11 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle, std::pair> Mutex::Unlock(std::shared_ptr owner, VAddr address) { - // The mutex address must be 4-byte aligned - if ((address % sizeof(u32)) != 0) { - LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); - return {ERR_INVALID_ADDRESS, nullptr}; - } + // The mutex address must be 4-byte aligned + if ((address % sizeof(u32)) != 0) { + LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); + return {ERR_INVALID_ADDRESS, nullptr}; + } auto [new_owner, num_waiters] = GetHighestPriorityMutexWaitingThread(owner, address); if (new_owner == nullptr) { diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index bce06ecea..3b81dc3df 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h @@ -29,7 +29,8 @@ public: Handle requesting_thread_handle); /// Unlocks a mutex for owner at address - std::pair> Unlock(std::shared_ptr owner, VAddr address); + std::pair> Unlock(std::shared_ptr owner, + VAddr address); /// Releases the mutex at the specified address. ResultCode Release(VAddr address); diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 751b994a7..85f6dec05 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { - class SpinLock; +class SpinLock; } namespace Kernel { @@ -27,9 +27,8 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, - Kernel::Scheduler& scheduler, - Core::CPUInterruptHandler& interrupt_handler); + PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp index e988a3f22..7b23a6889 100644 --- a/src/core/hle/kernel/server_session.cpp +++ b/src/core/hle/kernel/server_session.cpp @@ -17,9 +17,9 @@ #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/server_session.h" #include "core/hle/kernel/session.h" -#include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" #include "core/memory.h" -- cgit v1.2.3 From d24014358883987d7ebdafc4863a7bc36addfa1b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 13 May 2020 14:17:34 -0400 Subject: Kernel: Correct Host Context on Threads and Scheduler. --- src/core/hle/kernel/scheduler.cpp | 16 ++++++++-------- src/core/hle/kernel/scheduler.h | 2 +- src/core/hle/kernel/thread.cpp | 2 +- src/core/hle/kernel/thread.h | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 43c924fa0..61b8a396a 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -736,15 +736,15 @@ void Scheduler::SwitchContext() { previous_thread->context_guard.unlock(); } - std::shared_ptr old_context; + std::shared_ptr* old_context; if (previous_thread != nullptr) { - old_context = previous_thread->GetHostContext(); + old_context = &previous_thread->GetHostContext(); } else { - old_context = idle_thread->GetHostContext(); + old_context = &idle_thread->GetHostContext(); } guard.unlock(); - Common::Fiber::YieldTo(old_context, switch_fiber); + Common::Fiber::YieldTo(*old_context, switch_fiber); /// When a thread wakes up, the scheduler may have changed to other in another core. auto& next_scheduler = system.Kernel().CurrentScheduler(); next_scheduler.SwitchContextStep2(); @@ -774,13 +774,13 @@ void Scheduler::SwitchToCurrent() { break; } } - std::shared_ptr next_context; + std::shared_ptr* next_context; if (current_thread != nullptr) { - next_context = current_thread->GetHostContext(); + next_context = ¤t_thread->GetHostContext(); } else { - next_context = idle_thread->GetHostContext(); + next_context = &idle_thread->GetHostContext(); } - Common::Fiber::YieldTo(switch_fiber, next_context); + Common::Fiber::YieldTo(switch_fiber, *next_context); } } } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 10dc4b832..348107160 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -236,7 +236,7 @@ public: void OnThreadStart(); - std::shared_ptr ControlContext() { + std::shared_ptr& ControlContext() { return switch_fiber; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index fba2a9c85..2b1092697 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -150,7 +150,7 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, context.fpcr = 0; } -std::shared_ptr Thread::GetHostContext() const { +std::shared_ptr& Thread::GetHostContext() { return host_context; } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 3ae0df6ef..c0342c462 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -342,7 +342,7 @@ public: was_running = value; } - std::shared_ptr GetHostContext() const; + std::shared_ptr& GetHostContext(); ThreadStatus GetStatus() const { return status; -- cgit v1.2.3 From 272a87127a68bbb9d7c7984e619ee12702d7b8e0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 May 2020 15:00:17 -0400 Subject: Services/NvFlinger: Do vSync in a sepparate thread on Multicore. --- src/core/hle/service/nvflinger/nvflinger.cpp | 49 ++++++++++++++++++++++++++-- src/core/hle/service/nvflinger/nvflinger.h | 14 ++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index b97f71350..2f44d3779 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" +#include "common/thread.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -30,6 +31,33 @@ namespace Service::NVFlinger { constexpr s64 frame_ticks = static_cast(1000000000 / 60); constexpr s64 frame_ticks_30fps = static_cast(1000000000 / 30); +void NVFlinger::VSyncThread(NVFlinger& nv_flinger) { + nv_flinger.SplitVSync(); +} + +void NVFlinger::SplitVSync() { + system.RegisterHostThread(); + std::string name = "yuzu:VSyncThread"; + MicroProfileOnThreadCreate(name.c_str()); + Common::SetCurrentThreadName(name.c_str()); + Common::SetCurrentThreadPriority(Common::ThreadPriority::High); + s64 delay = 0; + while (is_running) { + guard->lock(); + const s64 time_start = system.CoreTiming().GetGlobalTimeNs().count(); + Compose(); + const auto ticks = GetNextTicks(); + const s64 time_end = system.CoreTiming().GetGlobalTimeNs().count(); + const s64 time_passed = time_end - time_start; + const s64 next_time = std::max(0, ticks - time_passed - delay); + guard->unlock(); + if (next_time > 0) { + wait_event->WaitFor(std::chrono::nanoseconds{next_time}); + } + delay = (system.CoreTiming().GetGlobalTimeNs().count() - time_end) - next_time; + } +} + NVFlinger::NVFlinger(Core::System& system) : system(system) { displays.emplace_back(0, "Default", system); displays.emplace_back(1, "External", system); @@ -47,12 +75,25 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { this->system.CoreTiming().ScheduleEvent(std::max(0LL, ticks - ns_late), composition_event); }); - - system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); + if (system.IsMulticore()) { + is_running = true; + wait_event = std::make_unique(); + vsync_thread = std::make_unique(VSyncThread, std::ref(*this)); + } else { + system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); + } } NVFlinger::~NVFlinger() { - system.CoreTiming().UnscheduleEvent(composition_event, 0); + if (system.IsMulticore()) { + is_running = false; + wait_event->Set(); + vsync_thread->join(); + vsync_thread.reset(); + wait_event.reset(); + } else { + system.CoreTiming().UnscheduleEvent(composition_event, 0); + } } void NVFlinger::SetNVDrvInstance(std::shared_ptr instance) { @@ -200,10 +241,12 @@ void NVFlinger::Compose() { auto& gpu = system.GPU(); const auto& multi_fence = buffer->get().multi_fence; + guard->unlock(); for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { const auto& fence = multi_fence.fences[fence_id]; gpu.WaitFence(fence.id, fence.value); } + guard->lock(); MicroProfileFlip(); diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 02c081494..4bc3d7ab2 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -4,16 +4,22 @@ #pragma once +#include #include #include #include #include #include #include +#include #include "common/common_types.h" #include "core/hle/kernel/object.h" +namespace Common { +class Event; +} // namespace Common + namespace Core::Timing { class CoreTiming; struct EventType; @@ -97,6 +103,10 @@ private: /// Finds the layer identified by the specified ID in the desired display. const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; + static void VSyncThread(NVFlinger& nv_flinger); + + void SplitVSync(); + std::shared_ptr nvdrv; std::vector displays; @@ -116,6 +126,10 @@ private: std::shared_ptr guard; Core::System& system; + + std::unique_ptr vsync_thread; + std::unique_ptr wait_event; + std::atomic is_running{}; }; } // namespace Service::NVFlinger -- cgit v1.2.3 From 7fd7d05838b88e9dd63a7329e29ea355669a5f18 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 May 2020 17:37:37 -0400 Subject: Common/Kernel: Corrections and small bug fixing. --- src/core/hle/kernel/svc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 781032cd1..013ae9e34 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -344,9 +344,9 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { SchedulerLock lock(system.Kernel()); auto* sync_object = thread->GetHLESyncObject(); sync_object->RemoveWaitingThread(SharedFrom(thread)); - - thread->InvokeHLECallback(SharedFrom(thread)); } + + thread->InvokeHLECallback(SharedFrom(thread)); } return thread->GetSignalingResult(); -- cgit v1.2.3 From 22ceaca2f415b962416637db9fff9782575746ce Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 18 Jun 2020 18:15:19 -0400 Subject: SVC: Add GetThreadPriority32 & SetThreadPriority32 --- src/core/hle/kernel/svc.cpp | 14 ++++++++++++-- src/core/hle/kernel/svc_wrap.h | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 013ae9e34..5674d9558 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1135,6 +1135,10 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri return RESULT_SUCCESS; } +static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { + return SetThreadPriority(system, handle, priority); +} + /// Get which CPU core is executing the current thread static u32 GetCurrentProcessorNumber(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); @@ -1933,6 +1937,12 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return thread->SetCoreAndAffinityMask(core, affinity_mask); } +static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, + u32 affinity_mask_low, u32 affinity_mask_high) { + const u64 affinity_mask = static_cast(affinity_mask_low) | (static_cast(affinity_mask_high) << 32); + return SetThreadCoreMask(system, thread_handle, core, affinity_mask); +} + static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { LOG_DEBUG(Kernel_SVC, "called"); @@ -2206,9 +2216,9 @@ static const FunctionDef SVC_Table_32[] = { {0x0a, nullptr, "ExitThread32"}, {0x0b, nullptr, "SleepThread32"}, {0x0c, SvcWrap32, "GetThreadPriority32"}, - {0x0d, nullptr, "SetThreadPriority32"}, + {0x0d, SvcWrap32, "SetThreadPriority32"}, {0x0e, nullptr, "GetThreadCoreMask32"}, - {0x0f, nullptr, "SetThreadCoreMask32"}, + {0x0f, SvcWrap32, "SetThreadCoreMask32"}, {0x10, nullptr, "GetCurrentProcessorNumber32"}, {0x11, nullptr, "SignalEvent32"}, {0x12, nullptr, "ClearEvent32"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 7d735e3fa..fd4edba2a 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -399,6 +399,24 @@ void SvcWrap32(Core::System& system) { func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))); } +// Used by SetThreadPriority32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1))).raw; + FuncReturn(system, retval); +} + +// Used by SetThreadCoreMask32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3))) + .raw; + FuncReturn(system, retval); +} + // Used by SendSyncRequest32 template void SvcWrap32(Core::System& system) { -- cgit v1.2.3 From ce350e7ce03b8d9e3e2c8ff8774f9b929a70047f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 18 Jun 2020 20:33:04 -0400 Subject: SVC: Add GetCurrentProcessorNumber32, CreateTransferMemory32, SetMemoryAttribute32 --- src/core/hle/kernel/svc.cpp | 29 +++++++++++++++++++++++------ src/core/hle/kernel/svc_wrap.h | 16 ++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 5674d9558..1d47a2779 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -232,6 +232,12 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si static_cast(attribute)); } +static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, + u32 attribute) { + return SetMemoryAttribute(system, static_cast(address), static_cast(size), + mask, attribute); +} + /// Maps a memory range into a different range. static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -1136,7 +1142,7 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri } static ResultCode SetThreadPriority32(Core::System& system, Handle handle, u32 priority) { - return SetThreadPriority(system, handle, priority); + return SetThreadPriority(system, handle, priority); } /// Get which CPU core is executing the current thread @@ -1145,6 +1151,10 @@ static u32 GetCurrentProcessorNumber(Core::System& system) { return static_cast(system.CurrentPhysicalCore().CoreIndex()); } +static u32 GetCurrentProcessorNumber32(Core::System& system) { + return GetCurrentProcessorNumber(system); +} + static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, u64 size, u32 permissions) { std::lock_guard lock{HLE::g_hle_lock}; @@ -1861,6 +1871,12 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd return RESULT_SUCCESS; } +static ResultCode CreateTransferMemory32(Core::System& system, Handle* handle, u32 addr, u32 size, + u32 permissions) { + return CreateTransferMemory(system, handle, static_cast(addr), + static_cast(size), permissions); +} + static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, u32* core, u64* mask) { LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); @@ -1938,8 +1954,9 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, } static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle, u32 core, - u32 affinity_mask_low, u32 affinity_mask_high) { - const u64 affinity_mask = static_cast(affinity_mask_low) | (static_cast(affinity_mask_high) << 32); + u32 affinity_mask_low, u32 affinity_mask_high) { + const u64 affinity_mask = + static_cast(affinity_mask_low) | (static_cast(affinity_mask_high) << 32); return SetThreadCoreMask(system, thread_handle, core, affinity_mask); } @@ -2206,7 +2223,7 @@ static const FunctionDef SVC_Table_32[] = { {0x00, nullptr, "Unknown"}, {0x01, SvcWrap32, "SetHeapSize32"}, {0x02, nullptr, "Unknown"}, - {0x03, nullptr, "SetMemoryAttribute32"}, + {0x03, SvcWrap32, "SetMemoryAttribute32"}, {0x04, nullptr, "MapMemory32"}, {0x05, nullptr, "UnmapMemory32"}, {0x06, SvcWrap32, "QueryMemory32"}, @@ -2219,12 +2236,12 @@ static const FunctionDef SVC_Table_32[] = { {0x0d, SvcWrap32, "SetThreadPriority32"}, {0x0e, nullptr, "GetThreadCoreMask32"}, {0x0f, SvcWrap32, "SetThreadCoreMask32"}, - {0x10, nullptr, "GetCurrentProcessorNumber32"}, + {0x10, SvcWrap32, "GetCurrentProcessorNumber32"}, {0x11, nullptr, "SignalEvent32"}, {0x12, nullptr, "ClearEvent32"}, {0x13, nullptr, "MapSharedMemory32"}, {0x14, nullptr, "UnmapSharedMemory32"}, - {0x15, nullptr, "CreateTransferMemory32"}, + {0x15, SvcWrap32, "CreateTransferMemory32"}, {0x16, SvcWrap32, "CloseHandle32"}, {0x17, nullptr, "ResetSignal32"}, {0x18, SvcWrap32, "WaitSynchronization32"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index fd4edba2a..ba90c354f 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -357,6 +357,12 @@ void SvcWrap32(Core::System& system) { func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw); } +// Used by GetCurrentProcessorNumber32 +template +void SvcWrap32(Core::System& system) { + FuncReturn(system, func(system)); +} + // Used by GetInfo32 template void SvcWrap32(Core::System& system) { @@ -423,6 +429,16 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0))).raw); } +// Used by CreateTransferMemory32 +template +void SvcWrap32(Core::System& system) { + Handle handle = 0; + const u32 retval = + func(system, &handle, Param32(system, 1), Param32(system, 2), Param32(system, 3)).raw; + system.CurrentArmInterface().SetReg(1, handle); + FuncReturn(system, retval); +} + // Used by WaitSynchronization32 template void SvcWrap32(Core::System& system) { -- cgit v1.2.3 From 4105f38022a525aab2e7d4288f121b4f0a0dd7b2 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 19 Jun 2020 19:40:07 -0400 Subject: SVC: Implement 32-bits wrappers and update Dynarmic. --- src/core/hle/kernel/svc.cpp | 198 +++++++++++++++++++++++++++++++++++------ src/core/hle/kernel/svc_wrap.h | 105 +++++++++++++++++++++- 2 files changed, 273 insertions(+), 30 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1d47a2779..5db19dcf3 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -254,6 +254,11 @@ static ResultCode MapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr return page_table.Map(dst_addr, src_addr, size); } +static ResultCode MapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { + return MapMemory(system, static_cast(dst_addr), static_cast(src_addr), + static_cast(size)); +} + /// Unmaps a region that was previously mapped with svcMapMemory static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -270,6 +275,11 @@ static ResultCode UnmapMemory(Core::System& system, VAddr dst_addr, VAddr src_ad return page_table.Unmap(dst_addr, src_addr, size); } +static ResultCode UnmapMemory32(Core::System& system, u32 dst_addr, u32 src_addr, u32 size) { + return UnmapMemory(system, static_cast(dst_addr), static_cast(src_addr), + static_cast(size)); +} + /// Connect to an OS service given the port name, returns the handle to the port to out static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, VAddr port_name_address) { @@ -417,6 +427,15 @@ static ResultCode GetProcessId(Core::System& system, u64* process_id, Handle han return ERR_INVALID_HANDLE; } +static ResultCode GetProcessId32(Core::System& system, u32* process_id_low, u32* process_id_high, + Handle handle) { + u64 process_id{}; + const auto result = GetProcessId(system, &process_id, handle); + *process_id_low = static_cast(process_id); + *process_id_high = static_cast(process_id >> 32); + return result; +} + /// Wait for the given handles to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization(Core::System& system, Handle* index, VAddr handles_address, u64 handle_count, s64 nano_seconds) { @@ -484,6 +503,10 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand return RESULT_SUCCESS; } +static ResultCode CancelSynchronization32(Core::System& system, Handle thread_handle) { + return CancelSynchronization(system, thread_handle); +} + /// Attempts to locks a mutex, creating it if it does not already exist static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_handle, VAddr mutex_addr, Handle requesting_thread_handle) { @@ -508,6 +531,12 @@ static ResultCode ArbitrateLock(Core::System& system, Handle holding_thread_hand requesting_thread_handle); } +static ResultCode ArbitrateLock32(Core::System& system, Handle holding_thread_handle, + u32 mutex_addr, Handle requesting_thread_handle) { + return ArbitrateLock(system, holding_thread_handle, static_cast(mutex_addr), + requesting_thread_handle); +} + /// Unlock a mutex static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); @@ -527,6 +556,10 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr mutex_addr) { return current_process->GetMutex().Release(mutex_addr); } +static ResultCode ArbitrateUnlock32(Core::System& system, u32 mutex_addr) { + return ArbitrateUnlock(system, static_cast(mutex_addr)); +} + enum class BreakType : u32 { Panic = 0, AssertionFailed = 1, @@ -645,6 +678,10 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) { } } +static void Break32(Core::System& system, u32 reason, u32 info1, u32 info2) { + Break(system, reason, static_cast(info1), static_cast(info2)); +} + /// Used to output a message on a debug hardware unit - does nothing on a retail unit static void OutputDebugString([[maybe_unused]] Core::System& system, VAddr address, u64 len) { if (len == 0) { @@ -973,6 +1010,10 @@ static ResultCode MapPhysicalMemory(Core::System& system, VAddr addr, u64 size) return page_table.MapPhysicalMemory(addr, size); } +static ResultCode MapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { + return MapPhysicalMemory(system, static_cast(addr), static_cast(size)); +} + /// Unmaps memory previously mapped via MapPhysicalMemory static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size) { std::lock_guard lock{HLE::g_hle_lock}; @@ -1023,6 +1064,10 @@ static ResultCode UnmapPhysicalMemory(Core::System& system, VAddr addr, u64 size return page_table.UnmapPhysicalMemory(addr, size); } +static ResultCode UnmapPhysicalMemory32(Core::System& system, u32 addr, u32 size) { + return UnmapPhysicalMemory(system, static_cast(addr), static_cast(size)); +} + /// Sets the thread activity static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 activity) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, activity=0x{:08X}", handle, activity); @@ -1055,6 +1100,10 @@ static ResultCode SetThreadActivity(Core::System& system, Handle handle, u32 act return thread->SetActivity(static_cast(activity)); } +static ResultCode SetThreadActivity32(Core::System& system, Handle handle, u32 activity) { + return SetThreadActivity(system, handle, activity); +} + /// Gets the thread context static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, Handle handle) { LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); @@ -1096,6 +1145,10 @@ static ResultCode GetThreadContext(Core::System& system, VAddr thread_context, H return RESULT_SUCCESS; } +static ResultCode GetThreadContext32(Core::System& system, u32 thread_context, Handle handle) { + return GetThreadContext(system, static_cast(thread_context), handle); +} + /// Gets the priority for the specified thread static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle handle) { LOG_TRACE(Kernel_SVC, "called"); @@ -1228,6 +1281,12 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return shared_memory->Map(*current_process, addr, size, permission_type); } +static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, + u32 size, u32 permissions) { + return MapSharedMemory(system, shared_memory_handle, static_cast(addr), + static_cast(size), permissions); +} + static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { @@ -1426,6 +1485,10 @@ static void ExitProcess(Core::System& system) { system.CurrentScheduler().GetCurrentThread()->Stop(); } +static void ExitProcess32(Core::System& system) { + ExitProcess(system); +} + /// Creates a new thread static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, u32 priority, s32 processor_id) { @@ -1489,6 +1552,12 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e return RESULT_SUCCESS; } +static ResultCode CreateThread32(Core::System& system, Handle* out_handle, u32 priority, + u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) { + return CreateThread(system, out_handle, static_cast(entry_point), static_cast(arg), + static_cast(stack_top), priority, processor_id); +} + /// Starts the thread for the provided handle static ResultCode StartThread(Core::System& system, Handle thread_handle) { LOG_DEBUG(Kernel_SVC, "called thread=0x{:08X}", thread_handle); @@ -1506,6 +1575,10 @@ static ResultCode StartThread(Core::System& system, Handle thread_handle) { return thread->Start(); } +static ResultCode StartThread32(Core::System& system, Handle thread_handle) { + return StartThread(system, thread_handle); +} + /// Called when a thread exits static void ExitThread(Core::System& system) { LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); @@ -1515,6 +1588,10 @@ static void ExitThread(Core::System& system) { current_thread->Stop(); } +static void ExitThread32(Core::System& system) { + ExitThread(system); +} + /// Sleep the current thread static void SleepThread(Core::System& system, s64 nanoseconds) { LOG_DEBUG(Kernel_SVC, "called nanoseconds={}", nanoseconds); @@ -1561,6 +1638,12 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } } +static void SleepThread32(Core::System& system, u32 nanoseconds_low, u32 nanoseconds_high) { + const s64 nanoseconds = static_cast(static_cast(nanoseconds_low) | + (static_cast(nanoseconds_high) << 32)); + SleepThread(system, nanoseconds); +} + /// Wait process wide key atomic static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_addr, VAddr condition_variable_addr, Handle thread_handle, @@ -1640,6 +1723,16 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr mutex_add return current_thread->GetSignalingResult(); } +static ResultCode WaitProcessWideKeyAtomic32(Core::System& system, u32 mutex_addr, + u32 condition_variable_addr, Handle thread_handle, + u32 nanoseconds_low, u32 nanoseconds_high) { + const s64 nanoseconds = + static_cast(nanoseconds_low | (static_cast(nanoseconds_high) << 32)); + return WaitProcessWideKeyAtomic(system, static_cast(mutex_addr), + static_cast(condition_variable_addr), thread_handle, + nanoseconds); +} + /// Signal process wide key static void SignalProcessWideKey(Core::System& system, VAddr condition_variable_addr, s32 target) { LOG_TRACE(Kernel_SVC, "called, condition_variable_addr=0x{:X}, target=0x{:08X}", @@ -1741,6 +1834,12 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, u32 type, return result; } +static ResultCode WaitForAddress32(Core::System& system, u32 address, u32 type, s32 value, + u32 timeout_low, u32 timeout_high) { + s64 timeout = static_cast(timeout_low | (static_cast(timeout_high) << 32)); + return WaitForAddress(system, static_cast(address), type, value, timeout); +} + // Signals to an address (via Address Arbiter) static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, s32 value, s32 num_to_wake) { @@ -1764,6 +1863,11 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, u32 type, return address_arbiter.SignalToAddress(address, signal_type, value, num_to_wake); } +static ResultCode SignalToAddress32(Core::System& system, u32 address, u32 type, s32 value, + s32 num_to_wake) { + return SignalToAddress(system, static_cast(address), type, value, num_to_wake); +} + static void KernelDebug([[maybe_unused]] Core::System& system, [[maybe_unused]] u32 kernel_debug_type, [[maybe_unused]] u64 param1, [[maybe_unused]] u64 param2, [[maybe_unused]] u64 param3) { @@ -1791,6 +1895,12 @@ static u64 GetSystemTick(Core::System& system) { return result; } +static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { + u64 time = GetSystemTick(system); + *time_low = static_cast(time); + *time_high = static_cast(time >> 32); +} + /// Close a handle static ResultCode CloseHandle(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); @@ -1823,6 +1933,10 @@ static ResultCode ResetSignal(Core::System& system, Handle handle) { return ERR_INVALID_HANDLE; } +static ResultCode ResetSignal32(Core::System& system, Handle handle) { + return ResetSignal(system, handle); +} + /// Creates a TransferMemory object static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAddr addr, u64 size, u32 permissions) { @@ -1897,6 +2011,15 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, return RESULT_SUCCESS; } +static ResultCode GetThreadCoreMask32(Core::System& system, Handle thread_handle, u32* core, + u32* mask_low, u32* mask_high) { + u64 mask{}; + const auto result = GetThreadCoreMask(system, thread_handle, core, &mask); + *mask_high = static_cast(mask >> 32); + *mask_low = static_cast(mask); + return result; +} + static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, u32 core, u64 affinity_mask) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, core=0x{:X}, affinity_mask=0x{:016X}", @@ -1988,6 +2111,10 @@ static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle return RESULT_SUCCESS; } +static ResultCode CreateEvent32(Core::System& system, Handle* write_handle, Handle* read_handle) { + return CreateEvent(system, write_handle, read_handle); +} + static ResultCode ClearEvent(Core::System& system, Handle handle) { LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); @@ -2009,6 +2136,10 @@ static ResultCode ClearEvent(Core::System& system, Handle handle) { return ERR_INVALID_HANDLE; } +static ResultCode ClearEvent32(Core::System& system, Handle handle) { + return ClearEvent(system, handle); +} + static ResultCode SignalEvent(Core::System& system, Handle handle) { LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle); @@ -2024,6 +2155,10 @@ static ResultCode SignalEvent(Core::System& system, Handle handle) { return RESULT_SUCCESS; } +static ResultCode SignalEvent32(Core::System& system, Handle handle) { + return SignalEvent(system, handle); +} + static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) { LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); @@ -2209,6 +2344,15 @@ static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAdd return RESULT_SUCCESS; } +static ResultCode FlushProcessDataCache32(Core::System& system, Handle handle, u32 address, + u32 size) { + // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a nope + // as all emulation is done in the same cache level in host architecture, thus data cache + // does not need flushing. + LOG_DEBUG(Kernel_SVC, "called"); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(Core::System&); @@ -2224,56 +2368,56 @@ static const FunctionDef SVC_Table_32[] = { {0x01, SvcWrap32, "SetHeapSize32"}, {0x02, nullptr, "Unknown"}, {0x03, SvcWrap32, "SetMemoryAttribute32"}, - {0x04, nullptr, "MapMemory32"}, - {0x05, nullptr, "UnmapMemory32"}, + {0x04, SvcWrap32, "MapMemory32"}, + {0x05, SvcWrap32, "UnmapMemory32"}, {0x06, SvcWrap32, "QueryMemory32"}, - {0x07, nullptr, "ExitProcess32"}, - {0x08, nullptr, "CreateThread32"}, - {0x09, nullptr, "StartThread32"}, - {0x0a, nullptr, "ExitThread32"}, - {0x0b, nullptr, "SleepThread32"}, + {0x07, SvcWrap32, "ExitProcess32"}, + {0x08, SvcWrap32, "CreateThread32"}, + {0x09, SvcWrap32, "StartThread32"}, + {0x0a, SvcWrap32, "ExitThread32"}, + {0x0b, SvcWrap32, "SleepThread32"}, {0x0c, SvcWrap32, "GetThreadPriority32"}, {0x0d, SvcWrap32, "SetThreadPriority32"}, - {0x0e, nullptr, "GetThreadCoreMask32"}, + {0x0e, SvcWrap32, "GetThreadCoreMask32"}, {0x0f, SvcWrap32, "SetThreadCoreMask32"}, {0x10, SvcWrap32, "GetCurrentProcessorNumber32"}, - {0x11, nullptr, "SignalEvent32"}, - {0x12, nullptr, "ClearEvent32"}, - {0x13, nullptr, "MapSharedMemory32"}, + {0x11, SvcWrap32, "SignalEvent32"}, + {0x12, SvcWrap32, "ClearEvent32"}, + {0x13, SvcWrap32, "MapSharedMemory32"}, {0x14, nullptr, "UnmapSharedMemory32"}, {0x15, SvcWrap32, "CreateTransferMemory32"}, {0x16, SvcWrap32, "CloseHandle32"}, - {0x17, nullptr, "ResetSignal32"}, + {0x17, SvcWrap32, "ResetSignal32"}, {0x18, SvcWrap32, "WaitSynchronization32"}, - {0x19, nullptr, "CancelSynchronization32"}, - {0x1a, nullptr, "ArbitrateLock32"}, - {0x1b, nullptr, "ArbitrateUnlock32"}, - {0x1c, nullptr, "WaitProcessWideKeyAtomic32"}, + {0x19, SvcWrap32, "CancelSynchronization32"}, + {0x1a, SvcWrap32, "ArbitrateLock32"}, + {0x1b, SvcWrap32, "ArbitrateUnlock32"}, + {0x1c, SvcWrap32, "WaitProcessWideKeyAtomic32"}, {0x1d, SvcWrap32, "SignalProcessWideKey32"}, - {0x1e, nullptr, "GetSystemTick32"}, + {0x1e, SvcWrap32, "GetSystemTick32"}, {0x1f, SvcWrap32, "ConnectToNamedPort32"}, {0x20, nullptr, "Unknown"}, {0x21, SvcWrap32, "SendSyncRequest32"}, {0x22, nullptr, "SendSyncRequestWithUserBuffer32"}, {0x23, nullptr, "Unknown"}, - {0x24, nullptr, "GetProcessId32"}, + {0x24, SvcWrap32, "GetProcessId32"}, {0x25, SvcWrap32, "GetThreadId32"}, - {0x26, nullptr, "Break32"}, + {0x26, SvcWrap32, "Break32"}, {0x27, nullptr, "OutputDebugString32"}, {0x28, nullptr, "Unknown"}, {0x29, SvcWrap32, "GetInfo32"}, {0x2a, nullptr, "Unknown"}, {0x2b, nullptr, "Unknown"}, - {0x2c, nullptr, "MapPhysicalMemory32"}, - {0x2d, nullptr, "UnmapPhysicalMemory32"}, + {0x2c, SvcWrap32, "MapPhysicalMemory32"}, + {0x2d, SvcWrap32, "UnmapPhysicalMemory32"}, {0x2e, nullptr, "Unknown"}, {0x2f, nullptr, "Unknown"}, {0x30, nullptr, "Unknown"}, {0x31, nullptr, "Unknown"}, - {0x32, nullptr, "SetThreadActivity32"}, - {0x33, nullptr, "GetThreadContext32"}, - {0x34, nullptr, "WaitForAddress32"}, - {0x35, nullptr, "SignalToAddress32"}, + {0x32, SvcWrap32, "SetThreadActivity32"}, + {0x33, SvcWrap32, "GetThreadContext32"}, + {0x34, SvcWrap32, "WaitForAddress32"}, + {0x35, SvcWrap32, "SignalToAddress32"}, {0x36, nullptr, "Unknown"}, {0x37, nullptr, "Unknown"}, {0x38, nullptr, "Unknown"}, @@ -2289,7 +2433,7 @@ static const FunctionDef SVC_Table_32[] = { {0x42, nullptr, "Unknown"}, {0x43, nullptr, "ReplyAndReceive32"}, {0x44, nullptr, "Unknown"}, - {0x45, nullptr, "CreateEvent32"}, + {0x45, SvcWrap32, "CreateEvent32"}, {0x46, nullptr, "Unknown"}, {0x47, nullptr, "Unknown"}, {0x48, nullptr, "Unknown"}, @@ -2315,7 +2459,7 @@ static const FunctionDef SVC_Table_32[] = { {0x5c, nullptr, "Unknown"}, {0x5d, nullptr, "Unknown"}, {0x5e, nullptr, "Unknown"}, - {0x5F, nullptr, "FlushProcessDataCache32"}, + {0x5F, SvcWrap32, "FlushProcessDataCache32"}, {0x60, nullptr, "Unknown"}, {0x61, nullptr, "Unknown"}, {0x62, nullptr, "Unknown"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index ba90c354f..0b6dd9df0 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -350,17 +350,48 @@ void SvcWrap64(Core::System& system) { func(system, static_cast(Param(system, 0)), Param(system, 1), Param(system, 2)); } -// Used by QueryMemory32 +// Used by QueryMemory32, ArbitrateLock32 template void SvcWrap32(Core::System& system) { FuncReturn32(system, func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)).raw); } +// Used by Break32 +template +void SvcWrap32(Core::System& system) { + func(system, Param32(system, 0), Param32(system, 1), Param32(system, 2)); +} + +// Used by ExitProcess32, ExitThread32 +template +void SvcWrap32(Core::System& system) { + func(system); +} + // Used by GetCurrentProcessorNumber32 template void SvcWrap32(Core::System& system) { - FuncReturn(system, func(system)); + FuncReturn32(system, func(system)); +} + +// Used by SleepThread32 +template +void SvcWrap32(Core::System& system) { + func(system, Param32(system, 0), Param32(system, 1)); +} + +// Used by CreateThread32 +template +void SvcWrap32(Core::System& system) { + Handle param_1 = 0; + + const u32 retval = func(system, ¶m_1, Param32(system, 0), Param32(system, 1), + Param32(system, 2), Param32(system, 3), Param32(system, 4)) + .raw; + + system.CurrentArmInterface().SetReg(1, param_1); + FuncReturn(system, retval); } // Used by GetInfo32 @@ -399,6 +430,43 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by GetSystemTick32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + + func(system, ¶m_1, ¶m_2); + system.CurrentArmInterface().SetReg(0, param_1); + system.CurrentArmInterface().SetReg(1, param_2); +} + +// Used by CreateEvent32 +template +void SvcWrap32(Core::System& system) { + Handle param_1 = 0; + Handle param_2 = 0; + + const u32 retval = func(system, ¶m_1, ¶m_2).raw; + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + FuncReturn(system, retval); +} + +// Used by GetThreadId32 +template +void SvcWrap32(Core::System& system) { + u32 param_1 = 0; + u32 param_2 = 0; + u32 param_3 = 0; + + const u32 retval = func(system, Param32(system, 2), ¶m_1, ¶m_2, ¶m_3).raw; + system.CurrentArmInterface().SetReg(1, param_1); + system.CurrentArmInterface().SetReg(2, param_2); + system.CurrentArmInterface().SetReg(3, param_3); + FuncReturn(system, retval); +} + // Used by SignalProcessWideKey32 template void SvcWrap32(Core::System& system) { @@ -423,7 +491,38 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } -// Used by SendSyncRequest32 +// Used by WaitProcessWideKeyAtomic32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3)), + static_cast(Param(system, 4))) + .raw; + FuncReturn(system, retval); +} + +// Used by WaitForAddress32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = func(system, static_cast(Param(system, 0)), + static_cast(Param(system, 1)), static_cast(Param(system, 2)), + static_cast(Param(system, 3)), static_cast(Param(system, 4))) + .raw; + FuncReturn(system, retval); +} + +// Used by SignalToAddress32 +template +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, static_cast(Param(system, 0)), static_cast(Param(system, 1)), + static_cast(Param(system, 2)), static_cast(Param(system, 3))) + .raw; + FuncReturn(system, retval); +} + +// Used by SendSyncRequest32, ArbitrateUnlock32 template void SvcWrap32(Core::System& system) { FuncReturn(system, func(system, static_cast(Param(system, 0))).raw); -- cgit v1.2.3 From e486c66850637a05ba2912e3f1e25a97cfebc41e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 27 Jun 2020 10:59:51 -0400 Subject: NvFlinger: Clang Format. --- src/core/hle/service/nvflinger/nvflinger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 4bc3d7ab2..e4959a9af 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -10,8 +10,8 @@ #include #include #include -#include #include +#include #include "common/common_types.h" #include "core/hle/kernel/object.h" -- cgit v1.2.3 From 2f8947583f2f0af4058600243d6c1d244e3c4890 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 27 Jun 2020 18:20:06 -0400 Subject: Core/Common: Address Feedback. --- src/core/hle/kernel/kernel.cpp | 14 +++++--------- src/core/hle/kernel/physical_core.cpp | 4 ++++ src/core/hle/kernel/physical_core.h | 7 ++----- src/core/hle/kernel/scheduler.cpp | 4 ++-- src/core/hle/kernel/scheduler.h | 4 ++++ 5 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index dbb75416d..1f2af7a1b 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -472,16 +472,12 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - if (!IsMulticore()) { - auto& threads = GlobalScheduler().GetThreadList(); - for (auto& thread : threads) { - if (!thread->IsHLEThread()) { - auto& arm_interface = thread->ArmInterface(); - arm_interface.ClearInstructionCache(); - } + auto& threads = GlobalScheduler().GetThreadList(); + for (auto& thread : threads) { + if (!thread->IsHLEThread()) { + auto& arm_interface = thread->ArmInterface(); + arm_interface.ClearInstructionCache(); } - } else { - UNIMPLEMENTED_MSG("Cache Invalidation unimplemented for multicore"); } } diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index c82c60a16..c6bbdb080 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -37,6 +37,10 @@ void PhysicalCore::Shutdown() { scheduler.Shutdown(); } +bool PhysicalCore::IsInterrupted() const { + return interrupt_handler.IsInterrupted(); +} + void PhysicalCore::Interrupt() { guard->lock(); interrupt_handler.SetInterrupt(true); diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 85f6dec05..d7a7a951c 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -7,8 +7,6 @@ #include #include -#include "core/arm/cpu_interrupt_handler.h" - namespace Common { class SpinLock; } @@ -19,6 +17,7 @@ class Scheduler; namespace Core { class ARM_Interface; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -45,9 +44,7 @@ public: void ClearInterrupt(); /// Check if this core is interrupted - bool IsInterrupted() const { - return interrupt_handler.IsInterrupted(); - } + bool IsInterrupted() const; // Shutdown this physical core. void Shutdown(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 61b8a396a..2b12c0dbf 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -658,7 +658,7 @@ void Scheduler::Reload() { cpu_core.LoadContext(thread->GetContext64()); cpu_core.SetTlsAddress(thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -691,7 +691,7 @@ void Scheduler::SwitchContextStep2() { cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 348107160..b3b4b5169 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -240,6 +240,10 @@ public: return switch_fiber; } + const std::shared_ptr& ControlContext() const { + return switch_fiber; + } + private: friend class GlobalScheduler; -- cgit v1.2.3 From f0baf2abf2f6b5e5638117998c21daec10820990 Mon Sep 17 00:00:00 2001 From: David Marcec Date: Sun, 28 Jun 2020 16:44:36 +1000 Subject: acc: ListOpenContextStoredUsers partial stub Needed by Baldur's Gate 1/2 --- src/core/hle/service/acc/acc.cpp | 9 +++++++++ src/core/hle/service/acc/acc.h | 1 + src/core/hle/service/acc/acc_su.cpp | 2 +- src/core/hle/service/acc/acc_u0.cpp | 4 ++-- src/core/hle/service/acc/acc_u1.cpp | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 94d8c1fc6..8ac856ec3 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -776,6 +776,15 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } +void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_ACC, "(STUBBED) called"); + + // TODO(ogniK): Handle open contexts + ctx.WriteBuffer(profile_manager->GetOpenUsers()); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); +} + void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_ACC, "called"); // A u8 is passed into this function which we can safely ignore. It's to determine if we have diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 74ca39d6e..d4c6395c6 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -34,6 +34,7 @@ public: void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); void GetProfileEditor(Kernel::HLERequestContext& ctx); void ListQualifiedUsers(Kernel::HLERequestContext& ctx); + void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); private: ResultCode InitializeApplicationInfoBase(); diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 85620bde3..d2bb8c2c8 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp @@ -20,7 +20,7 @@ ACC_SU::ACC_SU(std::shared_ptr module, std::shared_ptr p {6, nullptr, "GetProfileDigest"}, // 3.0.0+ {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, - {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 + {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ {100, nullptr, "GetUserRegistrationNotifier"}, {101, nullptr, "GetUserStateChangeNotifier"}, diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 49f6e20f1..cb44e06b7 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -20,7 +20,7 @@ ACC_U0::ACC_U0(std::shared_ptr module, std::shared_ptr p {6, nullptr, "GetProfileDigest"}, // 3.0.0+ {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, - {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 + {60, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, @@ -30,7 +30,7 @@ ACC_U0::ACC_U0(std::shared_ptr module, std::shared_ptr p {111, nullptr, "ClearSaveDataThumbnail"}, {120, nullptr, "CreateGuestLoginRequest"}, {130, nullptr, "LoadOpenContext"}, // 5.0.0+ - {131, nullptr, "ListOpenContextStoredUsers"}, // 6.0.0+ + {131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+ {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ {150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, // 6.0.0+ diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index f47004f84..a4aa5316a 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp @@ -20,7 +20,7 @@ ACC_U1::ACC_U1(std::shared_ptr module, std::shared_ptr p {6, nullptr, "GetProfileDigest"}, // 3.0.0+ {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, - {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 + {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ {100, nullptr, "GetUserRegistrationNotifier"}, {101, nullptr, "GetUserStateChangeNotifier"}, -- cgit v1.2.3 From dcf345febe605d2921487926f5ead337a798048f Mon Sep 17 00:00:00 2001 From: David Marcec Date: Sun, 28 Jun 2020 16:51:28 +1000 Subject: am: Stub GetIndirectLayerConsumerHandle Needed by Monster Hunter Generations Ultimate --- src/core/hle/service/am/am.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 20f366635..1bb544dd8 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -841,7 +841,7 @@ public: {110, nullptr, "NeedsToExitProcess"}, {120, nullptr, "GetLibraryAppletInfo"}, {150, nullptr, "RequestForAppletToGetForeground"}, - {160, nullptr, "GetIndirectLayerConsumerHandle"}, + {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, }; // clang-format on @@ -960,6 +960,18 @@ private: rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); } + void GetIndirectLayerConsumerHandle(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is + // actually used anywhere + constexpr u64 handle = 0xdeadbeef; + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(handle); + } + std::shared_ptr applet; }; -- cgit v1.2.3 From db824b59c84ddf67df69c493a4def49ca32eacfc Mon Sep 17 00:00:00 2001 From: David Marcec Date: Sun, 28 Jun 2020 20:54:37 +1000 Subject: ldr: Cleanup NRO & NRR structs --- src/core/hle/service/ldr/ldr.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 9f376657c..64a526b9e 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -46,7 +46,7 @@ constexpr std::size_t DATA_INDEX{2}; struct NRRCertification { u64_le application_id_mask; u64_le application_id_pattern; - std::array reserved; + INSERT_PADDING_BYTES(0x10); std::array public_key; // Also known as modulus std::array signature; }; @@ -55,16 +55,16 @@ static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid s struct NRRHeader { u32_le magic; u32_le certification_signature_key_generation; // 9.0.0+ - u64_le reserved; + INSERT_PADDING_WORDS(2); NRRCertification certification; std::array signature; u64_le application_id; u32_le size; u8 nrr_kind; // 7.0.0+ - std::array reserved_2; + INSERT_PADDING_BYTES(3); u32_le hash_offset; u32_le hash_count; - u64_le reserved_3; + INSERT_PADDING_WORDS(2); }; static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size."); @@ -76,9 +76,9 @@ static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size."); struct NROHeader { // Switchbrew calls this "Start" (0x10) - u32_le unused; + INSERT_PADDING_WORDS(1); u32_le mod_offset; - u64_le padding; + INSERT_PADDING_WORDS(2); // Switchbrew calls this "Header" (0x70) u32_le magic; @@ -88,10 +88,10 @@ struct NROHeader { // .text, .ro, .data std::array segment_headers; u32_le bss_size; - u32_le reserved; + INSERT_PADDING_WORDS(1); std::array build_id; u32_le dso_handle_offset; - u32_le unused_2; + INSERT_PADDING_WORDS(1); // .apiInfo, .dynstr, .dynsym std::array segment_headers_2; }; -- cgit v1.2.3 From fb13f053bb6ef304bc7656b521727c87eff697f1 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 1 Jul 2020 00:28:49 -0400 Subject: key_manager: Correct casing of instance() Our codebase uppercases member function names. --- src/core/hle/service/es/es.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle') diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index da6b74a22..a41c73c48 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -302,7 +302,7 @@ private: rb.Push(write_size); } - Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); + Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); }; void InstallInterfaces(SM::ServiceManager& service_manager) { -- cgit v1.2.3