Kernel/IPC: Implement MappedBuffer translation for HLE services that use the HLERequestContext architecture.

This commit is contained in:
wwylele 2017-07-14 22:24:57 +03:00
parent 4071da5012
commit 3ecf650bf9
2 changed files with 83 additions and 0 deletions

View file

@ -107,6 +107,12 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
cmd_buf[i++] = source_address; cmd_buf[i++] = source_address;
break; break;
} }
case IPC::DescriptorType::MappedBuffer: {
u32 next_id = static_cast<u32>(request_mapped_buffers.size());
request_mapped_buffers.emplace_back(src_process, descriptor, src_cmdbuf[i], next_id);
cmd_buf[i++] = next_id;
break;
}
default: default:
UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
} }
@ -166,6 +172,11 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P
dst_cmdbuf[i++] = target_address; dst_cmdbuf[i++] = target_address;
break; break;
} }
case IPC::DescriptorType::MappedBuffer: {
VAddr addr = request_mapped_buffers[cmd_buf[i]].address;
dst_cmdbuf[i++] = addr;
break;
}
default: default:
UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor); UNIMPLEMENTED_MSG("Unsupported handle translation: 0x%08X", descriptor);
} }
@ -174,4 +185,28 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
MappedBuffer& HLERequestContext::GetMappedBuffer(u32 id_from_cmdbuf) {
ASSERT_MSG(id_from_cmdbuf < request_mapped_buffers.size(), "Mapped Buffer ID out of range!");
return request_mapped_buffers[id_from_cmdbuf];
}
MappedBuffer::MappedBuffer(const Process& process, u32 descriptor, VAddr address, u32 id)
: process(&process), address(address), id(id) {
IPC::MappedBufferDescInfo desc{descriptor};
size = desc.size;
perms = desc.perms;
}
void MappedBuffer::Read(void* dest_buffer, size_t offset, size_t size) {
ASSERT(perms & IPC::R);
ASSERT(offset + size <= this->size);
Memory::ReadBlock(*process, address + offset, dest_buffer, size);
}
void MappedBuffer::Write(const void* src_buffer, size_t offset, size_t size) {
ASSERT(perms & IPC::W);
ASSERT(offset + size <= this->size);
Memory::WriteBlock(*process, address + offset, src_buffer, size);
}
} // namespace Kernel } // namespace Kernel

View file

@ -63,6 +63,35 @@ protected:
std::vector<SharedPtr<ServerSession>> connected_sessions; std::vector<SharedPtr<ServerSession>> connected_sessions;
}; };
class MappedBuffer {
public:
MappedBuffer(const Process& process, u32 descriptor, VAddr address, u32 id);
// interface for service
void Read(void* dest_buffer, size_t offset, size_t size);
void Write(const void* src_buffer, size_t offset, size_t size);
size_t GetSize() const {
return size;
}
// interface for ipc helper
u32 GenerateDescriptor() const {
return IPC::MappedBufferDesc(size, perms);
}
u32 GetId() const {
return id;
}
private:
friend class HLERequestContext;
u32 id;
VAddr address;
const Process* process;
size_t size;
IPC::MappedBufferPermissions perms;
};
/** /**
* Class containing information about an in-flight IPC request being handled by an HLE service * Class containing information about an in-flight IPC request being handled by an HLE service
* implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and
@ -81,6 +110,17 @@ protected:
* The end result is similar to just giving services their own real handle tables, but since these * The end result is similar to just giving services their own real handle tables, but since these
* ids are local to a specific context, it avoids requiring services to manage handles for objects * ids are local to a specific context, it avoids requiring services to manage handles for objects
* across multiple calls and ensuring that unneeded handles are cleaned up. * across multiple calls and ensuring that unneeded handles are cleaned up.
*
* HLE mapped buffer protocol
* ==========================
*
* HLE services don't have their own virtual memory space, a tweaked protocol is used to simulate
* memory mapping. The kernel will wrap the incoming buffers into a memory interface on which HLE
* services can operate, and insert a id in the buffer where the vaddr would normally be. The
* service then calls GetMappedBuffer with that id to get the memory interface. On response, like
* real services pushing back the mapped buffer address to unmap it, HLE services push back the
* id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is
* needed in this case, though.
*/ */
class HLERequestContext { class HLERequestContext {
public: public:
@ -131,6 +171,12 @@ public:
*/ */
void AddStaticBuffer(u8 buffer_id, std::vector<u8> data); void AddStaticBuffer(u8 buffer_id, std::vector<u8> data);
/**
* Gets a memory interface by the id from the request command buffer. See the "HLE mapped buffer
* protocol" section in the class documentation for more details.
*/
MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
/// Populates this context with data from the requesting process/thread. /// Populates this context with data from the requesting process/thread.
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process, ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process,
HandleTable& src_table); HandleTable& src_table);
@ -145,6 +191,8 @@ private:
boost::container::small_vector<SharedPtr<Object>, 8> request_handles; boost::container::small_vector<SharedPtr<Object>, 8> request_handles;
// The static buffers will be created when the IPC request is translated. // The static buffers will be created when the IPC request is translated.
std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers; std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers;
// The mapped buffers will be created when the IPC request is translated
boost::container::small_vector<MappedBuffer, 8> request_mapped_buffers;
}; };
} // namespace Kernel } // namespace Kernel