diff options
Diffstat (limited to 'src/core/hle/kernel')
30 files changed, 616 insertions, 419 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 5c3c47acf..2ff652f13 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -16,8 +16,10 @@ | |||
| 16 | 16 | ||
| 17 | namespace Kernel { | 17 | namespace Kernel { |
| 18 | 18 | ||
| 19 | AddressArbiter::AddressArbiter() {} | 19 | AddressArbiter::AddressArbiter() { |
| 20 | AddressArbiter::~AddressArbiter() {} | 20 | } |
| 21 | AddressArbiter::~AddressArbiter() { | ||
| 22 | } | ||
| 21 | 23 | ||
| 22 | SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) { | 24 | SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) { |
| 23 | SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); | 25 | SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter); |
| @@ -28,7 +30,7 @@ SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) { | |||
| 28 | } | 30 | } |
| 29 | 31 | ||
| 30 | ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, | 32 | ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, |
| 31 | u64 nanoseconds) { | 33 | u64 nanoseconds) { |
| 32 | switch (type) { | 34 | switch (type) { |
| 33 | 35 | ||
| 34 | // Signal thread(s) waiting for arbitrate address... | 36 | // Signal thread(s) waiting for arbitrate address... |
| @@ -38,7 +40,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 38 | ArbitrateAllThreads(address); | 40 | ArbitrateAllThreads(address); |
| 39 | } else { | 41 | } else { |
| 40 | // Resume first N threads | 42 | // Resume first N threads |
| 41 | for(int i = 0; i < value; i++) | 43 | for (int i = 0; i < value; i++) |
| 42 | ArbitrateHighestPriorityThread(address); | 44 | ArbitrateHighestPriorityThread(address); |
| 43 | } | 45 | } |
| 44 | break; | 46 | break; |
| @@ -55,8 +57,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 55 | GetCurrentThread()->WakeAfterDelay(nanoseconds); | 57 | GetCurrentThread()->WakeAfterDelay(nanoseconds); |
| 56 | } | 58 | } |
| 57 | break; | 59 | break; |
| 58 | case ArbitrationType::DecrementAndWaitIfLessThan: | 60 | case ArbitrationType::DecrementAndWaitIfLessThan: { |
| 59 | { | ||
| 60 | s32 memory_value = Memory::Read32(address); | 61 | s32 memory_value = Memory::Read32(address); |
| 61 | if (memory_value < value) { | 62 | if (memory_value < value) { |
| 62 | // Only change the memory value if the thread should wait | 63 | // Only change the memory value if the thread should wait |
| @@ -65,8 +66,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 65 | } | 66 | } |
| 66 | break; | 67 | break; |
| 67 | } | 68 | } |
| 68 | case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: | 69 | case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: { |
| 69 | { | ||
| 70 | s32 memory_value = Memory::Read32(address); | 70 | s32 memory_value = Memory::Read32(address); |
| 71 | if (memory_value < value) { | 71 | if (memory_value < value) { |
| 72 | // Only change the memory value if the thread should wait | 72 | // Only change the memory value if the thread should wait |
| @@ -79,17 +79,19 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 79 | 79 | ||
| 80 | default: | 80 | default: |
| 81 | LOG_ERROR(Kernel, "unknown type=%d", type); | 81 | LOG_ERROR(Kernel, "unknown type=%d", type); |
| 82 | return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage); | 82 | return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, |
| 83 | ErrorSummary::WrongArgument, ErrorLevel::Usage); | ||
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | HLE::Reschedule(__func__); | 86 | HLE::Reschedule(__func__); |
| 86 | 87 | ||
| 87 | // The calls that use a timeout seem to always return a Timeout error even if they did not put the thread to sleep | 88 | // The calls that use a timeout seem to always return a Timeout error even if they did not put |
| 89 | // the thread to sleep | ||
| 88 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || | 90 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || |
| 89 | type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { | 91 | type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { |
| 90 | 92 | ||
| 91 | return ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | 93 | return ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged, |
| 92 | ErrorSummary::StatusChanged, ErrorLevel::Info); | 94 | ErrorLevel::Info); |
| 93 | } | 95 | } |
| 94 | return RESULT_SUCCESS; | 96 | return RESULT_SUCCESS; |
| 95 | } | 97 | } |
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h index 8f6a1a8df..1a03993b2 100644 --- a/src/core/hle/kernel/address_arbiter.h +++ b/src/core/hle/kernel/address_arbiter.h | |||
| @@ -36,13 +36,19 @@ public: | |||
| 36 | */ | 36 | */ |
| 37 | static SharedPtr<AddressArbiter> Create(std::string name = "Unknown"); | 37 | static SharedPtr<AddressArbiter> Create(std::string name = "Unknown"); |
| 38 | 38 | ||
| 39 | std::string GetTypeName() const override { return "Arbiter"; } | 39 | std::string GetTypeName() const override { |
| 40 | std::string GetName() const override { return name; } | 40 | return "Arbiter"; |
| 41 | } | ||
| 42 | std::string GetName() const override { | ||
| 43 | return name; | ||
| 44 | } | ||
| 41 | 45 | ||
| 42 | static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; | 46 | static const HandleType HANDLE_TYPE = HandleType::AddressArbiter; |
| 43 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 47 | HandleType GetHandleType() const override { |
| 48 | return HANDLE_TYPE; | ||
| 49 | } | ||
| 44 | 50 | ||
| 45 | std::string name; ///< Name of address arbiter object (optional) | 51 | std::string name; ///< Name of address arbiter object (optional) |
| 46 | 52 | ||
| 47 | ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); | 53 | ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds); |
| 48 | 54 | ||
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 444ce8d45..5df769c6a 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp | |||
| @@ -10,7 +10,9 @@ | |||
| 10 | 10 | ||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | ClientPort::ClientPort() {} | 13 | ClientPort::ClientPort() { |
| 14 | ClientPort::~ClientPort() {} | 14 | } |
| 15 | ClientPort::~ClientPort() { | ||
| 16 | } | ||
| 15 | 17 | ||
| 16 | } // namespace | 18 | } // namespace |
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index 480b6ddae..70e0d56cc 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h | |||
| @@ -17,16 +17,22 @@ class ServerPort; | |||
| 17 | class ClientPort : public Object { | 17 | class ClientPort : public Object { |
| 18 | public: | 18 | public: |
| 19 | friend class ServerPort; | 19 | friend class ServerPort; |
| 20 | std::string GetTypeName() const override { return "ClientPort"; } | 20 | std::string GetTypeName() const override { |
| 21 | std::string GetName() const override { return name; } | 21 | return "ClientPort"; |
| 22 | } | ||
| 23 | std::string GetName() const override { | ||
| 24 | return name; | ||
| 25 | } | ||
| 22 | 26 | ||
| 23 | static const HandleType HANDLE_TYPE = HandleType::ClientPort; | 27 | static const HandleType HANDLE_TYPE = HandleType::ClientPort; |
| 24 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 28 | HandleType GetHandleType() const override { |
| 25 | 29 | return HANDLE_TYPE; | |
| 26 | SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. | 30 | } |
| 27 | u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have | 31 | |
| 28 | u32 active_sessions; ///< Number of currently open sessions to this port | 32 | SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port. |
| 29 | std::string name; ///< Name of client port (optional) | 33 | u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have |
| 34 | u32 active_sessions; ///< Number of currently open sessions to this port | ||
| 35 | std::string name; ///< Name of client port (optional) | ||
| 30 | 36 | ||
| 31 | protected: | 37 | protected: |
| 32 | ClientPort(); | 38 | ClientPort(); |
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 2b7c6992a..63375818d 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp | |||
| @@ -2,20 +2,22 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <map> | ||
| 6 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <map> | ||
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | 8 | ||
| 9 | #include "common/assert.h" | 9 | #include "common/assert.h" |
| 10 | 10 | ||
| 11 | #include "core/hle/kernel/kernel.h" | ||
| 12 | #include "core/hle/kernel/event.h" | 11 | #include "core/hle/kernel/event.h" |
| 12 | #include "core/hle/kernel/kernel.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | 13 | #include "core/hle/kernel/thread.h" |
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| 17 | Event::Event() {} | 17 | Event::Event() { |
| 18 | Event::~Event() {} | 18 | } |
| 19 | Event::~Event() { | ||
| 20 | } | ||
| 19 | 21 | ||
| 20 | SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { | 22 | SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) { |
| 21 | SharedPtr<Event> evt(new Event); | 23 | SharedPtr<Event> evt(new Event); |
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h index 73d0da419..e333a46ce 100644 --- a/src/core/hle/kernel/event.h +++ b/src/core/hle/kernel/event.h | |||
| @@ -16,7 +16,6 @@ enum class ResetType { | |||
| 16 | Pulse, | 16 | Pulse, |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | |||
| 20 | class Event final : public WaitObject { | 19 | class Event final : public WaitObject { |
| 21 | public: | 20 | public: |
| 22 | /** | 21 | /** |
| @@ -26,16 +25,22 @@ public: | |||
| 26 | */ | 25 | */ |
| 27 | static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown"); | 26 | static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown"); |
| 28 | 27 | ||
| 29 | std::string GetTypeName() const override { return "Event"; } | 28 | std::string GetTypeName() const override { |
| 30 | std::string GetName() const override { return name; } | 29 | return "Event"; |
| 30 | } | ||
| 31 | std::string GetName() const override { | ||
| 32 | return name; | ||
| 33 | } | ||
| 31 | 34 | ||
| 32 | static const HandleType HANDLE_TYPE = HandleType::Event; | 35 | static const HandleType HANDLE_TYPE = HandleType::Event; |
| 33 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 36 | HandleType GetHandleType() const override { |
| 37 | return HANDLE_TYPE; | ||
| 38 | } | ||
| 34 | 39 | ||
| 35 | ResetType reset_type; ///< Current ResetType | 40 | ResetType reset_type; ///< Current ResetType |
| 36 | 41 | ||
| 37 | bool signaled; ///< Whether the event has already been signaled | 42 | bool signaled; ///< Whether the event has already been signaled |
| 38 | std::string name; ///< Name of event (optional) | 43 | std::string name; ///< Name of event (optional) |
| 39 | 44 | ||
| 40 | bool ShouldWait() override; | 45 | bool ShouldWait() override; |
| 41 | void Acquire() override; | 46 | void Acquire() override; |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 7a401a965..1fd7c0326 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -61,7 +61,8 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | |||
| 61 | 61 | ||
| 62 | // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. | 62 | // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. |
| 63 | // CTR-OS doesn't use generation 0, so skip straight to 1. | 63 | // CTR-OS doesn't use generation 0, so skip straight to 1. |
| 64 | if (next_generation >= (1 << 15)) next_generation = 1; | 64 | if (next_generation >= (1 << 15)) |
| 65 | next_generation = 1; | ||
| 65 | 66 | ||
| 66 | generations[slot] = generation; | 67 | generations[slot] = generation; |
| 67 | objects[slot] = std::move(obj); | 68 | objects[slot] = std::move(obj); |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 27ba3f912..cc39652d5 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -23,48 +23,55 @@ class Thread; | |||
| 23 | 23 | ||
| 24 | // TODO: Verify code | 24 | // TODO: Verify code |
| 25 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | 25 | const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel, |
| 26 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); | 26 | ErrorSummary::OutOfResource, ErrorLevel::Temporary); |
| 27 | // TOOD: Verify code | 27 | // TOOD: Verify code |
| 28 | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, | 28 | const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel, |
| 29 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 29 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 30 | 30 | ||
| 31 | enum KernelHandle : Handle { | 31 | enum KernelHandle : Handle { |
| 32 | CurrentThread = 0xFFFF8000, | 32 | CurrentThread = 0xFFFF8000, |
| 33 | CurrentProcess = 0xFFFF8001, | 33 | CurrentProcess = 0xFFFF8001, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | enum class HandleType : u32 { | 36 | enum class HandleType : u32 { |
| 37 | Unknown = 0, | 37 | Unknown = 0, |
| 38 | 38 | ||
| 39 | Session = 2, | 39 | Session = 2, |
| 40 | Event = 3, | 40 | Event = 3, |
| 41 | Mutex = 4, | 41 | Mutex = 4, |
| 42 | SharedMemory = 5, | 42 | SharedMemory = 5, |
| 43 | Redirection = 6, | 43 | Redirection = 6, |
| 44 | Thread = 7, | 44 | Thread = 7, |
| 45 | Process = 8, | 45 | Process = 8, |
| 46 | AddressArbiter = 9, | 46 | AddressArbiter = 9, |
| 47 | Semaphore = 10, | 47 | Semaphore = 10, |
| 48 | Timer = 11, | 48 | Timer = 11, |
| 49 | ResourceLimit = 12, | 49 | ResourceLimit = 12, |
| 50 | CodeSet = 13, | 50 | CodeSet = 13, |
| 51 | ClientPort = 14, | 51 | ClientPort = 14, |
| 52 | ServerPort = 15, | 52 | ServerPort = 15, |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | enum { | 55 | enum { |
| 56 | DEFAULT_STACK_SIZE = 0x4000, | 56 | DEFAULT_STACK_SIZE = 0x4000, |
| 57 | }; | 57 | }; |
| 58 | 58 | ||
| 59 | class Object : NonCopyable { | 59 | class Object : NonCopyable { |
| 60 | public: | 60 | public: |
| 61 | virtual ~Object() {} | 61 | virtual ~Object() { |
| 62 | } | ||
| 62 | 63 | ||
| 63 | /// Returns a unique identifier for the object. For debugging purposes only. | 64 | /// Returns a unique identifier for the object. For debugging purposes only. |
| 64 | unsigned int GetObjectId() const { return object_id; } | 65 | unsigned int GetObjectId() const { |
| 66 | return object_id; | ||
| 67 | } | ||
| 65 | 68 | ||
| 66 | virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; } | 69 | virtual std::string GetTypeName() const { |
| 67 | virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; } | 70 | return "[BAD KERNEL OBJECT TYPE]"; |
| 71 | } | ||
| 72 | virtual std::string GetName() const { | ||
| 73 | return "[UNKNOWN KERNEL OBJECT]"; | ||
| 74 | } | ||
| 68 | virtual Kernel::HandleType GetHandleType() const = 0; | 75 | virtual Kernel::HandleType GetHandleType() const = 0; |
| 69 | 76 | ||
| 70 | /** | 77 | /** |
| @@ -122,7 +129,6 @@ using SharedPtr = boost::intrusive_ptr<T>; | |||
| 122 | /// Class that represents a Kernel object that a thread can be waiting on | 129 | /// Class that represents a Kernel object that a thread can be waiting on |
| 123 | class WaitObject : public Object { | 130 | class WaitObject : public Object { |
| 124 | public: | 131 | public: |
| 125 | |||
| 126 | /** | 132 | /** |
| 127 | * Check if the current thread should wait until the object is available | 133 | * Check if the current thread should wait until the object is available |
| 128 | * @return True if the current thread should wait due to this object being unavailable | 134 | * @return True if the current thread should wait due to this object being unavailable |
| @@ -247,8 +253,12 @@ private: | |||
| 247 | */ | 253 | */ |
| 248 | static const size_t MAX_COUNT = 4096; | 254 | static const size_t MAX_COUNT = 4096; |
| 249 | 255 | ||
| 250 | static u16 GetSlot(Handle handle) { return handle >> 15; } | 256 | static u16 GetSlot(Handle handle) { |
| 251 | static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; } | 257 | return handle >> 15; |
| 258 | } | ||
| 259 | static u16 GetGeneration(Handle handle) { | ||
| 260 | return handle & 0x7FFF; | ||
| 261 | } | ||
| 252 | 262 | ||
| 253 | /// Stores the Object referenced by the handle or null if the slot is empty. | 263 | /// Stores the Object referenced by the handle or null if the slot is empty. |
| 254 | std::array<SharedPtr<Object>, MAX_COUNT> objects; | 264 | std::array<SharedPtr<Object>, MAX_COUNT> objects; |
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index 17ae87aef..89a72808a 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp | |||
| @@ -31,7 +31,7 @@ static MemoryRegionInfo memory_regions[3]; | |||
| 31 | static const u32 memory_region_sizes[8][3] = { | 31 | static const u32 memory_region_sizes[8][3] = { |
| 32 | // Old 3DS layouts | 32 | // Old 3DS layouts |
| 33 | {0x04000000, 0x02C00000, 0x01400000}, // 0 | 33 | {0x04000000, 0x02C00000, 0x01400000}, // 0 |
| 34 | { /* This appears to be unused. */ }, // 1 | 34 | {/* This appears to be unused. */}, // 1 |
| 35 | {0x06000000, 0x00C00000, 0x01400000}, // 2 | 35 | {0x06000000, 0x00C00000, 0x01400000}, // 2 |
| 36 | {0x05000000, 0x01C00000, 0x01400000}, // 3 | 36 | {0x05000000, 0x01C00000, 0x01400000}, // 3 |
| 37 | {0x04800000, 0x02400000, 0x01400000}, // 4 | 37 | {0x04800000, 0x02400000, 0x01400000}, // 4 |
| @@ -95,7 +95,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) { | |||
| 95 | UNREACHABLE(); | 95 | UNREACHABLE(); |
| 96 | } | 96 | } |
| 97 | } | 97 | } |
| 98 | |||
| 99 | } | 98 | } |
| 100 | 99 | ||
| 101 | namespace Memory { | 100 | namespace Memory { |
| @@ -110,9 +109,8 @@ struct MemoryArea { | |||
| 110 | 109 | ||
| 111 | // We don't declare the IO regions in here since its handled by other means. | 110 | // We don't declare the IO regions in here since its handled by other means. |
| 112 | static MemoryArea memory_areas[] = { | 111 | static MemoryArea memory_areas[] = { |
| 113 | {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM) | 112 | {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM) |
| 114 | }; | 113 | }; |
| 115 | |||
| 116 | } | 114 | } |
| 117 | 115 | ||
| 118 | void Init() { | 116 | void Init() { |
| @@ -125,15 +123,21 @@ void InitLegacyAddressSpace(Kernel::VMManager& address_space) { | |||
| 125 | 123 | ||
| 126 | for (MemoryArea& area : memory_areas) { | 124 | for (MemoryArea& area : memory_areas) { |
| 127 | auto block = std::make_shared<std::vector<u8>>(area.size); | 125 | auto block = std::make_shared<std::vector<u8>>(area.size); |
| 128 | address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap(); | 126 | address_space |
| 127 | .MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private) | ||
| 128 | .Unwrap(); | ||
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR, | 131 | auto cfg_mem_vma = address_space |
| 132 | (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom(); | 132 | .MapBackingMemory(CONFIG_MEMORY_VADDR, (u8*)&ConfigMem::config_mem, |
| 133 | CONFIG_MEMORY_SIZE, MemoryState::Shared) | ||
| 134 | .MoveFrom(); | ||
| 133 | address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); | 135 | address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); |
| 134 | 136 | ||
| 135 | auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR, | 137 | auto shared_page_vma = address_space |
| 136 | (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom(); | 138 | .MapBackingMemory(SHARED_PAGE_VADDR, (u8*)&SharedPage::shared_page, |
| 139 | SHARED_PAGE_SIZE, MemoryState::Shared) | ||
| 140 | .MoveFrom(); | ||
| 137 | address_space.Reprotect(shared_page_vma, VMAPermission::Read); | 141 | address_space.Reprotect(shared_page_vma, VMAPermission::Read); |
| 138 | 142 | ||
| 139 | AudioCore::AddAddressSpace(address_space); | 143 | AudioCore::AddAddressSpace(address_space); |
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h index 091c1f89f..b941c24b6 100644 --- a/src/core/hle/kernel/memory.h +++ b/src/core/hle/kernel/memory.h | |||
| @@ -25,7 +25,6 @@ struct MemoryRegionInfo { | |||
| 25 | void MemoryInit(u32 mem_type); | 25 | void MemoryInit(u32 mem_type); |
| 26 | void MemoryShutdown(); | 26 | void MemoryShutdown(); |
| 27 | MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); | 27 | MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); |
| 28 | |||
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | namespace Memory { | 30 | namespace Memory { |
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index edb97d324..f92810804 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp | |||
| @@ -33,8 +33,10 @@ void ReleaseThreadMutexes(Thread* thread) { | |||
| 33 | thread->held_mutexes.clear(); | 33 | thread->held_mutexes.clear(); |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | Mutex::Mutex() {} | 36 | Mutex::Mutex() { |
| 37 | Mutex::~Mutex() {} | 37 | } |
| 38 | Mutex::~Mutex() { | ||
| 39 | } | ||
| 38 | 40 | ||
| 39 | SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { | 41 | SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) { |
| 40 | SharedPtr<Mutex> mutex(new Mutex); | 42 | SharedPtr<Mutex> mutex(new Mutex); |
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h index 1746360e4..cf6a51fdf 100644 --- a/src/core/hle/kernel/mutex.h +++ b/src/core/hle/kernel/mutex.h | |||
| @@ -24,15 +24,21 @@ public: | |||
| 24 | */ | 24 | */ |
| 25 | static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown"); | 25 | static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown"); |
| 26 | 26 | ||
| 27 | std::string GetTypeName() const override { return "Mutex"; } | 27 | std::string GetTypeName() const override { |
| 28 | std::string GetName() const override { return name; } | 28 | return "Mutex"; |
| 29 | } | ||
| 30 | std::string GetName() const override { | ||
| 31 | return name; | ||
| 32 | } | ||
| 29 | 33 | ||
| 30 | static const HandleType HANDLE_TYPE = HandleType::Mutex; | 34 | static const HandleType HANDLE_TYPE = HandleType::Mutex; |
| 31 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 35 | HandleType GetHandleType() const override { |
| 36 | return HANDLE_TYPE; | ||
| 37 | } | ||
| 32 | 38 | ||
| 33 | int lock_count; ///< Number of times the mutex has been acquired | 39 | int lock_count; ///< Number of times the mutex has been acquired |
| 34 | std::string name; ///< Name of mutex (optional) | 40 | std::string name; ///< Name of mutex (optional) |
| 35 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex | 41 | SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex |
| 36 | 42 | ||
| 37 | bool ShouldWait() override; | 43 | bool ShouldWait() override; |
| 38 | void Acquire() override; | 44 | void Acquire() override; |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 69302cc82..cc37e574c 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -26,8 +26,10 @@ SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) { | |||
| 26 | return codeset; | 26 | return codeset; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | CodeSet::CodeSet() {} | 29 | CodeSet::CodeSet() { |
| 30 | CodeSet::~CodeSet() {} | 30 | } |
| 31 | CodeSet::~CodeSet() { | ||
| 32 | } | ||
| 31 | 33 | ||
| 32 | u32 Process::next_process_id; | 34 | u32 Process::next_process_id; |
| 33 | 35 | ||
| @@ -60,7 +62,8 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 60 | 62 | ||
| 61 | while (bits && index < svc_access_mask.size()) { | 63 | while (bits && index < svc_access_mask.size()) { |
| 62 | svc_access_mask.set(index, bits & 1); | 64 | svc_access_mask.set(index, bits & 1); |
| 63 | ++index; bits >>= 1; | 65 | ++index; |
| 66 | bits >>= 1; | ||
| 64 | } | 67 | } |
| 65 | } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF | 68 | } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF |
| 66 | // Handle table size | 69 | // Handle table size |
| @@ -70,11 +73,11 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 70 | flags.raw = descriptor & 0xFFFF; | 73 | flags.raw = descriptor & 0xFFFF; |
| 71 | } else if ((type & 0xFFE) == 0xFF8) { // 0x001F | 74 | } else if ((type & 0xFFE) == 0xFF8) { // 0x001F |
| 72 | // Mapped memory range | 75 | // Mapped memory range |
| 73 | if (i+1 >= len || ((kernel_caps[i+1] >> 20) & 0xFFE) != 0xFF8) { | 76 | if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) { |
| 74 | LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); | 77 | LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored."); |
| 75 | continue; | 78 | continue; |
| 76 | } | 79 | } |
| 77 | u32 end_desc = kernel_caps[i+1]; | 80 | u32 end_desc = kernel_caps[i + 1]; |
| 78 | ++i; // Skip over the second descriptor on the next iteration | 81 | ++i; // Skip over the second descriptor on the next iteration |
| 79 | 82 | ||
| 80 | AddressMapping mapping; | 83 | AddressMapping mapping; |
| @@ -107,23 +110,28 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 107 | void Process::Run(s32 main_thread_priority, u32 stack_size) { | 110 | void Process::Run(s32 main_thread_priority, u32 stack_size) { |
| 108 | memory_region = GetMemoryRegion(flags.memory_region); | 111 | memory_region = GetMemoryRegion(flags.memory_region); |
| 109 | 112 | ||
| 110 | auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { | 113 | auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, |
| 111 | auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory, | 114 | MemoryState memory_state) { |
| 112 | segment.offset, segment.size, memory_state).Unwrap(); | 115 | auto vma = vm_manager |
| 116 | .MapMemoryBlock(segment.addr, codeset->memory, segment.offset, segment.size, | ||
| 117 | memory_state) | ||
| 118 | .Unwrap(); | ||
| 113 | vm_manager.Reprotect(vma, permissions); | 119 | vm_manager.Reprotect(vma, permissions); |
| 114 | misc_memory_used += segment.size; | 120 | misc_memory_used += segment.size; |
| 115 | memory_region->used += segment.size; | 121 | memory_region->used += segment.size; |
| 116 | }; | 122 | }; |
| 117 | 123 | ||
| 118 | // Map CodeSet segments | 124 | // Map CodeSet segments |
| 119 | MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code); | 125 | MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code); |
| 120 | MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code); | 126 | MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code); |
| 121 | MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private); | 127 | MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private); |
| 122 | 128 | ||
| 123 | // Allocate and map stack | 129 | // Allocate and map stack |
| 124 | vm_manager.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, | 130 | vm_manager |
| 125 | std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked | 131 | .MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size, |
| 126 | ).Unwrap(); | 132 | std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, |
| 133 | MemoryState::Locked) | ||
| 134 | .Unwrap(); | ||
| 127 | misc_memory_used += stack_size; | 135 | misc_memory_used += stack_size; |
| 128 | memory_region->used += stack_size; | 136 | memory_region->used += stack_size; |
| 129 | 137 | ||
| @@ -143,7 +151,8 @@ VAddr Process::GetLinearHeapLimit() const { | |||
| 143 | } | 151 | } |
| 144 | 152 | ||
| 145 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) { | 153 | ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) { |
| 146 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) { | 154 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || |
| 155 | target + size < target) { | ||
| 147 | return ERR_INVALID_ADDRESS; | 156 | return ERR_INVALID_ADDRESS; |
| 148 | } | 157 | } |
| 149 | 158 | ||
| @@ -166,7 +175,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per | |||
| 166 | } | 175 | } |
| 167 | ASSERT(heap_end - heap_start == heap_memory->size()); | 176 | ASSERT(heap_end - heap_start == heap_memory->size()); |
| 168 | 177 | ||
| 169 | CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, size, MemoryState::Private)); | 178 | CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, |
| 179 | size, MemoryState::Private)); | ||
| 170 | vm_manager.Reprotect(vma, perms); | 180 | vm_manager.Reprotect(vma, perms); |
| 171 | 181 | ||
| 172 | heap_used += size; | 182 | heap_used += size; |
| @@ -176,7 +186,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per | |||
| 176 | } | 186 | } |
| 177 | 187 | ||
| 178 | ResultCode Process::HeapFree(VAddr target, u32 size) { | 188 | ResultCode Process::HeapFree(VAddr target, u32 size) { |
| 179 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) { | 189 | if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || |
| 190 | target + size < target) { | ||
| 180 | return ERR_INVALID_ADDRESS; | 191 | return ERR_INVALID_ADDRESS; |
| 181 | } | 192 | } |
| 182 | 193 | ||
| @@ -185,7 +196,8 @@ ResultCode Process::HeapFree(VAddr target, u32 size) { | |||
| 185 | } | 196 | } |
| 186 | 197 | ||
| 187 | ResultCode result = vm_manager.UnmapRange(target, size); | 198 | ResultCode result = vm_manager.UnmapRange(target, size); |
| 188 | if (result.IsError()) return result; | 199 | if (result.IsError()) |
| 200 | return result; | ||
| 189 | 201 | ||
| 190 | heap_used -= size; | 202 | heap_used -= size; |
| 191 | memory_region->used -= size; | 203 | memory_region->used -= size; |
| @@ -203,8 +215,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p | |||
| 203 | target = heap_end; | 215 | target = heap_end; |
| 204 | } | 216 | } |
| 205 | 217 | ||
| 206 | if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || | 218 | if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || target > heap_end || |
| 207 | target > heap_end || target + size < target) { | 219 | target + size < target) { |
| 208 | 220 | ||
| 209 | return ERR_INVALID_ADDRESS; | 221 | return ERR_INVALID_ADDRESS; |
| 210 | } | 222 | } |
| @@ -220,7 +232,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p | |||
| 220 | // TODO(yuriks): As is, this lets processes map memory allocated by other processes from the | 232 | // TODO(yuriks): As is, this lets processes map memory allocated by other processes from the |
| 221 | // same region. It is unknown if or how the 3DS kernel checks against this. | 233 | // same region. It is unknown if or how the 3DS kernel checks against this. |
| 222 | size_t offset = target - GetLinearHeapBase(); | 234 | size_t offset = target - GetLinearHeapBase(); |
| 223 | CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous)); | 235 | CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, |
| 236 | MemoryState::Continuous)); | ||
| 224 | vm_manager.Reprotect(vma, perms); | 237 | vm_manager.Reprotect(vma, perms); |
| 225 | 238 | ||
| 226 | linear_heap_used += size; | 239 | linear_heap_used += size; |
| @@ -248,7 +261,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { | |||
| 248 | } | 261 | } |
| 249 | 262 | ||
| 250 | ResultCode result = vm_manager.UnmapRange(target, size); | 263 | ResultCode result = vm_manager.UnmapRange(target, size); |
| 251 | if (result.IsError()) return result; | 264 | if (result.IsError()) |
| 265 | return result; | ||
| 252 | 266 | ||
| 253 | linear_heap_used -= size; | 267 | linear_heap_used -= size; |
| 254 | memory_region->used -= size; | 268 | memory_region->used -= size; |
| @@ -268,9 +282,10 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { | |||
| 268 | return RESULT_SUCCESS; | 282 | return RESULT_SUCCESS; |
| 269 | } | 283 | } |
| 270 | 284 | ||
| 271 | Kernel::Process::Process() {} | 285 | Kernel::Process::Process() { |
| 272 | Kernel::Process::~Process() {} | 286 | } |
| 287 | Kernel::Process::~Process() { | ||
| 288 | } | ||
| 273 | 289 | ||
| 274 | SharedPtr<Process> g_current_process; | 290 | SharedPtr<Process> g_current_process; |
| 275 | |||
| 276 | } | 291 | } |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index d781ef32c..070b2b558 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -36,15 +36,18 @@ enum class MemoryRegion : u16 { | |||
| 36 | union ProcessFlags { | 36 | union ProcessFlags { |
| 37 | u16 raw; | 37 | u16 raw; |
| 38 | 38 | ||
| 39 | BitField< 0, 1, u16> allow_debug; ///< Allows other processes to attach to and debug this process. | 39 | BitField<0, 1, u16> |
| 40 | BitField< 1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they don't have allow_debug set. | 40 | allow_debug; ///< Allows other processes to attach to and debug this process. |
| 41 | BitField< 2, 1, u16> allow_nonalphanum; | 41 | BitField<1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they |
| 42 | BitField< 3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions. | 42 | /// don't have allow_debug set. |
| 43 | BitField< 4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24. | 43 | BitField<2, 1, u16> allow_nonalphanum; |
| 44 | BitField< 5, 1, u16> allow_main_args; | 44 | BitField<3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions. |
| 45 | BitField< 6, 1, u16> shared_device_mem; | 45 | BitField<4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24. |
| 46 | BitField< 7, 1, u16> runnable_on_sleep; | 46 | BitField<5, 1, u16> allow_main_args; |
| 47 | BitField< 8, 4, MemoryRegion> memory_region; ///< Default region for memory allocations for this process | 47 | BitField<6, 1, u16> shared_device_mem; |
| 48 | BitField<7, 1, u16> runnable_on_sleep; | ||
| 49 | BitField<8, 4, MemoryRegion> | ||
| 50 | memory_region; ///< Default region for memory allocations for this process | ||
| 48 | BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). | 51 | BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). |
| 49 | }; | 52 | }; |
| 50 | 53 | ||
| @@ -54,11 +57,17 @@ struct MemoryRegionInfo; | |||
| 54 | struct CodeSet final : public Object { | 57 | struct CodeSet final : public Object { |
| 55 | static SharedPtr<CodeSet> Create(std::string name, u64 program_id); | 58 | static SharedPtr<CodeSet> Create(std::string name, u64 program_id); |
| 56 | 59 | ||
| 57 | std::string GetTypeName() const override { return "CodeSet"; } | 60 | std::string GetTypeName() const override { |
| 58 | std::string GetName() const override { return name; } | 61 | return "CodeSet"; |
| 62 | } | ||
| 63 | std::string GetName() const override { | ||
| 64 | return name; | ||
| 65 | } | ||
| 59 | 66 | ||
| 60 | static const HandleType HANDLE_TYPE = HandleType::CodeSet; | 67 | static const HandleType HANDLE_TYPE = HandleType::CodeSet; |
| 61 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 68 | HandleType GetHandleType() const override { |
| 69 | return HANDLE_TYPE; | ||
| 70 | } | ||
| 62 | 71 | ||
| 63 | /// Name of the process | 72 | /// Name of the process |
| 64 | std::string name; | 73 | std::string name; |
| @@ -85,11 +94,17 @@ class Process final : public Object { | |||
| 85 | public: | 94 | public: |
| 86 | static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set); | 95 | static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set); |
| 87 | 96 | ||
| 88 | std::string GetTypeName() const override { return "Process"; } | 97 | std::string GetTypeName() const override { |
| 89 | std::string GetName() const override { return codeset->name; } | 98 | return "Process"; |
| 99 | } | ||
| 100 | std::string GetName() const override { | ||
| 101 | return codeset->name; | ||
| 102 | } | ||
| 90 | 103 | ||
| 91 | static const HandleType HANDLE_TYPE = HandleType::Process; | 104 | static const HandleType HANDLE_TYPE = HandleType::Process; |
| 92 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 105 | HandleType GetHandleType() const override { |
| 106 | return HANDLE_TYPE; | ||
| 107 | } | ||
| 93 | 108 | ||
| 94 | static u32 next_process_id; | 109 | static u32 next_process_id; |
| 95 | 110 | ||
| @@ -124,7 +139,6 @@ public: | |||
| 124 | */ | 139 | */ |
| 125 | void Run(s32 main_thread_priority, u32 stack_size); | 140 | void Run(s32 main_thread_priority, u32 stack_size); |
| 126 | 141 | ||
| 127 | |||
| 128 | /////////////////////////////////////////////////////////////////////////////////////////////// | 142 | /////////////////////////////////////////////////////////////////////////////////////////////// |
| 129 | // Memory Management | 143 | // Memory Management |
| 130 | 144 | ||
| @@ -144,7 +158,8 @@ public: | |||
| 144 | 158 | ||
| 145 | /// The Thread Local Storage area is allocated as processes create threads, | 159 | /// The Thread Local Storage area is allocated as processes create threads, |
| 146 | /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part | 160 | /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part |
| 147 | /// holds the TLS for a specific thread. This vector contains which parts are in use for each page as a bitmask. | 161 | /// holds the TLS for a specific thread. This vector contains which parts are in use for each |
| 162 | /// page as a bitmask. | ||
| 148 | /// This vector will grow as more pages are allocated for new threads. | 163 | /// This vector will grow as more pages are allocated for new threads. |
| 149 | std::vector<std::bitset<8>> tls_slots; | 164 | std::vector<std::bitset<8>> tls_slots; |
| 150 | 165 | ||
| @@ -164,5 +179,4 @@ private: | |||
| 164 | }; | 179 | }; |
| 165 | 180 | ||
| 166 | extern SharedPtr<Process> g_current_process; | 181 | extern SharedPtr<Process> g_current_process; |
| 167 | |||
| 168 | } | 182 | } |
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp index 67dde08c2..7bd1c1e08 100644 --- a/src/core/hle/kernel/resource_limit.cpp +++ b/src/core/hle/kernel/resource_limit.cpp | |||
| @@ -12,8 +12,10 @@ namespace Kernel { | |||
| 12 | 12 | ||
| 13 | static SharedPtr<ResourceLimit> resource_limits[4]; | 13 | static SharedPtr<ResourceLimit> resource_limits[4]; |
| 14 | 14 | ||
| 15 | ResourceLimit::ResourceLimit() {} | 15 | ResourceLimit::ResourceLimit() { |
| 16 | ResourceLimit::~ResourceLimit() {} | 16 | } |
| 17 | ResourceLimit::~ResourceLimit() { | ||
| 18 | } | ||
| 17 | 19 | ||
| 18 | SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) { | 20 | SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) { |
| 19 | SharedPtr<ResourceLimit> resource_limit(new ResourceLimit); | 21 | SharedPtr<ResourceLimit> resource_limit(new ResourceLimit); |
| @@ -23,70 +25,69 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) { | |||
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) { | 27 | SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) { |
| 26 | switch (category) | 28 | switch (category) { |
| 27 | { | 29 | case ResourceLimitCategory::APPLICATION: |
| 28 | case ResourceLimitCategory::APPLICATION: | 30 | case ResourceLimitCategory::SYS_APPLET: |
| 29 | case ResourceLimitCategory::SYS_APPLET: | 31 | case ResourceLimitCategory::LIB_APPLET: |
| 30 | case ResourceLimitCategory::LIB_APPLET: | 32 | case ResourceLimitCategory::OTHER: |
| 31 | case ResourceLimitCategory::OTHER: | 33 | return resource_limits[static_cast<u8>(category)]; |
| 32 | return resource_limits[static_cast<u8>(category)]; | 34 | default: |
| 33 | default: | 35 | LOG_CRITICAL(Kernel, "Unknown resource limit category"); |
| 34 | LOG_CRITICAL(Kernel, "Unknown resource limit category"); | 36 | UNREACHABLE(); |
| 35 | UNREACHABLE(); | ||
| 36 | } | 37 | } |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const { | 40 | s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const { |
| 40 | switch (resource) { | 41 | switch (resource) { |
| 41 | case COMMIT: | 42 | case COMMIT: |
| 42 | return current_commit; | 43 | return current_commit; |
| 43 | case THREAD: | 44 | case THREAD: |
| 44 | return current_threads; | 45 | return current_threads; |
| 45 | case EVENT: | 46 | case EVENT: |
| 46 | return current_events; | 47 | return current_events; |
| 47 | case MUTEX: | 48 | case MUTEX: |
| 48 | return current_mutexes; | 49 | return current_mutexes; |
| 49 | case SEMAPHORE: | 50 | case SEMAPHORE: |
| 50 | return current_semaphores; | 51 | return current_semaphores; |
| 51 | case TIMER: | 52 | case TIMER: |
| 52 | return current_timers; | 53 | return current_timers; |
| 53 | case SHARED_MEMORY: | 54 | case SHARED_MEMORY: |
| 54 | return current_shared_mems; | 55 | return current_shared_mems; |
| 55 | case ADDRESS_ARBITER: | 56 | case ADDRESS_ARBITER: |
| 56 | return current_address_arbiters; | 57 | return current_address_arbiters; |
| 57 | case CPU_TIME: | 58 | case CPU_TIME: |
| 58 | return current_cpu_time; | 59 | return current_cpu_time; |
| 59 | default: | 60 | default: |
| 60 | LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); | 61 | LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); |
| 61 | UNIMPLEMENTED(); | 62 | UNIMPLEMENTED(); |
| 62 | return 0; | 63 | return 0; |
| 63 | } | 64 | } |
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | s32 ResourceLimit::GetMaxResourceValue(u32 resource) const { | 67 | s32 ResourceLimit::GetMaxResourceValue(u32 resource) const { |
| 67 | switch (resource) { | 68 | switch (resource) { |
| 68 | case COMMIT: | 69 | case COMMIT: |
| 69 | return max_commit; | 70 | return max_commit; |
| 70 | case THREAD: | 71 | case THREAD: |
| 71 | return max_threads; | 72 | return max_threads; |
| 72 | case EVENT: | 73 | case EVENT: |
| 73 | return max_events; | 74 | return max_events; |
| 74 | case MUTEX: | 75 | case MUTEX: |
| 75 | return max_mutexes; | 76 | return max_mutexes; |
| 76 | case SEMAPHORE: | 77 | case SEMAPHORE: |
| 77 | return max_semaphores; | 78 | return max_semaphores; |
| 78 | case TIMER: | 79 | case TIMER: |
| 79 | return max_timers; | 80 | return max_timers; |
| 80 | case SHARED_MEMORY: | 81 | case SHARED_MEMORY: |
| 81 | return max_shared_mems; | 82 | return max_shared_mems; |
| 82 | case ADDRESS_ARBITER: | 83 | case ADDRESS_ARBITER: |
| 83 | return max_address_arbiters; | 84 | return max_address_arbiters; |
| 84 | case CPU_TIME: | 85 | case CPU_TIME: |
| 85 | return max_cpu_time; | 86 | return max_cpu_time; |
| 86 | default: | 87 | default: |
| 87 | LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); | 88 | LOG_ERROR(Kernel, "Unknown resource type=%08X", resource); |
| 88 | UNIMPLEMENTED(); | 89 | UNIMPLEMENTED(); |
| 89 | return 0; | 90 | return 0; |
| 90 | } | 91 | } |
| 91 | } | 92 | } |
| 92 | 93 | ||
| @@ -150,7 +151,6 @@ void ResourceLimitsInit() { | |||
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | void ResourceLimitsShutdown() { | 153 | void ResourceLimitsShutdown() { |
| 153 | |||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | } // namespace | 156 | } // namespace |
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index 1b8249c74..c08e744e6 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h | |||
| @@ -12,22 +12,22 @@ namespace Kernel { | |||
| 12 | 12 | ||
| 13 | enum class ResourceLimitCategory : u8 { | 13 | enum class ResourceLimitCategory : u8 { |
| 14 | APPLICATION = 0, | 14 | APPLICATION = 0, |
| 15 | SYS_APPLET = 1, | 15 | SYS_APPLET = 1, |
| 16 | LIB_APPLET = 2, | 16 | LIB_APPLET = 2, |
| 17 | OTHER = 3 | 17 | OTHER = 3 |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | enum ResourceTypes { | 20 | enum ResourceTypes { |
| 21 | PRIORITY = 0, | 21 | PRIORITY = 0, |
| 22 | COMMIT = 1, | 22 | COMMIT = 1, |
| 23 | THREAD = 2, | 23 | THREAD = 2, |
| 24 | EVENT = 3, | 24 | EVENT = 3, |
| 25 | MUTEX = 4, | 25 | MUTEX = 4, |
| 26 | SEMAPHORE = 5, | 26 | SEMAPHORE = 5, |
| 27 | TIMER = 6, | 27 | TIMER = 6, |
| 28 | SHARED_MEMORY = 7, | 28 | SHARED_MEMORY = 7, |
| 29 | ADDRESS_ARBITER = 8, | 29 | ADDRESS_ARBITER = 8, |
| 30 | CPU_TIME = 9, | 30 | CPU_TIME = 9, |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | class ResourceLimit final : public Object { | 33 | class ResourceLimit final : public Object { |
| @@ -44,11 +44,17 @@ public: | |||
| 44 | */ | 44 | */ |
| 45 | static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category); | 45 | static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category); |
| 46 | 46 | ||
| 47 | std::string GetTypeName() const override { return "ResourceLimit"; } | 47 | std::string GetTypeName() const override { |
| 48 | std::string GetName() const override { return name; } | 48 | return "ResourceLimit"; |
| 49 | } | ||
| 50 | std::string GetName() const override { | ||
| 51 | return name; | ||
| 52 | } | ||
| 49 | 53 | ||
| 50 | static const HandleType HANDLE_TYPE = HandleType::ResourceLimit; | 54 | static const HandleType HANDLE_TYPE = HandleType::ResourceLimit; |
| 51 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 55 | HandleType GetHandleType() const override { |
| 56 | return HANDLE_TYPE; | ||
| 57 | } | ||
| 52 | 58 | ||
| 53 | /** | 59 | /** |
| 54 | * Gets the current value for the specified resource. | 60 | * Gets the current value for the specified resource. |
| @@ -85,10 +91,12 @@ public: | |||
| 85 | /// Max CPU time that the processes in this category can utilize | 91 | /// Max CPU time that the processes in this category can utilize |
| 86 | s32 max_cpu_time = 0; | 92 | s32 max_cpu_time = 0; |
| 87 | 93 | ||
| 88 | // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that | 94 | // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind |
| 95 | // that | ||
| 89 | // APPLICATION resource limits should not be affected by the objects created by service modules. | 96 | // APPLICATION resource limits should not be affected by the objects created by service modules. |
| 90 | // Currently we have no way of distinguishing if a Create was called by the running application, | 97 | // Currently we have no way of distinguishing if a Create was called by the running application, |
| 91 | // or by a service module. Approach this once we have separated the service modules into their own processes | 98 | // or by a service module. Approach this once we have separated the service modules into their |
| 99 | // own processes | ||
| 92 | 100 | ||
| 93 | /// Current memory that the processes in this category are using | 101 | /// Current memory that the processes in this category are using |
| 94 | s32 current_commit = 0; | 102 | s32 current_commit = 0; |
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp index 4b359ed07..71e41079b 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp | |||
| @@ -10,11 +10,13 @@ | |||
| 10 | 10 | ||
| 11 | namespace Kernel { | 11 | namespace Kernel { |
| 12 | 12 | ||
| 13 | Semaphore::Semaphore() {} | 13 | Semaphore::Semaphore() { |
| 14 | Semaphore::~Semaphore() {} | 14 | } |
| 15 | Semaphore::~Semaphore() { | ||
| 16 | } | ||
| 15 | 17 | ||
| 16 | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, | 18 | ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count, |
| 17 | std::string name) { | 19 | std::string name) { |
| 18 | 20 | ||
| 19 | if (initial_count > max_count) | 21 | if (initial_count > max_count) |
| 20 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, | 22 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel, |
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h index 390f5e495..ed7d9a85c 100644 --- a/src/core/hle/kernel/semaphore.h +++ b/src/core/hle/kernel/semaphore.h | |||
| @@ -23,17 +23,23 @@ public: | |||
| 23 | * @return The created semaphore | 23 | * @return The created semaphore |
| 24 | */ | 24 | */ |
| 25 | static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, | 25 | static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count, |
| 26 | std::string name = "Unknown"); | 26 | std::string name = "Unknown"); |
| 27 | 27 | ||
| 28 | std::string GetTypeName() const override { return "Semaphore"; } | 28 | std::string GetTypeName() const override { |
| 29 | std::string GetName() const override { return name; } | 29 | return "Semaphore"; |
| 30 | } | ||
| 31 | std::string GetName() const override { | ||
| 32 | return name; | ||
| 33 | } | ||
| 30 | 34 | ||
| 31 | static const HandleType HANDLE_TYPE = HandleType::Semaphore; | 35 | static const HandleType HANDLE_TYPE = HandleType::Semaphore; |
| 32 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 36 | HandleType GetHandleType() const override { |
| 37 | return HANDLE_TYPE; | ||
| 38 | } | ||
| 33 | 39 | ||
| 34 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have | 40 | s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have |
| 35 | s32 available_count; ///< Number of free slots left in the semaphore | 41 | s32 available_count; ///< Number of free slots left in the semaphore |
| 36 | std::string name; ///< Name of semaphore (optional) | 42 | std::string name; ///< Name of semaphore (optional) |
| 37 | 43 | ||
| 38 | bool ShouldWait() override; | 44 | bool ShouldWait() override; |
| 39 | void Acquire() override; | 45 | void Acquire() override; |
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp index fcc684a20..7c690fa7f 100644 --- a/src/core/hle/kernel/server_port.cpp +++ b/src/core/hle/kernel/server_port.cpp | |||
| @@ -13,8 +13,10 @@ | |||
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | 15 | ||
| 16 | ServerPort::ServerPort() {} | 16 | ServerPort::ServerPort() { |
| 17 | ServerPort::~ServerPort() {} | 17 | } |
| 18 | ServerPort::~ServerPort() { | ||
| 19 | } | ||
| 18 | 20 | ||
| 19 | bool ServerPort::ShouldWait() { | 21 | bool ServerPort::ShouldWait() { |
| 20 | // If there are no pending sessions, we wait until a new one is added. | 22 | // If there are no pending sessions, we wait until a new one is added. |
| @@ -25,7 +27,8 @@ void ServerPort::Acquire() { | |||
| 25 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | 27 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); |
| 26 | } | 28 | } |
| 27 | 29 | ||
| 28 | std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(u32 max_sessions, std::string name) { | 30 | std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> |
| 31 | ServerPort::CreatePortPair(u32 max_sessions, std::string name) { | ||
| 29 | SharedPtr<ServerPort> server_port(new ServerPort); | 32 | SharedPtr<ServerPort> server_port(new ServerPort); |
| 30 | SharedPtr<ClientPort> client_port(new ClientPort); | 33 | SharedPtr<ClientPort> client_port(new ClientPort); |
| 31 | 34 | ||
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index e9c972ce6..e43d48674 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h | |||
| @@ -23,17 +23,25 @@ public: | |||
| 23 | * @param name Optional name of the ports | 23 | * @param name Optional name of the ports |
| 24 | * @return The created port tuple | 24 | * @return The created port tuple |
| 25 | */ | 25 | */ |
| 26 | static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(u32 max_sessions, std::string name = "UnknownPort"); | 26 | static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> |
| 27 | CreatePortPair(u32 max_sessions, std::string name = "UnknownPort"); | ||
| 27 | 28 | ||
| 28 | std::string GetTypeName() const override { return "ServerPort"; } | 29 | std::string GetTypeName() const override { |
| 29 | std::string GetName() const override { return name; } | 30 | return "ServerPort"; |
| 31 | } | ||
| 32 | std::string GetName() const override { | ||
| 33 | return name; | ||
| 34 | } | ||
| 30 | 35 | ||
| 31 | static const HandleType HANDLE_TYPE = HandleType::ServerPort; | 36 | static const HandleType HANDLE_TYPE = HandleType::ServerPort; |
| 32 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 37 | HandleType GetHandleType() const override { |
| 38 | return HANDLE_TYPE; | ||
| 39 | } | ||
| 33 | 40 | ||
| 34 | std::string name; ///< Name of port (optional) | 41 | std::string name; ///< Name of port (optional) |
| 35 | 42 | ||
| 36 | std::vector<SharedPtr<WaitObject>> pending_sessions; ///< ServerSessions waiting to be accepted by the port | 43 | std::vector<SharedPtr<WaitObject>> |
| 44 | pending_sessions; ///< ServerSessions waiting to be accepted by the port | ||
| 37 | 45 | ||
| 38 | bool ShouldWait() override; | 46 | bool ShouldWait() override; |
| 39 | void Acquire() override; | 47 | void Acquire() override; |
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 0594967f8..61457845a 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp | |||
| @@ -7,7 +7,8 @@ | |||
| 7 | 7 | ||
| 8 | namespace Kernel { | 8 | namespace Kernel { |
| 9 | 9 | ||
| 10 | Session::Session() {} | 10 | Session::Session() { |
| 11 | Session::~Session() {} | 11 | } |
| 12 | 12 | Session::~Session() { | |
| 13 | } | ||
| 13 | } | 14 | } |
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h index 8ec889967..8e4e010b8 100644 --- a/src/core/hle/kernel/session.h +++ b/src/core/hle/kernel/session.h | |||
| @@ -19,12 +19,13 @@ namespace IPC { | |||
| 19 | enum DescriptorType : u32 { | 19 | enum DescriptorType : u32 { |
| 20 | // Buffer related desciptors types (mask : 0x0F) | 20 | // Buffer related desciptors types (mask : 0x0F) |
| 21 | StaticBuffer = 0x02, | 21 | StaticBuffer = 0x02, |
| 22 | PXIBuffer = 0x04, | 22 | PXIBuffer = 0x04, |
| 23 | MappedBuffer = 0x08, | 23 | MappedBuffer = 0x08, |
| 24 | // Handle related descriptors types (mask : 0x30, but need to check for buffer related descriptors first ) | 24 | // Handle related descriptors types (mask : 0x30, but need to check for buffer related |
| 25 | CopyHandle = 0x00, | 25 | // descriptors first ) |
| 26 | MoveHandle = 0x10, | 26 | CopyHandle = 0x00, |
| 27 | CallingPid = 0x20, | 27 | MoveHandle = 0x10, |
| 28 | CallingPid = 0x20, | ||
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 30 | /** | 31 | /** |
| @@ -34,24 +35,28 @@ enum DescriptorType : u32 { | |||
| 34 | * @param translate_params_size Size of the translate parameters in words. Up to 63. | 35 | * @param translate_params_size Size of the translate parameters in words. Up to 63. |
| 35 | * @return The created IPC header. | 36 | * @return The created IPC header. |
| 36 | * | 37 | * |
| 37 | * Normal parameters are sent directly to the process while the translate parameters might go through modifications and checks by the kernel. | 38 | * Normal parameters are sent directly to the process while the translate parameters might go |
| 39 | * through modifications and checks by the kernel. | ||
| 38 | * The translate parameters are described by headers generated with the IPC::*Desc functions. | 40 | * The translate parameters are described by headers generated with the IPC::*Desc functions. |
| 39 | * | 41 | * |
| 40 | * @note While #normal_params is equivalent to the number of normal parameters, #translate_params_size includes the size occupied by the translate parameters headers. | 42 | * @note While #normal_params is equivalent to the number of normal parameters, |
| 43 | * #translate_params_size includes the size occupied by the translate parameters headers. | ||
| 41 | */ | 44 | */ |
| 42 | constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, unsigned int translate_params_size) { | 45 | constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, |
| 43 | return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | (u32(translate_params_size) & 0x3F); | 46 | unsigned int translate_params_size) { |
| 47 | return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | | ||
| 48 | (u32(translate_params_size) & 0x3F); | ||
| 44 | } | 49 | } |
| 45 | 50 | ||
| 46 | union Header { | 51 | union Header { |
| 47 | u32 raw; | 52 | u32 raw; |
| 48 | BitField< 0, 6, u32> translate_params_size; | 53 | BitField<0, 6, u32> translate_params_size; |
| 49 | BitField< 6, 6, u32> normal_params; | 54 | BitField<6, 6, u32> normal_params; |
| 50 | BitField<16, 16, u32> command_id; | 55 | BitField<16, 16, u32> command_id; |
| 51 | }; | 56 | }; |
| 52 | 57 | ||
| 53 | inline Header ParseHeader(u32 header) { | 58 | inline Header ParseHeader(u32 header) { |
| 54 | return{ header }; | 59 | return {header}; |
| 55 | } | 60 | } |
| 56 | 61 | ||
| 57 | constexpr u32 MoveHandleDesc(u32 num_handles = 1) { | 62 | constexpr u32 MoveHandleDesc(u32 num_handles = 1) { |
| @@ -80,27 +85,29 @@ constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) { | |||
| 80 | 85 | ||
| 81 | union StaticBufferDescInfo { | 86 | union StaticBufferDescInfo { |
| 82 | u32 raw; | 87 | u32 raw; |
| 83 | BitField< 10, 4, u32> buffer_id; | 88 | BitField<10, 4, u32> buffer_id; |
| 84 | BitField< 14, 18, u32> size; | 89 | BitField<14, 18, u32> size; |
| 85 | }; | 90 | }; |
| 86 | 91 | ||
| 87 | inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { | 92 | inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) { |
| 88 | return{ desc }; | 93 | return {desc}; |
| 89 | } | 94 | } |
| 90 | 95 | ||
| 91 | /** | 96 | /** |
| 92 | * @brief Creates a header describing a buffer to be sent over PXI. | 97 | * @brief Creates a header describing a buffer to be sent over PXI. |
| 93 | * @param size Size of the buffer. Max 0x00FFFFFF. | 98 | * @param size Size of the buffer. Max 0x00FFFFFF. |
| 94 | * @param buffer_id The Id of the buffer. Max 0xF. | 99 | * @param buffer_id The Id of the buffer. Max 0xF. |
| 95 | * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have read-write access. | 100 | * @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have |
| 101 | * read-write access. | ||
| 96 | * @return The created PXI buffer header. | 102 | * @return The created PXI buffer header. |
| 97 | * | 103 | * |
| 98 | * The next value is a phys-address of a table located in the BASE memregion. | 104 | * The next value is a phys-address of a table located in the BASE memregion. |
| 99 | */ | 105 | */ |
| 100 | inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { | 106 | inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) { |
| 101 | u32 type = PXIBuffer; | 107 | u32 type = PXIBuffer; |
| 102 | if (is_read_only) type |= 0x2; | 108 | if (is_read_only) |
| 103 | return type | (size << 8) | ((buffer_id & 0xF) << 4); | 109 | type |= 0x2; |
| 110 | return type | (size << 8) | ((buffer_id & 0xF) << 4); | ||
| 104 | } | 111 | } |
| 105 | 112 | ||
| 106 | enum MappedBufferPermissions { | 113 | enum MappedBufferPermissions { |
| @@ -115,12 +122,12 @@ constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) { | |||
| 115 | 122 | ||
| 116 | union MappedBufferDescInfo { | 123 | union MappedBufferDescInfo { |
| 117 | u32 raw; | 124 | u32 raw; |
| 118 | BitField< 4, 28, u32> size; | 125 | BitField<4, 28, u32> size; |
| 119 | BitField< 1, 2, MappedBufferPermissions> perms; | 126 | BitField<1, 2, MappedBufferPermissions> perms; |
| 120 | }; | 127 | }; |
| 121 | 128 | ||
| 122 | inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { | 129 | inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) { |
| 123 | return{ desc }; | 130 | return {desc}; |
| 124 | } | 131 | } |
| 125 | 132 | ||
| 126 | inline DescriptorType GetDescriptorType(u32 descriptor) { | 133 | inline DescriptorType GetDescriptorType(u32 descriptor) { |
| @@ -153,7 +160,8 @@ static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of | |||
| 153 | * @return Pointer to command buffer | 160 | * @return Pointer to command buffer |
| 154 | */ | 161 | */ |
| 155 | inline u32* GetCommandBuffer(const int offset = 0) { | 162 | inline u32* GetCommandBuffer(const int offset = 0) { |
| 156 | return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset); | 163 | return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + |
| 164 | offset); | ||
| 157 | } | 165 | } |
| 158 | 166 | ||
| 159 | /** | 167 | /** |
| @@ -183,10 +191,14 @@ public: | |||
| 183 | Session(); | 191 | Session(); |
| 184 | ~Session() override; | 192 | ~Session() override; |
| 185 | 193 | ||
| 186 | std::string GetTypeName() const override { return "Session"; } | 194 | std::string GetTypeName() const override { |
| 195 | return "Session"; | ||
| 196 | } | ||
| 187 | 197 | ||
| 188 | static const HandleType HANDLE_TYPE = HandleType::Session; | 198 | static const HandleType HANDLE_TYPE = HandleType::Session; |
| 189 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 199 | HandleType GetHandleType() const override { |
| 200 | return HANDLE_TYPE; | ||
| 201 | } | ||
| 190 | 202 | ||
| 191 | /** | 203 | /** |
| 192 | * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls | 204 | * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls |
| @@ -205,5 +217,4 @@ public: | |||
| 205 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); | 217 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); |
| 206 | } | 218 | } |
| 207 | }; | 219 | }; |
| 208 | |||
| 209 | } | 220 | } |
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 6a22c8986..74f40930c 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -6,17 +6,21 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | 8 | ||
| 9 | #include "core/memory.h" | ||
| 10 | #include "core/hle/kernel/memory.h" | 9 | #include "core/hle/kernel/memory.h" |
| 11 | #include "core/hle/kernel/shared_memory.h" | 10 | #include "core/hle/kernel/shared_memory.h" |
| 11 | #include "core/memory.h" | ||
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | 14 | ||
| 15 | SharedMemory::SharedMemory() {} | 15 | SharedMemory::SharedMemory() { |
| 16 | SharedMemory::~SharedMemory() {} | 16 | } |
| 17 | SharedMemory::~SharedMemory() { | ||
| 18 | } | ||
| 17 | 19 | ||
| 18 | SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions, | 20 | SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, |
| 19 | MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) { | 21 | MemoryPermission permissions, |
| 22 | MemoryPermission other_permissions, VAddr address, | ||
| 23 | MemoryRegion region, std::string name) { | ||
| 20 | SharedPtr<SharedMemory> shared_memory(new SharedMemory); | 24 | SharedPtr<SharedMemory> shared_memory(new SharedMemory); |
| 21 | 25 | ||
| 22 | shared_memory->owner_process = owner_process; | 26 | shared_memory->owner_process = owner_process; |
| @@ -31,7 +35,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 31 | MemoryRegionInfo* memory_region = GetMemoryRegion(region); | 35 | MemoryRegionInfo* memory_region = GetMemoryRegion(region); |
| 32 | auto& linheap_memory = memory_region->linear_heap_memory; | 36 | auto& linheap_memory = memory_region->linear_heap_memory; |
| 33 | 37 | ||
| 34 | ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, "Not enough space in region to allocate shared memory!"); | 38 | ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, |
| 39 | "Not enough space in region to allocate shared memory!"); | ||
| 35 | 40 | ||
| 36 | shared_memory->backing_block = linheap_memory; | 41 | shared_memory->backing_block = linheap_memory; |
| 37 | shared_memory->backing_block_offset = linheap_memory->size(); | 42 | shared_memory->backing_block_offset = linheap_memory->size(); |
| @@ -39,7 +44,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 39 | linheap_memory->insert(linheap_memory->end(), size, 0); | 44 | linheap_memory->insert(linheap_memory->end(), size, 0); |
| 40 | memory_region->used += size; | 45 | memory_region->used += size; |
| 41 | 46 | ||
| 42 | shared_memory->linear_heap_phys_address = Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset; | 47 | shared_memory->linear_heap_phys_address = |
| 48 | Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset; | ||
| 43 | 49 | ||
| 44 | // Increase the amount of used linear heap memory for the owner process. | 50 | // Increase the amount of used linear heap memory for the owner process. |
| 45 | if (shared_memory->owner_process != nullptr) { | 51 | if (shared_memory->owner_process != nullptr) { |
| @@ -51,18 +57,20 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 51 | Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); | 57 | Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); |
| 52 | } | 58 | } |
| 53 | } else { | 59 | } else { |
| 54 | // TODO(Subv): What happens if an application tries to create multiple memory blocks pointing to the same address? | 60 | // TODO(Subv): What happens if an application tries to create multiple memory blocks |
| 61 | // pointing to the same address? | ||
| 55 | auto& vm_manager = shared_memory->owner_process->vm_manager; | 62 | auto& vm_manager = shared_memory->owner_process->vm_manager; |
| 56 | // The memory is already available and mapped in the owner process. | 63 | // The memory is already available and mapped in the owner process. |
| 57 | auto vma = vm_manager.FindVMA(address)->second; | 64 | auto vma = vm_manager.FindVMA(address)->second; |
| 58 | // Copy it over to our own storage | 65 | // Copy it over to our own storage |
| 59 | shared_memory->backing_block = std::make_shared<std::vector<u8>>(vma.backing_block->data() + vma.offset, | 66 | shared_memory->backing_block = std::make_shared<std::vector<u8>>( |
| 60 | vma.backing_block->data() + vma.offset + size); | 67 | vma.backing_block->data() + vma.offset, vma.backing_block->data() + vma.offset + size); |
| 61 | shared_memory->backing_block_offset = 0; | 68 | shared_memory->backing_block_offset = 0; |
| 62 | // Unmap the existing pages | 69 | // Unmap the existing pages |
| 63 | vm_manager.UnmapRange(address, size); | 70 | vm_manager.UnmapRange(address, size); |
| 64 | // Map our own block into the address space | 71 | // Map our own block into the address space |
| 65 | vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared); | 72 | vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, |
| 73 | MemoryState::Shared); | ||
| 66 | // Reprotect the block with the new permissions | 74 | // Reprotect the block with the new permissions |
| 67 | vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions)); | 75 | vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions)); |
| 68 | } | 76 | } |
| @@ -71,8 +79,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u | |||
| 71 | return shared_memory; | 79 | return shared_memory; |
| 72 | } | 80 | } |
| 73 | 81 | ||
| 74 | SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size, | 82 | SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, |
| 75 | MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { | 83 | u32 offset, u32 size, |
| 84 | MemoryPermission permissions, | ||
| 85 | MemoryPermission other_permissions, | ||
| 86 | std::string name) { | ||
| 76 | SharedPtr<SharedMemory> shared_memory(new SharedMemory); | 87 | SharedPtr<SharedMemory> shared_memory(new SharedMemory); |
| 77 | 88 | ||
| 78 | shared_memory->owner_process = nullptr; | 89 | shared_memory->owner_process = nullptr; |
| @@ -88,27 +99,31 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vecto | |||
| 88 | } | 99 | } |
| 89 | 100 | ||
| 90 | ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, | 101 | ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, |
| 91 | MemoryPermission other_permissions) { | 102 | MemoryPermission other_permissions) { |
| 92 | 103 | ||
| 93 | MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions; | 104 | MemoryPermission own_other_permissions = |
| 105 | target_process == owner_process ? this->permissions : this->other_permissions; | ||
| 94 | 106 | ||
| 95 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare | 107 | // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare |
| 96 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { | 108 | if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { |
| 97 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 109 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, |
| 110 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 98 | } | 111 | } |
| 99 | 112 | ||
| 100 | // Error out if the requested permissions don't match what the creator process allows. | 113 | // Error out if the requested permissions don't match what the creator process allows. |
| 101 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { | 114 | if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) { |
| 102 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", | 115 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", |
| 103 | GetObjectId(), address, name.c_str()); | 116 | GetObjectId(), address, name.c_str()); |
| 104 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 117 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, |
| 118 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 105 | } | 119 | } |
| 106 | 120 | ||
| 107 | // Heap-backed memory blocks can not be mapped with other_permissions = DontCare | 121 | // Heap-backed memory blocks can not be mapped with other_permissions = DontCare |
| 108 | if (base_address != 0 && other_permissions == MemoryPermission::DontCare) { | 122 | if (base_address != 0 && other_permissions == MemoryPermission::DontCare) { |
| 109 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", | 123 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", |
| 110 | GetObjectId(), address, name.c_str()); | 124 | GetObjectId(), address, name.c_str()); |
| 111 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 125 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, |
| 126 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 112 | } | 127 | } |
| 113 | 128 | ||
| 114 | // Error out if the provided permissions are not compatible with what the creator process needs. | 129 | // Error out if the provided permissions are not compatible with what the creator process needs. |
| @@ -116,12 +131,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 116 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { | 131 | static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) { |
| 117 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", | 132 | LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match", |
| 118 | GetObjectId(), address, name.c_str()); | 133 | GetObjectId(), address, name.c_str()); |
| 119 | return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent); | 134 | return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, |
| 135 | ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||
| 120 | } | 136 | } |
| 121 | 137 | ||
| 122 | // TODO(Subv): Check for the Shared Device Mem flag in the creator process. | 138 | // TODO(Subv): Check for the Shared Device Mem flag in the creator process. |
| 123 | /*if (was_created_with_shared_device_mem && address != 0) { | 139 | /*if (was_created_with_shared_device_mem && address != 0) { |
| 124 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); | 140 | return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, |
| 141 | ErrorSummary::InvalidArgument, ErrorLevel::Usage); | ||
| 125 | }*/ | 142 | }*/ |
| 126 | 143 | ||
| 127 | // TODO(Subv): The same process that created a SharedMemory object | 144 | // TODO(Subv): The same process that created a SharedMemory object |
| @@ -144,23 +161,29 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi | |||
| 144 | } | 161 | } |
| 145 | 162 | ||
| 146 | // Map the memory block into the target process | 163 | // Map the memory block into the target process |
| 147 | auto result = target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | 164 | auto result = target_process->vm_manager.MapMemoryBlock( |
| 165 | target_address, backing_block, backing_block_offset, size, MemoryState::Shared); | ||
| 148 | if (result.Failed()) { | 166 | if (result.Failed()) { |
| 149 | LOG_ERROR(Kernel, "cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory", | 167 | LOG_ERROR( |
| 150 | GetObjectId(), target_address, name.c_str()); | 168 | Kernel, |
| 169 | "cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory", | ||
| 170 | GetObjectId(), target_address, name.c_str()); | ||
| 151 | return result.Code(); | 171 | return result.Code(); |
| 152 | } | 172 | } |
| 153 | 173 | ||
| 154 | return target_process->vm_manager.ReprotectRange(target_address, size, ConvertPermissions(permissions)); | 174 | return target_process->vm_manager.ReprotectRange(target_address, size, |
| 175 | ConvertPermissions(permissions)); | ||
| 155 | } | 176 | } |
| 156 | 177 | ||
| 157 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { | 178 | ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { |
| 158 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory. | 179 | // TODO(Subv): Verify what happens if the application tries to unmap an address that is not |
| 180 | // mapped to a SharedMemory. | ||
| 159 | return target_process->vm_manager.UnmapRange(address, size); | 181 | return target_process->vm_manager.UnmapRange(address, size); |
| 160 | } | 182 | } |
| 161 | 183 | ||
| 162 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { | 184 | VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { |
| 163 | u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute); | 185 | u32 masked_permissions = |
| 186 | static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute); | ||
| 164 | return static_cast<VMAPermission>(masked_permissions); | 187 | return static_cast<VMAPermission>(masked_permissions); |
| 165 | }; | 188 | }; |
| 166 | 189 | ||
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h index 0c404a9f8..afb142380 100644 --- a/src/core/hle/kernel/shared_memory.h +++ b/src/core/hle/kernel/shared_memory.h | |||
| @@ -16,15 +16,15 @@ namespace Kernel { | |||
| 16 | 16 | ||
| 17 | /// Permissions for mapped shared memory blocks | 17 | /// Permissions for mapped shared memory blocks |
| 18 | enum class MemoryPermission : u32 { | 18 | enum class MemoryPermission : u32 { |
| 19 | None = 0, | 19 | None = 0, |
| 20 | Read = (1u << 0), | 20 | Read = (1u << 0), |
| 21 | Write = (1u << 1), | 21 | Write = (1u << 1), |
| 22 | ReadWrite = (Read | Write), | 22 | ReadWrite = (Read | Write), |
| 23 | Execute = (1u << 2), | 23 | Execute = (1u << 2), |
| 24 | ReadExecute = (Read | Execute), | 24 | ReadExecute = (Read | Execute), |
| 25 | WriteExecute = (Write | Execute), | 25 | WriteExecute = (Write | Execute), |
| 26 | ReadWriteExecute = (Read | Write | Execute), | 26 | ReadWriteExecute = (Read | Write | Execute), |
| 27 | DontCare = (1u << 28) | 27 | DontCare = (1u << 28) |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | class SharedMemory final : public Object { | 30 | class SharedMemory final : public Object { |
| @@ -34,13 +34,18 @@ public: | |||
| 34 | * @param owner_process Process that created this shared memory object. | 34 | * @param owner_process Process that created this shared memory object. |
| 35 | * @param size Size of the memory block. Must be page-aligned. | 35 | * @param size Size of the memory block. Must be page-aligned. |
| 36 | * @param permissions Permission restrictions applied to the process which created the block. | 36 | * @param permissions Permission restrictions applied to the process which created the block. |
| 37 | * @param other_permissions Permission restrictions applied to other processes mapping the block. | 37 | * @param other_permissions Permission restrictions applied to other processes mapping the |
| 38 | * block. | ||
| 38 | * @param address The address from which to map the Shared Memory. | 39 | * @param address The address from which to map the Shared Memory. |
| 39 | * @param region If the address is 0, the shared memory will be allocated in this region of the linear heap. | 40 | * @param region If the address is 0, the shared memory will be allocated in this region of the |
| 41 | * linear heap. | ||
| 40 | * @param name Optional object name, used for debugging purposes. | 42 | * @param name Optional object name, used for debugging purposes. |
| 41 | */ | 43 | */ |
| 42 | static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions, | 44 | static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, |
| 43 | MemoryPermission other_permissions, VAddr address = 0, MemoryRegion region = MemoryRegion::BASE, std::string name = "Unknown"); | 45 | MemoryPermission permissions, |
| 46 | MemoryPermission other_permissions, VAddr address = 0, | ||
| 47 | MemoryRegion region = MemoryRegion::BASE, | ||
| 48 | std::string name = "Unknown"); | ||
| 44 | 49 | ||
| 45 | /** | 50 | /** |
| 46 | * Creates a shared memory object from a block of memory managed by an HLE applet. | 51 | * Creates a shared memory object from a block of memory managed by an HLE applet. |
| @@ -48,17 +53,27 @@ public: | |||
| 48 | * @param offset The offset into the heap block that the SharedMemory will map. | 53 | * @param offset The offset into the heap block that the SharedMemory will map. |
| 49 | * @param size Size of the memory block. Must be page-aligned. | 54 | * @param size Size of the memory block. Must be page-aligned. |
| 50 | * @param permissions Permission restrictions applied to the process which created the block. | 55 | * @param permissions Permission restrictions applied to the process which created the block. |
| 51 | * @param other_permissions Permission restrictions applied to other processes mapping the block. | 56 | * @param other_permissions Permission restrictions applied to other processes mapping the |
| 57 | * block. | ||
| 52 | * @param name Optional object name, used for debugging purposes. | 58 | * @param name Optional object name, used for debugging purposes. |
| 53 | */ | 59 | */ |
| 54 | static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size, | 60 | static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, |
| 55 | MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet"); | 61 | u32 offset, u32 size, |
| 56 | 62 | MemoryPermission permissions, | |
| 57 | std::string GetTypeName() const override { return "SharedMemory"; } | 63 | MemoryPermission other_permissions, |
| 58 | std::string GetName() const override { return name; } | 64 | std::string name = "Unknown Applet"); |
| 65 | |||
| 66 | std::string GetTypeName() const override { | ||
| 67 | return "SharedMemory"; | ||
| 68 | } | ||
| 69 | std::string GetName() const override { | ||
| 70 | return name; | ||
| 71 | } | ||
| 59 | 72 | ||
| 60 | static const HandleType HANDLE_TYPE = HandleType::SharedMemory; | 73 | static const HandleType HANDLE_TYPE = HandleType::SharedMemory; |
| 61 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 74 | HandleType GetHandleType() const override { |
| 75 | return HANDLE_TYPE; | ||
| 76 | } | ||
| 62 | 77 | ||
| 63 | /** | 78 | /** |
| 64 | * Converts the specified MemoryPermission into the equivalent VMAPermission. | 79 | * Converts the specified MemoryPermission into the equivalent VMAPermission. |
| @@ -73,7 +88,8 @@ public: | |||
| 73 | * @param permissions Memory block map permissions (specified by SVC field) | 88 | * @param permissions Memory block map permissions (specified by SVC field) |
| 74 | * @param other_permissions Memory block map other permissions (specified by SVC field) | 89 | * @param other_permissions Memory block map other permissions (specified by SVC field) |
| 75 | */ | 90 | */ |
| 76 | ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); | 91 | ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, |
| 92 | MemoryPermission other_permissions); | ||
| 77 | 93 | ||
| 78 | /** | 94 | /** |
| 79 | * Unmaps a shared memory block from the specified address in system memory | 95 | * Unmaps a shared memory block from the specified address in system memory |
| @@ -94,7 +110,8 @@ public: | |||
| 94 | SharedPtr<Process> owner_process; | 110 | SharedPtr<Process> owner_process; |
| 95 | /// Address of shared memory block in the owner process if specified. | 111 | /// Address of shared memory block in the owner process if specified. |
| 96 | VAddr base_address; | 112 | VAddr base_address; |
| 97 | /// Physical address of the shared memory block in the linear heap if no address was specified during creation. | 113 | /// Physical address of the shared memory block in the linear heap if no address was specified |
| 114 | /// during creation. | ||
| 98 | PAddr linear_heap_phys_address; | 115 | PAddr linear_heap_phys_address; |
| 99 | /// Backing memory for this shared memory block. | 116 | /// Backing memory for this shared memory block. |
| 100 | std::shared_ptr<std::vector<u8>> backing_block; | 117 | std::shared_ptr<std::vector<u8>> backing_block; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index f1e5cf3cb..59272715f 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -18,10 +18,10 @@ | |||
| 18 | #include "core/core_timing.h" | 18 | #include "core/core_timing.h" |
| 19 | #include "core/hle/hle.h" | 19 | #include "core/hle/hle.h" |
| 20 | #include "core/hle/kernel/kernel.h" | 20 | #include "core/hle/kernel/kernel.h" |
| 21 | #include "core/hle/kernel/process.h" | ||
| 22 | #include "core/hle/kernel/thread.h" | ||
| 23 | #include "core/hle/kernel/memory.h" | 21 | #include "core/hle/kernel/memory.h" |
| 24 | #include "core/hle/kernel/mutex.h" | 22 | #include "core/hle/kernel/mutex.h" |
| 23 | #include "core/hle/kernel/process.h" | ||
| 24 | #include "core/hle/kernel/thread.h" | ||
| 25 | #include "core/hle/result.h" | 25 | #include "core/hle/result.h" |
| 26 | #include "core/memory.h" | 26 | #include "core/memory.h" |
| 27 | 27 | ||
| @@ -46,7 +46,7 @@ static Kernel::HandleTable wakeup_callback_handle_table; | |||
| 46 | static std::vector<SharedPtr<Thread>> thread_list; | 46 | static std::vector<SharedPtr<Thread>> thread_list; |
| 47 | 47 | ||
| 48 | // Lists only ready thread ids. | 48 | // Lists only ready thread ids. |
| 49 | static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue; | 49 | static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue; |
| 50 | 50 | ||
| 51 | static Thread* current_thread; | 51 | static Thread* current_thread; |
| 52 | 52 | ||
| @@ -61,8 +61,10 @@ inline static u32 const NewThreadId() { | |||
| 61 | return next_thread_id++; | 61 | return next_thread_id++; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | Thread::Thread() {} | 64 | Thread::Thread() { |
| 65 | Thread::~Thread() {} | 65 | } |
| 66 | Thread::~Thread() { | ||
| 67 | } | ||
| 66 | 68 | ||
| 67 | Thread* GetCurrentThread() { | 69 | Thread* GetCurrentThread() { |
| 68 | return current_thread; | 70 | return current_thread; |
| @@ -103,7 +105,7 @@ void Thread::Stop() { | |||
| 103 | 105 | ||
| 104 | // Clean up thread from ready queue | 106 | // Clean up thread from ready queue |
| 105 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) | 107 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) |
| 106 | if (status == THREADSTATUS_READY){ | 108 | if (status == THREADSTATUS_READY) { |
| 107 | ready_queue.remove(current_priority, this); | 109 | ready_queue.remove(current_priority, this); |
| 108 | } | 110 | } |
| 109 | 111 | ||
| @@ -119,7 +121,8 @@ void Thread::Stop() { | |||
| 119 | 121 | ||
| 120 | // Mark the TLS slot in the thread's page as free. | 122 | // Mark the TLS slot in the thread's page as free. |
| 121 | u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; | 123 | u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; |
| 122 | u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; | 124 | u32 tls_slot = |
| 125 | ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; | ||
| 123 | Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); | 126 | Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); |
| 124 | 127 | ||
| 125 | HLE::Reschedule(__func__); | 128 | HLE::Reschedule(__func__); |
| @@ -137,7 +140,7 @@ Thread* ArbitrateHighestPriorityThread(u32 address) { | |||
| 137 | if (thread == nullptr) | 140 | if (thread == nullptr) |
| 138 | continue; | 141 | continue; |
| 139 | 142 | ||
| 140 | if(thread->current_priority <= priority) { | 143 | if (thread->current_priority <= priority) { |
| 141 | highest_priority_thread = thread.get(); | 144 | highest_priority_thread = thread.get(); |
| 142 | priority = thread->current_priority; | 145 | priority = thread->current_priority; |
| 143 | } | 146 | } |
| @@ -170,7 +173,7 @@ static void PriorityBoostStarvedThreads() { | |||
| 170 | // on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler | 173 | // on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler |
| 171 | // should probably be reversed to verify this. | 174 | // should probably be reversed to verify this. |
| 172 | 175 | ||
| 173 | const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long | 176 | const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long |
| 174 | 177 | ||
| 175 | u64 delta = current_ticks - thread->last_running_ticks; | 178 | u64 delta = current_ticks - thread->last_running_ticks; |
| 176 | 179 | ||
| @@ -193,10 +196,12 @@ static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* threa | |||
| 193 | 196 | ||
| 194 | if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { | 197 | if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) { |
| 195 | // svc #0x24 (WaitSynchronization1) | 198 | // svc #0x24 (WaitSynchronization1) |
| 196 | return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]); | 199 | return std::make_tuple(&thread->context.cpu_registers[2], |
| 200 | &thread->context.cpu_registers[3]); | ||
| 197 | } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { | 201 | } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) { |
| 198 | // svc #0x25 (WaitSynchronizationN) | 202 | // svc #0x25 (WaitSynchronizationN) |
| 199 | return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]); | 203 | return std::make_tuple(&thread->context.cpu_registers[0], |
| 204 | &thread->context.cpu_registers[4]); | ||
| 200 | } | 205 | } |
| 201 | 206 | ||
| 202 | UNREACHABLE(); | 207 | UNREACHABLE(); |
| @@ -245,7 +250,8 @@ static void SwitchContext(Thread* new_thread) { | |||
| 245 | 250 | ||
| 246 | // Load context of new thread | 251 | // Load context of new thread |
| 247 | if (new_thread) { | 252 | if (new_thread) { |
| 248 | DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); | 253 | DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, |
| 254 | "Thread must be ready to become running."); | ||
| 249 | 255 | ||
| 250 | // Cancel any outstanding wakeup events for this thread | 256 | // Cancel any outstanding wakeup events for this thread |
| 251 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); | 257 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); |
| @@ -263,7 +269,7 @@ static void SwitchContext(Thread* new_thread) { | |||
| 263 | new_thread->context.pc -= thumb_mode ? 2 : 4; | 269 | new_thread->context.pc -= thumb_mode ? 2 : 4; |
| 264 | 270 | ||
| 265 | // Get the register for timeout parameter | 271 | // Get the register for timeout parameter |
| 266 | u32* timeout_low, *timeout_high; | 272 | u32 *timeout_low, *timeout_high; |
| 267 | std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); | 273 | std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread); |
| 268 | 274 | ||
| 269 | // Update the timeout parameter | 275 | // Update the timeout parameter |
| @@ -307,7 +313,7 @@ static Thread* PopNextReadyThread() { | |||
| 307 | // Otherwise just keep going with the current thread | 313 | // Otherwise just keep going with the current thread |
| 308 | next = thread; | 314 | next = thread; |
| 309 | } | 315 | } |
| 310 | } else { | 316 | } else { |
| 311 | next = ready_queue.pop_first(); | 317 | next = ready_queue.pop_first(); |
| 312 | } | 318 | } |
| 313 | 319 | ||
| @@ -321,7 +327,8 @@ void WaitCurrentThread_Sleep() { | |||
| 321 | HLE::Reschedule(__func__); | 327 | HLE::Reschedule(__func__); |
| 322 | } | 328 | } |
| 323 | 329 | ||
| 324 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all) { | 330 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, |
| 331 | bool wait_set_output, bool wait_all) { | ||
| 325 | Thread* thread = GetCurrentThread(); | 332 | Thread* thread = GetCurrentThread(); |
| 326 | thread->wait_set_output = wait_set_output; | 333 | thread->wait_set_output = wait_set_output; |
| 327 | thread->wait_all = wait_all; | 334 | thread->wait_all = wait_all; |
| @@ -352,7 +359,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 352 | 359 | ||
| 353 | if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { | 360 | if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { |
| 354 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | 361 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, |
| 355 | ErrorSummary::StatusChanged, ErrorLevel::Info)); | 362 | ErrorSummary::StatusChanged, |
| 363 | ErrorLevel::Info)); | ||
| 356 | 364 | ||
| 357 | if (thread->wait_set_output) | 365 | if (thread->wait_set_output) |
| 358 | thread->SetWaitSynchronizationOutput(-1); | 366 | thread->SetWaitSynchronizationOutput(-1); |
| @@ -372,25 +380,25 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { | |||
| 372 | 380 | ||
| 373 | void Thread::ResumeFromWait() { | 381 | void Thread::ResumeFromWait() { |
| 374 | switch (status) { | 382 | switch (status) { |
| 375 | case THREADSTATUS_WAIT_SYNCH: | 383 | case THREADSTATUS_WAIT_SYNCH: |
| 376 | case THREADSTATUS_WAIT_ARB: | 384 | case THREADSTATUS_WAIT_ARB: |
| 377 | case THREADSTATUS_WAIT_SLEEP: | 385 | case THREADSTATUS_WAIT_SLEEP: |
| 378 | break; | 386 | break; |
| 379 | 387 | ||
| 380 | case THREADSTATUS_READY: | 388 | case THREADSTATUS_READY: |
| 381 | // If the thread is waiting on multiple wait objects, it might be awoken more than once | 389 | // If the thread is waiting on multiple wait objects, it might be awoken more than once |
| 382 | // before actually resuming. We can ignore subsequent wakeups if the thread status has | 390 | // before actually resuming. We can ignore subsequent wakeups if the thread status has |
| 383 | // already been set to THREADSTATUS_READY. | 391 | // already been set to THREADSTATUS_READY. |
| 384 | return; | 392 | return; |
| 385 | 393 | ||
| 386 | case THREADSTATUS_RUNNING: | 394 | case THREADSTATUS_RUNNING: |
| 387 | DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); | 395 | DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); |
| 388 | return; | 396 | return; |
| 389 | case THREADSTATUS_DEAD: | 397 | case THREADSTATUS_DEAD: |
| 390 | // This should never happen, as threads must complete before being stopped. | 398 | // This should never happen, as threads must complete before being stopped. |
| 391 | DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.", | 399 | DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.", |
| 392 | GetObjectId()); | 400 | GetObjectId()); |
| 393 | return; | 401 | return; |
| 394 | } | 402 | } |
| 395 | 403 | ||
| 396 | ready_queue.push_back(current_priority, this); | 404 | ready_queue.push_back(current_priority, this); |
| @@ -405,7 +413,8 @@ static void DebugThreadQueue() { | |||
| 405 | if (!thread) { | 413 | if (!thread) { |
| 406 | LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); | 414 | LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD"); |
| 407 | } else { | 415 | } else { |
| 408 | LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId()); | 416 | LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, |
| 417 | GetCurrentThread()->GetObjectId()); | ||
| 409 | } | 418 | } |
| 410 | 419 | ||
| 411 | for (auto& t : thread_list) { | 420 | for (auto& t : thread_list) { |
| @@ -448,7 +457,8 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t | |||
| 448 | * @param entry_point Address of entry point for execution | 457 | * @param entry_point Address of entry point for execution |
| 449 | * @param arg User argument for thread | 458 | * @param arg User argument for thread |
| 450 | */ | 459 | */ |
| 451 | static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) { | 460 | static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, |
| 461 | u32 arg) { | ||
| 452 | memset(&context, 0, sizeof(Core::ThreadContext)); | 462 | memset(&context, 0, sizeof(Core::ThreadContext)); |
| 453 | 463 | ||
| 454 | context.cpu_registers[0] = arg; | 464 | context.cpu_registers[0] = arg; |
| @@ -458,11 +468,11 @@ static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 | |||
| 458 | } | 468 | } |
| 459 | 469 | ||
| 460 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, | 470 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority, |
| 461 | u32 arg, s32 processor_id, VAddr stack_top) { | 471 | u32 arg, s32 processor_id, VAddr stack_top) { |
| 462 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { | 472 | if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { |
| 463 | s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | 473 | s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); |
| 464 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", | 474 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", name.c_str(), |
| 465 | name.c_str(), priority, new_priority); | 475 | priority, new_priority); |
| 466 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm | 476 | // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm |
| 467 | // validity of this | 477 | // validity of this |
| 468 | priority = new_priority; | 478 | priority = new_priority; |
| @@ -472,7 +482,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 472 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); | 482 | LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); |
| 473 | // TODO: Verify error | 483 | // TODO: Verify error |
| 474 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, | 484 | return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, |
| 475 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); | 485 | ErrorSummary::InvalidArgument, ErrorLevel::Permanent); |
| 476 | } | 486 | } |
| 477 | 487 | ||
| 478 | SharedPtr<Thread> thread(new Thread); | 488 | SharedPtr<Thread> thread(new Thread); |
| @@ -511,8 +521,10 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 511 | auto& linheap_memory = memory_region->linear_heap_memory; | 521 | auto& linheap_memory = memory_region->linear_heap_memory; |
| 512 | 522 | ||
| 513 | if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { | 523 | if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) { |
| 514 | LOG_ERROR(Kernel_SVC, "Not enough space in region to allocate a new TLS page for thread"); | 524 | LOG_ERROR(Kernel_SVC, |
| 515 | return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Permanent); | 525 | "Not enough space in region to allocate a new TLS page for thread"); |
| 526 | return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel, | ||
| 527 | ErrorSummary::OutOfResource, ErrorLevel::Permanent); | ||
| 516 | } | 528 | } |
| 517 | 529 | ||
| 518 | u32 offset = linheap_memory->size(); | 530 | u32 offset = linheap_memory->size(); |
| @@ -537,7 +549,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 537 | 549 | ||
| 538 | // Mark the slot as used | 550 | // Mark the slot as used |
| 539 | tls_slots[available_page].set(available_slot); | 551 | tls_slots[available_page].set(available_slot); |
| 540 | thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE; | 552 | thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + |
| 553 | available_slot * Memory::TLS_ENTRY_SIZE; | ||
| 541 | 554 | ||
| 542 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used | 555 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used |
| 543 | // to initialize the context | 556 | // to initialize the context |
| @@ -551,10 +564,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 551 | return MakeResult<SharedPtr<Thread>>(std::move(thread)); | 564 | return MakeResult<SharedPtr<Thread>>(std::move(thread)); |
| 552 | } | 565 | } |
| 553 | 566 | ||
| 554 | // TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be returned. | 567 | // TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be |
| 568 | // returned. | ||
| 555 | static void ClampPriority(const Thread* thread, s32* priority) { | 569 | static void ClampPriority(const Thread* thread, s32* priority) { |
| 556 | if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) { | 570 | if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) { |
| 557 | DEBUG_ASSERT_MSG(false, "Application passed an out of range priority. An error should be returned."); | 571 | DEBUG_ASSERT_MSG( |
| 572 | false, "Application passed an out of range priority. An error should be returned."); | ||
| 558 | 573 | ||
| 559 | s32 new_priority = MathUtil::Clamp<s32>(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); | 574 | s32 new_priority = MathUtil::Clamp<s32>(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); |
| 560 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", | 575 | LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", |
| @@ -586,12 +601,13 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) { | |||
| 586 | DEBUG_ASSERT(!GetCurrentThread()); | 601 | DEBUG_ASSERT(!GetCurrentThread()); |
| 587 | 602 | ||
| 588 | // Initialize new "main" thread | 603 | // Initialize new "main" thread |
| 589 | auto thread_res = Thread::Create("main", entry_point, priority, 0, | 604 | auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, |
| 590 | THREADPROCESSORID_0, Memory::HEAP_VADDR_END); | 605 | Memory::HEAP_VADDR_END); |
| 591 | 606 | ||
| 592 | SharedPtr<Thread> thread = thread_res.MoveFrom(); | 607 | SharedPtr<Thread> thread = thread_res.MoveFrom(); |
| 593 | 608 | ||
| 594 | thread->context.fpscr = FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 | 609 | thread->context.fpscr = |
| 610 | FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 | ||
| 595 | 611 | ||
| 596 | // Run new "main" thread | 612 | // Run new "main" thread |
| 597 | SwitchContext(thread.get()); | 613 | SwitchContext(thread.get()); |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index deab5d5a6..2ed5cf74e 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -17,29 +17,29 @@ | |||
| 17 | #include "core/hle/kernel/kernel.h" | 17 | #include "core/hle/kernel/kernel.h" |
| 18 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| 19 | 19 | ||
| 20 | enum ThreadPriority : s32{ | 20 | enum ThreadPriority : s32 { |
| 21 | THREADPRIO_HIGHEST = 0, ///< Highest thread priority | 21 | THREADPRIO_HIGHEST = 0, ///< Highest thread priority |
| 22 | THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps | 22 | THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps |
| 23 | THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps | 23 | THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps |
| 24 | THREADPRIO_LOWEST = 63, ///< Lowest thread priority | 24 | THREADPRIO_LOWEST = 63, ///< Lowest thread priority |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | enum ThreadProcessorId : s32 { | 27 | enum ThreadProcessorId : s32 { |
| 28 | THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader | 28 | THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader |
| 29 | THREADPROCESSORID_ALL = -1, ///< Run thread on either core | 29 | THREADPROCESSORID_ALL = -1, ///< Run thread on either core |
| 30 | THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore) | 30 | THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore) |
| 31 | THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore) | 31 | THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore) |
| 32 | THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this | 32 | THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | enum ThreadStatus { | 35 | enum ThreadStatus { |
| 36 | THREADSTATUS_RUNNING, ///< Currently running | 36 | THREADSTATUS_RUNNING, ///< Currently running |
| 37 | THREADSTATUS_READY, ///< Ready to run | 37 | THREADSTATUS_READY, ///< Ready to run |
| 38 | THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter | 38 | THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter |
| 39 | THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC | 39 | THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC |
| 40 | THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC | 40 | THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC |
| 41 | THREADSTATUS_DORMANT, ///< Created but not yet made ready | 41 | THREADSTATUS_DORMANT, ///< Created but not yet made ready |
| 42 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated | 42 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | namespace Kernel { | 45 | namespace Kernel { |
| @@ -60,13 +60,19 @@ public: | |||
| 60 | * @return A shared pointer to the newly created thread | 60 | * @return A shared pointer to the newly created thread |
| 61 | */ | 61 | */ |
| 62 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, | 62 | static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority, |
| 63 | u32 arg, s32 processor_id, VAddr stack_top); | 63 | u32 arg, s32 processor_id, VAddr stack_top); |
| 64 | 64 | ||
| 65 | std::string GetName() const override { return name; } | 65 | std::string GetName() const override { |
| 66 | std::string GetTypeName() const override { return "Thread"; } | 66 | return name; |
| 67 | } | ||
| 68 | std::string GetTypeName() const override { | ||
| 69 | return "Thread"; | ||
| 70 | } | ||
| 67 | 71 | ||
| 68 | static const HandleType HANDLE_TYPE = HandleType::Thread; | 72 | static const HandleType HANDLE_TYPE = HandleType::Thread; |
| 69 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 73 | HandleType GetHandleType() const override { |
| 74 | return HANDLE_TYPE; | ||
| 75 | } | ||
| 70 | 76 | ||
| 71 | bool ShouldWait() override; | 77 | bool ShouldWait() override; |
| 72 | void Acquire() override; | 78 | void Acquire() override; |
| @@ -75,7 +81,9 @@ public: | |||
| 75 | * Gets the thread's current priority | 81 | * Gets the thread's current priority |
| 76 | * @return The current thread's priority | 82 | * @return The current thread's priority |
| 77 | */ | 83 | */ |
| 78 | s32 GetPriority() const { return current_priority; } | 84 | s32 GetPriority() const { |
| 85 | return current_priority; | ||
| 86 | } | ||
| 79 | 87 | ||
| 80 | /** | 88 | /** |
| 81 | * Sets the thread's current priority | 89 | * Sets the thread's current priority |
| @@ -93,7 +101,9 @@ public: | |||
| 93 | * Gets the thread's thread ID | 101 | * Gets the thread's thread ID |
| 94 | * @return The thread's ID | 102 | * @return The thread's ID |
| 95 | */ | 103 | */ |
| 96 | u32 GetThreadId() const { return thread_id; } | 104 | u32 GetThreadId() const { |
| 105 | return thread_id; | ||
| 106 | } | ||
| 97 | 107 | ||
| 98 | /** | 108 | /** |
| 99 | * Resumes a thread from waiting | 109 | * Resumes a thread from waiting |
| @@ -127,7 +137,9 @@ public: | |||
| 127 | * Returns the Thread Local Storage address of the current thread | 137 | * Returns the Thread Local Storage address of the current thread |
| 128 | * @returns VAddr of the thread's TLS | 138 | * @returns VAddr of the thread's TLS |
| 129 | */ | 139 | */ |
| 130 | VAddr GetTLSAddress() const { return tls_address; } | 140 | VAddr GetTLSAddress() const { |
| 141 | return tls_address; | ||
| 142 | } | ||
| 131 | 143 | ||
| 132 | Core::ThreadContext context; | 144 | Core::ThreadContext context; |
| 133 | 145 | ||
| @@ -137,8 +149,8 @@ public: | |||
| 137 | u32 entry_point; | 149 | u32 entry_point; |
| 138 | u32 stack_top; | 150 | u32 stack_top; |
| 139 | 151 | ||
| 140 | s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application | 152 | s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application |
| 141 | s32 current_priority; ///< Current thread priority, can be temporarily changed | 153 | s32 current_priority; ///< Current thread priority, can be temporarily changed |
| 142 | 154 | ||
| 143 | u64 last_running_ticks; ///< CPU tick when thread was last running | 155 | u64 last_running_ticks; ///< CPU tick when thread was last running |
| 144 | 156 | ||
| @@ -151,11 +163,11 @@ public: | |||
| 151 | /// Mutexes currently held by this thread, which will be released when it exits. | 163 | /// Mutexes currently held by this thread, which will be released when it exits. |
| 152 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; | 164 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; |
| 153 | 165 | ||
| 154 | SharedPtr<Process> owner_process; ///< Process that owns this thread | 166 | SharedPtr<Process> owner_process; ///< Process that owns this thread |
| 155 | std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on | 167 | std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on |
| 156 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address | 168 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address |
| 157 | bool wait_all; ///< True if the thread is waiting on all objects before resuming | 169 | bool wait_all; ///< True if the thread is waiting on all objects before resuming |
| 158 | bool wait_set_output; ///< True if the output parameter should be set on thread wakeup | 170 | bool wait_set_output; ///< True if the output parameter should be set on thread wakeup |
| 159 | 171 | ||
| 160 | std::string name; | 172 | std::string name; |
| 161 | 173 | ||
| @@ -205,10 +217,12 @@ void WaitCurrentThread_Sleep(); | |||
| 205 | /** | 217 | /** |
| 206 | * Waits the current thread from a WaitSynchronization call | 218 | * Waits the current thread from a WaitSynchronization call |
| 207 | * @param wait_objects Kernel objects that we are waiting on | 219 | * @param wait_objects Kernel objects that we are waiting on |
| 208 | * @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only) | 220 | * @param wait_set_output If true, set the output parameter on thread wakeup (for |
| 221 | * WaitSynchronizationN only) | ||
| 209 | * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) | 222 | * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only) |
| 210 | */ | 223 | */ |
| 211 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all); | 224 | void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, |
| 225 | bool wait_set_output, bool wait_all); | ||
| 212 | 226 | ||
| 213 | /** | 227 | /** |
| 214 | * Waits the current thread from an ArbitrateAddress call | 228 | * Waits the current thread from an ArbitrateAddress call |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index b8daaeede..255cb1aca 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -9,8 +9,8 @@ | |||
| 9 | 9 | ||
| 10 | #include "core/core_timing.h" | 10 | #include "core/core_timing.h" |
| 11 | #include "core/hle/kernel/kernel.h" | 11 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/timer.h" | ||
| 13 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| 13 | #include "core/hle/kernel/timer.h" | ||
| 14 | 14 | ||
| 15 | namespace Kernel { | 15 | namespace Kernel { |
| 16 | 16 | ||
| @@ -20,8 +20,10 @@ static int timer_callback_event_type; | |||
| 20 | // us to simply use a pool index or similar. | 20 | // us to simply use a pool index or similar. |
| 21 | static Kernel::HandleTable timer_callback_handle_table; | 21 | static Kernel::HandleTable timer_callback_handle_table; |
| 22 | 22 | ||
| 23 | Timer::Timer() {} | 23 | Timer::Timer() { |
| 24 | Timer::~Timer() {} | 24 | } |
| 25 | Timer::~Timer() { | ||
| 26 | } | ||
| 25 | 27 | ||
| 26 | SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) { | 28 | SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) { |
| 27 | SharedPtr<Timer> timer(new Timer); | 29 | SharedPtr<Timer> timer(new Timer); |
| @@ -41,7 +43,7 @@ bool Timer::ShouldWait() { | |||
| 41 | } | 43 | } |
| 42 | 44 | ||
| 43 | void Timer::Acquire() { | 45 | void Timer::Acquire() { |
| 44 | ASSERT_MSG( !ShouldWait(), "object unavailable!"); | 46 | ASSERT_MSG(!ShouldWait(), "object unavailable!"); |
| 45 | 47 | ||
| 46 | if (reset_type == ResetType::OneShot) | 48 | if (reset_type == ResetType::OneShot) |
| 47 | signaled = false; | 49 | signaled = false; |
| @@ -55,8 +57,8 @@ void Timer::Set(s64 initial, s64 interval) { | |||
| 55 | interval_delay = interval; | 57 | interval_delay = interval; |
| 56 | 58 | ||
| 57 | u64 initial_microseconds = initial / 1000; | 59 | u64 initial_microseconds = initial / 1000; |
| 58 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), | 60 | CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type, |
| 59 | timer_callback_event_type, callback_handle); | 61 | callback_handle); |
| 60 | 62 | ||
| 61 | HLE::Reschedule(__func__); | 63 | HLE::Reschedule(__func__); |
| 62 | } | 64 | } |
| @@ -73,7 +75,8 @@ void Timer::Clear() { | |||
| 73 | 75 | ||
| 74 | /// The timer callback event, called when a timer is fired | 76 | /// The timer callback event, called when a timer is fired |
| 75 | static void TimerCallback(u64 timer_handle, int cycles_late) { | 77 | static void TimerCallback(u64 timer_handle, int cycles_late) { |
| 76 | SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle)); | 78 | SharedPtr<Timer> timer = |
| 79 | timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle)); | ||
| 77 | 80 | ||
| 78 | if (timer == nullptr) { | 81 | if (timer == nullptr) { |
| 79 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle); | 82 | LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle); |
| @@ -91,7 +94,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 91 | // Reschedule the timer with the interval delay | 94 | // Reschedule the timer with the interval delay |
| 92 | u64 interval_microseconds = timer->interval_delay / 1000; | 95 | u64 interval_microseconds = timer->interval_delay / 1000; |
| 93 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, | 96 | CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, |
| 94 | timer_callback_event_type, timer_handle); | 97 | timer_callback_event_type, timer_handle); |
| 95 | } | 98 | } |
| 96 | } | 99 | } |
| 97 | 100 | ||
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h index b1db60e8f..97cd0d63c 100644 --- a/src/core/hle/kernel/timer.h +++ b/src/core/hle/kernel/timer.h | |||
| @@ -21,19 +21,25 @@ public: | |||
| 21 | */ | 21 | */ |
| 22 | static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown"); | 22 | static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown"); |
| 23 | 23 | ||
| 24 | std::string GetTypeName() const override { return "Timer"; } | 24 | std::string GetTypeName() const override { |
| 25 | std::string GetName() const override { return name; } | 25 | return "Timer"; |
| 26 | } | ||
| 27 | std::string GetName() const override { | ||
| 28 | return name; | ||
| 29 | } | ||
| 26 | 30 | ||
| 27 | static const HandleType HANDLE_TYPE = HandleType::Timer; | 31 | static const HandleType HANDLE_TYPE = HandleType::Timer; |
| 28 | HandleType GetHandleType() const override { return HANDLE_TYPE; } | 32 | HandleType GetHandleType() const override { |
| 33 | return HANDLE_TYPE; | ||
| 34 | } | ||
| 29 | 35 | ||
| 30 | ResetType reset_type; ///< The ResetType of this timer | 36 | ResetType reset_type; ///< The ResetType of this timer |
| 31 | 37 | ||
| 32 | bool signaled; ///< Whether the timer has been signaled or not | 38 | bool signaled; ///< Whether the timer has been signaled or not |
| 33 | std::string name; ///< Name of timer (optional) | 39 | std::string name; ///< Name of timer (optional) |
| 34 | 40 | ||
| 35 | u64 initial_delay; ///< The delay until the timer fires for the first time | 41 | u64 initial_delay; ///< The delay until the timer fires for the first time |
| 36 | u64 interval_delay; ///< The delay until the timer fires after the first time | 42 | u64 interval_delay; ///< The delay until the timer fires after the first time |
| 37 | 43 | ||
| 38 | bool ShouldWait() override; | 44 | bool ShouldWait() override; |
| 39 | void Acquire() override; | 45 | void Acquire() override; |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 066146cff..4ad86cf48 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -15,8 +15,8 @@ namespace Kernel { | |||
| 15 | 15 | ||
| 16 | static const char* GetMemoryStateName(MemoryState state) { | 16 | static const char* GetMemoryStateName(MemoryState state) { |
| 17 | static const char* names[] = { | 17 | static const char* names[] = { |
| 18 | "Free", "Reserved", "IO", "Static", "Code", "Private", "Shared", "Continuous", "Aliased", | 18 | "Free", "Reserved", "IO", "Static", "Code", "Private", |
| 19 | "Alias", "AliasCode", "Locked", | 19 | "Shared", "Continuous", "Aliased", "Alias", "AliasCode", "Locked", |
| 20 | }; | 20 | }; |
| 21 | 21 | ||
| 22 | return names[(int)state]; | 22 | return names[(int)state]; |
| @@ -24,13 +24,12 @@ static const char* GetMemoryStateName(MemoryState state) { | |||
| 24 | 24 | ||
| 25 | bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { | 25 | bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { |
| 26 | ASSERT(base + size == next.base); | 26 | ASSERT(base + size == next.base); |
| 27 | if (permissions != next.permissions || | 27 | if (permissions != next.permissions || meminfo_state != next.meminfo_state || |
| 28 | meminfo_state != next.meminfo_state || | 28 | type != next.type) { |
| 29 | type != next.type) { | ||
| 30 | return false; | 29 | return false; |
| 31 | } | 30 | } |
| 32 | if (type == VMAType::AllocatedMemoryBlock && | 31 | if (type == VMAType::AllocatedMemoryBlock && |
| 33 | (backing_block != next.backing_block || offset + size != next.offset)) { | 32 | (backing_block != next.backing_block || offset + size != next.offset)) { |
| 34 | return false; | 33 | return false; |
| 35 | } | 34 | } |
| 36 | if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { | 35 | if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { |
| @@ -70,7 +69,9 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { | |||
| 70 | } | 69 | } |
| 71 | 70 | ||
| 72 | ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, | 71 | ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, |
| 73 | std::shared_ptr<std::vector<u8>> block, size_t offset, u32 size, MemoryState state) { | 72 | std::shared_ptr<std::vector<u8>> block, |
| 73 | size_t offset, u32 size, | ||
| 74 | MemoryState state) { | ||
| 74 | ASSERT(block != nullptr); | 75 | ASSERT(block != nullptr); |
| 75 | ASSERT(offset + size <= block->size()); | 76 | ASSERT(offset + size <= block->size()); |
| 76 | 77 | ||
| @@ -89,7 +90,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, | |||
| 89 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); | 90 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) { | 93 | ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size, |
| 94 | MemoryState state) { | ||
| 93 | ASSERT(memory != nullptr); | 95 | ASSERT(memory != nullptr); |
| 94 | 96 | ||
| 95 | // This is the appropriately sized VMA that will turn into our allocation. | 97 | // This is the appropriately sized VMA that will turn into our allocation. |
| @@ -106,7 +108,9 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * m | |||
| 106 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); | 108 | return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); |
| 107 | } | 109 | } |
| 108 | 110 | ||
| 109 | ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler) { | 111 | ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, |
| 112 | MemoryState state, | ||
| 113 | Memory::MMIORegionPointer mmio_handler) { | ||
| 110 | // This is the appropriately sized VMA that will turn into our allocation. | 114 | // This is the appropriately sized VMA that will turn into our allocation. |
| 111 | CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); | 115 | CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); |
| 112 | VirtualMemoryArea& final_vma = vma_handle->second; | 116 | VirtualMemoryArea& final_vma = vma_handle->second; |
| @@ -191,15 +195,16 @@ void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { | |||
| 191 | void VMManager::LogLayout(Log::Level log_level) const { | 195 | void VMManager::LogLayout(Log::Level log_level) const { |
| 192 | for (const auto& p : vma_map) { | 196 | for (const auto& p : vma_map) { |
| 193 | const VirtualMemoryArea& vma = p.second; | 197 | const VirtualMemoryArea& vma = p.second; |
| 194 | LOG_GENERIC(Log::Class::Kernel, log_level, "%08X - %08X size: %8X %c%c%c %s", | 198 | LOG_GENERIC(Log::Class::Kernel, log_level, "%08X - %08X size: %8X %c%c%c %s", vma.base, |
| 195 | vma.base, vma.base + vma.size, vma.size, | 199 | vma.base + vma.size, vma.size, |
| 196 | (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', | 200 | (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', |
| 197 | (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', | 201 | (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', |
| 198 | (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', GetMemoryStateName(vma.meminfo_state)); | 202 | (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', |
| 203 | GetMemoryStateName(vma.meminfo_state)); | ||
| 199 | } | 204 | } |
| 200 | } | 205 | } |
| 201 | 206 | ||
| 202 | VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) { | 207 | VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle& iter) { |
| 203 | // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given | 208 | // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given |
| 204 | // non-const access to its container. | 209 | // non-const access to its container. |
| 205 | return vma_map.erase(iter, iter); // Erases an empty range of elements | 210 | return vma_map.erase(iter, iter); // Erases an empty range of elements |
| @@ -337,5 +342,4 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | |||
| 337 | break; | 342 | break; |
| 338 | } | 343 | } |
| 339 | } | 344 | } |
| 340 | |||
| 341 | } | 345 | } |
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 91d40655b..fbcd9870f 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -15,13 +15,13 @@ | |||
| 15 | 15 | ||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| 17 | 17 | ||
| 18 | const ResultCode ERR_INVALID_ADDRESS{ // 0xE0E01BF5 | 18 | const ResultCode ERR_INVALID_ADDRESS{// 0xE0E01BF5 |
| 19 | ErrorDescription::InvalidAddress, ErrorModule::OS, | 19 | ErrorDescription::InvalidAddress, ErrorModule::OS, |
| 20 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; | 20 | ErrorSummary::InvalidArgument, ErrorLevel::Usage}; |
| 21 | 21 | ||
| 22 | const ResultCode ERR_INVALID_ADDRESS_STATE{ // 0xE0A01BF5 | 22 | const ResultCode ERR_INVALID_ADDRESS_STATE{// 0xE0A01BF5 |
| 23 | ErrorDescription::InvalidAddress, ErrorModule::OS, | 23 | ErrorDescription::InvalidAddress, ErrorModule::OS, |
| 24 | ErrorSummary::InvalidState, ErrorLevel::Usage}; | 24 | ErrorSummary::InvalidState, ErrorLevel::Usage}; |
| 25 | 25 | ||
| 26 | enum class VMAType : u8 { | 26 | enum class VMAType : u8 { |
| 27 | /// VMA represents an unmapped region of the address space. | 27 | /// VMA represents an unmapped region of the address space. |
| @@ -115,7 +115,8 @@ class VMManager final { | |||
| 115 | // TODO(yuriks): Make page tables switchable to support multiple VMManagers | 115 | // TODO(yuriks): Make page tables switchable to support multiple VMManagers |
| 116 | public: | 116 | public: |
| 117 | /** | 117 | /** |
| 118 | * The maximum amount of address space managed by the kernel. Addresses above this are never used. | 118 | * The maximum amount of address space managed by the kernel. Addresses above this are never |
| 119 | * used. | ||
| 119 | * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000. | 120 | * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000. |
| 120 | */ | 121 | */ |
| 121 | static const u32 MAX_ADDRESS = 0x40000000; | 122 | static const u32 MAX_ADDRESS = 0x40000000; |
| @@ -151,7 +152,7 @@ public: | |||
| 151 | * @param state MemoryState tag to attach to the VMA. | 152 | * @param state MemoryState tag to attach to the VMA. |
| 152 | */ | 153 | */ |
| 153 | ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, | 154 | ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, |
| 154 | size_t offset, u32 size, MemoryState state); | 155 | size_t offset, u32 size, MemoryState state); |
| 155 | 156 | ||
| 156 | /** | 157 | /** |
| 157 | * Maps an unmanaged host memory pointer at a given address. | 158 | * Maps an unmanaged host memory pointer at a given address. |
| @@ -172,7 +173,8 @@ public: | |||
| 172 | * @param state MemoryState tag to attach to the VMA. | 173 | * @param state MemoryState tag to attach to the VMA. |
| 173 | * @param mmio_handler The handler that will implement read and write for this MMIO region. | 174 | * @param mmio_handler The handler that will implement read and write for this MMIO region. |
| 174 | */ | 175 | */ |
| 175 | ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler); | 176 | ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, |
| 177 | Memory::MMIORegionPointer mmio_handler); | ||
| 176 | 178 | ||
| 177 | /// Unmaps a range of addresses, splitting VMAs as necessary. | 179 | /// Unmaps a range of addresses, splitting VMAs as necessary. |
| 178 | ResultCode UnmapRange(VAddr target, u32 size); | 180 | ResultCode UnmapRange(VAddr target, u32 size); |
| @@ -228,5 +230,4 @@ private: | |||
| 228 | /// Updates the pages corresponding to this VMA so they match the VMA's attributes. | 230 | /// Updates the pages corresponding to this VMA so they match the VMA's attributes. |
| 229 | void UpdatePageTableForVMA(const VirtualMemoryArea& vma); | 231 | void UpdatePageTableForVMA(const VirtualMemoryArea& vma); |
| 230 | }; | 232 | }; |
| 231 | |||
| 232 | } | 233 | } |