summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/applets/applet.h1
-rw-r--r--src/core/hle/applets/mii_selector.cpp9
-rw-r--r--src/core/hle/applets/swkbd.cpp8
-rw-r--r--src/core/hle/function_wrappers.h3
-rw-r--r--src/core/hle/kernel/memory.cpp5
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/hle/kernel/process.h7
-rw-r--r--src/core/hle/kernel/shared_memory.cpp177
-rw-r--r--src/core/hle/kernel/shared_memory.h48
-rw-r--r--src/core/hle/kernel/thread.cpp84
-rw-r--r--src/core/hle/kernel/thread.h4
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/apt/apt.cpp58
-rw-r--r--src/core/hle/service/apt/bcfnt/bcfnt.cpp71
-rw-r--r--src/core/hle/service/apt/bcfnt/bcfnt.h87
-rw-r--r--src/core/hle/service/csnd_snd.cpp13
-rw-r--r--src/core/hle/service/dsp_dsp.cpp4
-rw-r--r--src/core/hle/service/gsp_gpu.cpp5
-rw-r--r--src/core/hle/service/hid/hid.cpp5
-rw-r--r--src/core/hle/service/ir/ir.cpp5
-rw-r--r--src/core/hle/svc.cpp49
-rw-r--r--src/core/memory.h6
23 files changed, 496 insertions, 158 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a8d891689..f6a7566bf 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SRCS
hle/service/apt/apt_a.cpp
hle/service/apt/apt_s.cpp
hle/service/apt/apt_u.cpp
+ hle/service/apt/bcfnt/bcfnt.cpp
hle/service/boss/boss.cpp
hle/service/boss/boss_p.cpp
hle/service/boss/boss_u.cpp
@@ -185,6 +186,7 @@ set(HEADERS
hle/service/apt/apt_a.h
hle/service/apt/apt_s.h
hle/service/apt/apt_u.h
+ hle/service/apt/bcfnt/bcfnt.h
hle/service/boss/boss.h
hle/service/boss/boss_p.h
hle/service/boss/boss_u.h
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
index af442f81d..754c6f7db 100644
--- a/src/core/hle/applets/applet.h
+++ b/src/core/hle/applets/applet.h
@@ -65,6 +65,7 @@ protected:
virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
Service::APT::AppletId id; ///< Id of this Applet
+ std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
};
/// Returns whether a library applet is currently running
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp
index b4456ca90..bf39eca22 100644
--- a/src/core/hle/applets/mii_selector.cpp
+++ b/src/core/hle/applets/mii_selector.cpp
@@ -35,9 +35,14 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
ASSERT(sizeof(capture_info) == parameter.buffer_size);
memcpy(&capture_info, parameter.data, sizeof(capture_info));
+
using Kernel::MemoryPermission;
- framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite,
- MemoryPermission::ReadWrite, "MiiSelector Memory");
+ // Allocate a heap block of the required size for this applet.
+ heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
+ // Create a SharedMemory that directly points to this heap block.
+ framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
+ MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+ "MiiSelector Memory");
// Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result;
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 87238aa1c..90c6adc65 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -40,8 +40,12 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
memcpy(&capture_info, parameter.data, sizeof(capture_info));
using Kernel::MemoryPermission;
- framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite,
- MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
+ // Allocate a heap block of the required size for this applet.
+ heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
+ // Create a SharedMemory that directly points to this heap block.
+ framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
+ MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+ "SoftwareKeyboard Memory");
// Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result;
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 4d718b681..bf7f875b6 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -170,7 +170,8 @@ template<ResultCode func(s64*, u32, s32)> void Wrap() {
template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
u32 param_1 = 0;
- u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
+ // The last parameter is passed in R0 instead of R4
+ u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw;
Core::g_app_core->SetReg(1, param_1);
FuncReturn(retval);
}
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index 862643448..17ae87aef 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -55,6 +55,9 @@ void MemoryInit(u32 mem_type) {
memory_regions[i].size = memory_region_sizes[mem_type][i];
memory_regions[i].used = 0;
memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>();
+ // Reserve enough space for this region of FCRAM.
+ // We do not want this block of memory to be relocated when allocating from it.
+ memory_regions[i].linear_heap_memory->reserve(memory_regions[i].size);
base += memory_regions[i].size;
}
@@ -107,9 +110,7 @@ struct MemoryArea {
// We don't declare the IO regions in here since its handled by other means.
static MemoryArea memory_areas[] = {
- {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
{VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
- {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
};
}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 0546f6e16..69302cc82 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -209,7 +209,7 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
return ERR_INVALID_ADDRESS;
}
- // Expansion of the linear heap is only allowed if you do an allocation immediatelly at its
+ // Expansion of the linear heap is only allowed if you do an allocation immediately at its
// end. It's possible to free gaps in the middle of the heap and then reallocate them later,
// but expansions are only allowed at the end.
if (target == heap_end) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index a06afef2b..d781ef32c 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -142,8 +142,11 @@ public:
MemoryRegionInfo* memory_region = nullptr;
- /// Bitmask of the used TLS slots
- std::bitset<300> used_tls_slots;
+ /// The Thread Local Storage area is allocated as processes create threads,
+ /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
+ /// 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;
VAddr GetLinearHeapAreaAddress() const;
VAddr GetLinearHeapBase() const;
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index d90f0f00f..6a22c8986 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -7,6 +7,7 @@
#include "common/logging/log.h"
#include "core/memory.h"
+#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/shared_memory.h"
namespace Kernel {
@@ -14,93 +15,157 @@ namespace Kernel {
SharedMemory::SharedMemory() {}
SharedMemory::~SharedMemory() {}
-SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions,
- MemoryPermission other_permissions, std::string name) {
+SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
+ MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
+ shared_memory->owner_process = owner_process;
shared_memory->name = std::move(name);
- shared_memory->base_address = 0x0;
- shared_memory->fixed_address = 0x0;
shared_memory->size = size;
shared_memory->permissions = permissions;
shared_memory->other_permissions = other_permissions;
+ if (address == 0) {
+ // We need to allocate a block from the Linear Heap ourselves.
+ // We'll manually allocate some memory from the linear heap in the specified region.
+ MemoryRegionInfo* memory_region = GetMemoryRegion(region);
+ auto& linheap_memory = memory_region->linear_heap_memory;
+
+ ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, "Not enough space in region to allocate shared memory!");
+
+ shared_memory->backing_block = linheap_memory;
+ shared_memory->backing_block_offset = linheap_memory->size();
+ // Allocate some memory from the end of the linear heap for this region.
+ linheap_memory->insert(linheap_memory->end(), size, 0);
+ memory_region->used += size;
+
+ shared_memory->linear_heap_phys_address = Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
+
+ // Increase the amount of used linear heap memory for the owner process.
+ if (shared_memory->owner_process != nullptr) {
+ shared_memory->owner_process->linear_heap_used += size;
+ }
+
+ // Refresh the address mappings for the current process.
+ if (Kernel::g_current_process != nullptr) {
+ Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
+ }
+ } else {
+ // TODO(Subv): What happens if an application tries to create multiple memory blocks pointing to the same address?
+ auto& vm_manager = shared_memory->owner_process->vm_manager;
+ // The memory is already available and mapped in the owner process.
+ auto vma = vm_manager.FindVMA(address)->second;
+ // Copy it over to our own storage
+ shared_memory->backing_block = std::make_shared<std::vector<u8>>(vma.backing_block->data() + vma.offset,
+ vma.backing_block->data() + vma.offset + size);
+ shared_memory->backing_block_offset = 0;
+ // Unmap the existing pages
+ vm_manager.UnmapRange(address, size);
+ // Map our own block into the address space
+ vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared);
+ // Reprotect the block with the new permissions
+ vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions));
+ }
+
+ shared_memory->base_address = address;
return shared_memory;
}
-ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
- MemoryPermission other_permissions) {
+SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
+ MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
+ SharedPtr<SharedMemory> shared_memory(new SharedMemory);
- if (base_address != 0) {
- LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: already mapped at 0x%08X!",
- GetObjectId(), address, name.c_str(), base_address);
- // TODO: Verify error code with hardware
- return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
- ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
- }
+ shared_memory->owner_process = nullptr;
+ shared_memory->name = std::move(name);
+ shared_memory->size = size;
+ shared_memory->permissions = permissions;
+ shared_memory->other_permissions = other_permissions;
+ shared_memory->backing_block = heap_block;
+ shared_memory->backing_block_offset = offset;
+ shared_memory->base_address = Memory::HEAP_VADDR + offset;
- // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't
- // match what was specified when the memory block was created.
+ return shared_memory;
+}
- // TODO(Subv): Return E0E01BEE when address should be 0.
- // Note: Find out when that's the case.
+ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions,
+ MemoryPermission other_permissions) {
- if (fixed_address != 0) {
- if (address != 0 && address != fixed_address) {
- LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: fixed_addres is 0x%08X!",
- GetObjectId(), address, name.c_str(), fixed_address);
- // TODO: Verify error code with hardware
- return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
- ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
- }
+ MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions;
- // HACK(yuriks): This is only here to support the APT shared font mapping right now.
- // Later, this should actually map the memory block onto the address space.
- return RESULT_SUCCESS;
+ // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
+ if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
+ return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
}
- if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
- LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s outside of shared mem bounds!",
- GetObjectId(), address, name.c_str());
- // TODO: Verify error code with hardware
- return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
- ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
+ // Error out if the requested permissions don't match what the creator process allows.
+ if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
+ LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
+ GetObjectId(), address, name.c_str());
+ return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
}
- // TODO: Test permissions
+ // Heap-backed memory blocks can not be mapped with other_permissions = DontCare
+ if (base_address != 0 && other_permissions == MemoryPermission::DontCare) {
+ LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
+ GetObjectId(), address, name.c_str());
+ return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ }
- // HACK: Since there's no way to write to the memory block without mapping it onto the game
- // process yet, at least initialize memory the first time it's mapped.
- if (address != this->base_address) {
- std::memset(Memory::GetPointer(address), 0, size);
+ // Error out if the provided permissions are not compatible with what the creator process needs.
+ if (other_permissions != MemoryPermission::DontCare &&
+ static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
+ LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
+ GetObjectId(), address, name.c_str());
+ return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
}
- this->base_address = address;
+ // TODO(Subv): Check for the Shared Device Mem flag in the creator process.
+ /*if (was_created_with_shared_device_mem && address != 0) {
+ return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ }*/
- return RESULT_SUCCESS;
-}
+ // TODO(Subv): The same process that created a SharedMemory object
+ // can not map it in its own address space unless it was created with addr=0, result 0xD900182C.
-ResultCode SharedMemory::Unmap(VAddr address) {
- if (base_address == 0) {
- // TODO(Subv): Verify what actually happens when you want to unmap a memory block that
- // was originally mapped with address = 0
- return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ if (address != 0) {
+ if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
+ LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address",
+ GetObjectId(), address, name.c_str());
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ }
}
- if (base_address != address)
- return ResultCode(ErrorDescription::WrongAddress, ErrorModule::OS, ErrorSummary::InvalidState, ErrorLevel::Usage);
+ VAddr target_address = address;
- base_address = 0;
+ if (base_address == 0 && target_address == 0) {
+ // Calculate the address at which to map the memory block.
+ target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address);
+ }
+
+ // Map the memory block into the target process
+ auto result = target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
+ if (result.Failed()) {
+ LOG_ERROR(Kernel, "cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory",
+ GetObjectId(), target_address, name.c_str());
+ return result.Code();
+ }
- return RESULT_SUCCESS;
+ return target_process->vm_manager.ReprotectRange(target_address, size, ConvertPermissions(permissions));
}
-u8* SharedMemory::GetPointer(u32 offset) {
- if (base_address != 0)
- return Memory::GetPointer(base_address + offset);
+ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
+ // TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory.
+ return target_process->vm_manager.UnmapRange(address, size);
+}
+
+VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
+ u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
+ return static_cast<VMAPermission>(masked_permissions);
+};
- LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
- return nullptr;
+u8* SharedMemory::GetPointer(u32 offset) {
+ return backing_block->data() + backing_block_offset + offset;
}
} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index b51049ad0..0c404a9f8 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -9,6 +9,7 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/result.h"
namespace Kernel {
@@ -29,14 +30,29 @@ enum class MemoryPermission : u32 {
class SharedMemory final : public Object {
public:
/**
- * Creates a shared memory object
+ * Creates a shared memory object.
+ * @param owner_process Process that created this shared memory object.
* @param size Size of the memory block. Must be page-aligned.
* @param permissions Permission restrictions applied to the process which created the block.
* @param other_permissions Permission restrictions applied to other processes mapping the block.
+ * @param address The address from which to map the Shared Memory.
+ * @param region If the address is 0, the shared memory will be allocated in this region of the linear heap.
* @param name Optional object name, used for debugging purposes.
*/
- static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions,
- MemoryPermission other_permissions, std::string name = "Unknown");
+ static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
+ MemoryPermission other_permissions, VAddr address = 0, MemoryRegion region = MemoryRegion::BASE, std::string name = "Unknown");
+
+ /**
+ * Creates a shared memory object from a block of memory managed by an HLE applet.
+ * @param heap_block Heap block of the HLE applet.
+ * @param offset The offset into the heap block that the SharedMemory will map.
+ * @param size Size of the memory block. Must be page-aligned.
+ * @param permissions Permission restrictions applied to the process which created the block.
+ * @param other_permissions Permission restrictions applied to other processes mapping the block.
+ * @param name Optional object name, used for debugging purposes.
+ */
+ static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
+ MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet");
std::string GetTypeName() const override { return "SharedMemory"; }
std::string GetName() const override { return name; }
@@ -45,19 +61,27 @@ public:
HandleType GetHandleType() const override { return HANDLE_TYPE; }
/**
- * Maps a shared memory block to an address in system memory
+ * Converts the specified MemoryPermission into the equivalent VMAPermission.
+ * @param permission The MemoryPermission to convert.
+ */
+ static VMAPermission ConvertPermissions(MemoryPermission permission);
+
+ /**
+ * Maps a shared memory block to an address in the target process' address space
+ * @param target_process Process on which to map the memory block.
* @param address Address in system memory to map shared memory block to
* @param permissions Memory block map permissions (specified by SVC field)
* @param other_permissions Memory block map other permissions (specified by SVC field)
*/
- ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
+ ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
/**
* Unmaps a shared memory block from the specified address in system memory
+ * @param target_process Process from which to umap the memory block.
* @param address Address in system memory where the shared memory block is mapped
* @return Result code of the unmap operation
*/
- ResultCode Unmap(VAddr address);
+ ResultCode Unmap(Process* target_process, VAddr address);
/**
* Gets a pointer to the shared memory block
@@ -66,10 +90,16 @@ public:
*/
u8* GetPointer(u32 offset = 0);
- /// Address of shared memory block in the process.
+ /// Process that created this shared memory block.
+ SharedPtr<Process> owner_process;
+ /// Address of shared memory block in the owner process if specified.
VAddr base_address;
- /// Fixed address to allow mapping to. Used for blocks created from the linear heap.
- VAddr fixed_address;
+ /// Physical address of the shared memory block in the linear heap if no address was specified during creation.
+ PAddr linear_heap_phys_address;
+ /// Backing memory for this shared memory block.
+ std::shared_ptr<std::vector<u8>> backing_block;
+ /// Offset into the backing block for this shared memory.
+ u32 backing_block_offset;
/// Size of the memory block. Page-aligned.
u32 size;
/// Permission restrictions applied to the process which created the block.
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 6dc95d0f1..68f026918 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -117,9 +117,10 @@ void Thread::Stop() {
}
wait_objects.clear();
- Kernel::g_current_process->used_tls_slots[tls_index] = false;
- g_current_process->misc_memory_used -= Memory::TLS_ENTRY_SIZE;
- g_current_process->memory_region->used -= Memory::TLS_ENTRY_SIZE;
+ // Mark the TLS slot in the thread's page as free.
+ u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
+ u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
+ Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
HLE::Reschedule(__func__);
}
@@ -366,6 +367,31 @@ static void DebugThreadQueue() {
}
}
+/**
+ * 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).
+ */
+std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(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 (unsigned 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 (unsigned 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);
+}
+
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority,
u32 arg, s32 processor_id, VAddr stack_top) {
if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
@@ -403,22 +429,50 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
thread->owner_process = g_current_process;
- thread->tls_index = -1;
thread->waitsynch_waited = false;
// Find the next available TLS index, and mark it as used
- auto& used_tls_slots = Kernel::g_current_process->used_tls_slots;
- for (unsigned int i = 0; i < used_tls_slots.size(); ++i) {
- if (used_tls_slots[i] == false) {
- thread->tls_index = i;
- used_tls_slots[i] = true;
- break;
+ auto& tls_slots = Kernel::g_current_process->tls_slots;
+ bool needs_allocation = true;
+ u32 available_page; // Which allocated page has free space
+ u32 available_slot; // Which slot within the page is free
+
+ std::tie(available_page, available_slot, needs_allocation) = GetFreeThreadLocalSlot(tls_slots);
+
+ if (needs_allocation) {
+ // There are no already-allocated pages with free slots, lets allocate a new one.
+ // TLS pages are allocated from the BASE region in the linear heap.
+ MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE);
+ auto& linheap_memory = memory_region->linear_heap_memory;
+
+ if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
+ LOG_ERROR(Kernel_SVC, "Not enough space in region to allocate a new TLS page for thread");
+ return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Permanent);
}
+
+ u32 offset = linheap_memory->size();
+
+ // Allocate some memory from the end of the linear heap for this region.
+ linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0);
+ memory_region->used += Memory::PAGE_SIZE;
+ Kernel::g_current_process->linear_heap_used += Memory::PAGE_SIZE;
+
+ 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
+
+ auto& vm_manager = Kernel::g_current_process->vm_manager;
+ vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
+
+ // Map the page to the current process' address space.
+ // TODO(Subv): Find the correct MemoryState for this region.
+ vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
+ linheap_memory, offset, Memory::PAGE_SIZE, MemoryState::Private);
}
- ASSERT_MSG(thread->tls_index != -1, "Out of TLS space");
- g_current_process->misc_memory_used += Memory::TLS_ENTRY_SIZE;
- g_current_process->memory_region->used += Memory::TLS_ENTRY_SIZE;
+ // Mark the slot as used
+ tls_slots[available_page].set(available_slot);
+ thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
@@ -509,10 +563,6 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output;
}
-VAddr Thread::GetTLSAddress() const {
- return Memory::TLS_AREA_VADDR + tls_index * Memory::TLS_ENTRY_SIZE;
-}
-
////////////////////////////////////////////////////////////////////////////////////////////////////
void ThreadingInit() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 97ba57fc5..deab5d5a6 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -127,7 +127,7 @@ public:
* Returns the Thread Local Storage address of the current thread
* @returns VAddr of the thread's TLS
*/
- VAddr GetTLSAddress() const;
+ VAddr GetTLSAddress() const { return tls_address; }
Core::ThreadContext context;
@@ -144,7 +144,7 @@ public:
s32 processor_id;
- s32 tls_index; ///< Index of the Thread Local Storage of the thread
+ VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 3fc1ab4ee..bfb3327ce 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -17,6 +17,7 @@
/// Detailed description of the error. This listing is likely incomplete.
enum class ErrorDescription : u32 {
Success = 0,
+ WrongPermission = 46,
OS_InvalidBufferDescriptor = 48,
WrongAddress = 53,
FS_NotFound = 120,
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 6d72e8188..73fce6079 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -12,6 +12,7 @@
#include "core/hle/service/apt/apt_a.h"
#include "core/hle/service/apt/apt_s.h"
#include "core/hle/service/apt/apt_u.h"
+#include "core/hle/service/apt/bcfnt/bcfnt.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/kernel/event.h"
@@ -22,23 +23,14 @@
namespace Service {
namespace APT {
-// Address used for shared font (as observed on HW)
-// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via
-// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any
-// address other than 0x18000000 due to internal pointers in the shared font dump that would need to
-// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then
-// correctly mapping it in Citra, however we still do not understand how the mapping is determined.
-static const VAddr SHARED_FONT_VADDR = 0x18000000;
-
/// Handle to shared memory region designated to for shared system font
static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
+static bool shared_font_relocated = false;
static Kernel::SharedPtr<Kernel::Mutex> lock;
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
-static std::shared_ptr<std::vector<u8>> shared_font;
-
static u32 cpu_percent; ///< CPU time available to the running application
/// Parameter data to be returned in the next call to Glance/ReceiveParameter
@@ -74,23 +66,25 @@ void Initialize(Service::Interface* self) {
void GetSharedFont(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- if (shared_font != nullptr) {
- // TODO(yuriks): This is a hack to keep this working right now even with our completely
- // broken shared memory system.
- shared_font_mem->fixed_address = SHARED_FONT_VADDR;
- Kernel::g_current_process->vm_manager.MapMemoryBlock(shared_font_mem->fixed_address,
- shared_font, 0, shared_font_mem->size, Kernel::MemoryState::Shared);
-
- cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = SHARED_FONT_VADDR;
- cmd_buff[3] = IPC::MoveHandleDesc();
- cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
- } else {
- cmd_buff[0] = IPC::MakeHeader(0x44, 1, 0);
- cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
- LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT);
+ // The shared font has to be relocated to the new address before being passed to the application.
+ VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
+ // The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base,
+ // so we relocate it from there to our real address.
+ // TODO(Subv): This address is wrong if the shared font is dumped from a n3DS,
+ // we need a way to automatically calculate the original address of the font from the file.
+ static const VAddr SHARED_FONT_VADDR = 0x18000000;
+ if (!shared_font_relocated) {
+ BCFNT::RelocateSharedFont(shared_font_mem, SHARED_FONT_VADDR, target_address);
+ shared_font_relocated = true;
}
+ cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ // Since the SharedMemory interface doesn't provide the address at which the memory was allocated,
+ // the real APT service calculates this address by scanning the entire address space (using svcQueryMemory)
+ // and searches for an allocation of the same size as the Shared Font.
+ cmd_buff[2] = target_address;
+ cmd_buff[3] = IPC::MoveHandleDesc();
+ cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
}
void NotifyToWait(Service::Interface* self) {
@@ -433,14 +427,12 @@ void Init() {
FileUtil::IOFile file(filepath, "rb");
if (file.IsOpen()) {
- // Read shared font data
- shared_font = std::make_shared<std::vector<u8>>((size_t)file.GetSize());
- file.ReadBytes(shared_font->data(), shared_font->size());
-
// Create shared font memory object
using Kernel::MemoryPermission;
- shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB
- MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem");
+ shared_font_mem = Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
+ MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
+ // Read shared font data
+ file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
} else {
LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
shared_font_mem = nullptr;
@@ -459,8 +451,8 @@ void Init() {
}
void Shutdown() {
- shared_font = nullptr;
shared_font_mem = nullptr;
+ shared_font_relocated = false;
lock = nullptr;
notification_event = nullptr;
parameter_event = nullptr;
diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.cpp b/src/core/hle/service/apt/bcfnt/bcfnt.cpp
new file mode 100644
index 000000000..b0d39d4a5
--- /dev/null
+++ b/src/core/hle/service/apt/bcfnt/bcfnt.cpp
@@ -0,0 +1,71 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/apt/bcfnt/bcfnt.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace APT {
+namespace BCFNT {
+
+void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address) {
+ static const u32 SharedFontStartOffset = 0x80;
+ u8* data = shared_font->GetPointer(SharedFontStartOffset);
+
+ CFNT cfnt;
+ memcpy(&cfnt, data, sizeof(cfnt));
+
+ // Advance past the header
+ data = shared_font->GetPointer(SharedFontStartOffset + cfnt.header_size);
+
+ for (unsigned block = 0; block < cfnt.num_blocks; ++block) {
+
+ u32 section_size = 0;
+ if (memcmp(data, "FINF", 4) == 0) {
+ BCFNT::FINF finf;
+ memcpy(&finf, data, sizeof(finf));
+ section_size = finf.section_size;
+
+ // Relocate the offsets in the FINF section
+ finf.cmap_offset += new_address - previous_address;
+ finf.cwdh_offset += new_address - previous_address;
+ finf.tglp_offset += new_address - previous_address;
+
+ memcpy(data, &finf, sizeof(finf));
+ } else if (memcmp(data, "CMAP", 4) == 0) {
+ BCFNT::CMAP cmap;
+ memcpy(&cmap, data, sizeof(cmap));
+ section_size = cmap.section_size;
+
+ // Relocate the offsets in the CMAP section
+ cmap.next_cmap_offset += new_address - previous_address;
+
+ memcpy(data, &cmap, sizeof(cmap));
+ } else if (memcmp(data, "CWDH", 4) == 0) {
+ BCFNT::CWDH cwdh;
+ memcpy(&cwdh, data, sizeof(cwdh));
+ section_size = cwdh.section_size;
+
+ // Relocate the offsets in the CWDH section
+ cwdh.next_cwdh_offset += new_address - previous_address;
+
+ memcpy(data, &cwdh, sizeof(cwdh));
+ } else if (memcmp(data, "TGLP", 4) == 0) {
+ BCFNT::TGLP tglp;
+ memcpy(&tglp, data, sizeof(tglp));
+ section_size = tglp.section_size;
+
+ // Relocate the offsets in the TGLP section
+ tglp.sheet_data_offset += new_address - previous_address;
+
+ memcpy(data, &tglp, sizeof(tglp));
+ }
+
+ data += section_size;
+ }
+}
+
+} // namespace BCFNT
+} // namespace APT
+} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/apt/bcfnt/bcfnt.h b/src/core/hle/service/apt/bcfnt/bcfnt.h
new file mode 100644
index 000000000..388c6bea0
--- /dev/null
+++ b/src/core/hle/service/apt/bcfnt/bcfnt.h
@@ -0,0 +1,87 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/swap.h"
+
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace APT {
+namespace BCFNT { ///< BCFNT Shared Font file structures
+
+struct CFNT {
+ u8 magic[4];
+ u16_le endianness;
+ u16_le header_size;
+ u32_le version;
+ u32_le file_size;
+ u32_le num_blocks;
+};
+
+struct FINF {
+ u8 magic[4];
+ u32_le section_size;
+ u8 font_type;
+ u8 line_feed;
+ u16_le alter_char_index;
+ u8 default_width[3];
+ u8 encoding;
+ u32_le tglp_offset;
+ u32_le cwdh_offset;
+ u32_le cmap_offset;
+ u8 height;
+ u8 width;
+ u8 ascent;
+ u8 reserved;
+};
+
+struct TGLP {
+ u8 magic[4];
+ u32_le section_size;
+ u8 cell_width;
+ u8 cell_height;
+ u8 baseline_position;
+ u8 max_character_width;
+ u32_le sheet_size;
+ u16_le num_sheets;
+ u16_le sheet_image_format;
+ u16_le num_columns;
+ u16_le num_rows;
+ u16_le sheet_width;
+ u16_le sheet_height;
+ u32_le sheet_data_offset;
+};
+
+struct CMAP {
+ u8 magic[4];
+ u32_le section_size;
+ u16_le code_begin;
+ u16_le code_end;
+ u16_le mapping_method;
+ u16_le reserved;
+ u32_le next_cmap_offset;
+};
+
+struct CWDH {
+ u8 magic[4];
+ u32_le section_size;
+ u16_le start_index;
+ u16_le end_index;
+ u32_le next_cwdh_offset;
+};
+
+/**
+ * Relocates the internal addresses of the BCFNT Shared Font to the new base.
+ * @param shared_font SharedMemory object that contains the Shared Font
+ * @param previous_address Previous address at which the offsets in the structure were based.
+ * @param new_address New base for the offsets in the structure.
+ */
+void RelocateSharedFont(Kernel::SharedPtr<Kernel::SharedMemory> shared_font, VAddr previous_address, VAddr new_address);
+
+} // namespace BCFNT
+} // namespace APT
+} // namespace Service
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 6318bf2a7..d2bb8941c 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <cstring>
+#include "common/alignment.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/shared_memory.h"
@@ -41,14 +42,16 @@ static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
void Initialize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- shared_memory = Kernel::SharedMemory::Create(cmd_buff[1],
- Kernel::MemoryPermission::ReadWrite,
- Kernel::MemoryPermission::ReadWrite, "CSNDSharedMem");
+ u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
+ using Kernel::MemoryPermission;
+ shared_memory = Kernel::SharedMemory::Create(nullptr, size,
+ MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+ 0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
mutex = Kernel::Mutex::Create(false);
- cmd_buff[1] = 0;
- cmd_buff[2] = 0x4000000;
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = IPC::MoveHandleDesc(2);
cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom();
cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
}
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 274fc751a..10730d7ac 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -440,9 +440,9 @@ static void GetHeadphoneStatus(Service::Interface* self) {
cmd_buff[0] = IPC::MakeHeader(0x1F, 2, 0);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 0; // Not using headphones?
+ cmd_buff[2] = 0; // Not using headphones
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_DEBUG(Service_DSP, "called");
}
/**
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index b4c146e08..8ded9b09b 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -335,8 +335,9 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
g_interrupt_event->name = "GSP_GPU::interrupt_event";
using Kernel::MemoryPermission;
- g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
- MemoryPermission::ReadWrite, "GSPSharedMem");
+ g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
+ MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
+ 0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1053d0f40..d216cecb4 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -280,8 +280,9 @@ void Init() {
AddService(new HID_SPVR_Interface);
using Kernel::MemoryPermission;
- shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
- MemoryPermission::Read, "HID:SharedMem");
+ shared_mem = SharedMemory::Create(nullptr, 0x1000,
+ MemoryPermission::ReadWrite, MemoryPermission::Read,
+ 0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
next_pad_index = 0;
next_touch_index = 0;
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
index 505c441c6..079a87e48 100644
--- a/src/core/hle/service/ir/ir.cpp
+++ b/src/core/hle/service/ir/ir.cpp
@@ -94,8 +94,9 @@ void Init() {
AddService(new IR_User_Interface);
using Kernel::MemoryPermission;
- shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite,
- Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory");
+ shared_memory = SharedMemory::Create(nullptr, 0x1000,
+ Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::ReadWrite,
+ 0, Kernel::MemoryRegion::BASE, "IR:SharedMemory");
transfer_shared_memory = nullptr;
// Create event handle(s)
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 60c8747f3..3a53126c1 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -99,6 +99,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
switch (operation & MEMOP_OPERATION_MASK) {
case MEMOP_FREE:
{
+ // TODO(Subv): What happens if an application tries to FREE a block of memory that has a SharedMemory pointing to it?
if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
ResultCode result = process.HeapFree(addr0, size);
if (result.IsError()) return result;
@@ -160,8 +161,6 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
handle, addr, permissions, other_permissions);
- // TODO(Subv): The same process that created a SharedMemory object can not map it in its own address space
-
SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
if (shared_memory == nullptr)
return ERR_INVALID_HANDLE;
@@ -176,7 +175,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
case MemoryPermission::WriteExecute:
case MemoryPermission::ReadWriteExecute:
case MemoryPermission::DontCare:
- return shared_memory->Map(addr, permissions_type,
+ return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type,
static_cast<MemoryPermission>(other_permissions));
default:
LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
@@ -196,7 +195,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
if (shared_memory == nullptr)
return ERR_INVALID_HANDLE;
- return shared_memory->Unmap(addr);
+ return shared_memory->Unmap(Kernel::g_current_process.get(), addr);
}
/// Connect to an OS service given the port name, returns the handle to the port to out
@@ -790,18 +789,44 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
if (size % Memory::PAGE_SIZE != 0)
return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
- // TODO(Subv): Return E0A01BF5 if the address is not in the application's heap
-
- // TODO(Subv): Implement this function properly
+ SharedPtr<SharedMemory> shared_memory = nullptr;
using Kernel::MemoryPermission;
- SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
- (MemoryPermission)my_permission, (MemoryPermission)other_permission);
- // Map the SharedMemory to the specified address
- shared_memory->base_address = addr;
+ auto VerifyPermissions = [](MemoryPermission permission) {
+ // SharedMemory blocks can not be created with Execute permissions
+ switch (permission) {
+ case MemoryPermission::None:
+ case MemoryPermission::Read:
+ case MemoryPermission::Write:
+ case MemoryPermission::ReadWrite:
+ case MemoryPermission::DontCare:
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) ||
+ !VerifyPermissions(static_cast<MemoryPermission>(other_permission)))
+ return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+
+ if (addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) {
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ }
+
+ // When trying to create a memory block with address = 0,
+ // if the process has the Shared Device Memory flag in the exheader,
+ // then we have to allocate from the same region as the caller process instead of the BASE region.
+ Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE;
+ if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem)
+ region = Kernel::g_current_process->flags.memory_region;
+
+ shared_memory = SharedMemory::Create(Kernel::g_current_process, size,
+ static_cast<MemoryPermission>(my_permission), static_cast<MemoryPermission>(other_permission), addr, region);
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
- LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);
+ LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr);
return RESULT_SUCCESS;
}
diff --git a/src/core/memory.h b/src/core/memory.h
index 9caa3c3f5..126d60471 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -100,15 +100,9 @@ enum : VAddr {
SHARED_PAGE_SIZE = 0x00001000,
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
- // TODO(yuriks): The size of this area is dynamic, the kernel grows
- // it as more and more threads are created. For now we'll just use a
- // hardcoded value.
/// Area where TLS (Thread-Local Storage) buffers are allocated.
TLS_AREA_VADDR = 0x1FF82000,
TLS_ENTRY_SIZE = 0x200,
- TLS_AREA_SIZE = 300 * TLS_ENTRY_SIZE + 0x800, // Space for up to 300 threads + round to page size
- TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
-
/// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
NEW_LINEAR_HEAP_VADDR = 0x30000000,