htc: ReadDirectoryLarge/data channel support

This commit is contained in:
Michael Scire 2021-02-13 10:01:19 -08:00 committed by SciresM
parent 9daec3a66a
commit 1961cb1034
4 changed files with 100 additions and 5 deletions

View file

@ -23,6 +23,7 @@ namespace ams::htcfs {
/* TODO: Move to a header? */ /* TODO: Move to a header? */
constexpr u16 RpcChannelId = 0; constexpr u16 RpcChannelId = 0;
constexpr u16 DataChannelId = 1;
alignas(os::ThreadStackAlignment) constinit u8 g_monitor_thread_stack[os::MemoryPageSize]; alignas(os::ThreadStackAlignment) constinit u8 g_monitor_thread_stack[os::MemoryPageSize];
@ -266,6 +267,14 @@ namespace ams::htcfs {
return this->ReceiveFromHtclow(dst, size, std::addressof(m_rpc_channel)); return this->ReceiveFromHtclow(dst, size, std::addressof(m_rpc_channel));
} }
Result ClientImpl::ReceiveFromDataChannel(s64 size) {
return m_data_channel.WaitReceive(size);
}
Result ClientImpl::SendToDataChannel() {
return m_data_channel.Flush();
}
Result ClientImpl::SendToHtclow(const void *src, s64 size, htclow::Channel *channel) { Result ClientImpl::SendToHtclow(const void *src, s64 size, htclow::Channel *channel) {
/* Check size. */ /* Check size. */
R_UNLESS(size >= 0, htcfs::ResultInvalidArgument()); R_UNLESS(size >= 0, htcfs::ResultInvalidArgument());
@ -316,6 +325,52 @@ namespace ams::htcfs {
return ResultSuccess(); return ResultSuccess();
} }
void ClientImpl::InitializeDataChannelForReceive(void *dst, size_t size) {
/* Open the data channel. */
R_ABORT_UNLESS(m_data_channel.Open(std::addressof(m_module), DataChannelId));
/* Set our config. */
constexpr htclow::ChannelConfig BulkReceiveConfig = {
.flow_control_enabled = false,
.handshake_enabled = false,
.max_packet_size = 0x3E000,
};
m_data_channel.SetConfig(BulkReceiveConfig);
/* Set receive buffer. */
m_data_channel.SetReceiveBuffer(dst, size);
/* Connect. */
R_ABORT_UNLESS(m_data_channel.Connect());
}
void ClientImpl::InitializeDataChannelForSend(const void *src, size_t size) {
/* Open the data channel. */
R_ABORT_UNLESS(m_data_channel.Open(std::addressof(m_module), DataChannelId));
/* Check that the size is valid. */
AMS_ASSERT(util::IsIntValueRepresentable<s64>(size));
/* Set our config. */
constexpr htclow::ChannelConfig BulkSendConfig = {
.flow_control_enabled = false,
.handshake_enabled = false,
.max_packet_size = 0xE020,
};
m_data_channel.SetConfig(BulkSendConfig);
/* Set our send buffer. */
m_data_channel.SetSendBufferWithData(src, size);
/* Connect. */
R_ABORT_UNLESS(m_data_channel.Connect());
}
void ClientImpl::FinalizeDataChannel() {
/* Close our data channel. */
m_data_channel.Close();
}
Result ClientImpl::SendRequest(const Header &request, const void *arg1, size_t arg1_size, const void *arg2, size_t arg2_size) { Result ClientImpl::SendRequest(const Header &request, const void *arg1, size_t arg1_size, const void *arg2, size_t arg2_size) {
/* Try to perform an optimized send. */ /* Try to perform an optimized send. */
if (sizeof(request) + arg1_size + arg2_size < sizeof(m_packet_buffer)) { if (sizeof(request) + arg1_size + arg2_size < sizeof(m_packet_buffer)) {
@ -492,13 +547,46 @@ namespace ams::htcfs {
/* Initialize our rpc channel. */ /* Initialize our rpc channel. */
R_TRY(this->InitializeRpcChannel()); R_TRY(this->InitializeRpcChannel());
/* Setup data channel. */
const bool use_data_channel = max_out_entries > 0;
if (use_data_channel) {
this->InitializeDataChannelForReceive(out_entries, max_out_entries * sizeof(*out_entries));
}
ON_SCOPE_EXIT { if (use_data_channel) { this->FinalizeDataChannel(); } };
/* Create space for request and response. */ /* Create space for request and response. */
Header request, response; Header request, response;
/* Create header for the request. */ /* Create header for the request. */
m_header_factory.MakeReadDirectoryLargeHeader(std::addressof(request), handle, max_out_entries); m_header_factory.MakeReadDirectoryLargeHeader(std::addressof(request), handle, max_out_entries, DataChannelId);
AMS_ABORT("TODO: Data channel setup/teardown"); /* Send the request to the host. */
R_TRY(this->SendRequest(request));
/* Receive response from the host. */
R_TRY(this->ReceiveFromRpcChannel(std::addressof(response), sizeof(response)));
/* Check the response header. */
R_TRY(this->CheckResponseHeader(response, request.packet_type, 0));
/* Check that we succeeded. */
R_TRY(ConvertHtcfsResult(response.params[0]));
/* Check our operation's result. */
R_TRY(ConvertNativeResult(response.params[1]));
/* Check that the number of entries read is allowable. */
R_UNLESS(static_cast<size_t>(response.params[2]) <= max_out_entries, htcfs::ResultUnexpectedResponseBody());
/* Read the entries, if there are any. */
if (response.params[2] > 0) {
R_TRY(this->ReceiveFromDataChannel(response.params[2] * sizeof(*out_entries)));
}
/* Set the number of output entries. */
*out = response.params[2];
return ResultSuccess();
} }
Result ClientImpl::GetPriorityForDirectory(s32 *out, s32 handle) { Result ClientImpl::GetPriorityForDirectory(s32 *out, s32 handle) {

View file

@ -82,12 +82,19 @@ namespace ams::htcfs {
Result SendToRpcChannel(const void *src, s64 size); Result SendToRpcChannel(const void *src, s64 size);
Result ReceiveFromRpcChannel(void *dst, s64 size); Result ReceiveFromRpcChannel(void *dst, s64 size);
Result ReceiveFromDataChannel(s64 size);
Result SendToDataChannel();
Result SendToHtclow(const void *src, s64 size, htclow::Channel *channel); Result SendToHtclow(const void *src, s64 size, htclow::Channel *channel);
Result ReceiveFromHtclow(void *dst, s64 size, htclow::Channel *channel); Result ReceiveFromHtclow(void *dst, s64 size, htclow::Channel *channel);
Result SendRequest(const Header &request) { return this->SendRequest(request, nullptr, 0, nullptr, 0); } Result SendRequest(const Header &request) { return this->SendRequest(request, nullptr, 0, nullptr, 0); }
Result SendRequest(const Header &request, const void *arg1, size_t arg1_size) { return this->SendRequest(request, arg1, arg1_size, nullptr, 0); } Result SendRequest(const Header &request, const void *arg1, size_t arg1_size) { return this->SendRequest(request, arg1, arg1_size, nullptr, 0); }
Result SendRequest(const Header &request, const void *arg1, size_t arg1_size, const void *arg2, size_t arg2_size); Result SendRequest(const Header &request, const void *arg1, size_t arg1_size, const void *arg2, size_t arg2_size);
void InitializeDataChannelForReceive(void *dst, size_t size);
void InitializeDataChannelForSend(const void *src, size_t size);
void FinalizeDataChannel();
}; };
} }

View file

@ -131,8 +131,8 @@ namespace ams::htcfs {
return this->MakeRequestHeader(out, PacketType::ReadDirectory, 0, handle, max_out_entries); return this->MakeRequestHeader(out, PacketType::ReadDirectory, 0, handle, max_out_entries);
} }
void MakeReadDirectoryLargeHeader(Header *out, s32 handle, size_t max_out_entries) { void MakeReadDirectoryLargeHeader(Header *out, s32 handle, size_t max_out_entries, u16 data_channel_id) {
return this->MakeRequestHeader(out, PacketType::ReadDirectoryLarge, 0, handle, max_out_entries); return this->MakeRequestHeader(out, PacketType::ReadDirectoryLarge, 0, handle, max_out_entries, data_channel_id);
} }
void MakeGetPriorityForDirectoryHeader(Header *out, s32 handle) { void MakeGetPriorityForDirectoryHeader(Header *out, s32 handle) {

View file

@ -305,7 +305,7 @@ namespace ams::htclow::mux {
auto it = m_channel_impl_map.GetMap().find(channel); auto it = m_channel_impl_map.GetMap().find(channel);
R_UNLESS(it != m_channel_impl_map.GetMap().end(), htclow::ResultChannelNotExist()); R_UNLESS(it != m_channel_impl_map.GetMap().end(), htclow::ResultChannelNotExist());
/* Perform the RECEIVE. */ /* Perform the receive. */
return m_channel_impl_map[it->second].DoReceiveEnd(out, dst, dst_size); return m_channel_impl_map[it->second].DoReceiveEnd(out, dst, dst_size);
} else { } else {
*out = 0; *out = 0;