forked from ShuriZma/suyu
Merge pull request #1417 from lioncash/context
svc: Implement svcGetThreadContext
This commit is contained in:
commit
5e2f23e2b1
|
@ -22,10 +22,16 @@ public:
|
||||||
std::array<u64, 31> cpu_registers;
|
std::array<u64, 31> cpu_registers;
|
||||||
u64 sp;
|
u64 sp;
|
||||||
u64 pc;
|
u64 pc;
|
||||||
u64 pstate;
|
u32 pstate;
|
||||||
|
std::array<u8, 4> padding;
|
||||||
std::array<u128, 32> vector_registers;
|
std::array<u128, 32> vector_registers;
|
||||||
u64 fpcr;
|
u32 fpcr;
|
||||||
|
u32 fpsr;
|
||||||
|
u64 tpidr;
|
||||||
};
|
};
|
||||||
|
// Internally within the kernel, it expects the AArch64 version of the
|
||||||
|
// thread context to be 800 bytes in size.
|
||||||
|
static_assert(sizeof(ThreadContext) == 0x320);
|
||||||
|
|
||||||
/// Runs the CPU until an event happens
|
/// Runs the CPU until an event happens
|
||||||
virtual void Run() = 0;
|
virtual void Run() = 0;
|
||||||
|
|
|
@ -130,7 +130,7 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
|
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
|
||||||
auto& current_process = Core::CurrentProcess();
|
auto& current_process = Core::CurrentProcess();
|
||||||
auto** const page_table = current_process->vm_manager.page_table.pointers.data();
|
auto** const page_table = current_process->VMManager().page_table.pointers.data();
|
||||||
|
|
||||||
Dynarmic::A64::UserConfig config;
|
Dynarmic::A64::UserConfig config;
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
|
||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
config.page_table = reinterpret_cast<void**>(page_table);
|
config.page_table = reinterpret_cast<void**>(page_table);
|
||||||
config.page_table_address_space_bits = current_process->vm_manager.GetAddressSpaceWidth();
|
config.page_table_address_space_bits = current_process->VMManager().GetAddressSpaceWidth();
|
||||||
config.silently_mirror_page_table = false;
|
config.silently_mirror_page_table = false;
|
||||||
|
|
||||||
// Multi-process state
|
// Multi-process state
|
||||||
|
@ -247,15 +247,19 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
|
||||||
ctx.pstate = jit->GetPstate();
|
ctx.pstate = jit->GetPstate();
|
||||||
ctx.vector_registers = jit->GetVectors();
|
ctx.vector_registers = jit->GetVectors();
|
||||||
ctx.fpcr = jit->GetFpcr();
|
ctx.fpcr = jit->GetFpcr();
|
||||||
|
ctx.fpsr = jit->GetFpsr();
|
||||||
|
ctx.tpidr = cb->tpidr_el0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
|
void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
|
||||||
jit->SetRegisters(ctx.cpu_registers);
|
jit->SetRegisters(ctx.cpu_registers);
|
||||||
jit->SetSP(ctx.sp);
|
jit->SetSP(ctx.sp);
|
||||||
jit->SetPC(ctx.pc);
|
jit->SetPC(ctx.pc);
|
||||||
jit->SetPstate(static_cast<u32>(ctx.pstate));
|
jit->SetPstate(ctx.pstate);
|
||||||
jit->SetVectors(ctx.vector_registers);
|
jit->SetVectors(ctx.vector_registers);
|
||||||
jit->SetFpcr(static_cast<u32>(ctx.fpcr));
|
jit->SetFpcr(ctx.fpcr);
|
||||||
|
jit->SetFpsr(ctx.fpsr);
|
||||||
|
SetTPIDR_EL0(ctx.tpidr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic::PrepareReschedule() {
|
void ARM_Dynarmic::PrepareReschedule() {
|
||||||
|
|
|
@ -34,7 +34,7 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
|
||||||
if (!updatable)
|
if (!updatable)
|
||||||
return MakeResult<VirtualFile>(file);
|
return MakeResult<VirtualFile>(file);
|
||||||
|
|
||||||
const PatchManager patch_manager(Core::CurrentProcess()->program_id);
|
const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID());
|
||||||
return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset));
|
return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
|
||||||
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
|
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
|
||||||
// be interpreted as the title id of the current process.
|
// be interpreted as the title id of the current process.
|
||||||
if (type == SaveDataType::SaveData && title_id == 0)
|
if (type == SaveDataType::SaveData && title_id == 0)
|
||||||
title_id = Core::CurrentProcess()->program_id;
|
title_id = Core::CurrentProcess()->GetTitleID();
|
||||||
|
|
||||||
std::string out;
|
std::string out;
|
||||||
|
|
||||||
|
|
|
@ -250,7 +250,7 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
|
||||||
} else if (id == PC_REGISTER) {
|
} else if (id == PC_REGISTER) {
|
||||||
thread->context.pc = val;
|
thread->context.pc = val;
|
||||||
} else if (id == PSTATE_REGISTER) {
|
} else if (id == PSTATE_REGISTER) {
|
||||||
thread->context.pstate = val;
|
thread->context.pstate = static_cast<u32>(val);
|
||||||
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
|
} else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
|
||||||
thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
|
thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
|
||||||
}
|
}
|
||||||
|
@ -587,7 +587,7 @@ static void HandleQuery() {
|
||||||
strlen("Xfer:features:read:target.xml:")) == 0) {
|
strlen("Xfer:features:read:target.xml:")) == 0) {
|
||||||
SendReply(target_xml);
|
SendReply(target_xml);
|
||||||
} else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
|
} else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
|
||||||
const VAddr base_address = Core::CurrentProcess()->vm_manager.GetCodeRegionBaseAddress();
|
const VAddr base_address = Core::CurrentProcess()->VMManager().GetCodeRegionBaseAddress();
|
||||||
std::string buffer = fmt::format("TextSeg={:0x}", base_address);
|
std::string buffer = fmt::format("TextSeg={:0x}", base_address);
|
||||||
SendReply(buffer.c_str());
|
SendReply(buffer.c_str());
|
||||||
} else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
|
} else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
|
||||||
|
@ -909,7 +909,7 @@ static void ReadMemory() {
|
||||||
SendReply("E01");
|
SendReply("E01");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& vm_manager = Core::CurrentProcess()->vm_manager;
|
const auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||||
if (addr < vm_manager.GetCodeRegionBaseAddress() ||
|
if (addr < vm_manager.GetCodeRegionBaseAddress() ||
|
||||||
addr >= vm_manager.GetMapRegionEndAddress()) {
|
addr >= vm_manager.GetMapRegionEndAddress()) {
|
||||||
return SendReply("E00");
|
return SendReply("E00");
|
||||||
|
|
|
@ -31,6 +31,7 @@ enum {
|
||||||
TooLarge = 119,
|
TooLarge = 119,
|
||||||
InvalidEnumValue = 120,
|
InvalidEnumValue = 120,
|
||||||
NoSuchEntry = 121,
|
NoSuchEntry = 121,
|
||||||
|
AlreadyRegistered = 122,
|
||||||
InvalidState = 125,
|
InvalidState = 125,
|
||||||
ResourceLimitExceeded = 132,
|
ResourceLimitExceeded = 132,
|
||||||
};
|
};
|
||||||
|
@ -58,6 +59,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
|
||||||
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
|
||||||
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
||||||
constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
|
constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
|
||||||
|
constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered);
|
||||||
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
|
constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
|
||||||
constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
|
constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
|
||||||
ErrCodes::InvalidThreadPriority);
|
ErrCodes::InvalidThreadPriority);
|
||||||
|
|
|
@ -47,6 +47,7 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
|
||||||
|
|
||||||
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
|
||||||
program_id = metadata.GetTitleID();
|
program_id = metadata.GetTitleID();
|
||||||
|
is_64bit_process = metadata.Is64BitProgram();
|
||||||
vm_manager.Reset(metadata.GetAddressSpaceType());
|
vm_manager.Reset(metadata.GetAddressSpaceType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,16 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets a reference to the process' memory manager.
|
||||||
|
Kernel::VMManager& VMManager() {
|
||||||
|
return vm_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a const reference to the process' memory manager.
|
||||||
|
const Kernel::VMManager& VMManager() const {
|
||||||
|
return vm_manager;
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the current status of the process
|
/// Gets the current status of the process
|
||||||
ProcessStatus GetStatus() const {
|
ProcessStatus GetStatus() const {
|
||||||
return status;
|
return status;
|
||||||
|
@ -145,6 +155,45 @@ public:
|
||||||
return process_id;
|
return process_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the title ID corresponding to this process.
|
||||||
|
u64 GetTitleID() const {
|
||||||
|
return program_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the resource limit descriptor for this process
|
||||||
|
ResourceLimit& GetResourceLimit() {
|
||||||
|
return *resource_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the resource limit descriptor for this process
|
||||||
|
const ResourceLimit& GetResourceLimit() const {
|
||||||
|
return *resource_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the default CPU ID for this process
|
||||||
|
u8 GetDefaultProcessorID() const {
|
||||||
|
return ideal_processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the bitmask of allowed CPUs that this process' threads can run on.
|
||||||
|
u32 GetAllowedProcessorMask() const {
|
||||||
|
return allowed_processor_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the bitmask of allowed thread priorities.
|
||||||
|
u32 GetAllowedThreadPriorityMask() const {
|
||||||
|
return allowed_thread_priority_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 IsVirtualMemoryEnabled() const {
|
||||||
|
return is_virtual_address_memory_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether this process is an AArch64 or AArch32 process.
|
||||||
|
bool Is64BitProcess() const {
|
||||||
|
return is_64bit_process;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads process-specifics configuration info with metadata provided
|
* Loads process-specifics configuration info with metadata provided
|
||||||
* by an executable.
|
* by an executable.
|
||||||
|
@ -153,30 +202,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
|
void LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
|
||||||
|
|
||||||
/// Title ID corresponding to the process
|
|
||||||
u64 program_id;
|
|
||||||
|
|
||||||
/// Resource limit descriptor for this process
|
|
||||||
SharedPtr<ResourceLimit> resource_limit;
|
|
||||||
|
|
||||||
/// The process may only call SVCs which have the corresponding bit set.
|
|
||||||
std::bitset<0x80> svc_access_mask;
|
|
||||||
/// Maximum size of the handle table for the process.
|
|
||||||
unsigned int handle_table_size = 0x200;
|
|
||||||
/// Special memory ranges mapped into this processes address space. This is used to give
|
|
||||||
/// processes access to specific I/O regions and device memory.
|
|
||||||
boost::container::static_vector<AddressMapping, 8> address_mappings;
|
|
||||||
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;
|
|
||||||
/// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse
|
|
||||||
/// this value from the process header.
|
|
||||||
u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
|
|
||||||
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
|
|
||||||
u32 is_virtual_address_memory_enabled = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
|
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
|
||||||
* to this process.
|
* to this process.
|
||||||
|
@ -212,18 +237,43 @@ public:
|
||||||
|
|
||||||
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||||
|
|
||||||
VMManager vm_manager;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Process(KernelCore& kernel);
|
explicit Process(KernelCore& kernel);
|
||||||
~Process() override;
|
~Process() override;
|
||||||
|
|
||||||
|
/// Memory manager for this process.
|
||||||
|
Kernel::VMManager vm_manager;
|
||||||
|
|
||||||
/// Current status of the process
|
/// Current status of the process
|
||||||
ProcessStatus status;
|
ProcessStatus status;
|
||||||
|
|
||||||
/// The ID of this process
|
/// The ID of this process
|
||||||
u32 process_id = 0;
|
u32 process_id = 0;
|
||||||
|
|
||||||
|
/// Title ID corresponding to the process
|
||||||
|
u64 program_id;
|
||||||
|
|
||||||
|
/// Resource limit descriptor for this process
|
||||||
|
SharedPtr<ResourceLimit> resource_limit;
|
||||||
|
|
||||||
|
/// The process may only call SVCs which have the corresponding bit set.
|
||||||
|
std::bitset<0x80> svc_access_mask;
|
||||||
|
/// Maximum size of the handle table for the process.
|
||||||
|
u32 handle_table_size = 0x200;
|
||||||
|
/// Special memory ranges mapped into this processes address space. This is used to give
|
||||||
|
/// processes access to specific I/O regions and device memory.
|
||||||
|
boost::container::static_vector<AddressMapping, 8> address_mappings;
|
||||||
|
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;
|
||||||
|
/// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse
|
||||||
|
/// this value from the process header.
|
||||||
|
u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
|
||||||
|
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
|
||||||
|
u32 is_virtual_address_memory_enabled = 0;
|
||||||
|
|
||||||
// Memory used to back the allocations in the regular heap. A single vector is used to cover
|
// Memory used to back the allocations in the regular heap. A single vector is used to cover
|
||||||
// the entire virtual address space extents that bound the allocations, including any holes.
|
// the entire virtual address space extents that bound the allocations, including any holes.
|
||||||
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
|
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
|
||||||
|
@ -242,6 +292,11 @@ private:
|
||||||
/// This vector will grow as more pages are allocated for new threads.
|
/// This vector will grow as more pages are allocated for new threads.
|
||||||
std::vector<std::bitset<8>> tls_slots;
|
std::vector<std::bitset<8>> tls_slots;
|
||||||
|
|
||||||
|
/// Whether or not this process is AArch64, or AArch32.
|
||||||
|
/// By default, we currently assume this is true, unless otherwise
|
||||||
|
/// specified by metadata provided to the process during loading.
|
||||||
|
bool is_64bit_process = true;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
|
||||||
|
|
||||||
if (previous_process != current_thread->owner_process) {
|
if (previous_process != current_thread->owner_process) {
|
||||||
Core::CurrentProcess() = current_thread->owner_process;
|
Core::CurrentProcess() = current_thread->owner_process;
|
||||||
SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table);
|
SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_core.LoadContext(new_thread->context);
|
cpu_core.LoadContext(new_thread->context);
|
||||||
|
|
|
@ -35,11 +35,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce
|
||||||
|
|
||||||
// Refresh the address mappings for the current process.
|
// Refresh the address mappings for the current process.
|
||||||
if (Core::CurrentProcess() != nullptr) {
|
if (Core::CurrentProcess() != nullptr) {
|
||||||
Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings(
|
Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings(
|
||||||
shared_memory->backing_block.get());
|
shared_memory->backing_block.get());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto& vm_manager = shared_memory->owner_process->vm_manager;
|
auto& vm_manager = shared_memory->owner_process->VMManager();
|
||||||
|
|
||||||
// The memory is already available and mapped in the owner process.
|
// The memory is already available and mapped in the owner process.
|
||||||
auto vma = vm_manager.FindVMA(address);
|
auto vma = vm_manager.FindVMA(address);
|
||||||
|
@ -73,7 +73,7 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
|
||||||
shared_memory->backing_block = std::move(heap_block);
|
shared_memory->backing_block = std::move(heap_block);
|
||||||
shared_memory->backing_block_offset = offset;
|
shared_memory->backing_block_offset = offset;
|
||||||
shared_memory->base_address =
|
shared_memory->base_address =
|
||||||
kernel.CurrentProcess()->vm_manager.GetHeapRegionBaseAddress() + offset;
|
kernel.CurrentProcess()->VMManager().GetHeapRegionBaseAddress() + offset;
|
||||||
|
|
||||||
return shared_memory;
|
return shared_memory;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
||||||
VAddr target_address = address;
|
VAddr target_address = address;
|
||||||
|
|
||||||
// Map the memory block into the target process
|
// Map the memory block into the target process
|
||||||
auto result = target_process->vm_manager.MapMemoryBlock(
|
auto result = target_process->VMManager().MapMemoryBlock(
|
||||||
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
|
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
|
||||||
if (result.Failed()) {
|
if (result.Failed()) {
|
||||||
LOG_ERROR(
|
LOG_ERROR(
|
||||||
|
@ -117,14 +117,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
||||||
return result.Code();
|
return result.Code();
|
||||||
}
|
}
|
||||||
|
|
||||||
return target_process->vm_manager.ReprotectRange(target_address, size,
|
return target_process->VMManager().ReprotectRange(target_address, size,
|
||||||
ConvertPermissions(permissions));
|
ConvertPermissions(permissions));
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
|
ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
|
||||||
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not
|
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not
|
||||||
// mapped to a SharedMemory.
|
// mapped to a SharedMemory.
|
||||||
return target_process->vm_manager.UnmapRange(address, size);
|
return target_process->VMManager().UnmapRange(address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
|
VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& process = *Core::CurrentProcess();
|
auto& process = *Core::CurrentProcess();
|
||||||
const VAddr heap_base = process.vm_manager.GetHeapRegionBaseAddress();
|
const VAddr heap_base = process.VMManager().GetHeapRegionBaseAddress();
|
||||||
CASCADE_RESULT(*heap_addr,
|
CASCADE_RESULT(*heap_addr,
|
||||||
process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
|
process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
@ -327,14 +327,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||||
info_sub_id, handle);
|
info_sub_id, handle);
|
||||||
|
|
||||||
const auto& current_process = Core::CurrentProcess();
|
const auto& current_process = Core::CurrentProcess();
|
||||||
const auto& vm_manager = current_process->vm_manager;
|
const auto& vm_manager = current_process->VMManager();
|
||||||
|
|
||||||
switch (static_cast<GetInfoType>(info_id)) {
|
switch (static_cast<GetInfoType>(info_id)) {
|
||||||
case GetInfoType::AllowedCpuIdBitmask:
|
case GetInfoType::AllowedCpuIdBitmask:
|
||||||
*result = current_process->allowed_processor_mask;
|
*result = current_process->GetAllowedProcessorMask();
|
||||||
break;
|
break;
|
||||||
case GetInfoType::AllowedThreadPrioBitmask:
|
case GetInfoType::AllowedThreadPrioBitmask:
|
||||||
*result = current_process->allowed_thread_priority_mask;
|
*result = current_process->GetAllowedThreadPriorityMask();
|
||||||
break;
|
break;
|
||||||
case GetInfoType::MapRegionBaseAddr:
|
case GetInfoType::MapRegionBaseAddr:
|
||||||
*result = vm_manager.GetMapRegionBaseAddress();
|
*result = vm_manager.GetMapRegionBaseAddress();
|
||||||
|
@ -386,10 +386,10 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||||
*result = vm_manager.GetNewMapRegionSize();
|
*result = vm_manager.GetNewMapRegionSize();
|
||||||
break;
|
break;
|
||||||
case GetInfoType::IsVirtualAddressMemoryEnabled:
|
case GetInfoType::IsVirtualAddressMemoryEnabled:
|
||||||
*result = current_process->is_virtual_address_memory_enabled;
|
*result = current_process->IsVirtualMemoryEnabled();
|
||||||
break;
|
break;
|
||||||
case GetInfoType::TitleId:
|
case GetInfoType::TitleId:
|
||||||
*result = current_process->program_id;
|
*result = current_process->GetTitleID();
|
||||||
break;
|
break;
|
||||||
case GetInfoType::PrivilegedProcessId:
|
case GetInfoType::PrivilegedProcessId:
|
||||||
LOG_WARNING(Kernel_SVC,
|
LOG_WARNING(Kernel_SVC,
|
||||||
|
@ -415,8 +415,36 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the thread context
|
/// Gets the thread context
|
||||||
static ResultCode GetThreadContext(Handle handle, VAddr addr) {
|
static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
|
||||||
LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr);
|
LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
|
||||||
|
|
||||||
|
auto& kernel = Core::System::GetInstance().Kernel();
|
||||||
|
const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
|
||||||
|
if (!thread) {
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto current_process = Core::CurrentProcess();
|
||||||
|
if (thread->owner_process != current_process) {
|
||||||
|
return ERR_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread == GetCurrentThread()) {
|
||||||
|
return ERR_ALREADY_REGISTERED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::ARM_Interface::ThreadContext ctx = thread->context;
|
||||||
|
// Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
|
||||||
|
ctx.pstate &= 0xFF0FFE20;
|
||||||
|
|
||||||
|
// If 64-bit, we can just write the context registers directly and we're good.
|
||||||
|
// However, if 32-bit, we have to ensure some registers are zeroed out.
|
||||||
|
if (!current_process->Is64BitProcess()) {
|
||||||
|
std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0);
|
||||||
|
std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
|
||||||
|
}
|
||||||
|
|
||||||
|
Memory::WriteBlock(thread_context, &ctx, sizeof(ctx));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,8 +472,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
|
||||||
|
|
||||||
// Note: The kernel uses the current process's resource limit instead of
|
// Note: The kernel uses the current process's resource limit instead of
|
||||||
// the one from the thread owner's resource limit.
|
// the one from the thread owner's resource limit.
|
||||||
SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
|
const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
|
||||||
if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
|
if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
|
||||||
return ERR_NOT_AUTHORIZED;
|
return ERR_NOT_AUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,9 +547,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
|
||||||
if (!process) {
|
if (!process) {
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
}
|
}
|
||||||
auto vma = process->vm_manager.FindVMA(addr);
|
auto vma = process->VMManager().FindVMA(addr);
|
||||||
memory_info->attributes = 0;
|
memory_info->attributes = 0;
|
||||||
if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) {
|
if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) {
|
||||||
memory_info->base_address = 0;
|
memory_info->base_address = 0;
|
||||||
memory_info->permission = static_cast<u32>(VMAPermission::None);
|
memory_info->permission = static_cast<u32>(VMAPermission::None);
|
||||||
memory_info->size = 0;
|
memory_info->size = 0;
|
||||||
|
@ -568,14 +596,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
|
||||||
return ERR_INVALID_THREAD_PRIORITY;
|
return ERR_INVALID_THREAD_PRIORITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit;
|
const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
|
||||||
if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) {
|
if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
|
||||||
return ERR_NOT_AUTHORIZED;
|
return ERR_NOT_AUTHORIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processor_id == THREADPROCESSORID_DEFAULT) {
|
if (processor_id == THREADPROCESSORID_DEFAULT) {
|
||||||
// Set the target CPU to the one specified in the process' exheader.
|
// Set the target CPU to the one specified in the process' exheader.
|
||||||
processor_id = Core::CurrentProcess()->ideal_processor;
|
processor_id = Core::CurrentProcess()->GetDefaultProcessorID();
|
||||||
ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
|
ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,10 +930,10 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
|
if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
|
||||||
ASSERT(thread->owner_process->ideal_processor !=
|
ASSERT(thread->owner_process->GetDefaultProcessorID() !=
|
||||||
static_cast<u8>(THREADPROCESSORID_DEFAULT));
|
static_cast<u8>(THREADPROCESSORID_DEFAULT));
|
||||||
// Set the target CPU to the one specified in the process' exheader.
|
// Set the target CPU to the one specified in the process' exheader.
|
||||||
core = thread->owner_process->ideal_processor;
|
core = thread->owner_process->GetDefaultProcessorID();
|
||||||
mask = 1ull << core;
|
mask = 1ull << core;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,11 @@ void SvcWrap() {
|
||||||
FuncReturn(func(Param(0), (s32)Param(1)).raw);
|
FuncReturn(func(Param(0), (s32)Param(1)).raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <ResultCode func(u64, u32)>
|
||||||
|
void SvcWrap() {
|
||||||
|
FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
|
||||||
|
}
|
||||||
|
|
||||||
template <ResultCode func(u64*, u64)>
|
template <ResultCode func(u64*, u64)>
|
||||||
void SvcWrap() {
|
void SvcWrap() {
|
||||||
u64 param_1 = 0;
|
u64 param_1 = 0;
|
||||||
|
|
|
@ -259,10 +259,10 @@ void Thread::BoostPriority(u32 priority) {
|
||||||
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
|
||||||
Process& owner_process) {
|
Process& owner_process) {
|
||||||
// Setup page table so we can write to memory
|
// Setup page table so we can write to memory
|
||||||
SetCurrentPageTable(&owner_process.vm_manager.page_table);
|
SetCurrentPageTable(&owner_process.VMManager().page_table);
|
||||||
|
|
||||||
// Initialize new "main" thread
|
// Initialize new "main" thread
|
||||||
const VAddr stack_top = owner_process.vm_manager.GetTLSIORegionEndAddress();
|
const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
|
||||||
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
|
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
|
||||||
stack_top, &owner_process);
|
stack_top, &owner_process);
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ enum class FatalType : u32 {
|
||||||
};
|
};
|
||||||
|
|
||||||
static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
|
static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
|
||||||
const auto title_id = Core::CurrentProcess()->program_id;
|
const auto title_id = Core::CurrentProcess()->GetTitleID();
|
||||||
std::string crash_report =
|
std::string crash_report =
|
||||||
fmt::format("Yuzu {}-{} crash report\n"
|
fmt::format("Yuzu {}-{} crash report\n"
|
||||||
"Title ID: {:016x}\n"
|
"Title ID: {:016x}\n"
|
||||||
|
|
|
@ -317,7 +317,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||||
// Map backing memory for the font data
|
// Map backing memory for the font data
|
||||||
Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
|
Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
|
||||||
SHARED_FONT_MEM_SIZE,
|
SHARED_FONT_MEM_SIZE,
|
||||||
Kernel::MemoryState::Shared);
|
Kernel::MemoryState::Shared);
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
|
||||||
process.LoadFromMetadata(metadata);
|
process.LoadFromMetadata(metadata);
|
||||||
|
|
||||||
// Load NSO modules
|
// Load NSO modules
|
||||||
const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress();
|
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
|
||||||
VAddr next_load_addr = base_address;
|
VAddr next_load_addr = base_address;
|
||||||
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
|
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
|
||||||
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
|
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
|
||||||
|
|
|
@ -395,7 +395,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::Process& process) {
|
||||||
if (buffer.size() != file->GetSize())
|
if (buffer.size() != file->GetSize())
|
||||||
return ResultStatus::ErrorIncorrectELFFileSize;
|
return ResultStatus::ErrorIncorrectELFFileSize;
|
||||||
|
|
||||||
const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress();
|
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
|
||||||
ElfReader elf_reader(&buffer[0]);
|
ElfReader elf_reader(&buffer[0]);
|
||||||
SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address);
|
SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address);
|
||||||
codeset->name = file->GetName();
|
codeset->name = file->GetName();
|
||||||
|
|
|
@ -181,7 +181,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load NRO
|
// Load NRO
|
||||||
const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress();
|
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
|
||||||
|
|
||||||
if (!LoadNro(file, base_address)) {
|
if (!LoadNro(file, base_address)) {
|
||||||
return ResultStatus::ErrorLoadingNRO;
|
return ResultStatus::ErrorLoadingNRO;
|
||||||
|
|
|
@ -159,7 +159,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load module
|
// Load module
|
||||||
const VAddr base_address = process.vm_manager.GetCodeRegionBaseAddress();
|
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
|
||||||
LoadModule(file, base_address);
|
LoadModule(file, base_address);
|
||||||
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
|
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ void RemoveDebugHook(PageTable& page_table, VAddr base, u64 size, MemoryHookPoin
|
||||||
static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
|
static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
|
||||||
u8* direct_pointer = nullptr;
|
u8* direct_pointer = nullptr;
|
||||||
|
|
||||||
auto& vm_manager = process.vm_manager;
|
auto& vm_manager = process.VMManager();
|
||||||
|
|
||||||
auto it = vm_manager.FindVMA(vaddr);
|
auto it = vm_manager.FindVMA(vaddr);
|
||||||
ASSERT(it != vm_manager.vma_map.end());
|
ASSERT(it != vm_manager.vma_map.end());
|
||||||
|
@ -214,7 +214,7 @@ void Write(const VAddr vaddr, const T data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
const auto& page_table = process.VMManager().page_table;
|
||||||
|
|
||||||
const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
|
const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
|
||||||
if (page_pointer)
|
if (page_pointer)
|
||||||
|
@ -363,7 +363,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto& vm_manager = Core::CurrentProcess()->vm_manager;
|
const auto& vm_manager = Core::CurrentProcess()->VMManager();
|
||||||
|
|
||||||
CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress());
|
CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress());
|
||||||
CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress());
|
CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress());
|
||||||
|
@ -387,7 +387,7 @@ u64 Read64(const VAddr addr) {
|
||||||
|
|
||||||
void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
|
void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
|
||||||
const std::size_t size) {
|
const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
const auto& page_table = process.VMManager().page_table;
|
||||||
|
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
std::size_t page_index = src_addr >> PAGE_BITS;
|
std::size_t page_index = src_addr >> PAGE_BITS;
|
||||||
|
@ -452,7 +452,7 @@ void Write64(const VAddr addr, const u64 data) {
|
||||||
|
|
||||||
void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
|
void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
|
||||||
const std::size_t size) {
|
const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
const auto& page_table = process.VMManager().page_table;
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
std::size_t page_index = dest_addr >> PAGE_BITS;
|
std::size_t page_index = dest_addr >> PAGE_BITS;
|
||||||
std::size_t page_offset = dest_addr & PAGE_MASK;
|
std::size_t page_offset = dest_addr & PAGE_MASK;
|
||||||
|
@ -498,7 +498,7 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
|
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
const auto& page_table = process.VMManager().page_table;
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
std::size_t page_index = dest_addr >> PAGE_BITS;
|
std::size_t page_index = dest_addr >> PAGE_BITS;
|
||||||
std::size_t page_offset = dest_addr & PAGE_MASK;
|
std::size_t page_offset = dest_addr & PAGE_MASK;
|
||||||
|
@ -540,7 +540,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std:
|
||||||
|
|
||||||
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
||||||
const std::size_t size) {
|
const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
const auto& page_table = process.VMManager().page_table;
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
std::size_t page_index = src_addr >> PAGE_BITS;
|
std::size_t page_index = src_addr >> PAGE_BITS;
|
||||||
std::size_t page_offset = src_addr & PAGE_MASK;
|
std::size_t page_offset = src_addr & PAGE_MASK;
|
||||||
|
|
|
@ -16,7 +16,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
||||||
|
|
||||||
Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
|
Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
|
||||||
page_table = &Core::CurrentProcess()->vm_manager.page_table;
|
page_table = &Core::CurrentProcess()->VMManager().page_table;
|
||||||
|
|
||||||
std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
|
std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
|
||||||
page_table->special_regions.clear();
|
page_table->special_regions.clear();
|
||||||
|
|
|
@ -622,9 +622,9 @@ void GMainWindow::BootGame(const QString& filename) {
|
||||||
std::string title_name;
|
std::string title_name;
|
||||||
const auto res = Core::System::GetInstance().GetGameName(title_name);
|
const auto res = Core::System::GetInstance().GetGameName(title_name);
|
||||||
if (res != Loader::ResultStatus::Success) {
|
if (res != Loader::ResultStatus::Success) {
|
||||||
const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id;
|
const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
|
||||||
|
|
||||||
const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata();
|
const auto [nacp, icon_file] = FileSys::PatchManager(title_id).GetControlMetadata();
|
||||||
if (nacp != nullptr)
|
if (nacp != nullptr)
|
||||||
title_name = nacp->GetApplicationName();
|
title_name = nacp->GetApplicationName();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue