summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/kernel/process.cpp135
-rw-r--r--src/core/hle/kernel/process.h12
-rw-r--r--src/core/hle/kernel/svc.cpp20
-rw-r--r--src/core/hle/kernel/thread.cpp10
-rw-r--r--src/core/hle/kernel/thread.h16
-rw-r--r--src/core/hle/kernel/vm_manager.cpp76
-rw-r--r--src/core/hle/kernel/vm_manager.h51
-rw-r--r--src/core/hle/service/acc/acc.cpp73
-rw-r--r--src/core/hle/service/acc/acc.h24
-rw-r--r--src/core/hle/service/acc/acc_u0.cpp4
-rw-r--r--src/core/hle/service/acc/errors.h14
-rw-r--r--src/core/hle/service/am/am.cpp26
-rw-r--r--src/core/hle/service/am/am.h1
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp4
-rw-r--r--src/core/hle/service/audio/audren_u.cpp19
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp10
-rw-r--r--src/core/hle/service/filesystem/filesystem.h2
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp54
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h26
-rw-r--r--src/core/hle/service/friend/errors.h12
-rw-r--r--src/core/hle/service/friend/friend.cpp115
-rw-r--r--src/core/hle/service/friend/friend.h1
-rw-r--r--src/core/hle/service/friend/interface.cpp2
-rw-r--r--src/core/hle/service/service.cpp7
-rw-r--r--src/core/hle/service/service.h3
-rw-r--r--src/core/hle/service/set/set.cpp10
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/time/interface.cpp11
-rw-r--r--src/core/hle/service/time/interface.h5
-rw-r--r--src/core/hle/service/time/time.cpp115
-rw-r--r--src/core/hle/service/time/time.h11
-rw-r--r--src/core/hle/service/time/time_sharedmemory.cpp68
-rw-r--r--src/core/hle/service/time/time_sharedmemory.h74
33 files changed, 816 insertions, 196 deletions
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 4b5baf283..9fdcf2965 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -271,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"},
@@ -284,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;
@@ -450,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);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 88d1ba27c..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;
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/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/service.cpp b/src/core/hle/service/service.cpp
index e441b3730..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());
@@ -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