mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-15 03:27:49 +01:00
ipc::Reply -> implement Pointer handling logic
This commit is contained in:
parent
a510a1138d
commit
9d57783aa8
@ -25,6 +25,8 @@ namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline size_t PointerTransferBufferAlignment = 0x10;
|
||||
|
||||
class ReceiveList {
|
||||
private:
|
||||
u32 data[ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountMax * ipc::MessageBuffer::ReceiveListEntry::GetDataSize() / sizeof(u32)];
|
||||
@ -58,6 +60,60 @@ namespace ams::kern {
|
||||
constexpr bool IsIndex() const {
|
||||
return this->recv_list_count > ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset;
|
||||
}
|
||||
|
||||
void GetBuffer(uintptr_t &out, size_t size, int &key) const {
|
||||
switch (this->recv_list_count) {
|
||||
case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_None:
|
||||
{
|
||||
out = 0;
|
||||
}
|
||||
break;
|
||||
case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer:
|
||||
{
|
||||
const uintptr_t buf = util::AlignUp(this->msg_buffer_end, PointerTransferBufferAlignment);
|
||||
|
||||
if ((buf < buf + size) && (buf + size <= this->msg_buffer_space_end)) {
|
||||
out = buf;
|
||||
key = buf + size - this->msg_buffer_end;
|
||||
} else {
|
||||
out = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToSingleBuffer:
|
||||
{
|
||||
const ipc::MessageBuffer::ReceiveListEntry entry(this->data[0], this->data[1]);
|
||||
const uintptr_t buf = util::AlignUp(entry.GetAddress() + key, PointerTransferBufferAlignment);
|
||||
|
||||
const uintptr_t entry_addr = entry.GetAddress();
|
||||
const size_t entry_size = entry.GetSize();
|
||||
|
||||
if ((buf < buf + size) && (entry_addr < entry_addr + entry_size) && (buf + size <= entry_addr + entry_size)) {
|
||||
out = buf;
|
||||
key = buf + size - entry_addr;
|
||||
} else {
|
||||
out = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (key < this->recv_list_count - ipc::MessageBuffer::MessageHeader::ReceiveListCountType_CountOffset) {
|
||||
const ipc::MessageBuffer::ReceiveListEntry entry(this->data[2 * key + 0], this->data[2 * key + 1]);
|
||||
|
||||
const uintptr_t entry_addr = entry.GetAddress();
|
||||
const size_t entry_size = entry.GetSize();
|
||||
|
||||
if ((entry_addr < entry_addr + entry_size) && (entry_size >= size)) {
|
||||
out = entry_addr;
|
||||
}
|
||||
} else {
|
||||
out = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<bool MoveHandleAllowed>
|
||||
@ -136,6 +192,54 @@ namespace ams::kern {
|
||||
return result;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result ProcessReceiveMessagePointerDescriptors(int &offset, int &pointer_key, KProcessPageTable &dst_page_table, KProcessPageTable &src_page_table, const ipc::MessageBuffer &dst_msg, const ipc::MessageBuffer &src_msg, const ReceiveList &dst_recv_list, bool dst_user) {
|
||||
/* Get the offset at the start of processing. */
|
||||
const int cur_offset = offset;
|
||||
|
||||
/* Get the pointer desc. */
|
||||
ipc::MessageBuffer::PointerDescriptor src_desc(src_msg, cur_offset);
|
||||
offset += ipc::MessageBuffer::PointerDescriptor::GetDataSize() / sizeof(u32);
|
||||
|
||||
/* Extract address/size. */
|
||||
const uintptr_t src_pointer = src_desc.GetAddress();
|
||||
const size_t recv_size = src_desc.GetSize();
|
||||
uintptr_t recv_pointer = 0;
|
||||
|
||||
/* There's nothing to do if there's no size. */
|
||||
if (recv_size > 0) {
|
||||
/* If using indexing, set index. */
|
||||
if (dst_recv_list.IsIndex()) {
|
||||
pointer_key = src_desc.GetIndex();
|
||||
}
|
||||
|
||||
/* Get the buffer. */
|
||||
dst_recv_list.GetBuffer(recv_pointer, recv_size, pointer_key);
|
||||
R_UNLESS(recv_pointer != 0, svc::ResultOutOfResource());
|
||||
|
||||
/* Perform the pointer data copy. */
|
||||
if (dst_user) {
|
||||
R_TRY(src_page_table.CopyMemoryFromLinearToLinearWithoutCheckDestination(dst_page_table, recv_pointer, recv_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite),
|
||||
KMemoryAttribute_AnyLocked | KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked,
|
||||
src_pointer,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
KMemoryPermission_UserRead,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
} else {
|
||||
R_TRY(src_page_table.CopyMemoryFromLinearToUser(recv_pointer, recv_size, src_pointer,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
KMemoryPermission_UserRead,
|
||||
KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the output descriptor. */
|
||||
dst_msg.Set(cur_offset, ipc::MessageBuffer::PointerDescriptor(reinterpret_cast<void *>(recv_pointer), recv_size, src_desc.GetIndex()));
|
||||
|
||||
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) {
|
||||
/* Prepare variables for receive. */
|
||||
const KThread &dst_thread = GetCurrentThread();
|
||||
@ -233,7 +337,10 @@ namespace ams::kern {
|
||||
|
||||
/* Process any pointer buffers. */
|
||||
for (auto i = 0; i < src_header.GetPointerCount(); ++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; } };
|
||||
|
||||
R_TRY(ProcessReceiveMessagePointerDescriptors(offset, pointer_key, dst_page_table, src_page_table, dst_msg, src_msg, dst_recv_list, dst_user && dst_header.GetReceiveListCount() == ipc::MessageBuffer::MessageHeader::ReceiveListCountType_ToMessageBuffer));
|
||||
}
|
||||
|
||||
/* Process any map alias buffers. */
|
||||
@ -271,7 +378,7 @@ namespace ams::kern {
|
||||
if (fast_size < raw_size) {
|
||||
R_TRY(src_page_table.CopyMemoryFromLinearToLinear(dst_page_table, dst_message_buffer + max_fast_size, raw_size - fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_UserRead),
|
||||
static_cast<KMemoryPermission>(KMemoryPermission_NotMapped | KMemoryPermission_KernelReadWrite),
|
||||
KMemoryAttribute_AnyLocked | KMemoryAttribute_Uncached | KMemoryAttribute_Locked, KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked,
|
||||
src_message_buffer + max_fast_size,
|
||||
KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted,
|
||||
|
@ -351,7 +351,7 @@ namespace ams::svc::ipc {
|
||||
|
||||
ALWAYS_INLINE ReceiveListEntry(u32 a, u32 b) : data{util::BitPack32{a}, util::BitPack32{b}} { /* ... */ }
|
||||
|
||||
constexpr ALWAYS_INLINE uintptr_t GetAddress() {
|
||||
constexpr ALWAYS_INLINE uintptr_t GetAddress() const {
|
||||
const u64 address = (static_cast<u64>(this->data[1].Get<AddressHigh>()) << AddressLow::Count) | this->data[0].Get<AddressLow>();
|
||||
return address;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user