diff options
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r-- | src/core/hle/kernel/errors.h | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/object.cpp | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/object.h | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/process.cpp | 24 | ||||
-rw-r--r-- | src/core/hle/kernel/process.h | 49 | ||||
-rw-r--r-- | src/core/hle/kernel/svc.cpp | 130 | ||||
-rw-r--r-- | src/core/hle/kernel/svc_wrap.h | 64 | ||||
-rw-r--r-- | src/core/hle/kernel/thread.cpp | 5 |
8 files changed, 188 insertions, 88 deletions
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h index e5fa67ae8..885259618 100644 --- a/src/core/hle/kernel/errors.h +++ b/src/core/hle/kernel/errors.h @@ -22,6 +22,7 @@ enum { HandleTableFull = 105, InvalidMemoryState = 106, InvalidMemoryPermissions = 108, + InvalidMemoryRange = 110, InvalidThreadPriority = 112, InvalidProcessorId = 113, InvalidHandle = 114, @@ -56,6 +57,7 @@ constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidA constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, ErrCodes::InvalidMemoryPermissions); +constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange); constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp index d51562d92..d87a62bb9 100644 --- a/src/core/hle/kernel/object.cpp +++ b/src/core/hle/kernel/object.cpp @@ -25,7 +25,6 @@ bool Object::IsWaitable() const { case HandleType::Process: case HandleType::AddressArbiter: case HandleType::ResourceLimit: - case HandleType::CodeSet: case HandleType::ClientPort: case HandleType::ClientSession: return false; diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h index 9eb72315c..c9f4d0bb3 100644 --- a/src/core/hle/kernel/object.h +++ b/src/core/hle/kernel/object.h @@ -26,7 +26,6 @@ enum class HandleType : u32 { AddressArbiter, Timer, ResourceLimit, - CodeSet, ClientPort, ServerPort, ClientSession, diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index fb0027a71..c80b2c507 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -20,13 +20,7 @@ namespace Kernel { -SharedPtr<CodeSet> CodeSet::Create(KernelCore& kernel, std::string name) { - SharedPtr<CodeSet> codeset(new CodeSet(kernel)); - codeset->name = std::move(name); - return codeset; -} - -CodeSet::CodeSet(KernelCore& kernel) : Object{kernel} {} +CodeSet::CodeSet() = default; CodeSet::~CodeSet() = default; SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { @@ -224,20 +218,20 @@ void Process::FreeTLSSlot(VAddr tls_address) { tls_slots[tls_page].reset(tls_slot); } -void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { +void Process::LoadModule(CodeSet module_, VAddr base_addr) { const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { - auto vma = vm_manager - .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, - segment.size, memory_state) - .Unwrap(); + const auto vma = vm_manager + .MapMemoryBlock(segment.addr + base_addr, module_.memory, + segment.offset, segment.size, memory_state) + .Unwrap(); vm_manager.Reprotect(vma, permissions); }; // Map CodeSet segments - MapSegment(module_->CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); - MapSegment(module_->RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); - MapSegment(module_->DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); + MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); + MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); + MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); } ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 590e0c73d..f2816943a 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -24,6 +24,7 @@ class ProgramMetadata; namespace Kernel { class KernelCore; +class ResourceLimit; struct AddressMapping { // Address and size must be page-aligned @@ -57,30 +58,33 @@ union ProcessFlags { BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). }; -enum class ProcessStatus { Created, Running, Exited }; - -class ResourceLimit; +/** + * Indicates the status of a Process instance. + * + * @note These match the values as used by kernel, + * so new entries should only be added if RE + * shows that a new value has been introduced. + */ +enum class ProcessStatus { + Created, + CreatedWithDebuggerAttached, + Running, + WaitingForDebuggerToAttach, + DebuggerAttached, + Exiting, + Exited, + DebugBreak, +}; -struct CodeSet final : public Object { +struct CodeSet final { struct Segment { std::size_t offset = 0; VAddr addr = 0; u32 size = 0; }; - static SharedPtr<CodeSet> Create(KernelCore& kernel, std::string name); - - std::string GetTypeName() const override { - return "CodeSet"; - } - std::string GetName() const override { - return name; - } - - static const HandleType HANDLE_TYPE = HandleType::CodeSet; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } + explicit CodeSet(); + ~CodeSet(); Segment& CodeSegment() { return segments[0]; @@ -109,14 +113,7 @@ struct CodeSet final : public Object { std::shared_ptr<std::vector<u8>> memory; std::array<Segment, 3> segments; - VAddr entrypoint; - - /// Name of the process - std::string name; - -private: - explicit CodeSet(KernelCore& kernel); - ~CodeSet() override; + VAddr entrypoint = 0; }; class Process final : public Object { @@ -219,7 +216,7 @@ public: */ void PrepareForTermination(); - void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr); + void LoadModule(CodeSet module_, VAddr base_addr); /////////////////////////////////////////////////////////////////////////////////////////////// // Memory Management diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 3afcce3fe..7a053da1e 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -39,6 +39,73 @@ namespace { constexpr bool Is4KBAligned(VAddr address) { return (address & 0xFFF) == 0; } + +// Checks if address + size is greater than the given address +// This can return false if the size causes an overflow of a 64-bit type +// or if the given size is zero. +constexpr bool IsValidAddressRange(VAddr address, u64 size) { + return address + size > address; +} + +// Checks if a given address range lies within a larger address range. +constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin, + VAddr address_range_end) { + const VAddr end_address = address + size - 1; + return address_range_begin <= address && end_address <= address_range_end - 1; +} + +bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) { + return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(), + vm.GetAddressSpaceEndAddress()); +} + +bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) { + return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(), + vm.GetNewMapRegionEndAddress()); +} + +// Helper function that performs the common sanity checks for svcMapMemory +// and svcUnmapMemory. This is doable, as both functions perform their sanitizing +// in the same order. +ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, + u64 size) { + if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { + return ERR_INVALID_ADDRESS; + } + + if (size == 0 || !Is4KBAligned(size)) { + return ERR_INVALID_SIZE; + } + + if (!IsValidAddressRange(dst_addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsValidAddressRange(src_addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { + return ERR_INVALID_ADDRESS_STATE; + } + + if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { + return ERR_INVALID_MEMORY_RANGE; + } + + const VAddr dst_end_address = dst_addr + size; + if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && + vm_manager.GetHeapRegionEndAddress() > dst_addr) { + return ERR_INVALID_MEMORY_RANGE; + } + + if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && + vm_manager.GetMapRegionEndAddress() > dst_addr) { + return ERR_INVALID_MEMORY_RANGE; + } + + return RESULT_SUCCESS; +} } // Anonymous namespace /// Set the process heap to a given Size. It can both extend and shrink the heap. @@ -69,15 +136,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { - return ERR_INVALID_ADDRESS; - } + auto* const current_process = Core::CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); - if (size == 0 || !Is4KBAligned(size)) { - return ERR_INVALID_SIZE; + const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); + if (result != RESULT_SUCCESS) { + return result; } - return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); + return current_process->MirrorMemory(dst_addr, src_addr, size); } /// Unmaps a region that was previously mapped with svcMapMemory @@ -85,15 +152,15 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { - return ERR_INVALID_ADDRESS; - } + auto* const current_process = Core::CurrentProcess(); + const auto& vm_manager = current_process->VMManager(); - if (size == 0 || !Is4KBAligned(size)) { - return ERR_INVALID_SIZE; + const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size); + if (result != RESULT_SUCCESS) { + return result; } - return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); + return current_process->UnmapMemory(dst_addr, src_addr, size); } /// Connect to an OS service given the port name, returns the handle to the port to out @@ -303,15 +370,15 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) { struct BreakReason { union { - u64 raw; - BitField<31, 1, u64> dont_kill_application; + u32 raw; + BitField<31, 1, u32> signal_debugger; }; }; /// Break program execution -static void Break(u64 reason, u64 info1, u64 info2) { +static void Break(u32 reason, u64 info1, u64 info2) { BreakReason break_reason{reason}; - if (break_reason.dont_kill_application) { + if (break_reason.signal_debugger) { LOG_ERROR( Debug_Emulated, "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", @@ -322,6 +389,12 @@ static void Break(u64 reason, u64 info1, u64 info2) { "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", reason, info1, info2); ASSERT(false); + + Core::CurrentProcess()->PrepareForTermination(); + + // Kill the current thread + GetCurrentThread()->Stop(); + Core::System::GetInstance().PrepareReschedule(); } } @@ -1025,6 +1098,29 @@ static ResultCode ClearEvent(Handle handle) { return RESULT_SUCCESS; } +static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { + LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type); + + // This function currently only allows retrieving a process' status. + enum class InfoType { + Status, + }; + + const auto& kernel = Core::System::GetInstance().Kernel(); + const auto process = kernel.HandleTable().Get<Process>(process_handle); + if (!process) { + return ERR_INVALID_HANDLE; + } + + const auto info_type = static_cast<InfoType>(type); + if (info_type != InfoType::Status) { + return ERR_INVALID_ENUM_VALUE; + } + + *out = static_cast<u64>(process->GetStatus()); + return RESULT_SUCCESS; +} + namespace { struct FunctionDef { using Func = void(); @@ -1160,7 +1256,7 @@ static const FunctionDef SVC_Table[] = { {0x79, nullptr, "CreateProcess"}, {0x7A, nullptr, "StartProcess"}, {0x7B, nullptr, "TerminateProcess"}, - {0x7C, nullptr, "GetProcessInfo"}, + {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, {0x7D, nullptr, "CreateResourceLimit"}, {0x7E, nullptr, "SetResourceLimitLimitValue"}, {0x7F, nullptr, "CallSecureMonitor"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 22712e64f..b09753c80 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -35,18 +35,18 @@ void SvcWrap() { template <ResultCode func(u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0)).raw); + FuncReturn(func(static_cast<u32>(Param(0))).raw); } template <ResultCode func(u32, u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0), (u32)Param(1)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); } template <ResultCode func(u32*, u32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, (u32)Param(1)).raw; + u32 retval = func(¶m_1, static_cast<u32>(Param(1))).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -61,7 +61,7 @@ void SvcWrap() { template <ResultCode func(u64, s32)> void SvcWrap() { - FuncReturn(func(Param(0), (s32)Param(1)).raw); + FuncReturn(func(Param(0), static_cast<s32>(Param(1))).raw); } template <ResultCode func(u64, u32)> @@ -77,21 +77,29 @@ void SvcWrap() { FuncReturn(retval); } +template <ResultCode func(u64*, u32, u32)> +void SvcWrap() { + u64 param_1 = 0; + u32 retval = func(¶m_1, static_cast<u32>(Param(1)), static_cast<u32>(Param(2))).raw; + Core::CurrentArmInterface().SetReg(1, param_1); + FuncReturn(retval); +} + template <ResultCode func(u32, u64)> void SvcWrap() { - FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), Param(1)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), Param(1)).raw); } template <ResultCode func(u32, u32, u64)> void SvcWrap() { - FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), (u32)(Param(1) & 0xFFFFFFFF), Param(2)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1)), Param(2)).raw); } template <ResultCode func(u32, u32*, u64*)> void SvcWrap() { u32 param_1 = 0; u64 param_2 = 0; - ResultCode retval = func((u32)(Param(2) & 0xFFFFFFFF), ¶m_1, ¶m_2); + ResultCode retval = func(static_cast<u32>(Param(2)), ¶m_1, ¶m_2); Core::CurrentArmInterface().SetReg(1, param_1); Core::CurrentArmInterface().SetReg(2, param_2); FuncReturn(retval.raw); @@ -100,12 +108,12 @@ void SvcWrap() { template <ResultCode func(u64, u64, u32, u32)> void SvcWrap() { FuncReturn( - func(Param(0), Param(1), (u32)(Param(3) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw); + func(Param(0), Param(1), static_cast<u32>(Param(3)), static_cast<u32>(Param(3))).raw); } template <ResultCode func(u32, u64, u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0), Param(1), (u32)Param(2)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw); } template <ResultCode func(u64, u64, u64)> @@ -115,25 +123,28 @@ void SvcWrap() { template <ResultCode func(u32, u64, u64, u32)> void SvcWrap() { - FuncReturn(func((u32)Param(0), Param(1), Param(2), (u32)Param(3)).raw); + FuncReturn( + func(static_cast<u32>(Param(0)), Param(1), Param(2), static_cast<u32>(Param(3))).raw); } template <ResultCode func(u32, u64, u64)> void SvcWrap() { - FuncReturn(func((u32)Param(0), Param(1), Param(2)).raw); + FuncReturn(func(static_cast<u32>(Param(0)), Param(1), Param(2)).raw); } template <ResultCode func(u32*, u64, u64, s64)> void SvcWrap() { u32 param_1 = 0; - ResultCode retval = func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)); + ResultCode retval = + func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))); Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval.raw); } template <ResultCode func(u64, u64, u32, s64)> void SvcWrap() { - FuncReturn(func(Param(0), Param(1), (u32)Param(2), (s64)Param(3)).raw); + FuncReturn( + func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))).raw); } template <ResultCode func(u64*, u64, u64, u64)> @@ -147,9 +158,9 @@ void SvcWrap() { template <ResultCode func(u32*, u64, u64, u64, u32, s32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = - func(¶m_1, Param(1), Param(2), Param(3), (u32)Param(4), (s32)(Param(5) & 0xFFFFFFFF)) - .raw; + u32 retval = func(¶m_1, Param(1), Param(2), Param(3), static_cast<u32>(Param(4)), + static_cast<s32>(Param(5))) + .raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -172,7 +183,7 @@ void SvcWrap() { template <ResultCode func(u32*, u64, u64, u32)> void SvcWrap() { u32 param_1 = 0; - u32 retval = func(¶m_1, Param(1), Param(2), (u32)(Param(3) & 0xFFFFFFFF)).raw; + u32 retval = func(¶m_1, Param(1), Param(2), static_cast<u32>(Param(3))).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } @@ -181,22 +192,22 @@ template <ResultCode func(Handle*, u64, u32, u32)> void SvcWrap() { u32 param_1 = 0; u32 retval = - func(¶m_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw; + func(¶m_1, Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw; Core::CurrentArmInterface().SetReg(1, param_1); FuncReturn(retval); } template <ResultCode func(u64, u32, s32, s64)> void SvcWrap() { - FuncReturn( - func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)) - .raw); + FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)), + static_cast<s64>(Param(3))) + .raw); } template <ResultCode func(u64, u32, s32, s32)> void SvcWrap() { - FuncReturn(func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), - (s32)(Param(3) & 0xFFFFFFFF)) + FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)), + static_cast<s32>(Param(3))) .raw); } @@ -226,7 +237,7 @@ void SvcWrap() { template <void func(s64)> void SvcWrap() { - func((s64)Param(0)); + func(static_cast<s64>(Param(0))); } template <void func(u64, u64 len)> @@ -239,4 +250,9 @@ void SvcWrap() { func(Param(0), Param(1), Param(2)); } +template <void func(u32, u64, u64)> +void SvcWrap() { + func(static_cast<u32>(Param(0)), Param(1), Param(2)); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 33aed8c23..352ce1725 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -183,13 +183,10 @@ void Thread::ResumeFromWait() { */ static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAddr stack_top, VAddr entry_point, u64 arg) { - memset(&context, 0, sizeof(Core::ARM_Interface::ThreadContext)); - + context = {}; context.cpu_registers[0] = arg; context.pc = entry_point; context.sp = stack_top; - context.pstate = 0; - context.fpcr = 0; } ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, |