mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-01-01 07:06:02 +00:00
ipc: add MapAlias processing logic for Receive
This commit is contained in:
parent
9d57783aa8
commit
804aa0e55d
6 changed files with 155 additions and 2 deletions
|
@ -128,6 +128,17 @@ namespace ams::kern::arch::arm64 {
|
||||||
return this->page_table.CopyMemoryFromLinearToLinearWithoutCheckDestination(dst_page_table.page_table, dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
|
return this->page_table.CopyMemoryFromLinearToLinearWithoutCheckDestination(dst_page_table.page_table, dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KProcessPageTable &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send) {
|
||||||
|
return this->page_table.SetupForIpc(out_dst_addr, size, src_addr, src_page_table.page_table, test_perm, dst_state, send);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process) {
|
||||||
|
return this->page_table.CleanupForIpcServer(address, size, dst_state, server_process);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
||||||
|
return this->page_table.CleanupForIpcClient(address, size, dst_state);
|
||||||
|
}
|
||||||
|
|
||||||
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
|
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
|
||||||
return this->page_table.GetPhysicalAddress(out, address);
|
return this->page_table.GetPhysicalAddress(out, address);
|
||||||
|
|
|
@ -287,6 +287,10 @@ namespace ams::kern {
|
||||||
Result CopyMemoryFromKernelToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr);
|
Result CopyMemoryFromKernelToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr);
|
||||||
Result CopyMemoryFromLinearToLinear(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
Result CopyMemoryFromLinearToLinear(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
||||||
Result CopyMemoryFromLinearToLinearWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
Result CopyMemoryFromLinearToLinearWithoutCheckDestination(KPageTableBase &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr);
|
||||||
|
|
||||||
|
Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send);
|
||||||
|
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process);
|
||||||
|
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state);
|
||||||
public:
|
public:
|
||||||
KProcessAddress GetAddressSpaceStart() const { return this->address_space_start; }
|
KProcessAddress GetAddressSpaceStart() const { return this->address_space_start; }
|
||||||
KProcessAddress GetHeapRegionStart() const { return this->heap_region_start; }
|
KProcessAddress GetHeapRegionStart() const { return this->heap_region_start; }
|
||||||
|
|
|
@ -66,7 +66,13 @@ namespace ams::kern {
|
||||||
size_t GetReceiveCount() const { return this->num_recv; }
|
size_t GetReceiveCount() const { return this->num_recv; }
|
||||||
size_t GetExchangeCount() const { return this->num_exch; }
|
size_t GetExchangeCount() const { return this->num_exch; }
|
||||||
|
|
||||||
|
Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state);
|
||||||
|
Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state);
|
||||||
|
Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state);
|
||||||
|
|
||||||
/* TODO: More functionality. */
|
/* TODO: More functionality. */
|
||||||
|
private:
|
||||||
|
Result PushMap(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state, size_t index);
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
SessionMappings mappings;
|
SessionMappings mappings;
|
||||||
|
@ -140,6 +146,18 @@ namespace ams::kern {
|
||||||
size_t GetReceiveCount() const { return this->mappings.GetReceiveCount(); }
|
size_t GetReceiveCount() const { return this->mappings.GetReceiveCount(); }
|
||||||
size_t GetExchangeCount() const { return this->mappings.GetExchangeCount(); }
|
size_t GetExchangeCount() const { return this->mappings.GetExchangeCount(); }
|
||||||
|
|
||||||
|
Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
|
||||||
|
return this->mappings.PushSend(client, server, size, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
|
||||||
|
return this->mappings.PushReceive(client, server, size, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
|
||||||
|
return this->mappings.PushExchange(client, server, size, state);
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: More functionality. */
|
/* TODO: More functionality. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1316,4 +1316,16 @@ namespace ams::kern {
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KPageTableBase &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send) {
|
||||||
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process) {
|
||||||
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) {
|
||||||
|
MESOSPHERE_UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,7 @@ namespace ams::kern {
|
||||||
const size_t recv_size = src_desc.GetSize();
|
const size_t recv_size = src_desc.GetSize();
|
||||||
uintptr_t recv_pointer = 0;
|
uintptr_t recv_pointer = 0;
|
||||||
|
|
||||||
/* There's nothing to do if there's no size. */
|
/* Process the buffer, if it has a size. */
|
||||||
if (recv_size > 0) {
|
if (recv_size > 0) {
|
||||||
/* If using indexing, set index. */
|
/* If using indexing, set index. */
|
||||||
if (dst_recv_list.IsIndex()) {
|
if (dst_recv_list.IsIndex()) {
|
||||||
|
@ -240,6 +240,64 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE Result GetMapAliasMemoryState(KMemoryState &out, ipc::MessageBuffer::MapAliasDescriptor::Attribute attr) {
|
||||||
|
switch (attr) {
|
||||||
|
case ipc::MessageBuffer::MapAliasDescriptor::Attribute_Ipc: out = KMemoryState_Ipc; break;
|
||||||
|
case ipc::MessageBuffer::MapAliasDescriptor::Attribute_NonSecureIpc: out = KMemoryState_NonSecureIpc; break;
|
||||||
|
case ipc::MessageBuffer::MapAliasDescriptor::Attribute_NonDeviceIpc: out = KMemoryState_NonDeviceIpc; break;
|
||||||
|
default: return svc::ResultInvalidCombination();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE Result ProcessReceiveMessageMapAliasDescriptors(int &offset, KProcessPageTable &dst_page_table, KProcessPageTable &src_page_table, const ipc::MessageBuffer &dst_msg, const ipc::MessageBuffer &src_msg, KSessionRequest *request, KMemoryPermission perm, bool send) {
|
||||||
|
/* Get the offset at the start of processing. */
|
||||||
|
const int cur_offset = offset;
|
||||||
|
|
||||||
|
/* Get the map alias descriptor. */
|
||||||
|
ipc::MessageBuffer::MapAliasDescriptor src_desc(src_msg, cur_offset);
|
||||||
|
offset += ipc::MessageBuffer::MapAliasDescriptor::GetDataSize() / sizeof(u32);
|
||||||
|
|
||||||
|
/* Extract address/size. */
|
||||||
|
const KProcessAddress src_address = src_desc.GetAddress();
|
||||||
|
const size_t size = src_desc.GetSize();
|
||||||
|
KProcessAddress dst_address = 0;
|
||||||
|
|
||||||
|
/* Determine the result memory state. */
|
||||||
|
KMemoryState dst_state;
|
||||||
|
R_TRY(GetMapAliasMemoryState(dst_state, src_desc.GetAttribute()));
|
||||||
|
|
||||||
|
/* Process the buffer, if it has a size. */
|
||||||
|
if (size > 0) {
|
||||||
|
/* Set up the source pages for ipc. */
|
||||||
|
R_TRY(dst_page_table.SetupForIpc(std::addressof(dst_address), size, src_address, src_page_table, perm, dst_state, send));
|
||||||
|
|
||||||
|
/* Ensure that we clean up on failure. */
|
||||||
|
auto setup_guard = SCOPE_GUARD {
|
||||||
|
dst_page_table.CleanupForIpcServer(dst_address, size, dst_state, request->GetServerProcess());
|
||||||
|
src_page_table.CleanupForIpcClient(src_address, size, dst_state);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Push the appropriate mapping. */
|
||||||
|
if (perm == KMemoryPermission_UserRead) {
|
||||||
|
R_TRY(request->PushSend(src_address, dst_address, size, dst_state));
|
||||||
|
} else if (send) {
|
||||||
|
R_TRY(request->PushExchange(src_address, dst_address, size, dst_state));
|
||||||
|
} else {
|
||||||
|
R_TRY(request->PushReceive(src_address, dst_address, size, dst_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We successfully pushed the mapping. */
|
||||||
|
setup_guard.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the output descriptor. */
|
||||||
|
dst_msg.Set(cur_offset, ipc::MessageBuffer::MapAliasDescriptor(GetVoidPointer(dst_address), size, src_desc.GetAttribute()));
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Result ReceiveMessage(bool &recv_list_broken, uintptr_t dst_message_buffer, size_t dst_buffer_size, KPhysicalAddress dst_message_paddr, KThread &src_thread, uintptr_t src_message_buffer, size_t src_buffer_size, KServerSession *session, KSessionRequest *request) {
|
ALWAYS_INLINE Result ReceiveMessage(bool &recv_list_broken, uintptr_t dst_message_buffer, size_t dst_buffer_size, KPhysicalAddress dst_message_paddr, KThread &src_thread, uintptr_t src_message_buffer, size_t src_buffer_size, KServerSession *session, KSessionRequest *request) {
|
||||||
/* Prepare variables for receive. */
|
/* Prepare variables for receive. */
|
||||||
const KThread &dst_thread = GetCurrentThread();
|
const KThread &dst_thread = GetCurrentThread();
|
||||||
|
@ -345,7 +403,16 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Process any map alias buffers. */
|
/* Process any map alias buffers. */
|
||||||
for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
|
for (auto i = 0; i < src_header.GetMapAliasCount(); ++i) {
|
||||||
MESOSPHERE_UNIMPLEMENTED();
|
/* After we process, make sure we track whether the receive list is broken. */
|
||||||
|
ON_SCOPE_EXIT { if (offset > dst_recv_list_idx) { recv_list_broken = true; } };
|
||||||
|
|
||||||
|
/* We process in order send, recv, exch. Buffers after send (recv/exch) are ReadWrite. */
|
||||||
|
const KMemoryPermission perm = (i >= src_header.GetSendCount()) ? KMemoryPermission_UserReadWrite : KMemoryPermission_UserRead;
|
||||||
|
|
||||||
|
/* Buffer is send if it is send or exch. */
|
||||||
|
const bool send = (i < src_header.GetSendCount()) || (i >= src_header.GetSendCount() + src_header.GetReceiveCount());
|
||||||
|
|
||||||
|
R_TRY(ProcessReceiveMessageMapAliasDescriptors(offset, dst_page_table, src_page_table, dst_msg, src_msg, request, perm, send));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process any raw data. */
|
/* Process any raw data. */
|
||||||
|
|
|
@ -17,6 +17,47 @@
|
||||||
|
|
||||||
namespace ams::kern {
|
namespace ams::kern {
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushMap(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state, size_t index) {
|
||||||
|
/* At most 15 buffers of each type (4-bit descriptor counts). */
|
||||||
|
MESOSPHERE_ASSERT(index < ((1ul << 4) - 1) * 3);
|
||||||
|
|
||||||
|
/* Get the mapping. */
|
||||||
|
Mapping *mapping;
|
||||||
|
if (index < NumStaticMappings) {
|
||||||
|
mapping = std::addressof(this->static_mappings[index]);
|
||||||
|
} else {
|
||||||
|
/* Allocate a page for the extra mappings. */
|
||||||
|
if (this->mappings == nullptr) {
|
||||||
|
KPageBuffer *page_buffer = KPageBuffer::Allocate();
|
||||||
|
R_UNLESS(page_buffer != nullptr, svc::ResultOutOfMemory());
|
||||||
|
|
||||||
|
this->mappings = reinterpret_cast<Mapping *>(page_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping = std::addressof(this->mappings[index - NumStaticMappings]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the mapping. */
|
||||||
|
mapping->Set(client, server, size, state);
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
|
||||||
|
MESOSPHERE_ASSERT(this->num_recv == 0);
|
||||||
|
MESOSPHERE_ASSERT(this->num_exch == 0);
|
||||||
|
return this->PushMap(client, server, size, state, this->num_send++);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
|
||||||
|
MESOSPHERE_ASSERT(this->num_exch == 0);
|
||||||
|
return this->PushMap(client, server, size, state, this->num_send + this->num_recv++);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KSessionRequest::SessionMappings::PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
|
||||||
|
return this->PushMap(client, server, size, state, this->num_send + this->num_recv + this->num_exch++);
|
||||||
|
}
|
||||||
|
|
||||||
void KSessionRequest::SessionMappings::Finalize() {
|
void KSessionRequest::SessionMappings::Finalize() {
|
||||||
if (this->mappings) {
|
if (this->mappings) {
|
||||||
KPageBuffer::Free(reinterpret_cast<KPageBuffer *>(this->mappings));
|
KPageBuffer::Free(reinterpret_cast<KPageBuffer *>(this->mappings));
|
||||||
|
|
Loading…
Reference in a new issue