summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel')
-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.h9
-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.cpp89
-rw-r--r--src/core/hle/kernel/thread.h4
7 files changed, 244 insertions, 90 deletions
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 6d2ca96a2..d781ef32c 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -107,6 +107,8 @@ public:
ProcessFlags flags;
/// Kernel compatibility version for this process
u16 kernel_version = 0;
+ /// The default CPU for this process, threads are scheduled on this cpu by default.
+ u8 ideal_processor = 0;
/// The id of this process
u32 process_id = next_process_id++;
@@ -140,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 bf32f653d..43def6146 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
@@ -472,6 +526,8 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
SharedPtr<Thread> thread = thread_res.MoveFrom();
+ thread->context.fpscr = FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
+
// Run new "main" thread
SwitchContext(thread.get());
@@ -483,7 +539,8 @@ void Reschedule() {
Thread* cur = GetCurrentThread();
Thread* next = PopNextReadyThread();
- HLE::g_reschedule = false;
+
+ HLE::DoneRescheduling();
// Don't bother switching to the same thread
if (next == cur)
@@ -508,10 +565,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