diff options
Diffstat (limited to 'src/core/hle')
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 72 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 8 | ||||
| -rw-r--r-- | src/core/hle/service/es/es.cpp | 230 |
3 files changed, 261 insertions, 49 deletions
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 40cea1e7c..c7af87073 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -296,12 +296,6 @@ ResultVal<VAddr> VMManager::SetHeapSize(u64 size) { } ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { - const auto end_addr = target + size; - const auto last_addr = end_addr - 1; - VAddr cur_addr = target; - - ResultCode result = RESULT_SUCCESS; - // Check how much memory we've already mapped. const auto mapped_size_result = SizeOfAllocatedVMAsInRange(target, size); if (mapped_size_result.Failed()) { @@ -324,13 +318,16 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { // Keep track of the memory regions we unmap. std::vector<std::pair<u64, u64>> mapped_regions; + ResultCode result = RESULT_SUCCESS; // Iterate, trying to map memory. { - cur_addr = target; + const auto end_addr = target + size; + const auto last_addr = end_addr - 1; + VAddr cur_addr = target; auto iter = FindVMA(target); - ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -342,7 +339,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { const auto map_size = std::min(end_addr - cur_addr, vma_end - cur_addr); if (vma.state == MemoryState::Unmapped) { const auto map_res = - MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size, 0), 0, + MapMemoryBlock(cur_addr, std::make_shared<PhysicalMemory>(map_size), 0, map_size, MemoryState::Heap, VMAPermission::ReadWrite); result = map_res.Code(); if (result.IsError()) { @@ -360,7 +357,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { // Advance to the next block. cur_addr = vma_end; iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "MapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); } } @@ -368,7 +365,7 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { if (result.IsError()) { for (const auto [unmap_address, unmap_size] : mapped_regions) { ASSERT_MSG(UnmapRange(unmap_address, unmap_size).IsSuccess(), - "MapPhysicalMemory un-map on error"); + "Failed to unmap memory range."); } return result; @@ -381,12 +378,6 @@ ResultCode VMManager::MapPhysicalMemory(VAddr target, u64 size) { } ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { - const auto end_addr = target + size; - const auto last_addr = end_addr - 1; - VAddr cur_addr = target; - - ResultCode result = RESULT_SUCCESS; - // Check how much memory is currently mapped. const auto mapped_size_result = SizeOfUnmappablePhysicalMemoryInRange(target, size); if (mapped_size_result.Failed()) { @@ -401,13 +392,16 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { // Keep track of the memory regions we unmap. std::vector<std::pair<u64, u64>> unmapped_regions; + ResultCode result = RESULT_SUCCESS; // Try to unmap regions. { - cur_addr = target; + const auto end_addr = target + size; + const auto last_addr = end_addr - 1; + VAddr cur_addr = target; auto iter = FindVMA(target); - ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -434,7 +428,7 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { // Advance to the next block. cur_addr = vma_end; iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "UnmapPhysicalMemory iter != end"); + ASSERT(iter != vma_map.end()); } } @@ -443,10 +437,12 @@ ResultCode VMManager::UnmapPhysicalMemory(VAddr target, u64 size) { if (result.IsError()) { for (const auto [map_address, map_size] : unmapped_regions) { const auto remap_res = - MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size, 0), 0, - map_size, MemoryState::Heap, VMAPermission::None); - ASSERT_MSG(remap_res.Succeeded(), "UnmapPhysicalMemory re-map on error"); + MapMemoryBlock(map_address, std::make_shared<PhysicalMemory>(map_size), 0, map_size, + MemoryState::Heap, VMAPermission::None); + ASSERT_MSG(remap_res.Succeeded(), "Failed to remap a memory block."); } + + return result; } // Update mapped amount @@ -757,20 +753,26 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre // Always merge allocated memory blocks, even when they don't share the same backing block. if (left.type == VMAType::AllocatedMemoryBlock && (left.backing_block != right.backing_block || left.offset + left.size != right.offset)) { + const auto right_begin = right.backing_block->begin() + right.offset; + const auto right_end = right_begin + right.size; + // Check if we can save work. if (left.offset == 0 && left.size == left.backing_block->size()) { // Fast case: left is an entire backing block. - left.backing_block->insert(left.backing_block->end(), - right.backing_block->begin() + right.offset, - right.backing_block->begin() + right.offset + right.size); + left.backing_block->insert(left.backing_block->end(), right_begin, right_end); } else { // Slow case: make a new memory block for left and right. + const auto left_begin = left.backing_block->begin() + left.offset; + const auto left_end = left_begin + left.size; + const auto left_size = static_cast<std::size_t>(std::distance(left_begin, left_end)); + const auto right_size = static_cast<std::size_t>(std::distance(right_begin, right_end)); + auto new_memory = std::make_shared<PhysicalMemory>(); - new_memory->insert(new_memory->end(), left.backing_block->begin() + left.offset, - left.backing_block->begin() + left.offset + left.size); - new_memory->insert(new_memory->end(), right.backing_block->begin() + right.offset, - right.backing_block->begin() + right.offset + right.size); - left.backing_block = new_memory; + new_memory->reserve(left_size + right_size); + new_memory->insert(new_memory->end(), left_begin, left_end); + new_memory->insert(new_memory->end(), right_begin, right_end); + + left.backing_block = std::move(new_memory); left.offset = 0; } @@ -965,7 +967,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address, VAddr cur_addr = address; auto iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -986,7 +988,7 @@ ResultVal<std::size_t> VMManager::SizeOfAllocatedVMAsInRange(VAddr address, // Advance to the next block. cur_addr = vma_end; iter = std::next(iter); - ASSERT_MSG(iter != vma_map.end(), "SizeOfAllocatedVMAsInRange iter != end"); + ASSERT(iter != vma_map.end()); } return MakeResult(mapped_size); @@ -1000,7 +1002,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad VAddr cur_addr = address; auto iter = FindVMA(cur_addr); - ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); + ASSERT(iter != vma_map.end()); while (true) { const auto& vma = iter->second; @@ -1029,7 +1031,7 @@ ResultVal<std::size_t> VMManager::SizeOfUnmappablePhysicalMemoryInRange(VAddr ad // Advance to the next block. cur_addr = vma_end; iter = std::next(iter); - ASSERT_MSG(iter != vma_map.end(), "SizeOfUnmappablePhysicalMemoryInRange iter != end"); + ASSERT(iter != vma_map.end()); } return MakeResult(mapped_size); diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index b18cde619..850a7ebc3 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -454,8 +454,8 @@ public: /// Maps memory at a given address. /// - /// @param addr The virtual address to map memory at. - /// @param size The amount of memory to map. + /// @param target The virtual address to map memory at. + /// @param size The amount of memory to map. /// /// @note The destination address must lie within the Map region. /// @@ -468,8 +468,8 @@ public: /// Unmaps memory at a given address. /// - /// @param addr The virtual address to unmap memory at. - /// @param size The amount of memory to unmap. + /// @param target The virtual address to unmap memory at. + /// @param size The amount of memory to unmap. /// /// @note The destination address must lie within the Map region. /// diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index 6701cb913..af70d174d 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -2,32 +2,37 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/crypto/key_manager.h" +#include "core/hle/ipc_helpers.h" #include "core/hle/service/service.h" namespace Service::ES { +constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::ETicket, 2}; +constexpr ResultCode ERROR_INVALID_RIGHTS_ID{ErrorModule::ETicket, 3}; + class ETicket final : public ServiceFramework<ETicket> { public: explicit ETicket() : ServiceFramework{"es"} { // clang-format off static const FunctionInfo functions[] = { - {1, nullptr, "ImportTicket"}, + {1, &ETicket::ImportTicket, "ImportTicket"}, {2, nullptr, "ImportTicketCertificateSet"}, {3, nullptr, "DeleteTicket"}, {4, nullptr, "DeletePersonalizedTicket"}, {5, nullptr, "DeleteAllCommonTicket"}, {6, nullptr, "DeleteAllPersonalizedTicket"}, {7, nullptr, "DeleteAllPersonalizedTicketEx"}, - {8, nullptr, "GetTitleKey"}, - {9, nullptr, "CountCommonTicket"}, - {10, nullptr, "CountPersonalizedTicket"}, - {11, nullptr, "ListCommonTicket"}, - {12, nullptr, "ListPersonalizedTicket"}, + {8, &ETicket::GetTitleKey, "GetTitleKey"}, + {9, &ETicket::CountCommonTicket, "CountCommonTicket"}, + {10, &ETicket::CountPersonalizedTicket, "CountPersonalizedTicket"}, + {11, &ETicket::ListCommonTicket, "ListCommonTicket"}, + {12, &ETicket::ListPersonalizedTicket, "ListPersonalizedTicket"}, {13, nullptr, "ListMissingPersonalizedTicket"}, - {14, nullptr, "GetCommonTicketSize"}, - {15, nullptr, "GetPersonalizedTicketSize"}, - {16, nullptr, "GetCommonTicketData"}, - {17, nullptr, "GetPersonalizedTicketData"}, + {14, &ETicket::GetCommonTicketSize, "GetCommonTicketSize"}, + {15, &ETicket::GetPersonalizedTicketSize, "GetPersonalizedTicketSize"}, + {16, &ETicket::GetCommonTicketData, "GetCommonTicketData"}, + {17, &ETicket::GetPersonalizedTicketData, "GetPersonalizedTicketData"}, {18, nullptr, "OwnTicket"}, {19, nullptr, "GetTicketInfo"}, {20, nullptr, "ListLightTicketInfo"}, @@ -51,7 +56,212 @@ public: }; // clang-format on RegisterHandlers(functions); + + keys.PopulateTickets(); + keys.SynthesizeTickets(); + } + +private: + bool CheckRightsId(Kernel::HLERequestContext& ctx, const u128& rights_id) { + if (rights_id == u128{}) { + LOG_ERROR(Service_ETicket, "The rights ID was invalid!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_RIGHTS_ID); + return false; + } + + return true; + } + + void ImportTicket(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto ticket = ctx.ReadBuffer(); + const auto cert = ctx.ReadBuffer(1); + + if (ticket.size() < sizeof(Core::Crypto::Ticket)) { + LOG_ERROR(Service_ETicket, "The input buffer is not large enough!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + Core::Crypto::Ticket raw{}; + std::memcpy(&raw, ticket.data(), sizeof(Core::Crypto::Ticket)); + + if (!keys.AddTicketPersonalized(raw)) { + LOG_ERROR(Service_ETicket, "The ticket could not be imported!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_ARGUMENT); + return; + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void GetTitleKey(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto key = + keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); + + if (key == Core::Crypto::Key128{}) { + LOG_ERROR(Service_ETicket, + "The titlekey doesn't exist in the KeyManager or the rights ID was invalid!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ERROR_INVALID_RIGHTS_ID); + return; + } + + ctx.WriteBuffer(key.data(), key.size()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void CountCommonTicket(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ETicket, "called"); + + const auto count = keys.GetCommonTickets().size(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(count); + } + + void CountPersonalizedTicket(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_ETicket, "called"); + + const auto count = keys.GetPersonalizedTickets().size(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(count); + } + + void ListCommonTicket(Kernel::HLERequestContext& ctx) { + u32 out_entries; + if (keys.GetCommonTickets().empty()) + out_entries = 0; + else + out_entries = ctx.GetWriteBufferSize() / sizeof(u128); + + LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); + + keys.PopulateTickets(); + const auto tickets = keys.GetCommonTickets(); + std::vector<u128> ids; + std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), + [](const auto& pair) { return pair.first; }); + + out_entries = std::min<u32>(ids.size(), out_entries); + ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(out_entries); } + + void ListPersonalizedTicket(Kernel::HLERequestContext& ctx) { + u32 out_entries; + if (keys.GetPersonalizedTickets().empty()) + out_entries = 0; + else + out_entries = ctx.GetWriteBufferSize() / sizeof(u128); + + LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); + + keys.PopulateTickets(); + const auto tickets = keys.GetPersonalizedTickets(); + std::vector<u128> ids; + std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), + [](const auto& pair) { return pair.first; }); + + out_entries = std::min<u32>(ids.size(), out_entries); + ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(out_entries); + } + + void GetCommonTicketSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetCommonTickets().at(rights_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(ticket.GetSize()); + } + + void GetPersonalizedTicketSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetPersonalizedTickets().at(rights_id); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(ticket.GetSize()); + } + + void GetCommonTicketData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetCommonTickets().at(rights_id); + + const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize()); + ctx.WriteBuffer(&ticket, write_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(write_size); + } + + void GetPersonalizedTicketData(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto rights_id = rp.PopRaw<u128>(); + + LOG_DEBUG(Service_ETicket, "called, rights_id={:016X}{:016X}", rights_id[1], rights_id[0]); + + if (!CheckRightsId(ctx, rights_id)) + return; + + const auto ticket = keys.GetPersonalizedTickets().at(rights_id); + + const auto write_size = std::min<u64>(ticket.GetSize(), ctx.GetWriteBufferSize()); + ctx.WriteBuffer(&ticket, write_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push<u64>(write_size); + } + + Core::Crypto::KeyManager keys; }; void InstallInterfaces(SM::ServiceManager& service_manager) { |
