Merge remote-tracking branch 'upstream/master' into nx

# Conflicts:
#	src/core/CMakeLists.txt
#	src/core/arm/dynarmic/arm_dynarmic.cpp
#	src/core/arm/dyncom/arm_dyncom.cpp
#	src/core/hle/kernel/process.cpp
#	src/core/hle/kernel/thread.cpp
#	src/core/hle/kernel/thread.h
#	src/core/hle/kernel/vm_manager.cpp
#	src/core/loader/3dsx.cpp
#	src/core/loader/elf.cpp
#	src/core/loader/ncch.cpp
#	src/core/memory.cpp
#	src/core/memory.h
#	src/core/memory_setup.h
This commit is contained in:
bunnei
2017-10-09 23:56:20 -04:00
241 changed files with 20955 additions and 2730 deletions

View File

@ -37,7 +37,7 @@ SharedPtr<Object> HLERequestContext::GetIncomingHandle(u32 id_from_cmdbuf) const
u32 HLERequestContext::AddOutgoingHandle(SharedPtr<Object> object) {
request_handles.push_back(std::move(object));
return request_handles.size() - 1;
return static_cast<u32>(request_handles.size() - 1);
}
void HLERequestContext::ClearIncomingObjects() {

View File

@ -8,6 +8,7 @@
#include <string>
#include <utility>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include "common/assert.h"
#include "common/common_types.h"
namespace Kernel {
@ -84,6 +85,8 @@ public:
case HandleType::ClientSession:
return false;
}
UNREACHABLE();
}
public:
@ -129,4 +132,4 @@ void Init(u32 system_mode);
/// Shutdown the kernel
void Shutdown();
} // namespace
} // namespace Kernel

View File

@ -8,7 +8,6 @@
#include <memory>
#include <utility>
#include <vector>
#include "audio_core/audio_core.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
@ -24,7 +23,7 @@
namespace Kernel {
static MemoryRegionInfo memory_regions[3];
MemoryRegionInfo memory_regions[3];
/// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system
/// memory configuration type.
@ -96,9 +95,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
}
}
std::array<u8, Memory::VRAM_SIZE> vram;
std::array<u8, Memory::N3DS_EXTRA_RAM_SIZE> n3ds_extra_ram;
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {
using namespace Memory;
@ -143,30 +139,14 @@ void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mappin
return;
}
// TODO(yuriks): Use GetPhysicalPointer when that becomes independent of the virtual
// mappings.
u8* target_pointer = nullptr;
switch (area->paddr_base) {
case VRAM_PADDR:
target_pointer = vram.data();
break;
case DSP_RAM_PADDR:
target_pointer = AudioCore::GetDspMemory().data();
break;
case N3DS_EXTRA_RAM_PADDR:
target_pointer = n3ds_extra_ram.data();
break;
default:
UNREACHABLE();
}
u8* target_pointer = Memory::GetPhysicalPointer(area->paddr_base + offset_into_region);
// TODO(yuriks): This flag seems to have some other effect, but it's unknown what
MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO;
auto vma = address_space
.MapBackingMemory(mapping.address, target_pointer + offset_into_region,
mapping.size, memory_state)
.Unwrap();
auto vma =
address_space.MapBackingMemory(mapping.address, target_pointer, mapping.size, memory_state)
.Unwrap();
address_space.Reprotect(vma,
mapping.read_only ? VMAPermission::Read : VMAPermission::ReadWrite);
}

View File

@ -26,4 +26,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
void MapSharedPages(VMManager& address_space);
extern MemoryRegionInfo memory_regions[3];
} // namespace Kernel

View File

@ -25,10 +25,11 @@ void ReleaseThreadMutexes(Thread* thread) {
Mutex::Mutex() {}
Mutex::~Mutex() {}
SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
SharedPtr<Mutex> Mutex::Create(bool initial_locked, VAddr addr, std::string name) {
SharedPtr<Mutex> mutex(new Mutex);
mutex->lock_count = 0;
mutex->addr = addr;
mutex->name = std::move(name);
mutex->holding_thread = nullptr;
@ -90,7 +91,7 @@ void Mutex::UpdatePriority() {
if (!holding_thread)
return;
s32 best_priority = THREADPRIO_LOWEST;
u32 best_priority = THREADPRIO_LOWEST;
for (auto& waiter : GetWaitingThreads()) {
if (waiter->current_priority < best_priority)
best_priority = waiter->current_priority;

View File

@ -21,7 +21,7 @@ public:
* @param name Optional name of mutex
* @return Pointer to new Mutex object
*/
static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown");
static SharedPtr<Mutex> Create(bool initial_locked, VAddr addr, std::string name = "Unknown");
std::string GetTypeName() const override {
return "Mutex";
@ -39,6 +39,7 @@ public:
u32 priority; ///< The priority of the mutex, used for priority inheritance.
std::string name; ///< Name of mutex (optional)
SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
VAddr addr;
/**
* Elevate the mutex priority to the best priority

View File

@ -129,7 +129,8 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
}
vm_manager.LogLayout(Log::Level::Debug);
Kernel::SetupMainThread(entry_point, main_thread_priority);
Kernel::SetupMainThread(entry_point, main_thread_priority, this);
}
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {

View File

@ -61,7 +61,7 @@ s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const {
}
}
s32 ResourceLimit::GetMaxResourceValue(u32 resource) const {
u32 ResourceLimit::GetMaxResourceValue(u32 resource) const {
switch (resource) {
case PRIORITY:
return max_priority;

View File

@ -67,7 +67,7 @@ public:
* @param resource Requested resource type
* @returns The max value of the resource type
*/
s32 GetMaxResourceValue(u32 resource) const;
u32 GetMaxResourceValue(u32 resource) const;
/// Name of resource limit object.
std::string name;

View File

@ -13,7 +13,7 @@ namespace Kernel {
Semaphore::Semaphore() {}
Semaphore::~Semaphore() {}
ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count,
ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, VAddr address,
std::string name) {
if (initial_count > max_count)
@ -25,6 +25,7 @@ ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_cou
// and the rest is reserved for the caller thread
semaphore->max_count = max_count;
semaphore->available_count = initial_count;
semaphore->address = address;
semaphore->name = std::move(name);
return MakeResult<SharedPtr<Semaphore>>(std::move(semaphore));

View File

@ -22,7 +22,7 @@ public:
* @param name Optional name of semaphore
* @return The created semaphore
*/
static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count,
static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, VAddr address,
std::string name = "Unknown");
std::string GetTypeName() const override {
@ -39,6 +39,7 @@ public:
s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
s32 available_count; ///< Number of free slots left in the semaphore
VAddr address;
std::string name; ///< Name of semaphore (optional)
bool ShouldWait(Thread* thread) const override;

View File

@ -42,7 +42,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
memory_region->used += size;
shared_memory->linear_heap_phys_address =
Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
Memory::FCRAM_PADDR + memory_region->base +
static_cast<PAddr>(shared_memory->backing_block_offset);
// Increase the amount of used linear heap memory for the owner process.
if (shared_memory->owner_process != nullptr) {
@ -54,22 +55,19 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
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));
auto vma = vm_manager.FindVMA(address);
ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
// The returned VMA might be a bigger one encompassing the desired address.
auto vma_offset = address - vma->first;
ASSERT_MSG(vma_offset + size <= vma->second.size,
"Shared memory exceeds bounds of mapped block");
shared_memory->backing_block = vma->second.backing_block;
shared_memory->backing_block_offset = vma->second.offset + vma_offset;
}
shared_memory->base_address = address;
@ -183,4 +181,4 @@ u8* SharedMemory::GetPointer(u32 offset) {
return backing_block->data() + backing_block_offset + offset;
}
} // namespace
} // namespace Kernel

View File

@ -114,7 +114,7 @@ public:
/// 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_t backing_block_offset;
/// Size of the memory block. Page-aligned.
u32 size;
/// Permission restrictions applied to the process which created the block.

View File

@ -111,7 +111,7 @@ void Thread::Stop() {
Thread* ArbitrateHighestPriorityThread(u32 address) {
Thread* highest_priority_thread = nullptr;
s32 priority = THREADPRIO_LOWEST;
u32 priority = THREADPRIO_LOWEST;
// Iterate through threads, find highest priority thread that is waiting to be arbitrated...
for (auto& thread : thread_list) {
@ -171,15 +171,24 @@ static void SwitchContext(Thread* new_thread) {
// Cancel any outstanding wakeup events for this thread
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
auto previous_process = Kernel::g_current_process;
current_thread = new_thread;
ready_queue.remove(new_thread->current_priority, new_thread);
new_thread->status = THREADSTATUS_RUNNING;
if (previous_process != current_thread->owner_process) {
Kernel::g_current_process = current_thread->owner_process;
SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
}
Core::CPU().LoadContext(new_thread->context);
Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
} else {
current_thread = nullptr;
// Note: We do not reset the current process and current page table when idling because
// technically we haven't changed processes, our threads are just paused.
}
}
@ -238,12 +247,15 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) {
thread->wait_set_output = false;
// Invoke the wakeup callback before clearing the wait objects
if (thread->wakeup_callback)
thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr);
// Remove the thread from each of its waiting objects' waitlists
for (auto& object : thread->wait_objects)
object->RemoveWaitingThread(thread.get());
thread->wait_objects.clear();
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
}
thread->ResumeFromWait();
@ -269,6 +281,9 @@ void Thread::ResumeFromWait() {
break;
case THREADSTATUS_READY:
// The thread's wakeup callback must have already been cleared when the thread was first
// awoken.
ASSERT(wakeup_callback == nullptr);
// If the thread is waiting on multiple wait objects, it might be awoken more than once
// before actually resuming. We can ignore subsequent wakeups if the thread status has
// already been set to THREADSTATUS_READY.
@ -284,6 +299,8 @@ void Thread::ResumeFromWait() {
return;
}
wakeup_callback = nullptr;
ready_queue.push_back(current_priority, this);
status = THREADSTATUS_READY;
Core::System::GetInstance().PrepareReschedule();
@ -302,7 +319,7 @@ static void DebugThreadQueue() {
}
for (auto& t : thread_list) {
s32 priority = ready_queue.contains(t.get());
u32 priority = ready_queue.contains(t.get());
if (priority != -1) {
LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId());
}
@ -352,7 +369,8 @@ static void ResetThreadContext(ARM_Interface::ThreadContext& context, VAddr stac
}
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority,
u32 arg, s32 processor_id, VAddr stack_top) {
u32 arg, s32 processor_id, VAddr stack_top,
SharedPtr<Process> owner_process) {
// Check if priority is in ranged. Lowest priority -> highest priority id.
if (priority > THREADPRIO_LOWEST) {
LOG_ERROR(Kernel_SVC, "Invalid thread priority: %d", priority);
@ -366,7 +384,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
// TODO(yuriks): Other checks, returning 0xD9001BEA
if (!Memory::IsValidVirtualAddress(entry_point)) {
if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
// TODO: Verify error
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
@ -385,15 +403,14 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->nominal_priority = thread->current_priority = priority;
thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
thread->wait_set_output = false;
thread->wait_objects.clear();
thread->wait_address = 0;
thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap();
thread->owner_process = g_current_process;
thread->owner_process = owner_process;
// Find the next available TLS index, and mark it as used
auto& tls_slots = Kernel::g_current_process->tls_slots;
auto& tls_slots = owner_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
@ -412,18 +429,18 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
return ERR_OUT_OF_MEMORY;
}
u32 offset = linheap_memory->size();
size_t 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;
owner_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_page = static_cast<u32>(tls_slots.size() - 1);
available_slot = 0; // Use the first slot in the new page
auto& vm_manager = Kernel::g_current_process->vm_manager;
auto& vm_manager = owner_process->vm_manager;
vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
// Map the page to the current process' address space.
@ -447,7 +464,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
return MakeResult<SharedPtr<Thread>>(std::move(thread));
}
void Thread::SetPriority(s32 priority) {
void Thread::SetPriority(u32 priority) {
ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST,
"Invalid priority value.");
// If thread was ready, adjust queues
@ -460,7 +477,7 @@ void Thread::SetPriority(s32 priority) {
}
void Thread::UpdatePriority() {
s32 best_priority = nominal_priority;
u32 best_priority = nominal_priority;
for (auto& mutex : held_mutexes) {
if (mutex->priority < best_priority)
best_priority = mutex->priority;
@ -468,7 +485,7 @@ void Thread::UpdatePriority() {
BoostPriority(best_priority);
}
void Thread::BoostPriority(s32 priority) {
void Thread::BoostPriority(u32 priority) {
// If thread was ready, adjust queues
if (status == THREADSTATUS_READY)
ready_queue.move(this, current_priority, priority);
@ -477,21 +494,20 @@ void Thread::BoostPriority(s32 priority) {
current_priority = priority;
}
SharedPtr<Thread> SetupMainThread(VAddr entry_point, s32 priority) {
DEBUG_ASSERT(!GetCurrentThread());
SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Process> owner_process) {
// Setup page table so we can write to memory
SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
// Initialize new "main" thread
auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
Memory::HEAP_VADDR_END);
Memory::HEAP_VADDR_END, owner_process);
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
thread->context.fpscr =
FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
// Run new "main" thread
SwitchContext(thread.get());
// Note: The newly created thread will be run when the scheduler fires.
return thread;
}
@ -525,7 +541,13 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
s32 Thread::GetWaitObjectIndex(WaitObject* object) const {
ASSERT_MSG(!wait_objects.empty(), "Thread is not waiting for anything");
auto match = std::find(wait_objects.rbegin(), wait_objects.rend(), object);
return std::distance(match, wait_objects.rend()) - 1;
return static_cast<s32>(std::distance(match, wait_objects.rend()) - 1);
}
VAddr Thread::GetCommandBufferAddress() const {
// Offset from the start of TLS at which the IPC command buffer begins.
static constexpr int CommandHeaderOffset = 0x80;
return GetTLSAddress() + CommandHeaderOffset;
}
////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -15,7 +15,7 @@
#include "core/hle/kernel/wait_object.h"
#include "core/hle/result.h"
enum ThreadPriority : s32 {
enum ThreadPriority : u32 {
THREADPRIO_HIGHEST = 0, ///< Highest thread priority
THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps
@ -41,6 +41,11 @@ enum ThreadStatus {
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
};
enum class ThreadWakeupReason {
Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal.
Timeout // The thread was woken up due to a wait timeout.
};
namespace Kernel {
class Mutex;
@ -56,10 +61,12 @@ public:
* @param arg User data to pass to the thread
* @param processor_id The ID(s) of the processors on which the thread is desired to be run
* @param stack_top The address of the thread's stack top
* @param owner_process The parent process for the thread
* @return A shared pointer to the newly created thread
*/
static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority,
u32 arg, s32 processor_id, VAddr stack_top);
u32 arg, s32 processor_id, VAddr stack_top,
SharedPtr<Process> owner_process);
std::string GetName() const override {
return name;
@ -80,7 +87,7 @@ public:
* Gets the thread's current priority
* @return The current thread's priority
*/
s32 GetPriority() const {
u32 GetPriority() const {
return current_priority;
}
@ -88,7 +95,7 @@ public:
* Sets the thread's current priority
* @param priority The new priority
*/
void SetPriority(s32 priority);
void SetPriority(u32 priority);
/**
* Boost's a thread's priority to the best priority among the thread's held mutexes.
@ -100,7 +107,7 @@ public:
* Temporarily boosts the thread's priority until the next time it is scheduled
* @param priority The new priority
*/
void BoostPriority(s32 priority);
void BoostPriority(u32 priority);
/**
* Gets the thread's thread ID
@ -116,9 +123,9 @@ public:
void ResumeFromWait();
/**
* Schedules an event to wake up the specified thread after the specified delay
* @param nanoseconds The time this thread will be allowed to sleep for
*/
* Schedules an event to wake up the specified thread after the specified delay
* @param nanoseconds The time this thread will be allowed to sleep for
*/
void WakeAfterDelay(s64 nanoseconds);
/**
@ -157,6 +164,12 @@ public:
return tls_address;
}
/*
* Returns the address of the current thread's command buffer, located in the TLS.
* @returns VAddr of the thread's command buffer.
*/
VAddr GetCommandBufferAddress() const;
/**
* Returns whether this thread is waiting for all the objects in
* its wait list to become ready, as a result of a WaitSynchronizationN call
@ -174,8 +187,8 @@ public:
VAddr entry_point;
VAddr stack_top;
s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
s32 current_priority; ///< Current thread priority, can be temporarily changed
u32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
u32 current_priority; ///< Current thread priority, can be temporarily changed
u64 last_running_ticks; ///< CPU tick when thread was last running
@ -197,14 +210,18 @@ public:
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
/// True if the WaitSynchronizationN output parameter should be set on thread wakeup.
bool wait_set_output;
std::string name;
/// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
Handle callback_handle;
using WakeupCallback = void(ThreadWakeupReason reason, SharedPtr<Thread> thread,
SharedPtr<WaitObject> object);
// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
// was waiting via WaitSynchronizationN then the object will be the last object that became
// available. In case of a timeout, the object will be nullptr.
std::function<WakeupCallback> wakeup_callback;
private:
Thread();
~Thread() override;
@ -214,9 +231,10 @@ private:
* Sets up the primary application thread
* @param entry_point The address at which the thread should start execution
* @param priority The priority to give the main thread
* @param owner_process The parent process for the main thread
* @return A shared pointer to the main thread
*/
SharedPtr<Thread> SetupMainThread(VAddr entry_point, s32 priority);
SharedPtr<Thread> SetupMainThread(u32 entry_point, u32 priority, SharedPtr<Process> owner_process);
/**
* Returns whether there are any threads that are ready to run.
@ -276,4 +294,4 @@ void ThreadingShutdown();
*/
const std::vector<SharedPtr<Thread>>& GetThreadList();
} // namespace
} // namespace Kernel

View File

@ -4,8 +4,10 @@
#include <iterator>
#include "common/assert.h"
#include "core/arm/arm_interface.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/core.h"
#include "core/memory.h"
#include "core/memory_setup.h"
#include "core/mmio.h"
@ -56,6 +58,10 @@ void VMManager::Reset() {
initial_vma.size = MAX_ADDRESS;
vma_map.emplace(initial_vma.base, initial_vma);
page_table.pointers.fill(nullptr);
page_table.attributes.fill(Memory::PageType::Unmapped);
page_table.cached_res_count.fill(0);
//UpdatePageTableForVMA(initial_vma);
}
@ -79,6 +85,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
VirtualMemoryArea& final_vma = vma_handle->second;
ASSERT(final_vma.size == size);
Core::CPU().MapBackingMemory(target, size, block->data() + offset, VMAPermission::ReadWriteExecute);
final_vma.type = VMAType::AllocatedMemoryBlock;
final_vma.permissions = VMAPermission::ReadWrite;
final_vma.meminfo_state = state;
@ -98,6 +106,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
VirtualMemoryArea& final_vma = vma_handle->second;
ASSERT(final_vma.size == size);
Core::CPU().MapBackingMemory(target, size, memory, VMAPermission::ReadWriteExecute);
final_vma.type = VMAType::BackingMemory;
final_vma.permissions = VMAPermission::ReadWrite;
final_vma.meminfo_state = state;
@ -328,16 +338,17 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
switch (vma.type) {
case VMAType::Free:
Memory::UnmapRegion(vma.base, vma.size);
Memory::UnmapRegion(page_table, vma.base, vma.size);
break;
case VMAType::AllocatedMemoryBlock:
Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset);
Memory::MapMemoryRegion(page_table, vma.base, vma.size,
vma.backing_block->data() + vma.offset);
break;
case VMAType::BackingMemory:
Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
break;
case VMAType::MMIO:
Memory::MapIoRegion(vma.base, vma.size, vma.mmio_handler);
Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
break;
}
}

View File

@ -9,6 +9,7 @@
#include <vector>
#include "common/common_types.h"
#include "core/hle/result.h"
#include "core/memory.h"
#include "core/mmio.h"
namespace Kernel {
@ -102,7 +103,6 @@ struct VirtualMemoryArea {
* - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
*/
class VMManager final {
// TODO(yuriks): Make page tables switchable to support multiple VMManagers
public:
/**
* The maximum amount of address space managed by the kernel. Addresses above this are never
@ -184,6 +184,10 @@ public:
/// Dumps the address space layout to the log, for debugging
void LogLayout(Log::Level log_level) const;
/// Each VMManager has its own page table, which is set as the main one when the owning process
/// is scheduled.
Memory::PageTable page_table;
private:
using VMAIter = decltype(vma_map)::iterator;

View File

@ -34,7 +34,7 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
Thread* candidate = nullptr;
s32 candidate_priority = THREADPRIO_LOWEST + 1;
u32 candidate_priority = THREADPRIO_LOWEST + 1;
for (const auto& thread : waiting_threads) {
// The list of waiting threads must not contain threads that are not waiting to be awakened.
@ -71,23 +71,20 @@ void WaitObject::WakeupAllWaitingThreads() {
while (auto thread = GetHighestPriorityReadyThread()) {
if (!thread->IsSleepingOnWaitAll()) {
Acquire(thread.get());
// Set the output index of the WaitSynchronizationN call to the index of this object.
if (thread->wait_set_output) {
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
thread->wait_set_output = false;
}
} else {
for (auto& object : thread->wait_objects) {
object->Acquire(thread.get());
}
// Note: This case doesn't update the output index of WaitSynchronizationN.
}
// Invoke the wakeup callback before clearing the wait objects
if (thread->wakeup_callback)
thread->wakeup_callback(ThreadWakeupReason::Signal, thread, this);
for (auto& object : thread->wait_objects)
object->RemoveWaitingThread(thread.get());
thread->wait_objects.clear();
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
thread->ResumeFromWait();
}
}