diff options
Diffstat (limited to 'src/core')
64 files changed, 1275 insertions, 341 deletions
| diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index cb77b99ee..f4325f0f8 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -175,6 +175,7 @@ add_library(core STATIC      hle/service/acc/acc_u0.h      hle/service/acc/acc_u1.cpp      hle/service/acc/acc_u1.h +    hle/service/acc/errors.h      hle/service/acc/profile_manager.cpp      hle/service/acc/profile_manager.h      hle/service/am/am.cpp @@ -207,6 +208,8 @@ add_library(core STATIC      hle/service/aoc/aoc_u.h      hle/service/apm/apm.cpp      hle/service/apm/apm.h +    hle/service/apm/controller.cpp +    hle/service/apm/controller.h      hle/service/apm/interface.cpp      hle/service/apm/interface.h      hle/service/audio/audctl.cpp @@ -270,6 +273,7 @@ add_library(core STATIC      hle/service/filesystem/fsp_srv.h      hle/service/fgm/fgm.cpp      hle/service/fgm/fgm.h +    hle/service/friend/errors.h      hle/service/friend/friend.cpp      hle/service/friend/friend.h      hle/service/friend/interface.cpp @@ -291,6 +295,7 @@ add_library(core STATIC      hle/service/hid/irs.h      hle/service/hid/xcd.cpp      hle/service/hid/xcd.h +    hle/service/hid/errors.h      hle/service/hid/controllers/controller_base.cpp      hle/service/hid/controllers/controller_base.h      hle/service/hid/controllers/debug_pad.cpp @@ -429,6 +434,8 @@ add_library(core STATIC      hle/service/time/interface.h      hle/service/time/time.cpp      hle/service/time/time.h +    hle/service/time/time_sharedmemory.cpp +    hle/service/time/time_sharedmemory.h      hle/service/usb/usb.cpp      hle/service/usb/usb.h      hle/service/vi/display/vi_display.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 262411db8..4aceee785 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -25,6 +25,7 @@  #include "core/hle/kernel/scheduler.h"  #include "core/hle/kernel/thread.h"  #include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/apm/controller.h"  #include "core/hle/service/glue/manager.h"  #include "core/hle/service/service.h"  #include "core/hle/service/sm/sm.h" @@ -143,7 +144,7 @@ struct System::Impl {          telemetry_session = std::make_unique<Core::TelemetrySession>();          service_manager = std::make_shared<Service::SM::ServiceManager>(); -        Service::Init(service_manager, system, *virtual_filesystem); +        Service::Init(service_manager, system);          GDBStub::Init();          renderer = VideoCore::CreateRenderer(emu_window, system); @@ -306,6 +307,9 @@ struct System::Impl {      /// Frontend applets      Service::AM::Applets::AppletManager applet_manager; +    /// APM (Performance) services +    Service::APM::Controller apm_controller{core_timing}; +      /// Glue services      Service::Glue::ARPManager arp_manager; @@ -568,6 +572,14 @@ const Service::Glue::ARPManager& System::GetARPManager() const {      return impl->arp_manager;  } +Service::APM::Controller& System::GetAPMController() { +    return impl->apm_controller; +} + +const Service::APM::Controller& System::GetAPMController() const { +    return impl->apm_controller; +} +  System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {      return impl->Init(*this, emu_window);  } diff --git a/src/core/core.h b/src/core/core.h index 70adb7af9..11e73278e 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -43,6 +43,10 @@ struct AppletFrontendSet;  class AppletManager;  } // namespace AM::Applets +namespace APM { +class Controller; +} +  namespace Glue {  class ARPManager;  } @@ -296,6 +300,10 @@ public:      const Service::Glue::ARPManager& GetARPManager() const; +    Service::APM::Controller& GetAPMController(); + +    const Service::APM::Controller& GetAPMController() const; +  private:      System(); diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp index ba63c3e61..99b7d387d 100644 --- a/src/core/core_cpu.cpp +++ b/src/core/core_cpu.cpp @@ -53,7 +53,7 @@ bool CpuBarrier::Rendezvous() {  Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,           std::size_t core_index)      : cpu_barrier{cpu_barrier}, core_timing{system.CoreTiming()}, core_index{core_index} { -    if (Settings::values.use_cpu_jit) { +    if (Settings::values.cpu_jit_enabled) {  #ifdef ARCHITECTURE_x86_64          arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);  #else @@ -70,7 +70,7 @@ Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_ba  Cpu::~Cpu() = default;  std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { -    if (Settings::values.use_cpu_jit) { +    if (Settings::values.cpu_jit_enabled) {  #ifdef ARCHITECTURE_x86_64          return std::make_unique<DynarmicExclusiveMonitor>(num_cores);  #else diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 41adb2302..a58f7b131 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -56,12 +56,12 @@ void CoreTiming::Initialize() {  }  void CoreTiming::Shutdown() { -    MoveEvents();      ClearPendingEvents();      UnregisterAllEvents();  }  EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) { +    std::lock_guard guard{inner_mutex};      // check for existing type with same name.      // we want event type names to remain unique so that we can use them for serialization.      ASSERT_MSG(event_types.find(name) == event_types.end(), @@ -82,6 +82,7 @@ void CoreTiming::UnregisterAllEvents() {  void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {      ASSERT(event_type != nullptr); +    std::lock_guard guard{inner_mutex};      const s64 timeout = GetTicks() + cycles_into_future;      // If this event needs to be scheduled before the next advance(), force one early @@ -93,12 +94,8 @@ void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_ty      std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());  } -void CoreTiming::ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, -                                         u64 userdata) { -    ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type}); -} -  void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) { +    std::lock_guard guard{inner_mutex};      const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {          return e.type == event_type && e.userdata == userdata;      }); @@ -110,10 +107,6 @@ void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {      }  } -void CoreTiming::UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) { -    unschedule_queue.Push(std::make_pair(event_type, userdata)); -} -  u64 CoreTiming::GetTicks() const {      u64 ticks = static_cast<u64>(global_timer);      if (!is_global_timer_sane) { @@ -135,6 +128,7 @@ void CoreTiming::ClearPendingEvents() {  }  void CoreTiming::RemoveEvent(const EventType* event_type) { +    std::lock_guard guard{inner_mutex};      const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),                                      [&](const Event& e) { return e.type == event_type; }); @@ -145,11 +139,6 @@ void CoreTiming::RemoveEvent(const EventType* event_type) {      }  } -void CoreTiming::RemoveNormalAndThreadsafeEvent(const EventType* event_type) { -    MoveEvents(); -    RemoveEvent(event_type); -} -  void CoreTiming::ForceExceptionCheck(s64 cycles) {      cycles = std::max<s64>(0, cycles);      if (downcount <= cycles) { @@ -162,19 +151,8 @@ void CoreTiming::ForceExceptionCheck(s64 cycles) {      downcount = static_cast<int>(cycles);  } -void CoreTiming::MoveEvents() { -    for (Event ev; ts_queue.Pop(ev);) { -        ev.fifo_order = event_fifo_id++; -        event_queue.emplace_back(std::move(ev)); -        std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); -    } -} -  void CoreTiming::Advance() { -    MoveEvents(); -    for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) { -        UnscheduleEvent(ev.first, ev.second); -    } +    std::unique_lock<std::mutex> guard(inner_mutex);      const int cycles_executed = slice_length - downcount;      global_timer += cycles_executed; @@ -186,7 +164,9 @@ void CoreTiming::Advance() {          Event evt = std::move(event_queue.front());          std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());          event_queue.pop_back(); +        inner_mutex.unlock();          evt.type->callback(evt.userdata, global_timer - evt.time); +        inner_mutex.lock();      }      is_global_timer_sane = false; diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 9d2efde37..161c7007d 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -6,6 +6,7 @@  #include <chrono>  #include <functional> +#include <mutex>  #include <string>  #include <unordered_map>  #include <vector> @@ -67,7 +68,7 @@ public:      ///      EventType* RegisterEvent(const std::string& name, TimedCallback callback); -    /// Unregisters all registered events thus far. +    /// Unregisters all registered events thus far. Note: not thread unsafe      void UnregisterAllEvents();      /// After the first Advance, the slice lengths and the downcount will be reduced whenever an @@ -76,20 +77,10 @@ public:      /// Scheduling from a callback will not update the downcount until the Advance() completes.      void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata = 0); -    /// This is to be called when outside of hle threads, such as the graphics thread, wants to -    /// schedule things to be executed on the main thread. -    /// -    /// @note This doesn't change slice_length and thus events scheduled by this might be -    /// called with a delay of up to MAX_SLICE_LENGTH -    void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, -                                 u64 userdata = 0); -      void UnscheduleEvent(const EventType* event_type, u64 userdata); -    void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata);      /// We only permit one event of each type in the queue at a time.      void RemoveEvent(const EventType* event_type); -    void RemoveNormalAndThreadsafeEvent(const EventType* event_type);      void ForceExceptionCheck(s64 cycles); @@ -120,7 +111,6 @@ private:      /// Clear all pending events. This should ONLY be done on exit.      void ClearPendingEvents(); -    void MoveEvents();      s64 global_timer = 0;      s64 idled_cycles = 0; @@ -143,14 +133,9 @@ private:      // remain stable regardless of rehashes/resizing.      std::unordered_map<std::string, EventType> event_types; -    // The queue for storing the events from other threads threadsafe until they will be added -    // to the event_queue by the emu thread -    Common::MPSCQueue<Event> ts_queue; - -    // The queue for unscheduling the events from other threads threadsafe -    Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue; -      EventType* ev_lost = nullptr; + +    std::mutex inner_mutex;  };  } // namespace Core::Timing diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h index 84d5cd1e0..1f82fff0a 100644 --- a/src/core/file_sys/nca_metadata.h +++ b/src/core/file_sys/nca_metadata.h @@ -35,9 +35,9 @@ enum class ContentRecordType : u8 {      Program = 1,      Data = 2,      Control = 3, -    Manual = 4, -    Legal = 5, -    Patch = 6, +    HtmlDocument = 4, +    LegalInformation = 5, +    DeltaFragment = 6,  };  struct ContentRecord { diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 4608490e0..3725b10f7 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -99,7 +99,7 @@ ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {          return ContentRecordType::Data;      case NCAContentType::Manual:          // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal. -        return ContentRecordType::Manual; +        return ContentRecordType::HtmlDocument;      default:          UNREACHABLE_MSG("Invalid NCAContentType={:02X}", static_cast<u8>(type));      } @@ -397,8 +397,8 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex      });      if (meta_iter == ncas.end()) { -        LOG_ERROR(Loader, "The XCI you are attempting to install does not have a metadata NCA and " -                          "is therefore malformed. Double check your encryption keys."); +        LOG_ERROR(Loader, "The file you are attempting to install does not have a metadata NCA and " +                          "is therefore malformed. Check your encryption keys.");          return InstallResult::ErrorMetaFailed;      } @@ -415,6 +415,9 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex      const auto cnmt_file = section0->GetFiles()[0];      const CNMT cnmt(cnmt_file);      for (const auto& record : cnmt.GetContentRecords()) { +        // Ignore DeltaFragments, they are not useful to us +        if (record.type == ContentRecordType::DeltaFragment) +            continue;          const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);          if (nca == nullptr)              return InstallResult::ErrorCopyFailed; diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index d0428a457..8b3b14e25 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp @@ -248,10 +248,13 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {                  auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));                  if (next_file == nullptr) { -                    LOG_WARNING(Service_FS, -                                "NCA with ID {}.nca is listed in content metadata, but cannot " -                                "be found in PFS. NSP appears to be corrupted.", -                                id_string); +                    if (rec.type != ContentRecordType::DeltaFragment) { +                        LOG_WARNING(Service_FS, +                                    "NCA with ID {}.nca is listed in content metadata, but cannot " +                                    "be found in PFS. NSP appears to be corrupted.", +                                    id_string); +                    } +                      continue;                  } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 7cfc513a1..f45ef05f6 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -3,6 +3,7 @@  // Refer to the license.txt file included.  #include <algorithm> +#include <bitset>  #include <memory>  #include <random>  #include "common/alignment.h" @@ -48,8 +49,58 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) {  }  } // Anonymous namespace -SharedPtr<Process> Process::Create(Core::System& system, std::string name, -                                   Process::ProcessType type) { +// Represents a page used for thread-local storage. +// +// Each TLS page contains slots that may be used by processes and threads. +// Every process and thread is created with a slot in some arbitrary page +// (whichever page happens to have an available slot). +class TLSPage { +public: +    static constexpr std::size_t num_slot_entries = Memory::PAGE_SIZE / Memory::TLS_ENTRY_SIZE; + +    explicit TLSPage(VAddr address) : base_address{address} {} + +    bool HasAvailableSlots() const { +        return !is_slot_used.all(); +    } + +    VAddr GetBaseAddress() const { +        return base_address; +    } + +    std::optional<VAddr> ReserveSlot() { +        for (std::size_t i = 0; i < is_slot_used.size(); i++) { +            if (is_slot_used[i]) { +                continue; +            } + +            is_slot_used[i] = true; +            return base_address + (i * Memory::TLS_ENTRY_SIZE); +        } + +        return std::nullopt; +    } + +    void ReleaseSlot(VAddr address) { +        // Ensure that all given addresses are consistent with how TLS pages +        // are intended to be used when releasing slots. +        ASSERT(IsWithinPage(address)); +        ASSERT((address % Memory::TLS_ENTRY_SIZE) == 0); + +        const std::size_t index = (address - base_address) / Memory::TLS_ENTRY_SIZE; +        is_slot_used[index] = false; +    } + +private: +    bool IsWithinPage(VAddr address) const { +        return base_address <= address && address < base_address + Memory::PAGE_SIZE; +    } + +    VAddr base_address; +    std::bitset<num_slot_entries> is_slot_used; +}; + +SharedPtr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) {      auto& kernel = system.Kernel();      SharedPtr<Process> process(new Process(system)); @@ -181,61 +232,55 @@ void Process::PrepareForTermination() {  }  /** - * Finds a free location for the TLS section of a thread. - * @param tls_slots The TLS page array of the thread's owner process. - * Returns a tuple of (page, slot, alloc_needed) where: - * page: The index of the first allocated TLS page that has free slots. - * slot: The index of the first free slot in the indicated page. - * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full). + * Attempts to find a TLS page that contains a free slot for + * use by a thread. + * + * @returns If a page with an available slot is found, then an iterator + *          pointing to the page is returned. Otherwise the end iterator + *          is returned instead.   */ -static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot( -    const std::vector<std::bitset<8>>& tls_slots) { -    // Iterate over all the allocated pages, and try to find one where not all slots are used. -    for (std::size_t page = 0; page < tls_slots.size(); ++page) { -        const auto& page_tls_slots = tls_slots[page]; -        if (!page_tls_slots.all()) { -            // We found a page with at least one free slot, find which slot it is -            for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) { -                if (!page_tls_slots.test(slot)) { -                    return std::make_tuple(page, slot, false); -                } -            } -        } -    } - -    return std::make_tuple(0, 0, true); +static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) { +    return std::find_if(tls_pages.begin(), tls_pages.end(), +                        [](const auto& page) { return page.HasAvailableSlots(); });  } -VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { -    auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots); -    const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress(); +VAddr Process::CreateTLSRegion() { +    auto tls_page_iter = FindTLSPageWithAvailableSlots(tls_pages); -    if (needs_allocation) { -        tls_slots.emplace_back(0); // The page is completely available at the start -        available_page = tls_slots.size() - 1; -        available_slot = 0; // Use the first slot in the new page +    if (tls_page_iter == tls_pages.cend()) { +        const auto region_address = +            vm_manager.FindFreeRegion(vm_manager.GetTLSIORegionBaseAddress(), +                                      vm_manager.GetTLSIORegionEndAddress(), Memory::PAGE_SIZE); +        ASSERT(region_address.Succeeded()); -        // Allocate some memory from the end of the linear heap for this region. -        auto& tls_memory = thread.GetTLSMemory(); -        tls_memory->insert(tls_memory->end(), Memory::PAGE_SIZE, 0); +        const auto map_result = vm_manager.MapMemoryBlock( +            *region_address, std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE), 0, +            Memory::PAGE_SIZE, MemoryState::ThreadLocal); +        ASSERT(map_result.Succeeded()); -        vm_manager.RefreshMemoryBlockMappings(tls_memory.get()); +        tls_pages.emplace_back(*region_address); -        vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0, -                                  Memory::PAGE_SIZE, MemoryState::ThreadLocal); -    } +        const auto reserve_result = tls_pages.back().ReserveSlot(); +        ASSERT(reserve_result.has_value()); -    tls_slots[available_page].set(available_slot); +        return *reserve_result; +    } -    return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE; +    return *tls_page_iter->ReserveSlot();  } -void Process::FreeTLSSlot(VAddr tls_address) { -    const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress(); -    const VAddr tls_page = tls_base / Memory::PAGE_SIZE; -    const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; +void Process::FreeTLSRegion(VAddr tls_address) { +    const VAddr aligned_address = Common::AlignDown(tls_address, Memory::PAGE_SIZE); +    auto iter = +        std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { +            return page.GetBaseAddress() == aligned_address; +        }); + +    // Something has gone very wrong if we're freeing a region +    // with no actual page available. +    ASSERT(iter != tls_pages.cend()); -    tls_slots[tls_page].reset(tls_slot); +    iter->ReleaseSlot(tls_address);  }  void Process::LoadModule(CodeSet module_, VAddr base_addr) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 248fd3840..83ea02bee 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -5,7 +5,6 @@  #pragma once  #include <array> -#include <bitset>  #include <cstddef>  #include <list>  #include <string> @@ -32,6 +31,7 @@ namespace Kernel {  class KernelCore;  class ResourceLimit;  class Thread; +class TLSPage;  struct CodeSet; @@ -260,10 +260,10 @@ public:      // Thread-local storage management      // Marks the next available region as used and returns the address of the slot. -    VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread); +    [[nodiscard]] VAddr CreateTLSRegion();      // Frees a used TLS slot identified by the given address -    void FreeTLSSlot(VAddr tls_address); +    void FreeTLSRegion(VAddr tls_address);  private:      explicit Process(Core::System& system); @@ -290,7 +290,7 @@ private:      u64 code_memory_size = 0;      /// Current status of the process -    ProcessStatus status; +    ProcessStatus status{};      /// The ID of this process      u64 process_id = 0; @@ -310,7 +310,7 @@ private:      /// holds the TLS for a specific thread. This vector contains which parts are in use for each      /// page as a bitmask.      /// This vector will grow as more pages are allocated for new threads. -    std::vector<std::bitset<8>> tls_slots; +    std::vector<TLSPage> tls_pages;      /// Contains the parsed process capability descriptors.      ProcessCapabilities capabilities; @@ -339,7 +339,7 @@ private:      Mutex mutex;      /// Random values for svcGetInfo RandomEntropy -    std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; +    std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{};      /// List of threads that are running with this process as their owner.      std::list<const Thread*> thread_list; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index de6363ff2..332573a95 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -98,9 +98,9 @@ ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_add          return ERR_INVALID_ADDRESS_STATE;      } -    if (!vm_manager.IsWithinNewMapRegion(dst_addr, size)) { +    if (!vm_manager.IsWithinStackRegion(dst_addr, size)) {          LOG_ERROR(Kernel_SVC, -                  "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}", +                  "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}",                    dst_addr, size);          return ERR_INVALID_MEMORY_RANGE;      } @@ -726,8 +726,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha          // 2.0.0+          ASLRRegionBaseAddr = 12,          ASLRRegionSize = 13, -        NewMapRegionBaseAddr = 14, -        NewMapRegionSize = 15, +        StackRegionBaseAddr = 14, +        StackRegionSize = 15,          // 3.0.0+          IsVirtualAddressMemoryEnabled = 16,          PersonalMmHeapUsage = 17, @@ -752,8 +752,8 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha      case GetInfoType::HeapRegionSize:      case GetInfoType::ASLRRegionBaseAddr:      case GetInfoType::ASLRRegionSize: -    case GetInfoType::NewMapRegionBaseAddr: -    case GetInfoType::NewMapRegionSize: +    case GetInfoType::StackRegionBaseAddr: +    case GetInfoType::StackRegionSize:      case GetInfoType::TotalPhysicalMemoryAvailable:      case GetInfoType::TotalPhysicalMemoryUsed:      case GetInfoType::IsVirtualAddressMemoryEnabled: @@ -806,12 +806,12 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, u64 ha              *result = process->VMManager().GetASLRRegionSize();              return RESULT_SUCCESS; -        case GetInfoType::NewMapRegionBaseAddr: -            *result = process->VMManager().GetNewMapRegionBaseAddress(); +        case GetInfoType::StackRegionBaseAddr: +            *result = process->VMManager().GetStackRegionBaseAddress();              return RESULT_SUCCESS; -        case GetInfoType::NewMapRegionSize: -            *result = process->VMManager().GetNewMapRegionSize(); +        case GetInfoType::StackRegionSize: +            *result = process->VMManager().GetStackRegionSize();              return RESULT_SUCCESS;          case GetInfoType::TotalPhysicalMemoryAvailable: diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index c73a40977..ec529e7f2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -65,7 +65,7 @@ void Thread::Stop() {      owner_process->UnregisterThread(this);      // Mark the TLS slot in the thread's page as free. -    owner_process->FreeTLSSlot(tls_address); +    owner_process->FreeTLSRegion(tls_address);  }  void Thread::WakeAfterDelay(s64 nanoseconds) { @@ -76,13 +76,13 @@ 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().ScheduleEventThreadsafe( +    Core::System::GetInstance().CoreTiming().ScheduleEvent(          cycles, kernel.ThreadWakeupCallbackEventType(), callback_handle);  }  void Thread::CancelWakeupTimer() { -    Core::System::GetInstance().CoreTiming().UnscheduleEventThreadsafe( -        kernel.ThreadWakeupCallbackEventType(), callback_handle); +    Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), +                                                             callback_handle);  }  static std::optional<s32> GetNextProcessorId(u64 mask) { @@ -205,9 +205,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name      thread->name = std::move(name);      thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();      thread->owner_process = &owner_process; +    thread->tls_address = thread->owner_process->CreateTLSRegion();      thread->scheduler = &system.Scheduler(processor_id);      thread->scheduler->AddThread(thread); -    thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);      thread->owner_process->RegisterThread(thread.get()); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index b4b9cda7c..07e989637 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -5,7 +5,6 @@  #pragma once  #include <functional> -#include <memory>  #include <string>  #include <vector> @@ -78,9 +77,6 @@ enum class ThreadActivity : u32 {  class Thread final : public WaitObject {  public: -    using TLSMemory = std::vector<u8>; -    using TLSMemoryPtr = std::shared_ptr<TLSMemory>; -      using MutexWaitingThreads = std::vector<SharedPtr<Thread>>;      using ThreadContext = Core::ARM_Interface::ThreadContext; @@ -169,14 +165,6 @@ public:          return thread_id;      } -    TLSMemoryPtr& GetTLSMemory() { -        return tls_memory; -    } - -    const TLSMemoryPtr& GetTLSMemory() const { -        return tls_memory; -    } -      /// Resumes a thread from waiting      void ResumeFromWait(); @@ -463,11 +451,9 @@ private:      u32 ideal_core{0xFFFFFFFF};      u64 affinity_mask{0x1}; -    TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>(); +    ThreadActivity activity = ThreadActivity::Normal;      std::string name; - -    ThreadActivity activity = ThreadActivity::Normal;  };  /** diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index c929c2a52..501544090 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -152,22 +152,33 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me  }  ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const { -    // Find the first Free VMA. -    const VAddr base = GetASLRRegionBaseAddress(); -    const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { -        if (vma.second.type != VMAType::Free) -            return false; +    return FindFreeRegion(GetASLRRegionBaseAddress(), GetASLRRegionEndAddress(), size); +} -        const VAddr vma_end = vma.second.base + vma.second.size; -        return vma_end > base && vma_end >= base + size; -    }); +ResultVal<VAddr> VMManager::FindFreeRegion(VAddr begin, VAddr end, u64 size) const { +    ASSERT(begin < end); +    ASSERT(size <= end - begin); -    if (vma_handle == vma_map.end()) { +    const VMAHandle vma_handle = +        std::find_if(vma_map.begin(), vma_map.end(), [begin, end, size](const auto& vma) { +            if (vma.second.type != VMAType::Free) { +                return false; +            } +            const VAddr vma_base = vma.second.base; +            const VAddr vma_end = vma_base + vma.second.size; +            const VAddr assumed_base = (begin < vma_base) ? vma_base : begin; +            const VAddr used_range = assumed_base + size; + +            return vma_base <= assumed_base && assumed_base < used_range && used_range < end && +                   used_range <= vma_end; +        }); + +    if (vma_handle == vma_map.cend()) {          // TODO(Subv): Find the correct error code here.          return ResultCode(-1);      } -    const VAddr target = std::max(base, vma_handle->second.base); +    const VAddr target = std::max(begin, vma_handle->second.base);      return MakeResult<VAddr>(target);  } @@ -614,9 +625,11 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {  void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) {      u64 map_region_size = 0;      u64 heap_region_size = 0; -    u64 new_map_region_size = 0; +    u64 stack_region_size = 0;      u64 tls_io_region_size = 0; +    u64 stack_and_tls_io_end = 0; +      switch (type) {      case FileSys::ProgramAddressSpaceType::Is32Bit:      case FileSys::ProgramAddressSpaceType::Is32BitNoMap: @@ -632,6 +645,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty              map_region_size = 0;              heap_region_size = 0x80000000;          } +        stack_and_tls_io_end = 0x40000000;          break;      case FileSys::ProgramAddressSpaceType::Is36Bit:          address_space_width = 36; @@ -641,6 +655,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty          aslr_region_end = aslr_region_base + 0xFF8000000;          map_region_size = 0x180000000;          heap_region_size = 0x180000000; +        stack_and_tls_io_end = 0x80000000;          break;      case FileSys::ProgramAddressSpaceType::Is39Bit:          address_space_width = 39; @@ -650,7 +665,7 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty          aslr_region_end = aslr_region_base + 0x7FF8000000;          map_region_size = 0x1000000000;          heap_region_size = 0x180000000; -        new_map_region_size = 0x80000000; +        stack_region_size = 0x80000000;          tls_io_region_size = 0x1000000000;          break;      default: @@ -658,6 +673,8 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty          return;      } +    const u64 stack_and_tls_io_begin = aslr_region_base; +      address_space_base = 0;      address_space_end = 1ULL << address_space_width; @@ -668,15 +685,20 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty      heap_region_end = heap_region_base + heap_region_size;      heap_end = heap_region_base; -    new_map_region_base = heap_region_end; -    new_map_region_end = new_map_region_base + new_map_region_size; +    stack_region_base = heap_region_end; +    stack_region_end = stack_region_base + stack_region_size; -    tls_io_region_base = new_map_region_end; +    tls_io_region_base = stack_region_end;      tls_io_region_end = tls_io_region_base + tls_io_region_size; -    if (new_map_region_size == 0) { -        new_map_region_base = address_space_base; -        new_map_region_end = address_space_end; +    if (stack_region_size == 0) { +        stack_region_base = stack_and_tls_io_begin; +        stack_region_end = stack_and_tls_io_end; +    } + +    if (tls_io_region_size == 0) { +        tls_io_region_base = stack_and_tls_io_begin; +        tls_io_region_end = stack_and_tls_io_end;      }  } @@ -868,21 +890,21 @@ bool VMManager::IsWithinMapRegion(VAddr address, u64 size) const {      return IsInsideAddressRange(address, size, GetMapRegionBaseAddress(), GetMapRegionEndAddress());  } -VAddr VMManager::GetNewMapRegionBaseAddress() const { -    return new_map_region_base; +VAddr VMManager::GetStackRegionBaseAddress() const { +    return stack_region_base;  } -VAddr VMManager::GetNewMapRegionEndAddress() const { -    return new_map_region_end; +VAddr VMManager::GetStackRegionEndAddress() const { +    return stack_region_end;  } -u64 VMManager::GetNewMapRegionSize() const { -    return new_map_region_end - new_map_region_base; +u64 VMManager::GetStackRegionSize() const { +    return stack_region_end - stack_region_base;  } -bool VMManager::IsWithinNewMapRegion(VAddr address, u64 size) const { -    return IsInsideAddressRange(address, size, GetNewMapRegionBaseAddress(), -                                GetNewMapRegionEndAddress()); +bool VMManager::IsWithinStackRegion(VAddr address, u64 size) const { +    return IsInsideAddressRange(address, size, GetStackRegionBaseAddress(), +                                GetStackRegionEndAddress());  }  VAddr VMManager::GetTLSIORegionBaseAddress() const { diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index dfbf7a894..9fe6ac3f4 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -362,14 +362,39 @@ public:      ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state);      /** -     * Finds the first free address that can hold a region of the desired size. +     * Finds the first free memory region of the given size within +     * the user-addressable ASLR memory region.       * -     * @param size Size of the desired region. -     * @return The found free address. +     * @param size The size of the desired region in bytes. +     * +     * @returns If successful, the base address of the free region with +     *          the given size.       */      ResultVal<VAddr> FindFreeRegion(u64 size) const;      /** +     * Finds the first free address range that can hold a region of the desired size +     * +     * @param begin The starting address of the range. +     *              This is treated as an inclusive beginning address. +     * +     * @param end   The ending address of the range. +     *              This is treated as an exclusive ending address. +     * +     * @param size  The size of the free region to attempt to locate, +     *              in bytes. +     * +     * @returns If successful, the base address of the free region with +     *          the given size. +     * +     * @returns If unsuccessful, a result containing an error code. +     * +     * @pre The starting address must be less than the ending address. +     * @pre The size must not exceed the address range itself. +     */ +    ResultVal<VAddr> FindFreeRegion(VAddr begin, VAddr end, u64 size) const; + +    /**       * Maps a memory-mapped IO region at a given address.       *       * @param target The guest address to start the mapping at. @@ -571,17 +596,17 @@ public:      /// Determines whether or not the specified range is within the map region.      bool IsWithinMapRegion(VAddr address, u64 size) const; -    /// Gets the base address of the new map region. -    VAddr GetNewMapRegionBaseAddress() const; +    /// Gets the base address of the stack region. +    VAddr GetStackRegionBaseAddress() const; -    /// Gets the end address of the new map region. -    VAddr GetNewMapRegionEndAddress() const; +    /// Gets the end address of the stack region. +    VAddr GetStackRegionEndAddress() const; -    /// Gets the total size of the new map region in bytes. -    u64 GetNewMapRegionSize() const; +    /// Gets the total size of the stack region in bytes. +    u64 GetStackRegionSize() const; -    /// Determines whether or not the given address range is within the new map region -    bool IsWithinNewMapRegion(VAddr address, u64 size) const; +    /// Determines whether or not the given address range is within the stack region +    bool IsWithinStackRegion(VAddr address, u64 size) const;      /// Gets the base address of the TLS IO region.      VAddr GetTLSIORegionBaseAddress() const; @@ -701,8 +726,8 @@ private:      VAddr map_region_base = 0;      VAddr map_region_end = 0; -    VAddr new_map_region_base = 0; -    VAddr new_map_region_end = 0; +    VAddr stack_region_base = 0; +    VAddr stack_region_end = 0;      VAddr tls_io_region_base = 0;      VAddr tls_io_region_end = 0; diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 0cd8158df..c01ee3eda 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -15,13 +15,18 @@  #include "core/file_sys/control_metadata.h"  #include "core/file_sys/patch_manager.h"  #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/kernel.h"  #include "core/hle/kernel/process.h"  #include "core/hle/service/acc/acc.h"  #include "core/hle/service/acc/acc_aa.h"  #include "core/hle/service/acc/acc_su.h"  #include "core/hle/service/acc/acc_u0.h"  #include "core/hle/service/acc/acc_u1.h" +#include "core/hle/service/acc/errors.h"  #include "core/hle/service/acc/profile_manager.h" +#include "core/hle/service/glue/arp.h" +#include "core/hle/service/glue/manager.h" +#include "core/hle/service/sm/sm.h"  #include "core/loader/loader.h"  namespace Service::Account { @@ -217,10 +222,72 @@ void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestCon      rb.Push(profile_manager->CanSystemRegisterUser());  } -void Module::Interface::InitializeApplicationInfoOld(Kernel::HLERequestContext& ctx) { -    LOG_WARNING(Service_ACC, "(STUBBED) called"); +void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    auto pid = rp.Pop<u64>(); + +    LOG_DEBUG(Service_ACC, "called, process_id={}", pid);      IPC::ResponseBuilder rb{ctx, 2}; -    rb.Push(RESULT_SUCCESS); +    rb.Push(InitializeApplicationInfoBase(pid)); +} + +void Module::Interface::InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    auto pid = rp.Pop<u64>(); + +    LOG_WARNING(Service_ACC, "(Partial implementation) called, process_id={}", pid); + +    // TODO(ogniK): We require checking if the user actually owns the title and what not. As of +    // currently, we assume the user owns the title. InitializeApplicationInfoBase SHOULD be called +    // first then we do extra checks if the game is a digital copy. + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(InitializeApplicationInfoBase(pid)); +} + +ResultCode Module::Interface::InitializeApplicationInfoBase(u64 process_id) { +    if (application_info) { +        LOG_ERROR(Service_ACC, "Application already initialized"); +        return ERR_ACCOUNTINFO_ALREADY_INITIALIZED; +    } + +    const auto& list = system.Kernel().GetProcessList(); +    const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) { +        return process->GetProcessID() == process_id; +    }); + +    if (iter == list.end()) { +        LOG_ERROR(Service_ACC, "Failed to find process ID"); +        application_info.application_type = ApplicationType::Unknown; + +        return ERR_ACCOUNTINFO_BAD_APPLICATION; +    } + +    const auto launch_property = system.GetARPManager().GetLaunchProperty((*iter)->GetTitleID()); + +    if (launch_property.Failed()) { +        LOG_ERROR(Service_ACC, "Failed to get launch property"); +        return ERR_ACCOUNTINFO_BAD_APPLICATION; +    } + +    switch (launch_property->base_game_storage_id) { +    case FileSys::StorageId::GameCard: +        application_info.application_type = ApplicationType::GameCard; +        break; +    case FileSys::StorageId::Host: +    case FileSys::StorageId::NandUser: +    case FileSys::StorageId::SdCard: +        application_info.application_type = ApplicationType::Digital; +        break; +    default: +        LOG_ERROR(Service_ACC, "Invalid game storage ID"); +        return ERR_ACCOUNTINFO_BAD_APPLICATION; +    } + +    LOG_WARNING(Service_ACC, "ApplicationInfo init required"); +    // TODO(ogniK): Actual initalization here + +    return RESULT_SUCCESS;  }  void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 350f123a0..f651773b7 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h @@ -4,6 +4,7 @@  #pragma once +#include "core/hle/service/glue/manager.h"  #include "core/hle/service/service.h"  namespace Service::Account { @@ -25,12 +26,33 @@ public:          void ListOpenUsers(Kernel::HLERequestContext& ctx);          void GetLastOpenedUser(Kernel::HLERequestContext& ctx);          void GetProfile(Kernel::HLERequestContext& ctx); -        void InitializeApplicationInfoOld(Kernel::HLERequestContext& ctx); +        void InitializeApplicationInfo(Kernel::HLERequestContext& ctx); +        void InitializeApplicationInfoRestricted(Kernel::HLERequestContext& ctx);          void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);          void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);          void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);          void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); +    private: +        ResultCode InitializeApplicationInfoBase(u64 process_id); + +        enum class ApplicationType : u32_le { +            GameCard = 0, +            Digital = 1, +            Unknown = 3, +        }; + +        struct ApplicationInfo { +            Service::Glue::ApplicationLaunchProperty launch_property; +            ApplicationType application_type; + +            constexpr explicit operator bool() const { +                return launch_property.title_id != 0x0; +            } +        }; + +        ApplicationInfo application_info{}; +      protected:          std::shared_ptr<Module> module;          std::shared_ptr<ProfileManager> profile_manager; diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 2f239e8c0..0ac19f4ff 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp @@ -22,7 +22,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p          {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},          {60, nullptr, "ListOpenContextStoredUsers"},          {99, nullptr, "DebugActivateOpenContextRetention"}, -        {100, &ACC_U0::InitializeApplicationInfoOld, "InitializeApplicationInfoOld"}, +        {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},          {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},          {102, nullptr, "AuthenticateApplicationAsync"},          {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, @@ -31,7 +31,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p          {120, nullptr, "CreateGuestLoginRequest"},          {130, nullptr, "LoadOpenContext"},          {131, nullptr, "ListOpenContextStoredUsers"}, -        {140, nullptr, "InitializeApplicationInfo"}, +        {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"},          {141, nullptr, "ListQualifiedUsers"},          {150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"},      }; diff --git a/src/core/hle/service/acc/errors.h b/src/core/hle/service/acc/errors.h new file mode 100644 index 000000000..1f0577239 --- /dev/null +++ b/src/core/hle/service/acc/errors.h @@ -0,0 +1,14 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Service::Account { + +constexpr ResultCode ERR_ACCOUNTINFO_BAD_APPLICATION{ErrorModule::Account, 22}; +constexpr ResultCode ERR_ACCOUNTINFO_ALREADY_INITIALIZED{ErrorModule::Account, 41}; + +} // namespace Service::Account diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 33cebb48b..9fdcf2965 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -29,7 +29,8 @@  #include "core/hle/service/am/omm.h"  #include "core/hle/service/am/spsm.h"  #include "core/hle/service/am/tcap.h" -#include "core/hle/service/apm/apm.h" +#include "core/hle/service/apm/controller.h" +#include "core/hle/service/apm/interface.h"  #include "core/hle/service/filesystem/filesystem.h"  #include "core/hle/service/ns/ns.h"  #include "core/hle/service/nvflinger/nvflinger.h" @@ -270,7 +271,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger          {70, nullptr, "ReportMultimediaError"},          {71, nullptr, "GetCurrentIlluminanceEx"},          {80, nullptr, "SetWirelessPriorityMode"}, -        {90, nullptr, "GetAccumulatedSuspendedTickValue"}, +        {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},          {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},          {100, nullptr, "SetAlbumImageTakenNotificationEnabled"},          {1000, nullptr, "GetDebugStorageChannel"}, @@ -283,10 +284,14 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger      launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,                                                                "ISelfController:LaunchableEvent"); -    // TODO(ogniK): Figure out where, when and why this event gets signalled +    // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is +    // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple +    // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not +    // suspended if the event has previously been created by a call to +    // GetAccumulatedSuspendedTickChangedEvent.      accumulated_suspended_tick_changed_event = Kernel::WritableEvent::CreateEventPair(          kernel, Kernel::ResetType::Manual, "ISelfController:AccumulatedSuspendedTickChangedEvent"); -    accumulated_suspended_tick_changed_event.writable->Signal(); //	Is signalled on creation +    accumulated_suspended_tick_changed_event.writable->Signal();  }  ISelfController::~ISelfController() = default; @@ -449,11 +454,19 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c      rb.Push<u32>(idle_time_detection_extension);  } +void ISelfController::GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_AM, "called."); + +    // This command returns the total number of system ticks since ISelfController creation +    // where the game was suspended. Since Yuzu doesn't implement game suspension, this command +    // can just always return 0 ticks. +    IPC::ResponseBuilder rb{ctx, 4}; +    rb.Push(RESULT_SUCCESS); +    rb.Push<u64>(0); +} +  void ISelfController::GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx) { -    // The implementation of this function is fine as is, the reason we're labelling it as stubbed -    // is because we're currently unsure when and where accumulated_suspended_tick_changed_event is -    // actually signalled for the time being. -    LOG_WARNING(Service_AM, "(STUBBED) called"); +    LOG_DEBUG(Service_AM, "called.");      IPC::ResponseBuilder rb{ctx, 2, 1};      rb.Push(RESULT_SUCCESS); @@ -508,8 +521,9 @@ void AppletMessageQueue::OperationModeChanged() {      on_operation_mode_changed.writable->Signal();  } -ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) -    : ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) { +ICommonStateGetter::ICommonStateGetter(Core::System& system, +                                       std::shared_ptr<AppletMessageQueue> msg_queue) +    : ServiceFramework("ICommonStateGetter"), system(system), msg_queue(std::move(msg_queue)) {      // clang-format off      static const FunctionInfo functions[] = {          {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, @@ -542,7 +556,7 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q          {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},          {64, nullptr, "SetTvPowerStateMatchingMode"},          {65, nullptr, "GetApplicationIdByContentActionName"}, -        {66, nullptr, "SetCpuBoostMode"}, +        {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},          {80, nullptr, "PerformSystemButtonPressingIfInFocus"},          {90, nullptr, "SetPerformanceConfigurationChangedNotification"},          {91, nullptr, "GetCurrentPerformanceConfiguration"}, @@ -623,6 +637,16 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&      }  } +void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS"); + +    const auto& sm = system.ServiceManager(); +    const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys"); +    ASSERT(apm_sys != nullptr); + +    apm_sys->SetCpuBoostMode(ctx); +} +  IStorage::IStorage(std::vector<u8> buffer)      : ServiceFramework("IStorage"), buffer(std::move(buffer)) {      // clang-format off @@ -651,13 +675,11 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {  }  void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { -    const bool use_docked_mode{Settings::values.use_docked_mode}; -    LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); +    LOG_DEBUG(Service_AM, "called");      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked -                                             : APM::PerformanceMode::Handheld)); +    rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());  }  class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 4ea609d23..14b010164 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -133,6 +133,7 @@ private:      void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx);      void SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);      void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); +    void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);      void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);      std::shared_ptr<NVFlinger::NVFlinger> nvflinger; @@ -145,7 +146,8 @@ private:  class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {  public: -    explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue); +    explicit ICommonStateGetter(Core::System& system, +                                std::shared_ptr<AppletMessageQueue> msg_queue);      ~ICommonStateGetter() override;  private: @@ -167,7 +169,9 @@ private:      void GetPerformanceMode(Kernel::HLERequestContext& ctx);      void GetBootMode(Kernel::HLERequestContext& ctx);      void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); +    void SetCpuBoostMode(Kernel::HLERequestContext& ctx); +    Core::System& system;      std::shared_ptr<AppletMessageQueue> msg_queue;  }; diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index fe5beb8f9..a34368c8b 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp @@ -42,7 +42,7 @@ private:          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ICommonStateGetter>(msg_queue); +        rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);      }      void GetSelfController(Kernel::HLERequestContext& ctx) { @@ -146,7 +146,7 @@ private:          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ICommonStateGetter>(msg_queue); +        rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);      }      void GetSelfController(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index 6e255fe95..5d53ef113 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp @@ -80,7 +80,7 @@ private:          IPC::ResponseBuilder rb{ctx, 2, 0, 1};          rb.Push(RESULT_SUCCESS); -        rb.PushIpcInterface<ICommonStateGetter>(msg_queue); +        rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);      }      void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 2762e0653..f3c9fef0e 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -459,10 +459,10 @@ void WebBrowser::InitializeOffline() {      case OfflineWebSource::OfflineHtmlPage:          // While there is an AppID TLV field, in official SW this is always ignored.          title_id = 0; -        type = FileSys::ContentRecordType::Manual; +        type = FileSys::ContentRecordType::HtmlDocument;          break;      case OfflineWebSource::ApplicationLegalInformation: -        type = FileSys::ContentRecordType::Legal; +        type = FileSys::ContentRecordType::LegalInformation;          break;      case OfflineWebSource::SystemDataPage:          type = FileSys::ContentRecordType::Data; diff --git a/src/core/hle/service/apm/apm.cpp b/src/core/hle/service/apm/apm.cpp index f3c09bbb1..85bbf5988 100644 --- a/src/core/hle/service/apm/apm.cpp +++ b/src/core/hle/service/apm/apm.cpp @@ -2,7 +2,6 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. -#include "common/logging/log.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/service/apm/apm.h"  #include "core/hle/service/apm/interface.h" @@ -12,11 +11,15 @@ namespace Service::APM {  Module::Module() = default;  Module::~Module() = default; -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(Core::System& system) {      auto module_ = std::make_shared<Module>(); -    std::make_shared<APM>(module_, "apm")->InstallAsService(service_manager); -    std::make_shared<APM>(module_, "apm:p")->InstallAsService(service_manager); -    std::make_shared<APM_Sys>()->InstallAsService(service_manager); +    std::make_shared<APM>(module_, system.GetAPMController(), "apm") +        ->InstallAsService(system.ServiceManager()); +    std::make_shared<APM>(module_, system.GetAPMController(), "apm:p") +        ->InstallAsService(system.ServiceManager()); +    std::make_shared<APM>(module_, system.GetAPMController(), "apm:am") +        ->InstallAsService(system.ServiceManager()); +    std::make_shared<APM_Sys>(system.GetAPMController())->InstallAsService(system.ServiceManager());  }  } // namespace Service::APM diff --git a/src/core/hle/service/apm/apm.h b/src/core/hle/service/apm/apm.h index 4d7d5bb7c..cf4c2bb11 100644 --- a/src/core/hle/service/apm/apm.h +++ b/src/core/hle/service/apm/apm.h @@ -8,11 +8,6 @@  namespace Service::APM { -enum class PerformanceMode : u8 { -    Handheld = 0, -    Docked = 1, -}; -  class Module final {  public:      Module(); @@ -20,6 +15,6 @@ public:  };  /// Registers all AM services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(Core::System& system);  } // namespace Service::APM diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp new file mode 100644 index 000000000..4376612eb --- /dev/null +++ b/src/core/hle/service/apm/controller.cpp @@ -0,0 +1,68 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/core_timing.h" +#include "core/hle/service/apm/controller.h" +#include "core/settings.h" + +namespace Service::APM { + +constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION = +    PerformanceConfiguration::Config7; + +Controller::Controller(Core::Timing::CoreTiming& core_timing) +    : core_timing(core_timing), configs{ +                                    {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, +                                    {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, +                                } {} + +Controller::~Controller() = default; + +void Controller::SetPerformanceConfiguration(PerformanceMode mode, +                                             PerformanceConfiguration config) { +    static const std::map<PerformanceConfiguration, u32> PCONFIG_TO_SPEED_MAP{ +        {PerformanceConfiguration::Config1, 1020},  {PerformanceConfiguration::Config2, 1020}, +        {PerformanceConfiguration::Config3, 1224},  {PerformanceConfiguration::Config4, 1020}, +        {PerformanceConfiguration::Config5, 1020},  {PerformanceConfiguration::Config6, 1224}, +        {PerformanceConfiguration::Config7, 1020},  {PerformanceConfiguration::Config8, 1020}, +        {PerformanceConfiguration::Config9, 1020},  {PerformanceConfiguration::Config10, 1020}, +        {PerformanceConfiguration::Config11, 1020}, {PerformanceConfiguration::Config12, 1020}, +        {PerformanceConfiguration::Config13, 1785}, {PerformanceConfiguration::Config14, 1785}, +        {PerformanceConfiguration::Config15, 1020}, {PerformanceConfiguration::Config16, 1020}, +    }; + +    SetClockSpeed(PCONFIG_TO_SPEED_MAP.find(config)->second); +    configs.insert_or_assign(mode, config); +} + +void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { +    constexpr std::array<PerformanceConfiguration, 3> BOOST_MODE_TO_CONFIG_MAP{{ +        PerformanceConfiguration::Config7, +        PerformanceConfiguration::Config13, +        PerformanceConfiguration::Config15, +    }}; + +    SetPerformanceConfiguration(PerformanceMode::Docked, +                                BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode))); +} + +PerformanceMode Controller::GetCurrentPerformanceMode() { +    return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; +} + +PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { +    if (configs.find(mode) == configs.end()) { +        configs.insert_or_assign(mode, DEFAULT_PERFORMANCE_CONFIGURATION); +    } + +    return configs[mode]; +} + +void Controller::SetClockSpeed(u32 mhz) { +    LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); +    // TODO(DarkLordZach): Actually signal core_timing to change clock speed. +} + +} // namespace Service::APM diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h new file mode 100644 index 000000000..8ac80eaea --- /dev/null +++ b/src/core/hle/service/apm/controller.h @@ -0,0 +1,70 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <map> +#include "common/common_types.h" + +namespace Core::Timing { +class CoreTiming; +} + +namespace Service::APM { + +enum class PerformanceConfiguration : u32 { +    Config1 = 0x00010000, +    Config2 = 0x00010001, +    Config3 = 0x00010002, +    Config4 = 0x00020000, +    Config5 = 0x00020001, +    Config6 = 0x00020002, +    Config7 = 0x00020003, +    Config8 = 0x00020004, +    Config9 = 0x00020005, +    Config10 = 0x00020006, +    Config11 = 0x92220007, +    Config12 = 0x92220008, +    Config13 = 0x92220009, +    Config14 = 0x9222000A, +    Config15 = 0x9222000B, +    Config16 = 0x9222000C, +}; + +enum class CpuBoostMode : u32 { +    Disabled = 0, +    Full = 1,    // CPU + GPU -> Config 13, 14, 15, or 16 +    Partial = 2, // GPU Only -> Config 15 or 16 +}; + +enum class PerformanceMode : u8 { +    Handheld = 0, +    Docked = 1, +}; + +// Class to manage the state and change of the emulated system performance. +// Specifically, this deals with PerformanceMode, which corresponds to the system being docked or +// undocked, and PerformanceConfig which specifies the exact CPU, GPU, and Memory clocks to operate +// at. Additionally, this manages 'Boost Mode', which allows games to temporarily overclock the +// system during times of high load -- this simply maps to different PerformanceConfigs to use. +class Controller { +public: +    Controller(Core::Timing::CoreTiming& core_timing); +    ~Controller(); + +    void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); +    void SetFromCpuBoostMode(CpuBoostMode mode); + +    PerformanceMode GetCurrentPerformanceMode(); +    PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode); + +private: +    void SetClockSpeed(u32 mhz); + +    std::map<PerformanceMode, PerformanceConfiguration> configs; + +    Core::Timing::CoreTiming& core_timing; +}; + +} // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index d058c0245..06f0f8edd 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp @@ -5,43 +5,32 @@  #include "common/logging/log.h"  #include "core/hle/ipc_helpers.h"  #include "core/hle/service/apm/apm.h" +#include "core/hle/service/apm/controller.h"  #include "core/hle/service/apm/interface.h"  namespace Service::APM {  class ISession final : public ServiceFramework<ISession> {  public: -    ISession() : ServiceFramework("ISession") { +    ISession(Controller& controller) : ServiceFramework("ISession"), controller(controller) {          static const FunctionInfo functions[] = {              {0, &ISession::SetPerformanceConfiguration, "SetPerformanceConfiguration"},              {1, &ISession::GetPerformanceConfiguration, "GetPerformanceConfiguration"}, +            {2, nullptr, "SetCpuOverclockEnabled"},          };          RegisterHandlers(functions);      }  private: -    enum class PerformanceConfiguration : u32 { -        Config1 = 0x00010000, -        Config2 = 0x00010001, -        Config3 = 0x00010002, -        Config4 = 0x00020000, -        Config5 = 0x00020001, -        Config6 = 0x00020002, -        Config7 = 0x00020003, -        Config8 = 0x00020004, -        Config9 = 0x00020005, -        Config10 = 0x00020006, -        Config11 = 0x92220007, -        Config12 = 0x92220008, -    }; -      void SetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {          IPC::RequestParser rp{ctx}; -        auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); -        u32 config = rp.Pop<u32>(); -        LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), -                    config); +        const auto mode = rp.PopEnum<PerformanceMode>(); +        const auto config = rp.PopEnum<PerformanceConfiguration>(); +        LOG_DEBUG(Service_APM, "called mode={} config={}", static_cast<u32>(mode), +                  static_cast<u32>(config)); + +        controller.SetPerformanceConfiguration(mode, config);          IPC::ResponseBuilder rb{ctx, 2};          rb.Push(RESULT_SUCCESS); @@ -50,20 +39,23 @@ private:      void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {          IPC::RequestParser rp{ctx}; -        auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); -        LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); +        const auto mode = rp.PopEnum<PerformanceMode>(); +        LOG_DEBUG(Service_APM, "called mode={}", static_cast<u32>(mode));          IPC::ResponseBuilder rb{ctx, 3};          rb.Push(RESULT_SUCCESS); -        rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); +        rb.PushEnum(controller.GetCurrentPerformanceConfiguration(mode));      } + +    Controller& controller;  }; -APM::APM(std::shared_ptr<Module> apm, const char* name) -    : ServiceFramework(name), apm(std::move(apm)) { +APM::APM(std::shared_ptr<Module> apm, Controller& controller, const char* name) +    : ServiceFramework(name), apm(std::move(apm)), controller(controller) {      static const FunctionInfo functions[] = {          {0, &APM::OpenSession, "OpenSession"}, -        {1, nullptr, "GetPerformanceMode"}, +        {1, &APM::GetPerformanceMode, "GetPerformanceMode"}, +        {6, nullptr, "IsCpuOverclockEnabled"},      };      RegisterHandlers(functions);  } @@ -75,10 +67,17 @@ void APM::OpenSession(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ISession>(); +    rb.PushIpcInterface<ISession>(controller); +} + +void APM::GetPerformanceMode(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_APM, "called"); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.PushEnum(controller.GetCurrentPerformanceMode());  } -APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { +APM_Sys::APM_Sys(Controller& controller) : ServiceFramework{"apm:sys"}, controller(controller) {      // clang-format off      static const FunctionInfo functions[] = {          {0, nullptr, "RequestPerformanceMode"}, @@ -87,8 +86,8 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {          {3, nullptr, "GetLastThrottlingState"},          {4, nullptr, "ClearLastThrottlingState"},          {5, nullptr, "LoadAndApplySettings"}, -        {6, nullptr, "SetCpuBoostMode"}, -        {7, nullptr, "GetCurrentPerformanceConfiguration"}, +        {6, &APM_Sys::SetCpuBoostMode, "SetCpuBoostMode"}, +        {7, &APM_Sys::GetCurrentPerformanceConfiguration, "GetCurrentPerformanceConfiguration"},      };      // clang-format on @@ -102,7 +101,28 @@ void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ISession>(); +    rb.PushIpcInterface<ISession>(controller); +} + +void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto mode = rp.PopEnum<CpuBoostMode>(); + +    LOG_DEBUG(Service_APM, "called, mode={:08X}", static_cast<u32>(mode)); + +    controller.SetFromCpuBoostMode(mode); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +void APM_Sys::GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_APM, "called"); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum( +        controller.GetCurrentPerformanceConfiguration(controller.GetCurrentPerformanceMode()));  }  } // namespace Service::APM diff --git a/src/core/hle/service/apm/interface.h b/src/core/hle/service/apm/interface.h index 773541aa4..de1b89437 100644 --- a/src/core/hle/service/apm/interface.h +++ b/src/core/hle/service/apm/interface.h @@ -8,24 +8,34 @@  namespace Service::APM { +class Controller; +class Module; +  class APM final : public ServiceFramework<APM> {  public: -    explicit APM(std::shared_ptr<Module> apm, const char* name); +    explicit APM(std::shared_ptr<Module> apm, Controller& controller, const char* name);      ~APM() override;  private:      void OpenSession(Kernel::HLERequestContext& ctx); +    void GetPerformanceMode(Kernel::HLERequestContext& ctx);      std::shared_ptr<Module> apm; +    Controller& controller;  };  class APM_Sys final : public ServiceFramework<APM_Sys> {  public: -    explicit APM_Sys(); +    explicit APM_Sys(Controller& controller);      ~APM_Sys() override; +    void SetCpuBoostMode(Kernel::HLERequestContext& ctx); +  private:      void GetPerformanceEvent(Kernel::HLERequestContext& ctx); +    void GetCurrentPerformanceConfiguration(Kernel::HLERequestContext& ctx); + +    Controller& controller;  };  } // namespace Service::APM diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 75db0c2dc..3711e1ea1 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -167,13 +167,12 @@ public:              {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},              {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},              {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"}, -            {6, &IAudioDevice::ListAudioDeviceName, -             "ListAudioDeviceNameAuto"}, // TODO(ogniK): Confirm if autos are identical to non auto +            {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},              {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},              {8, nullptr, "GetAudioDeviceOutputVolumeAuto"},              {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},              {11, nullptr, "QueryAudioDeviceInputEvent"}, -            {12, nullptr, "QueryAudioDeviceOutputEvent"}, +            {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},              {13, nullptr, "GetAudioSystemMasterVolumeSetting"},          };          RegisterHandlers(functions); @@ -181,6 +180,11 @@ public:          auto& kernel = Core::System::GetInstance().Kernel();          buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,                                                                "IAudioOutBufferReleasedEvent"); + +        // Should only be signalled when an audio output device has been changed, example: speaker +        // to headset +        audio_output_device_switch_event = Kernel::WritableEvent::CreateEventPair( +            kernel, Kernel::ResetType::Automatic, "IAudioDevice:AudioOutputDeviceSwitchedEvent");      }  private: @@ -237,7 +241,16 @@ private:          rb.Push<u32>(1);      } +    void QueryAudioDeviceOutputEvent(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_Audio, "called"); + +        IPC::ResponseBuilder rb{ctx, 2, 1}; +        rb.Push(RESULT_SUCCESS); +        rb.PushCopyObjects(audio_output_device_switch_event.readable); +    } +      Kernel::EventPair buffer_event; +    Kernel::EventPair audio_output_device_switch_event;  }; // namespace Audio diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 1ebfeb4bf..8ce110dd1 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -472,12 +472,12 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {      }  } -void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { +void InstallInterfaces(Core::System& system) {      romfs_factory = nullptr; -    CreateFactories(vfs, false); -    std::make_shared<FSP_LDR>()->InstallAsService(service_manager); -    std::make_shared<FSP_PR>()->InstallAsService(service_manager); -    std::make_shared<FSP_SRV>()->InstallAsService(service_manager); +    CreateFactories(*system.GetFilesystem(), false); +    std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager()); +    std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager()); +    std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager());  }  } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 6481f237c..3849dd89e 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -65,7 +65,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);  // above is called.  void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); -void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs); +void InstallInterfaces(Core::System& system);  // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of  // pointers and booleans. This makes using a VfsDirectory with switch services much easier and diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index e7df8fd98..d3cd46a9b 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -26,6 +26,7 @@  #include "core/hle/kernel/process.h"  #include "core/hle/service/filesystem/filesystem.h"  #include "core/hle/service/filesystem/fsp_srv.h" +#include "core/reporter.h"  namespace Service::FileSystem { @@ -613,7 +614,7 @@ private:      u64 next_entry_index = 0;  }; -FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { +FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) {      // clang-format off      static const FunctionInfo functions[] = {          {0, nullptr, "OpenFileSystem"}, @@ -710,14 +711,14 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {          {1001, nullptr, "SetSaveDataSize"},          {1002, nullptr, "SetSaveDataRootPath"},          {1003, nullptr, "DisableAutoSaveDataCreation"}, -        {1004, nullptr, "SetGlobalAccessLogMode"}, +        {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},          {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, -        {1006, nullptr, "OutputAccessLogToSdCard"}, +        {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},          {1007, nullptr, "RegisterUpdatePartition"},          {1008, nullptr, "OpenRegisteredUpdatePartition"},          {1009, nullptr, "GetAndClearMemoryReportInfo"},          {1010, nullptr, "SetDataStorageRedirectTarget"}, -        {1011, nullptr, "OutputAccessLogToSdCard2"}, +        {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"},          {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},          {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},          {1200, nullptr, "OpenMultiCommitManager"}, @@ -814,21 +815,22 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&      rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));  } -void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { -    LOG_WARNING(Service_FS, "(STUBBED) called"); +void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    log_mode = rp.PopEnum<LogMode>(); -    enum class LogMode : u32 { -        Off, -        Log, -        RedirectToSdCard, -        LogToSdCard = Log | RedirectToSdCard, -    }; +    LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode)); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_FS, "called"); -    // Given we always want to receive logging information, -    // we always specify logging as enabled.      IPC::ResponseBuilder rb{ctx, 3};      rb.Push(RESULT_SUCCESS); -    rb.PushEnum(LogMode::Log); +    rb.PushEnum(log_mode);  }  void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { @@ -902,4 +904,26 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ct      rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);  } +void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) { +    const auto raw = ctx.ReadBuffer(); +    auto log = Common::StringFromFixedZeroTerminatedBuffer( +        reinterpret_cast<const char*>(raw.data()), raw.size()); + +    LOG_DEBUG(Service_FS, "called, log='{}'", log); + +    reporter.SaveFilesystemAccessReport(log_mode, std::move(log)); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_FS, "called"); + +    IPC::ResponseBuilder rb{ctx, 4}; +    rb.Push(RESULT_SUCCESS); +    rb.PushEnum(AccessLogVersion::Latest); +    rb.Push(access_log_program_index); +} +  } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index d7572ba7a..b5486a193 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -7,15 +7,32 @@  #include <memory>  #include "core/hle/service/service.h" +namespace Core { +class Reporter; +} +  namespace FileSys {  class FileSystemBackend;  }  namespace Service::FileSystem { +enum class AccessLogVersion : u32 { +    V7_0_0 = 2, + +    Latest = V7_0_0, +}; + +enum class LogMode : u32 { +    Off, +    Log, +    RedirectToSdCard, +    LogToSdCard = Log | RedirectToSdCard, +}; +  class FSP_SRV final : public ServiceFramework<FSP_SRV> {  public: -    explicit FSP_SRV(); +    explicit FSP_SRV(const Core::Reporter& reporter);      ~FSP_SRV() override;  private: @@ -26,13 +43,20 @@ private:      void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);      void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);      void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx); +    void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);      void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);      void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);      void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);      void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); +    void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); +    void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);      FileSys::VirtualFile romfs;      u64 current_process_id = 0; +    u32 access_log_program_index = 0; +    LogMode log_mode = LogMode::LogToSdCard; + +    const Core::Reporter& reporter;  };  } // namespace Service::FileSystem diff --git a/src/core/hle/service/friend/errors.h b/src/core/hle/service/friend/errors.h new file mode 100644 index 000000000..b3996e275 --- /dev/null +++ b/src/core/hle/service/friend/errors.h @@ -0,0 +1,12 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Service::Friend { + +constexpr ResultCode ERR_NO_NOTIFICATIONS{ErrorModule::Account, 15}; +} diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 5100e376c..dec541f2e 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -2,8 +2,13 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <queue>  #include "common/logging/log.h" +#include "common/uuid.h"  #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/readable_event.h" +#include "core/hle/kernel/writable_event.h" +#include "core/hle/service/friend/errors.h"  #include "core/hle/service/friend/friend.h"  #include "core/hle/service/friend/interface.h" @@ -109,6 +114,105 @@ private:      }  }; +class INotificationService final : public ServiceFramework<INotificationService> { +public: +    INotificationService(Common::UUID uuid) : ServiceFramework("INotificationService"), uuid(uuid) { +        // clang-format off +        static const FunctionInfo functions[] = { +            {0, &INotificationService::GetEvent, "GetEvent"}, +            {1, &INotificationService::Clear, "Clear"}, +            {2, &INotificationService::Pop, "Pop"} +        }; +        // clang-format on + +        RegisterHandlers(functions); +    } + +private: +    void GetEvent(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_ACC, "called"); + +        IPC::ResponseBuilder rb{ctx, 2, 1}; +        rb.Push(RESULT_SUCCESS); + +        if (!is_event_created) { +            auto& kernel = Core::System::GetInstance().Kernel(); +            notification_event = Kernel::WritableEvent::CreateEventPair( +                kernel, Kernel::ResetType::Manual, "INotificationService:NotifyEvent"); +            is_event_created = true; +        } +        rb.PushCopyObjects(notification_event.readable); +    } + +    void Clear(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_ACC, "called"); +        while (!notifications.empty()) { +            notifications.pop(); +        } +        std::memset(&states, 0, sizeof(States)); + +        IPC::ResponseBuilder rb{ctx, 2}; +        rb.Push(RESULT_SUCCESS); +    } + +    void Pop(Kernel::HLERequestContext& ctx) { +        LOG_DEBUG(Service_ACC, "called"); + +        if (notifications.empty()) { +            LOG_ERROR(Service_ACC, "No notifications in queue!"); +            IPC::ResponseBuilder rb{ctx, 2}; +            rb.Push(ERR_NO_NOTIFICATIONS); +            return; +        } + +        const auto notification = notifications.front(); +        notifications.pop(); + +        switch (notification.notification_type) { +        case NotificationTypes::HasUpdatedFriendsList: +            states.has_updated_friends = false; +            break; +        case NotificationTypes::HasReceivedFriendRequest: +            states.has_received_friend_request = false; +            break; +        default: +            // HOS seems not have an error case for an unknown notification +            LOG_WARNING(Service_ACC, "Unknown notification {:08X}", +                        static_cast<u32>(notification.notification_type)); +            break; +        } + +        IPC::ResponseBuilder rb{ctx, 6}; +        rb.Push(RESULT_SUCCESS); +        rb.PushRaw<SizedNotificationInfo>(notification); +    } + +    enum class NotificationTypes : u32 { +        HasUpdatedFriendsList = 0x65, +        HasReceivedFriendRequest = 0x1 +    }; + +    struct SizedNotificationInfo { +        NotificationTypes notification_type; +        INSERT_PADDING_WORDS( +            1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now +        u64_le account_id; +    }; +    static_assert(sizeof(SizedNotificationInfo) == 0x10, +                  "SizedNotificationInfo is an incorrect size"); + +    struct States { +        bool has_updated_friends; +        bool has_received_friend_request; +    }; + +    Common::UUID uuid; +    bool is_event_created = false; +    Kernel::EventPair notification_event; +    std::queue<SizedNotificationInfo> notifications; +    States states{}; +}; +  void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); @@ -116,6 +220,17 @@ void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_ACC, "called");  } +void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    auto uuid = rp.PopRaw<Common::UUID>(); + +    LOG_DEBUG(Service_ACC, "called, uuid={}", uuid.Format()); + +    IPC::ResponseBuilder rb{ctx, 2, 0, 1}; +    rb.Push(RESULT_SUCCESS); +    rb.PushIpcInterface<INotificationService>(uuid); +} +  Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)      : ServiceFramework(name), module(std::move(module)) {} diff --git a/src/core/hle/service/friend/friend.h b/src/core/hle/service/friend/friend.h index e762840cb..38d05fa8e 100644 --- a/src/core/hle/service/friend/friend.h +++ b/src/core/hle/service/friend/friend.h @@ -16,6 +16,7 @@ public:          ~Interface() override;          void CreateFriendService(Kernel::HLERequestContext& ctx); +        void CreateNotificationService(Kernel::HLERequestContext& ctx);      protected:          std::shared_ptr<Module> module; diff --git a/src/core/hle/service/friend/interface.cpp b/src/core/hle/service/friend/interface.cpp index 5a6840af5..5b384f733 100644 --- a/src/core/hle/service/friend/interface.cpp +++ b/src/core/hle/service/friend/interface.cpp @@ -10,7 +10,7 @@ Friend::Friend(std::shared_ptr<Module> module, const char* name)      : Interface(std::move(module), name) {      static const FunctionInfo functions[] = {          {0, &Friend::CreateFriendService, "CreateFriendService"}, -        {1, nullptr, "CreateNotificationService"}, +        {1, &Friend::CreateNotificationService, "CreateNotificationService"},          {2, nullptr, "CreateDaemonSuspendSessionService"},      };      RegisterHandlers(functions); diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index fdd6d79a2..1e81f776f 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -548,6 +548,37 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) {      connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;  } +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 +    is_in_lr_assignment_mode = true; +} + +void Controller_NPad::StopLRAssignmentMode() { +    is_in_lr_assignment_mode = false; +} + +bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { +    if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN || +        npad_id_2 == NPAD_UNKNOWN) { +        return true; +    } +    const auto npad_index_1 = NPadIdToIndex(npad_id_1); +    const auto npad_index_2 = NPadIdToIndex(npad_id_2); + +    if (!IsControllerSupported(connected_controllers[npad_index_1].type) || +        !IsControllerSupported(connected_controllers[npad_index_2].type)) { +        return false; +    } + +    std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type); + +    InitNewlyAddedControler(npad_index_1); +    InitNewlyAddedControler(npad_index_2); + +    return true; +} +  bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {      if (controller == NPadControllerType::Handheld) {          // Handheld is not even a supported type, lets stop here diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 4ff50b3cd..4b6c1083f 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -124,6 +124,10 @@ public:      void ConnectAllDisconnectedControllers();      void ClearAllControllers(); +    void StartLRAssignmentMode(); +    void StopLRAssignmentMode(); +    bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); +      // Logical OR for all buttons presses on all controllers      // Specifically for cheat engine and other features.      u32 GetAndResetPressState(); @@ -321,5 +325,6 @@ private:      void RequestPadStateUpdate(u32 npad_id);      std::array<ControllerPad, 10> npad_pad_states{};      bool IsControllerSupported(NPadControllerType controller); +    bool is_in_lr_assignment_mode{false};  };  } // namespace Service::HID diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h new file mode 100644 index 000000000..3583642e7 --- /dev/null +++ b/src/core/hle/service/hid/errors.h @@ -0,0 +1,13 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/result.h" + +namespace Service::HID { + +constexpr ResultCode ERR_NPAD_NOT_CONNECTED{ErrorModule::HID, 710}; + +} // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index a4ad95d96..0bd24b8eb 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -16,6 +16,7 @@  #include "core/hle/kernel/readable_event.h"  #include "core/hle/kernel/shared_memory.h"  #include "core/hle/kernel/writable_event.h" +#include "core/hle/service/hid/errors.h"  #include "core/hle/service/hid/hid.h"  #include "core/hle/service/hid/irs.h"  #include "core/hle/service/hid/xcd.h" @@ -202,11 +203,11 @@ Hid::Hid() : ServiceFramework("hid") {          {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},          {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},          {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"}, -        {126, nullptr, "StartLrAssignmentMode"}, -        {127, nullptr, "StopLrAssignmentMode"}, +        {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"}, +        {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"},          {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},          {129, nullptr, "GetNpadHandheldActivationMode"}, -        {130, nullptr, "SwapNpadAssignment"}, +        {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},          {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},          {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},          {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"}, @@ -733,6 +734,49 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {      rb.Push(RESULT_SUCCESS);  } +void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto applet_resource_user_id{rp.Pop<u64>()}; + +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +    controller.StartLRAssignmentMode(); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto applet_resource_user_id{rp.Pop<u64>()}; + +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); +    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +    controller.StopLRAssignmentMode(); + +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto npad_1{rp.Pop<u32>()}; +    const auto npad_2{rp.Pop<u32>()}; +    const auto applet_resource_user_id{rp.Pop<u64>()}; + +    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", +              applet_resource_user_id, npad_1, npad_2); + +    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); +    IPC::ResponseBuilder rb{ctx, 2}; +    if (controller.SwapNpadAssignment(npad_1, npad_2)) { +        rb.Push(RESULT_SUCCESS); +    } else { +        LOG_ERROR(Service_HID, "Npads are not connected!"); +        rb.Push(ERR_NPAD_NOT_CONNECTED); +    } +} +  class HidDbg final : public ServiceFramework<HidDbg> {  public:      explicit HidDbg() : ServiceFramework{"hid:dbg"} { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index d3660cad2..28260ef1b 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -119,6 +119,9 @@ private:      void StopSixAxisSensor(Kernel::HLERequestContext& ctx);      void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);      void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); +    void StartLrAssignmentMode(Kernel::HLERequestContext& ctx); +    void StopLrAssignmentMode(Kernel::HLERequestContext& ctx); +    void SwapNpadAssignment(Kernel::HLERequestContext& ctx);      std::shared_ptr<IAppletResource> applet_resource;  }; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index ec9d755b7..952c03e27 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -195,8 +195,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co  // Module interface  /// Initialize ServiceManager -void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, -          FileSys::VfsFilesystem& vfs) { +void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {      // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it      // here and pass it into the respective InstallInterfaces functions.      auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming()); @@ -206,7 +205,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,      Account::InstallInterfaces(system);      AM::InstallInterfaces(*sm, nv_flinger, system);      AOC::InstallInterfaces(*sm); -    APM::InstallInterfaces(*sm); +    APM::InstallInterfaces(system);      Audio::InstallInterfaces(*sm);      BCAT::InstallInterfaces(*sm);      BPC::InstallInterfaces(*sm); @@ -218,7 +217,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,      EUPLD::InstallInterfaces(*sm);      Fatal::InstallInterfaces(*sm);      FGM::InstallInterfaces(*sm); -    FileSystem::InstallInterfaces(*sm, vfs); +    FileSystem::InstallInterfaces(system);      Friend::InstallInterfaces(*sm);      Glue::InstallInterfaces(system);      GRC::InstallInterfaces(*sm); @@ -249,7 +248,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system,      Sockets::InstallInterfaces(*sm);      SPL::InstallInterfaces(*sm);      SSL::InstallInterfaces(*sm); -    Time::InstallInterfaces(*sm); +    Time::InstallInterfaces(system);      USB::InstallInterfaces(*sm);      VI::InstallInterfaces(*sm, nv_flinger);      WLAN::InstallInterfaces(*sm); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index abbfe5524..c6c4bdae5 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -182,8 +182,7 @@ private:  };  /// Initialize ServiceManager -void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system, -          FileSys::VfsFilesystem& vfs); +void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system);  /// Shutdown ServiceManager  void Shutdown(); diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 298d85011..b54214421 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -95,6 +95,14 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {      PushResponseLanguageCode(ctx, post4_0_0_max_entries);  } +void SET::GetQuestFlag(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_SET, "called"); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.Push(static_cast<u32>(Settings::values.quest_flag)); +} +  void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {      LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index); @@ -114,7 +122,7 @@ SET::SET() : ServiceFramework("set") {          {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},          {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"},          {7, nullptr, "GetKeyCodeMap"}, -        {8, nullptr, "GetQuestFlag"}, +        {8, &SET::GetQuestFlag, "GetQuestFlag"},          {9, nullptr, "GetKeyCodeMap2"},      };      // clang-format on diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 31f9cb296..b154e08aa 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -42,6 +42,7 @@ private:      void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);      void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);      void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); +    void GetQuestFlag(Kernel::HLERequestContext& ctx);  };  } // namespace Service::Set diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index 8d122ae33..1030185e0 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp @@ -6,8 +6,9 @@  namespace Service::Time { -Time::Time(std::shared_ptr<Module> time, const char* name) -    : Module::Interface(std::move(time), name) { +Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, +           const char* name) +    : Module::Interface(std::move(time), std::move(shared_memory), name) {      // clang-format off      static const FunctionInfo functions[] = {          {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, @@ -16,12 +17,12 @@ Time::Time(std::shared_ptr<Module> time, const char* name)          {3, &Time::GetTimeZoneService, "GetTimeZoneService"},          {4, &Time::GetStandardLocalSystemClock, "GetStandardLocalSystemClock"},          {5, nullptr, "GetEphemeralNetworkSystemClock"}, -        {20, nullptr, "GetSharedMemoryNativeHandle"}, +        {20, &Time::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},          {30, nullptr, "GetStandardNetworkClockOperationEventReadableHandle"},          {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},          {50, nullptr, "SetStandardSteadyClockInternalOffset"}, -        {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, -        {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, +        {100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, +        {101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},          {102, nullptr, "GetStandardUserSystemClockInitialYear"},          {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},          {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h index cd6b44dec..bdf0883e2 100644 --- a/src/core/hle/service/time/interface.h +++ b/src/core/hle/service/time/interface.h @@ -8,9 +8,12 @@  namespace Service::Time { +class SharedMemory; +  class Time final : public Module::Interface {  public: -    explicit Time(std::shared_ptr<Module> time, const char* name); +    explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, +                  const char* name);      ~Time() override;  }; diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 346bad80d..ae6446204 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp @@ -13,6 +13,7 @@  #include "core/hle/kernel/client_session.h"  #include "core/hle/service/time/interface.h"  #include "core/hle/service/time/time.h" +#include "core/hle/service/time/time_sharedmemory.h"  #include "core/settings.h"  namespace Service::Time { @@ -61,9 +62,18 @@ static u64 CalendarToPosix(const CalendarTime& calendar_time,      return static_cast<u64>(epoch_time);  } +enum class ClockContextType { +    StandardSteady, +    StandardUserSystem, +    StandardNetworkSystem, +    StandardLocalSystem, +}; +  class ISystemClock final : public ServiceFramework<ISystemClock> {  public: -    ISystemClock() : ServiceFramework("ISystemClock") { +    ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory, +                 ClockContextType clock_type) +        : ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) {          static const FunctionInfo functions[] = {              {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},              {1, nullptr, "SetCurrentTime"}, @@ -72,6 +82,8 @@ public:          };          RegisterHandlers(functions); + +        UpdateSharedMemoryContext(system_clock_context);      }  private: @@ -87,34 +99,63 @@ private:      void GetSystemClockContext(Kernel::HLERequestContext& ctx) {          LOG_WARNING(Service_Time, "(STUBBED) called"); -        SystemClockContext system_clock_ontext{}; +        // TODO(ogniK): This should be updated periodically however since we have it stubbed we'll +        // only update when we get a new context +        UpdateSharedMemoryContext(system_clock_context); +          IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};          rb.Push(RESULT_SUCCESS); -        rb.PushRaw(system_clock_ontext); +        rb.PushRaw(system_clock_context);      } + +    void UpdateSharedMemoryContext(const SystemClockContext& clock_context) { +        switch (clock_type) { +        case ClockContextType::StandardLocalSystem: +            shared_memory->SetStandardLocalSystemClockContext(clock_context); +            break; +        case ClockContextType::StandardNetworkSystem: +            shared_memory->SetStandardNetworkSystemClockContext(clock_context); +            break; +        } +    } + +    SystemClockContext system_clock_context{}; +    std::shared_ptr<Service::Time::SharedMemory> shared_memory; +    ClockContextType clock_type;  };  class ISteadyClock final : public ServiceFramework<ISteadyClock> {  public: -    ISteadyClock() : ServiceFramework("ISteadyClock") { +    ISteadyClock(std::shared_ptr<SharedMemory> shared_memory) +        : ServiceFramework("ISteadyClock"), shared_memory(shared_memory) {          static const FunctionInfo functions[] = {              {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},          };          RegisterHandlers(functions); + +        shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint());      }  private:      void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {          LOG_DEBUG(Service_Time, "called"); -        const auto& core_timing = Core::System::GetInstance().CoreTiming(); -        const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); -        const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), -                                                           {}}; +        const auto time_point = GetCurrentTimePoint(); +        // TODO(ogniK): This should be updated periodically +        shared_memory->SetStandardSteadyClockTimepoint(time_point); +          IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};          rb.Push(RESULT_SUCCESS); -        rb.PushRaw(steady_clock_time_point); +        rb.PushRaw(time_point);      } + +    SteadyClockTimePoint GetCurrentTimePoint() const { +        const auto& core_timing = Core::System::GetInstance().CoreTiming(); +        const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); +        return {static_cast<u64_le>(ms.count() / 1000), {}}; +    } + +    std::shared_ptr<SharedMemory> shared_memory;  };  class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { @@ -233,7 +274,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ISystemClock>(); +    rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem);  }  void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { @@ -241,7 +282,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ISystemClock>(); +    rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem);  }  void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { @@ -249,7 +290,7 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ISteadyClock>(); +    rb.PushIpcInterface<ISteadyClock>(shared_memory);  }  void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { @@ -265,7 +306,7 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c      IPC::ResponseBuilder rb{ctx, 2, 0, 1};      rb.Push(RESULT_SUCCESS); -    rb.PushIpcInterface<ISystemClock>(); +    rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem);  }  void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { @@ -333,16 +374,52 @@ void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(      rb.PushRaw<u64>(difference);  } -Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) -    : ServiceFramework(name), time(std::move(time)) {} +void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { +    LOG_DEBUG(Service_Time, "called"); +    IPC::ResponseBuilder rb{ctx, 2, 1}; +    rb.Push(RESULT_SUCCESS); +    rb.PushCopyObjects(shared_memory->GetSharedMemoryHolder()); +} + +void Module::Interface::IsStandardUserSystemClockAutomaticCorrectionEnabled( +    Kernel::HLERequestContext& ctx) { +    // ogniK(TODO): When clock contexts are implemented, the value should be read from the context +    // instead of our shared memory holder +    LOG_DEBUG(Service_Time, "called"); + +    IPC::ResponseBuilder rb{ctx, 3}; +    rb.Push(RESULT_SUCCESS); +    rb.Push<u8>(shared_memory->GetStandardUserSystemClockAutomaticCorrectionEnabled()); +} + +void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled( +    Kernel::HLERequestContext& ctx) { +    IPC::RequestParser rp{ctx}; +    const auto enabled = rp.Pop<u8>(); + +    LOG_WARNING(Service_Time, "(PARTIAL IMPLEMENTATION) called"); + +    // TODO(ogniK): Update clock contexts and correct timespans + +    shared_memory->SetStandardUserSystemClockAutomaticCorrectionEnabled(enabled > 0); +    IPC::ResponseBuilder rb{ctx, 2}; +    rb.Push(RESULT_SUCCESS); +} + +Module::Interface::Interface(std::shared_ptr<Module> time, +                             std::shared_ptr<SharedMemory> shared_memory, const char* name) +    : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)) {}  Module::Interface::~Interface() = default; -void InstallInterfaces(SM::ServiceManager& service_manager) { +void InstallInterfaces(Core::System& system) {      auto time = std::make_shared<Module>(); -    std::make_shared<Time>(time, "time:a")->InstallAsService(service_manager); -    std::make_shared<Time>(time, "time:s")->InstallAsService(service_manager); -    std::make_shared<Time>(time, "time:u")->InstallAsService(service_manager); +    auto shared_mem = std::make_shared<SharedMemory>(system); + +    std::make_shared<Time>(time, shared_mem, "time:a")->InstallAsService(system.ServiceManager()); +    std::make_shared<Time>(time, shared_mem, "time:s")->InstallAsService(system.ServiceManager()); +    std::make_shared<Time>(std::move(time), shared_mem, "time:u") +        ->InstallAsService(system.ServiceManager());  }  } // namespace Service::Time diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index f11affe95..e0708f856 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h @@ -10,6 +10,8 @@  namespace Service::Time { +class SharedMemory; +  struct LocationName {      std::array<u8, 0x24> name;  }; @@ -77,7 +79,8 @@ class Module final {  public:      class Interface : public ServiceFramework<Interface> {      public: -        explicit Interface(std::shared_ptr<Module> time, const char* name); +        explicit Interface(std::shared_ptr<Module> time, +                           std::shared_ptr<SharedMemory> shared_memory, const char* name);          ~Interface() override;          void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); @@ -87,13 +90,17 @@ public:          void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);          void GetClockSnapshot(Kernel::HLERequestContext& ctx);          void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx); +        void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); +        void IsStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx); +        void SetStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);      protected:          std::shared_ptr<Module> time; +        std::shared_ptr<SharedMemory> shared_memory;      };  };  /// Registers all Time services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(Core::System& system);  } // namespace Service::Time diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp new file mode 100644 index 000000000..bfc81b83c --- /dev/null +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -0,0 +1,68 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/hle/service/time/time_sharedmemory.h" + +namespace Service::Time { +const std::size_t SHARED_MEMORY_SIZE = 0x1000; + +SharedMemory::SharedMemory(Core::System& system) : system(system) { +    shared_memory_holder = Kernel::SharedMemory::Create( +        system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, +        Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory"); + +    // Seems static from 1.0.0 -> 8.1.0. Specific games seem to check this value and crash +    // if it's set to anything else +    shared_memory_format.format_version = 14; +    std::memcpy(shared_memory_holder->GetPointer(), &shared_memory_format, sizeof(Format)); +} + +SharedMemory::~SharedMemory() = default; + +Kernel::SharedPtr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() const { +    return shared_memory_holder; +} + +void SharedMemory::SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint) { +    shared_memory_format.standard_steady_clock_timepoint.StoreData( +        shared_memory_holder->GetPointer(), timepoint); +} + +void SharedMemory::SetStandardLocalSystemClockContext(const SystemClockContext& context) { +    shared_memory_format.standard_local_system_clock_context.StoreData( +        shared_memory_holder->GetPointer(), context); +} + +void SharedMemory::SetStandardNetworkSystemClockContext(const SystemClockContext& context) { +    shared_memory_format.standard_network_system_clock_context.StoreData( +        shared_memory_holder->GetPointer(), context); +} + +void SharedMemory::SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled) { +    shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( +        shared_memory_holder->GetPointer(), enabled); +} + +SteadyClockTimePoint SharedMemory::GetStandardSteadyClockTimepoint() { +    return shared_memory_format.standard_steady_clock_timepoint.ReadData( +        shared_memory_holder->GetPointer()); +} + +SystemClockContext SharedMemory::GetStandardLocalSystemClockContext() { +    return shared_memory_format.standard_local_system_clock_context.ReadData( +        shared_memory_holder->GetPointer()); +} + +SystemClockContext SharedMemory::GetStandardNetworkSystemClockContext() { +    return shared_memory_format.standard_network_system_clock_context.ReadData( +        shared_memory_holder->GetPointer()); +} + +bool SharedMemory::GetStandardUserSystemClockAutomaticCorrectionEnabled() { +    return shared_memory_format.standard_user_system_clock_automatic_correction.ReadData( +        shared_memory_holder->GetPointer()); +} + +} // namespace Service::Time diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h new file mode 100644 index 000000000..cb8253541 --- /dev/null +++ b/src/core/hle/service/time/time_sharedmemory.h @@ -0,0 +1,74 @@ +// Copyright 2019 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/service/time/time.h" + +namespace Service::Time { +class SharedMemory { +public: +    explicit SharedMemory(Core::System& system); +    ~SharedMemory(); + +    // Return the shared memory handle +    Kernel::SharedPtr<Kernel::SharedMemory> GetSharedMemoryHolder() const; + +    // Set memory barriers in shared memory and update them +    void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint); +    void SetStandardLocalSystemClockContext(const SystemClockContext& context); +    void SetStandardNetworkSystemClockContext(const SystemClockContext& context); +    void SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled); + +    // Pull from memory barriers in the shared memory +    SteadyClockTimePoint GetStandardSteadyClockTimepoint(); +    SystemClockContext GetStandardLocalSystemClockContext(); +    SystemClockContext GetStandardNetworkSystemClockContext(); +    bool GetStandardUserSystemClockAutomaticCorrectionEnabled(); + +    // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? +    template <typename T, std::size_t Offset> +    struct MemoryBarrier { +        static_assert(std::is_trivially_constructible_v<T>, "T must be trivially constructable"); +        u32_le read_attempt{}; +        std::array<T, 2> data{}; + +        // These are not actually memory barriers at the moment as we don't have multicore and all +        // HLE is mutexed. This will need to properly be implemented when we start updating the time +        // points on threads. As of right now, we'll be updated both values synchronously and just +        // incrementing the read_attempt to indicate that we waited. +        void StoreData(u8* shared_memory, T data_to_store) { +            std::memcpy(this, shared_memory + Offset, sizeof(*this)); +            read_attempt++; +            data[read_attempt & 1] = data_to_store; +            std::memcpy(shared_memory + Offset, this, sizeof(*this)); +        } + +        // For reading we're just going to read the last stored value. If there was no value stored +        // it will just end up reading an empty value as intended. +        T ReadData(u8* shared_memory) { +            std::memcpy(this, shared_memory + Offset, sizeof(*this)); +            return data[(read_attempt - 1) & 1]; +        } +    }; + +    // Shared memory format +    struct Format { +        MemoryBarrier<SteadyClockTimePoint, 0x0> standard_steady_clock_timepoint; +        MemoryBarrier<SystemClockContext, 0x38> standard_local_system_clock_context; +        MemoryBarrier<SystemClockContext, 0x80> standard_network_system_clock_context; +        MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction; +        u32_le format_version; +    }; +    static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); + +private: +    Kernel::SharedPtr<Kernel::SharedMemory> shared_memory_holder{}; +    Core::System& system; +    Format shared_memory_format{}; +}; + +} // namespace Service::Time diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 3a22ec2c6..b1171ce65 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -168,7 +168,8 @@ ResultStatus AppLoader_NSP::ReadControlData(FileSys::NACP& nacp) {  }  ResultStatus AppLoader_NSP::ReadManualRomFS(FileSys::VirtualFile& file) { -    const auto nca = nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Manual); +    const auto nca = +        nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::HtmlDocument);      if (nsp->GetStatus() != ResultStatus::Success || nca == nullptr)          return ResultStatus::ErrorNoRomFS;      file = nca->GetRomFS(); diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index a5c4d3688..5e8553db9 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -134,7 +134,7 @@ ResultStatus AppLoader_XCI::ReadControlData(FileSys::NACP& control) {  ResultStatus AppLoader_XCI::ReadManualRomFS(FileSys::VirtualFile& file) {      const auto nca = xci->GetSecurePartitionNSP()->GetNCA(xci->GetProgramTitleID(), -                                                          FileSys::ContentRecordType::Manual); +                                                          FileSys::ContentRecordType::HtmlDocument);      if (xci->GetStatus() != ResultStatus::Success || nca == nullptr)          return ResultStatus::ErrorXCIMissingPartition;      file = nca->GetRomFS(); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index f18f6226b..8555691c0 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -16,11 +16,9 @@  #include "core/core.h"  #include "core/hle/kernel/process.h"  #include "core/hle/kernel/vm_manager.h" -#include "core/hle/lock.h"  #include "core/memory.h"  #include "core/memory_setup.h"  #include "video_core/gpu.h" -#include "video_core/renderer_base.h"  namespace Memory { diff --git a/src/core/memory.h b/src/core/memory.h index 04e2c5f1d..09008e1dd 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -8,10 +8,6 @@  #include <string>  #include "common/common_types.h" -namespace Common { -struct PageTable; -} -  namespace Kernel {  class Process;  } diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 774022569..5d4c3e6ea 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -2,8 +2,13 @@  // Licensed under GPLv2 or any later version  // Refer to the license.txt file included. +#include <ctime>  #include <fstream> + +#include <fmt/format.h> +#include <fmt/time.h>  #include <json.hpp> +  #include "common/file_util.h"  #include "common/hex_util.h"  #include "common/scm_rev.h" @@ -14,7 +19,6 @@  #include "core/hle/result.h"  #include "core/reporter.h"  #include "core/settings.h" -#include "fmt/time.h"  namespace { @@ -30,9 +34,11 @@ std::string GetTimestamp() {  using namespace nlohmann; -void SaveToFile(const json& json, const std::string& filename) { -    if (!FileUtil::CreateFullPath(filename)) +void SaveToFile(json json, const std::string& filename) { +    if (!FileUtil::CreateFullPath(filename)) {          LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename); +        return; +    }      std::ofstream file(          FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault)); @@ -61,8 +67,11 @@ json GetReportCommonData(u64 title_id, ResultCode result, const std::string& tim          {"result_description", fmt::format("{:08X}", result.description.Value())},          {"timestamp", timestamp},      }; -    if (user_id.has_value()) + +    if (user_id.has_value()) {          out["user_id"] = fmt::format("{:016X}{:016X}", (*user_id)[1], (*user_id)[0]); +    } +      return out;  } @@ -171,14 +180,14 @@ json GetHLERequestContextData(Kernel::HLERequestContext& ctx) {      out["buffer_descriptor_c"] = GetHLEBufferDescriptorData<false>(ctx.BufferDescriptorC());      out["buffer_descriptor_x"] = GetHLEBufferDescriptorData<true>(ctx.BufferDescriptorX()); -    return std::move(out); +    return out;  }  } // Anonymous namespace  namespace Core { -Reporter::Reporter(Core::System& system) : system(system) {} +Reporter::Reporter(System& system) : system(system) {}  Reporter::~Reporter() = default; @@ -187,8 +196,9 @@ void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u                                 const std::array<u64, 31>& registers,                                 const std::array<u64, 32>& backtrace, u32 backtrace_size,                                 const std::string& arch, u32 unk10) const { -    if (!IsReportingEnabled()) +    if (!IsReportingEnabled()) {          return; +    }      const auto timestamp = GetTimestamp();      json out; @@ -212,8 +222,9 @@ void Reporter::SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u  void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64 info2,                                    std::optional<std::vector<u8>> resolved_buffer) const { -    if (!IsReportingEnabled()) +    if (!IsReportingEnabled()) {          return; +    }      const auto timestamp = GetTimestamp();      const auto title_id = system.CurrentProcess()->GetTitleID(); @@ -238,8 +249,9 @@ void Reporter::SaveSvcBreakReport(u32 type, bool signal_debugger, u64 info1, u64  void Reporter::SaveUnimplementedFunctionReport(Kernel::HLERequestContext& ctx, u32 command_id,                                                 const std::string& name,                                                 const std::string& service_name) const { -    if (!IsReportingEnabled()) +    if (!IsReportingEnabled()) {          return; +    }      const auto timestamp = GetTimestamp();      const auto title_id = system.CurrentProcess()->GetTitleID(); @@ -259,8 +271,9 @@ void Reporter::SaveUnimplementedAppletReport(      u32 applet_id, u32 common_args_version, u32 library_version, u32 theme_color,      bool startup_sound, u64 system_tick, std::vector<std::vector<u8>> normal_channel,      std::vector<std::vector<u8>> interactive_channel) const { -    if (!IsReportingEnabled()) +    if (!IsReportingEnabled()) {          return; +    }      const auto timestamp = GetTimestamp();      const auto title_id = system.CurrentProcess()->GetTitleID(); @@ -293,8 +306,9 @@ void Reporter::SaveUnimplementedAppletReport(  void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vector<u8>> data,                                std::optional<u128> user_id) const { -    if (!IsReportingEnabled()) +    if (!IsReportingEnabled()) {          return; +    }      const auto timestamp = GetTimestamp();      json out; @@ -316,8 +330,9 @@ void Reporter::SavePlayReport(u64 title_id, u64 process_id, std::vector<std::vec  void Reporter::SaveErrorReport(u64 title_id, ResultCode result,                                 std::optional<std::string> custom_text_main,                                 std::optional<std::string> custom_text_detail) const { -    if (!IsReportingEnabled()) +    if (!IsReportingEnabled()) {          return; +    }      const auto timestamp = GetTimestamp();      json out; @@ -335,12 +350,31 @@ void Reporter::SaveErrorReport(u64 title_id, ResultCode result,      SaveToFile(std::move(out), GetPath("error_report", title_id, timestamp));  } -void Reporter::SaveUserReport() const { +void Reporter::SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, +                                          std::string log_message) const {      if (!IsReportingEnabled())          return;      const auto timestamp = GetTimestamp();      const auto title_id = system.CurrentProcess()->GetTitleID(); +    json out; + +    out["yuzu_version"] = GetYuzuVersionData(); +    out["report_common"] = GetReportCommonData(title_id, RESULT_SUCCESS, timestamp); + +    out["log_mode"] = fmt::format("{:08X}", static_cast<u32>(log_mode)); +    out["log_message"] = std::move(log_message); + +    SaveToFile(std::move(out), GetPath("filesystem_access_report", title_id, timestamp)); +} + +void Reporter::SaveUserReport() const { +    if (!IsReportingEnabled()) { +        return; +    } + +    const auto timestamp = GetTimestamp(); +    const auto title_id = system.CurrentProcess()->GetTitleID();      SaveToFile(GetFullDataAuto(timestamp, title_id, system),                 GetPath("user_report", title_id, timestamp)); diff --git a/src/core/reporter.h b/src/core/reporter.h index 3de19c0f7..44256de50 100644 --- a/src/core/reporter.h +++ b/src/core/reporter.h @@ -4,7 +4,9 @@  #pragma once +#include <array>  #include <optional> +#include <string>  #include <vector>  #include "common/common_types.h" @@ -14,11 +16,17 @@ namespace Kernel {  class HLERequestContext;  } // namespace Kernel +namespace Service::FileSystem { +enum class LogMode : u32; +} +  namespace Core { +class System; +  class Reporter {  public: -    explicit Reporter(Core::System& system); +    explicit Reporter(System& system);      ~Reporter();      void SaveCrashReport(u64 title_id, ResultCode result, u64 set_flags, u64 entry_point, u64 sp, @@ -45,12 +53,15 @@ public:                           std::optional<std::string> custom_text_main = {},                           std::optional<std::string> custom_text_detail = {}) const; +    void SaveFilesystemAccessReport(Service::FileSystem::LogMode log_mode, +                                    std::string log_message) const; +      void SaveUserReport() const;  private:      bool IsReportingEnabled() const; -    Core::System& system; +    System& system;  };  } // namespace Core diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 6d32ebea3..63aa59690 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -85,7 +85,7 @@ void LogSettings() {      LogSetting("System_RngSeed", Settings::values.rng_seed.value_or(0));      LogSetting("System_CurrentUser", Settings::values.current_user);      LogSetting("System_LanguageIndex", Settings::values.language_index); -    LogSetting("Core_UseCpuJit", Settings::values.use_cpu_jit); +    LogSetting("Core_CpuJitEnabled", Settings::values.cpu_jit_enabled);      LogSetting("Core_UseMultiCore", Settings::values.use_multi_core);      LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor);      LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); diff --git a/src/core/settings.h b/src/core/settings.h index e2ffcaaf7..acf18d653 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -378,7 +378,7 @@ struct Values {      std::atomic_bool is_device_reload_pending{true};      // Core -    bool use_cpu_jit; +    bool cpu_jit_enabled;      bool use_multi_core;      // Data Storage @@ -416,6 +416,7 @@ struct Values {      bool dump_exefs;      bool dump_nso;      bool reporting_services; +    bool quest_flag;      // WebService      bool enable_telemetry; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 90d06830f..98f49042a 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -168,7 +168,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {      AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id);      AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",               Settings::values.enable_audio_stretching); -    AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit); +    AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.cpu_jit_enabled);      AddField(Telemetry::FieldType::UserConfig, "Core_UseMultiCore",               Settings::values.use_multi_core);      AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor", | 
