mirror of
https://github.com/citra-emu/citra-nightly.git
synced 2024-12-27 01:46:01 +00:00
Kernel/IPC: Implement MappedBuffer translation for HLE services that use the HLERequestContext architecture.
This commit is contained in:
parent
4071da5012
commit
3ecf650bf9
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue