mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #3077 from Subv/hle_static_buffer
Kernel/IPC: Implement StaticBuffer translation for HLE services that use the HLERequestContext architecture.
This commit is contained in:
		
						commit
						555c8ba7c1
					
				
					 11 changed files with 182 additions and 45 deletions
				
			
		|  | @ -40,13 +40,16 @@ static const int kStaticBuffersOffset = 0x100; | |||
| inline u32* GetStaticBuffers(const int offset = 0) { | ||||
|     return GetCommandBuffer(kStaticBuffersOffset + offset); | ||||
| } | ||||
| } | ||||
| } // namespace Kernel
 | ||||
| 
 | ||||
| namespace IPC { | ||||
| 
 | ||||
| /// Size of the command buffer area, in 32-bit words.
 | ||||
| constexpr size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32); | ||||
| 
 | ||||
| // Maximum number of static buffers per thread.
 | ||||
| constexpr size_t MAX_STATIC_BUFFERS = 16; | ||||
| 
 | ||||
| // These errors are commonly returned by invalid IPC translations, so alias them here for
 | ||||
| // convenience.
 | ||||
| // TODO(yuriks): These will probably go away once translation is implemented inside the kernel.
 | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| #include "core/hle/ipc.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/hle_ipc.h" | ||||
|  | @ -117,7 +118,8 @@ public: | |||
| 
 | ||||
|     void PushCurrentPIDHandle(); | ||||
| 
 | ||||
|     void PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 buffer_id); | ||||
|     [[deprecated]] void PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 buffer_id); | ||||
|     void PushStaticBuffer(const std::vector<u8>& buffer, u8 buffer_id); | ||||
| 
 | ||||
|     void PushMappedBuffer(VAddr buffer_vaddr, size_t size, MappedBufferPermissions perms); | ||||
| }; | ||||
|  | @ -195,6 +197,16 @@ inline void RequestBuilder::PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 | |||
|     Push(buffer_vaddr); | ||||
| } | ||||
| 
 | ||||
| inline void RequestBuilder::PushStaticBuffer(const std::vector<u8>& buffer, u8 buffer_id) { | ||||
|     ASSERT_MSG(buffer_id < MAX_STATIC_BUFFERS, "Invalid static buffer id"); | ||||
| 
 | ||||
|     Push(StaticBufferDesc(buffer.size(), buffer_id)); | ||||
|     // This address will be replaced by the correct static buffer address during IPC translation.
 | ||||
|     Push<VAddr>(0xDEADC0DE); | ||||
| 
 | ||||
|     context->AddStaticBuffer(buffer_id, buffer); | ||||
| } | ||||
| 
 | ||||
| inline void RequestBuilder::PushMappedBuffer(VAddr buffer_vaddr, size_t size, | ||||
|                                              MappedBufferPermissions perms) { | ||||
|     Push(MappedBufferDesc(size, perms)); | ||||
|  | @ -295,17 +307,23 @@ public: | |||
|      * @brief Pops the static buffer vaddr | ||||
|      * @return                  The virtual address of the buffer | ||||
|      * @param[out] data_size    If non-null, the pointed value will be set to the size of the data | ||||
|      * @param[out] useStaticBuffersToGetVaddr Indicates if we should read the vaddr from the static | ||||
|      * buffers (which is the correct thing to do, but no service presently implement it) instead of | ||||
|      * using the same value as the process who sent the request | ||||
|      * given by the source process | ||||
|      * | ||||
|      * Static buffers must be set up before any IPC request using those is sent. | ||||
|      * In real services, static buffers must be set up before any IPC request using those is sent. | ||||
|      * It is the duty of the process (usually services) to allocate and set up the receiving static | ||||
|      * buffer information | ||||
|      * buffer information. Our HLE services do not need to set up the buffers beforehand. | ||||
|      * Please note that the setup uses virtual addresses. | ||||
|      */ | ||||
|     VAddr PopStaticBuffer(size_t* data_size = nullptr, bool useStaticBuffersToGetVaddr = false); | ||||
|     [[deprecated]] VAddr PopStaticBuffer(size_t* data_size); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Pops a static buffer from the IPC request buffer. | ||||
|      * @return The buffer that was copied from the IPC request originator. | ||||
|      * | ||||
|      * In real services, static buffers must be set up before any IPC request using those is sent. | ||||
|      * It is the duty of the process (usually services) to allocate and set up the receiving static | ||||
|      * buffer information. Our HLE services do not need to set up the buffers beforehand. | ||||
|      */ | ||||
|     const std::vector<u8>& PopStaticBuffer(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Pops the mapped buffer vaddr | ||||
|  | @ -451,21 +469,21 @@ inline std::tuple<Kernel::SharedPtr<T>...> RequestParser::PopObjects() { | |||
|                                           std::index_sequence_for<T...>{}); | ||||
| } | ||||
| 
 | ||||
| inline VAddr RequestParser::PopStaticBuffer(size_t* data_size, bool useStaticBuffersToGetVaddr) { | ||||
| inline VAddr RequestParser::PopStaticBuffer(size_t* data_size) { | ||||
|     const u32 sbuffer_descriptor = Pop<u32>(); | ||||
|     StaticBufferDescInfo bufferInfo{sbuffer_descriptor}; | ||||
|     if (data_size != nullptr) | ||||
|         *data_size = bufferInfo.size; | ||||
|     if (!useStaticBuffersToGetVaddr) | ||||
|     return Pop<VAddr>(); | ||||
|     else { | ||||
|         ASSERT_MSG(0, "remove the assert if multiprocess/IPC translation are implemented."); | ||||
|         // The buffer has already been copied to the static buffer by the kernel during
 | ||||
|         // translation
 | ||||
|         Pop<VAddr>(); // Pop the calling process buffer address
 | ||||
|                       // and get the vaddr from the static buffers
 | ||||
|         return cmdbuf[(0x100 >> 2) + bufferInfo.buffer_id * 2 + 1]; | ||||
| } | ||||
| 
 | ||||
| inline const std::vector<u8>& RequestParser::PopStaticBuffer() { | ||||
|     const u32 sbuffer_descriptor = Pop<u32>(); | ||||
|     // Pop the address from the incoming request buffer
 | ||||
|     Pop<VAddr>(); | ||||
| 
 | ||||
|     StaticBufferDescInfo buffer_info{sbuffer_descriptor}; | ||||
|     return context->GetStaticBuffer(buffer_info.buffer_id); | ||||
| } | ||||
| 
 | ||||
| inline VAddr RequestParser::PopMappedBuffer(size_t* data_size, | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <boost/range/algorithm_ext/erase.hpp> | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
|  | @ -44,6 +45,16 @@ void HLERequestContext::ClearIncomingObjects() { | |||
|     request_handles.clear(); | ||||
| } | ||||
| 
 | ||||
| const std::vector<u8>& HLERequestContext::GetStaticBuffer(u8 buffer_id) const { | ||||
|     ASSERT_MSG(!static_buffers[buffer_id].empty(), "Empty static buffer!"); | ||||
|     return static_buffers[buffer_id]; | ||||
| } | ||||
| 
 | ||||
| void HLERequestContext::AddStaticBuffer(u8 buffer_id, std::vector<u8> data) { | ||||
|     ASSERT(static_buffers[buffer_id].empty() && !data.empty()); | ||||
|     static_buffers[buffer_id] = std::move(data); | ||||
| } | ||||
| 
 | ||||
| ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, | ||||
|                                                                 Process& src_process, | ||||
|                                                                 HandleTable& src_table) { | ||||
|  | @ -84,6 +95,18 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr | |||
|             cmd_buf[i++] = src_process.process_id; | ||||
|             break; | ||||
|         } | ||||
|         case IPC::DescriptorType::StaticBuffer: { | ||||
|             VAddr source_address = src_cmdbuf[i]; | ||||
|             IPC::StaticBufferDescInfo buffer_info{descriptor}; | ||||
| 
 | ||||
|             // Copy the input buffer into our own vector and store it.
 | ||||
|             std::vector<u8> data(buffer_info.size); | ||||
|             Memory::ReadBlock(src_process, source_address, data.data(), data.size()); | ||||
| 
 | ||||
|             AddStaticBuffer(buffer_info.buffer_id, std::move(data)); | ||||
|             cmd_buf[i++] = source_address; | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||||
|         } | ||||
|  | @ -124,6 +147,25 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P | |||
|             } | ||||
|             break; | ||||
|         } | ||||
|         case IPC::DescriptorType::StaticBuffer: { | ||||
|             IPC::StaticBufferDescInfo buffer_info{descriptor}; | ||||
| 
 | ||||
|             const auto& data = GetStaticBuffer(buffer_info.buffer_id); | ||||
| 
 | ||||
|             // Grab the address that the target thread set up to receive the response static buffer
 | ||||
|             // and write our data there. The static buffers area is located right after the command
 | ||||
|             // buffer area.
 | ||||
|             size_t static_buffer_offset = IPC::COMMAND_BUFFER_LENGTH + 2 * buffer_info.buffer_id; | ||||
|             IPC::StaticBufferDescInfo target_descriptor{dst_cmdbuf[static_buffer_offset]}; | ||||
|             VAddr target_address = dst_cmdbuf[static_buffer_offset + 1]; | ||||
| 
 | ||||
|             ASSERT_MSG(target_descriptor.size >= data.size(), "Static buffer data is too big"); | ||||
| 
 | ||||
|             Memory::WriteBlock(dst_process, target_address, data.data(), data.size()); | ||||
| 
 | ||||
|             dst_cmdbuf[i++] = target_address; | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); | ||||
|         } | ||||
|  |  | |||
|  | @ -119,6 +119,18 @@ public: | |||
|      */ | ||||
|     void ClearIncomingObjects(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Retrieves the static buffer identified by the input buffer_id. The static buffer *must* have | ||||
|      * been created in PopulateFromIncomingCommandBuffer by way of an input StaticBuffer descriptor. | ||||
|      */ | ||||
|     const std::vector<u8>& GetStaticBuffer(u8 buffer_id) const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Sets up a static buffer that will be copied to the target process when the request is | ||||
|      * translated. | ||||
|      */ | ||||
|     void AddStaticBuffer(u8 buffer_id, std::vector<u8> data); | ||||
| 
 | ||||
|     /// Populates this context with data from the requesting process/thread.
 | ||||
|     ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, | ||||
|                                                  HandleTable& src_table); | ||||
|  | @ -131,6 +143,8 @@ private: | |||
|     SharedPtr<ServerSession> session; | ||||
|     // TODO(yuriks): Check common usage of this and optimize size accordingly
 | ||||
|     boost::container::small_vector<SharedPtr<Object>, 8> request_handles; | ||||
|     // The static buffers will be created when the IPC request is translated.
 | ||||
|     std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <vector> | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/ipc.h" | ||||
|  | @ -19,17 +20,12 @@ namespace AC { | |||
| void Module::Interface::CreateDefaultConfig(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx, 0x1, 0, 0); | ||||
| 
 | ||||
|     std::size_t desc_size; | ||||
|     VAddr ac_config_addr = rp.PeekStaticBuffer(0, &desc_size); | ||||
| 
 | ||||
|     ASSERT_MSG(desc_size >= sizeof(Module::ACConfig), | ||||
|                "Output buffer size can't fit ACConfig structure"); | ||||
| 
 | ||||
|     Memory::WriteBlock(ac_config_addr, &ac->default_config, sizeof(ACConfig)); | ||||
|     std::vector<u8> buffer(sizeof(ACConfig)); | ||||
|     std::memcpy(buffer.data(), &ac->default_config, buffer.size()); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.PushStaticBuffer(ac_config_addr, sizeof(ACConfig), 0); | ||||
|     rb.PushStaticBuffer(std::move(buffer), 0); | ||||
| 
 | ||||
|     LOG_WARNING(Service_AC, "(STUBBED) called"); | ||||
| } | ||||
|  | @ -106,7 +102,7 @@ void Module::Interface::GetWifiStatus(Kernel::HLERequestContext& ctx) { | |||
| 
 | ||||
| void Module::Interface::GetInfraPriority(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp(ctx, 0x27, 0, 2); | ||||
|     VAddr ac_config = rp.PopStaticBuffer(); | ||||
|     const std::vector<u8>& ac_config = rp.PopStaticBuffer(); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|  | @ -121,13 +117,13 @@ void Module::Interface::SetRequestEulaVersion(Kernel::HLERequestContext& ctx) { | |||
|     u32 major = rp.Pop<u8>(); | ||||
|     u32 minor = rp.Pop<u8>(); | ||||
| 
 | ||||
|     VAddr ac_config = rp.PopStaticBuffer(); | ||||
|     const std::vector<u8>& ac_config = rp.PopStaticBuffer(); | ||||
| 
 | ||||
|     // TODO(Subv): Copy over the input ACConfig to the stored ACConfig.
 | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||
|     rb.Push(RESULT_SUCCESS); | ||||
|     rb.PushStaticBuffer(ac_config, sizeof(ACConfig), 0); | ||||
|     rb.PushStaticBuffer(std::move(ac_config), 0); | ||||
| 
 | ||||
|     LOG_WARNING(Service_AC, "(STUBBED) called, major=%u, minor=%u", major, minor); | ||||
| } | ||||
|  |  | |||
|  | @ -720,7 +720,7 @@ void AppletUtility(Service::Interface* self) { | |||
|     u32 utility_command = rp.Pop<u32>(); | ||||
|     u32 input_size = rp.Pop<u32>(); | ||||
|     u32 output_size = rp.Pop<u32>(); | ||||
|     VAddr input_addr = rp.PopStaticBuffer(); | ||||
|     VAddr input_addr = rp.PopStaticBuffer(nullptr); | ||||
| 
 | ||||
|     VAddr output_addr = rp.PeekStaticBuffer(0); | ||||
| 
 | ||||
|  | @ -823,7 +823,7 @@ void StartLibraryApplet(Service::Interface* self) { | |||
| 
 | ||||
|     size_t buffer_size = rp.Pop<u32>(); | ||||
|     Kernel::Handle handle = rp.PopHandle(); | ||||
|     VAddr buffer_addr = rp.PopStaticBuffer(); | ||||
|     VAddr buffer_addr = rp.PopStaticBuffer(nullptr); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_APT, "called applet_id=%08X", static_cast<u32>(applet_id)); | ||||
| 
 | ||||
|  |  | |||
|  | @ -113,7 +113,7 @@ void UnscrambleLocalFriendCode(Service::Interface* self) { | |||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1C, 1, 2); | ||||
|     const u32 friend_code_count = rp.Pop<u32>(); | ||||
|     size_t in_buffer_size; | ||||
|     const VAddr scrambled_friend_codes = rp.PopStaticBuffer(&in_buffer_size, false); | ||||
|     const VAddr scrambled_friend_codes = rp.PopStaticBuffer(&in_buffer_size); | ||||
|     ASSERT_MSG(in_buffer_size == (friend_code_count * scrambled_friend_code_size), | ||||
|                "Wrong input buffer size"); | ||||
| 
 | ||||
|  |  | |||
|  | @ -72,7 +72,7 @@ static void OpenFile(Service::Interface* self) { | |||
|     FileSys::Mode mode; | ||||
|     mode.hex = rp.Pop<u32>(); | ||||
|     u32 attributes = rp.Pop<u32>(); // TODO(Link Mauve): do something with those attributes.
 | ||||
|     VAddr filename_ptr = rp.PopStaticBuffer(); | ||||
|     VAddr filename_ptr = rp.PopStaticBuffer(nullptr); | ||||
|     FileSys::Path file_path(filename_type, filename_size, filename_ptr); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex, | ||||
|  |  | |||
|  | @ -433,7 +433,7 @@ static void FinalizeIrNop(Interface* self) { | |||
| static void SendIrNop(Interface* self) { | ||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0D, 1, 2); | ||||
|     const u32 size = rp.Pop<u32>(); | ||||
|     const VAddr address = rp.PopStaticBuffer(); | ||||
|     const VAddr address = rp.PopStaticBuffer(nullptr); | ||||
| 
 | ||||
|     std::vector<u8> buffer(size); | ||||
|     Memory::ReadBlock(address, buffer.data(), size); | ||||
|  |  | |||
|  | @ -771,9 +771,9 @@ static void BeginHostingNetwork(Interface* self) { | |||
|     const u32 passphrase_size = rp.Pop<u32>(); | ||||
| 
 | ||||
|     size_t desc_size; | ||||
|     const VAddr network_info_address = rp.PopStaticBuffer(&desc_size, false); | ||||
|     const VAddr network_info_address = rp.PopStaticBuffer(&desc_size); | ||||
|     ASSERT(desc_size == sizeof(NetworkInfo)); | ||||
|     const VAddr passphrase_address = rp.PopStaticBuffer(&desc_size, false); | ||||
|     const VAddr passphrase_address = rp.PopStaticBuffer(&desc_size); | ||||
|     ASSERT(desc_size == passphrase_size); | ||||
| 
 | ||||
|     // TODO(Subv): Store the passphrase and verify it when attempting a connection.
 | ||||
|  | @ -907,7 +907,7 @@ static void SendTo(Interface* self) { | |||
|     u32 flags = rp.Pop<u32>(); | ||||
| 
 | ||||
|     size_t desc_size; | ||||
|     const VAddr input_address = rp.PopStaticBuffer(&desc_size, false); | ||||
|     const VAddr input_address = rp.PopStaticBuffer(&desc_size); | ||||
|     ASSERT(desc_size >= data_size); | ||||
| 
 | ||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||
|  | @ -1093,7 +1093,7 @@ static void SetApplicationData(Interface* self) { | |||
|     u32 size = rp.Pop<u32>(); | ||||
| 
 | ||||
|     size_t desc_size; | ||||
|     const VAddr address = rp.PopStaticBuffer(&desc_size, false); | ||||
|     const VAddr address = rp.PopStaticBuffer(&desc_size); | ||||
|     ASSERT(desc_size == size); | ||||
| 
 | ||||
|     LOG_DEBUG(Service_NWM, "called"); | ||||
|  |  | |||
|  | @ -116,25 +116,58 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel | |||
|         REQUIRE(context.CommandBuffer()[2] == process->process_id); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("translates StaticBuffer descriptors") { | ||||
|         auto buffer = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE); | ||||
|         std::fill(buffer->begin(), buffer->end(), 0xAB); | ||||
| 
 | ||||
|         VAddr target_address = 0x10000000; | ||||
|         auto result = process->vm_manager.MapMemoryBlock(target_address, buffer, 0, buffer->size(), | ||||
|                                                          MemoryState::Private); | ||||
|         REQUIRE(result.Code() == RESULT_SUCCESS); | ||||
| 
 | ||||
|         const u32_le input[]{ | ||||
|             IPC::MakeHeader(0, 0, 2), IPC::StaticBufferDesc(buffer->size(), 0), target_address, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); | ||||
| 
 | ||||
|         CHECK(context.GetStaticBuffer(0) == *buffer); | ||||
| 
 | ||||
|         REQUIRE(process->vm_manager.UnmapRange(target_address, buffer->size()) == RESULT_SUCCESS); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("translates mixed params") { | ||||
|         auto buffer = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE); | ||||
|         std::fill(buffer->begin(), buffer->end(), 0xCE); | ||||
| 
 | ||||
|         VAddr target_address = 0x10000000; | ||||
|         auto result = process->vm_manager.MapMemoryBlock(target_address, buffer, 0, buffer->size(), | ||||
|                                                          MemoryState::Private); | ||||
|         REQUIRE(result.Code() == RESULT_SUCCESS); | ||||
| 
 | ||||
|         auto a = MakeObject(); | ||||
|         const u32_le input[]{ | ||||
|             IPC::MakeHeader(0, 2, 4), | ||||
|             IPC::MakeHeader(0, 2, 6), | ||||
|             0x12345678, | ||||
|             0xABCDEF00, | ||||
|             IPC::MoveHandleDesc(1), | ||||
|             handle_table.Create(a).Unwrap(), | ||||
|             IPC::CallingPidDesc(), | ||||
|             0, | ||||
|             IPC::StaticBufferDesc(buffer->size(), 0), | ||||
|             target_address, | ||||
|         }; | ||||
| 
 | ||||
|         context.PopulateFromIncomingCommandBuffer(input, *process, handle_table); | ||||
| 
 | ||||
|         auto* output = context.CommandBuffer(); | ||||
|         REQUIRE(output[1] == 0x12345678); | ||||
|         REQUIRE(output[2] == 0xABCDEF00); | ||||
|         REQUIRE(context.GetIncomingHandle(output[4]) == a); | ||||
|         REQUIRE(output[6] == process->process_id); | ||||
|         CHECK(output[1] == 0x12345678); | ||||
|         CHECK(output[2] == 0xABCDEF00); | ||||
|         CHECK(context.GetIncomingHandle(output[4]) == a); | ||||
|         CHECK(output[6] == process->process_id); | ||||
|         CHECK(context.GetStaticBuffer(0) == *buffer); | ||||
| 
 | ||||
|         REQUIRE(process->vm_manager.UnmapRange(target_address, buffer->size()) == RESULT_SUCCESS); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -211,6 +244,37 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") { | |||
|         REQUIRE(handle_table.GetGeneric(output[3]) == b); | ||||
|         REQUIRE(handle_table.GetGeneric(output[5]) == c); | ||||
|     } | ||||
| 
 | ||||
|     SECTION("translates StaticBuffer descriptors") { | ||||
|         std::vector<u8> input_buffer(Memory::PAGE_SIZE); | ||||
|         std::fill(input_buffer.begin(), input_buffer.end(), 0xAB); | ||||
| 
 | ||||
|         context.AddStaticBuffer(0, input_buffer); | ||||
| 
 | ||||
|         auto output_buffer = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE); | ||||
|         VAddr target_address = 0x10000000; | ||||
|         auto result = process->vm_manager.MapMemoryBlock( | ||||
|             target_address, output_buffer, 0, output_buffer->size(), MemoryState::Private); | ||||
|         REQUIRE(result.Code() == RESULT_SUCCESS); | ||||
| 
 | ||||
|         input[0] = IPC::MakeHeader(0, 0, 2); | ||||
|         input[1] = IPC::StaticBufferDesc(input_buffer.size(), 0); | ||||
|         input[2] = target_address; | ||||
| 
 | ||||
|         // An entire command buffer plus enough space for one static buffer descriptor and its
 | ||||
|         // target address
 | ||||
|         std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2> output_cmdbuff; | ||||
|         // Set up the output StaticBuffer
 | ||||
|         output_cmdbuff[IPC::COMMAND_BUFFER_LENGTH] = | ||||
|             IPC::StaticBufferDesc(output_buffer->size(), 0); | ||||
|         output_cmdbuff[IPC::COMMAND_BUFFER_LENGTH + 1] = target_address; | ||||
| 
 | ||||
|         context.WriteToOutgoingCommandBuffer(output_cmdbuff.data(), *process, handle_table); | ||||
| 
 | ||||
|         CHECK(*output_buffer == input_buffer); | ||||
|         REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) == | ||||
|                 RESULT_SUCCESS); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace Kernel
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue