diff --git a/stratosphere/TioServer/source/tio_file_server.cpp b/stratosphere/TioServer/source/tio_file_server.cpp
new file mode 100644
index 000000000..8c02dcfab
--- /dev/null
+++ b/stratosphere/TioServer/source/tio_file_server.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "tio_file_server.hpp"
+#include "tio_file_server_packet.hpp"
+#include "tio_file_server_htcs_server.hpp"
+#include "tio_file_server_processor.hpp"
+
+namespace ams::tio {
+
+ namespace {
+
+ constexpr inline auto NumDispatchThreads = 2;
+ constexpr inline auto DispatchThreadPriority = 21;
+ constexpr inline size_t RequestBufferSize = 1_MB + util::AlignUp(0x40 + fs::EntryNameLengthMax, 1_KB);
+
+ struct FileServerRequest {
+ int socket;
+ FileServerRequestHeader header;
+ u8 body[RequestBufferSize];
+ };
+
+ constexpr const char HtcsPortName[] = "iywys@$TioServer_FileServer";
+
+ alignas(os::ThreadStackAlignment) u8 g_server_stack[os::MemoryPageSize];
+ alignas(os::ThreadStackAlignment) u8 g_dispatch_stacks[NumDispatchThreads][os::MemoryPageSize];
+
+ constinit FileServerHtcsServer g_file_server_htcs_server;
+ constinit FileServerProcessor g_file_server_processor(g_file_server_htcs_server);
+
+ constinit os::ThreadType g_file_server_dispatch_threads[NumDispatchThreads];
+
+ constinit FileServerRequest g_requests[NumDispatchThreads];
+
+ constinit os::MessageQueueType g_free_mq;
+ constinit os::MessageQueueType g_dispatch_mq;
+
+ constinit uintptr_t g_free_mq_storage[NumDispatchThreads];
+ constinit uintptr_t g_dispatch_mq_storage[NumDispatchThreads];
+
+ void OnFileServerHtcsSocketAccepted(int fd) {
+ /* Service requests, while we can. */
+ while (true) {
+ /* Receive a free request. */
+ uintptr_t request_address;
+ os::ReceiveMessageQueue(std::addressof(request_address), std::addressof(g_free_mq));
+
+ /* Ensure we manage our request properly. */
+ auto req_guard = SCOPE_GUARD { os::SendMessageQueue(std::addressof(g_free_mq), request_address); };
+
+ /* Receive the request header. */
+ FileServerRequest *request = reinterpret_cast(request_address);
+ if (htcs::Recv(fd, std::addressof(request->header), sizeof(request->header), htcs::HTCS_MSG_WAITALL) != sizeof(request->header)) {
+ break;
+ }
+
+ /* Receive the request body, if necessary. */
+ if (request->header.body_size > 0) {
+ if (htcs::Recv(fd, request->body, request->header.body_size, htcs::HTCS_MSG_WAITALL) != sizeof(request->header.body_size)) {
+ break;
+ }
+ }
+
+ /* Dispatch the request. */
+ req_guard.Cancel();
+ request->socket = fd;
+ os::SendMessageQueue(std::addressof(g_dispatch_mq), request_address);
+ }
+
+ /* Our socket is no longer making requests, so close it. */
+ htcs::Close(fd);
+
+ /* Clean up any server resources. */
+ g_file_server_processor.Unmount();
+ }
+
+ void FileServerDispatchThreadFunction(void *) {
+ while (true) {
+ /* Receive a request. */
+ uintptr_t request_address;
+ os::ReceiveMessageQueue(std::addressof(request_address), std::addressof(g_dispatch_mq));
+
+ /* Process the request. */
+ FileServerRequest *request = reinterpret_cast(request_address);
+ if (!g_file_server_processor.ProcessRequest(std::addressof(request->header), request->body, request->socket)) {
+ htcs::Close(request->socket);
+ }
+
+ /* Free the request. */
+ os::SendMessageQueue(std::addressof(g_free_mq), request_address);
+ }
+ }
+
+ }
+
+ void InitializeFileServer() {
+ /* Initialize the htcs server. */
+ g_file_server_htcs_server.Initialize(HtcsPortName, g_server_stack, sizeof(g_server_stack), OnFileServerHtcsSocketAccepted);
+
+ /* TODO: Initialize SD card observer. */
+
+ /* Initialize the command processor. */
+ g_file_server_processor.SetInserted(false);
+ g_file_server_processor.SetRequestBufferSize(RequestBufferSize);
+
+ /* Initialize the dispatch message queues. */
+ os::InitializeMessageQueue(std::addressof(g_free_mq), g_free_mq_storage, util::size(g_free_mq_storage));
+ os::InitializeMessageQueue(std::addressof(g_dispatch_mq), g_dispatch_mq_storage, util::size(g_dispatch_mq_storage));
+
+ /* Begin with all requests free. */
+ for (auto i = 0; i < NumDispatchThreads; ++i) {
+ os::SendMessageQueue(std::addressof(g_free_mq), reinterpret_cast(g_requests + i));
+ }
+
+ /* Initialize the dispatch threads. */
+ /* NOTE: Nintendo does not name these threads. */
+ for (auto i = 0; i < NumDispatchThreads; ++i) {
+ R_ABORT_UNLESS(os::CreateThread(g_file_server_dispatch_threads + i, FileServerDispatchThreadFunction, nullptr, g_dispatch_stacks + i, sizeof(g_dispatch_stacks[i]), DispatchThreadPriority));
+ }
+ }
+
+ void StartFileServer() {
+ /* Start the htcs server. */
+ g_file_server_htcs_server.Start();
+
+ /* Start the dispatch threads. */
+ for (auto i = 0; i < NumDispatchThreads; ++i) {
+ os::StartThread(g_file_server_dispatch_threads + i);
+ }
+ }
+
+ void WaitFileServer() {
+ /* Wait for the htcs server to finish. */
+ g_file_server_htcs_server.Wait();
+ }
+
+}
\ No newline at end of file
diff --git a/stratosphere/TioServer/source/tio_file_server.hpp b/stratosphere/TioServer/source/tio_file_server.hpp
new file mode 100644
index 000000000..f20803042
--- /dev/null
+++ b/stratosphere/TioServer/source/tio_file_server.hpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::tio {
+
+ void InitializeFileServer();
+ void StartFileServer();
+ void WaitFileServer();
+
+}
\ No newline at end of file
diff --git a/stratosphere/TioServer/source/tio_file_server_htcs_server.cpp b/stratosphere/TioServer/source/tio_file_server_htcs_server.cpp
new file mode 100644
index 000000000..91b65b2d0
--- /dev/null
+++ b/stratosphere/TioServer/source/tio_file_server_htcs_server.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "tio_file_server_htcs_server.hpp"
+
+namespace ams::tio {
+
+ void FileServerHtcsServer::Initialize(const char *port_name, void *thread_stack, size_t thread_stack_size, SocketAcceptedCallback on_socket_accepted) {
+ /* Set our port name. */
+ std::strcpy(m_port_name.name, port_name);
+
+ /* Set our callback. */
+ m_on_socket_accepted = on_socket_accepted;
+
+ /* Setup our thread. */
+ R_ABORT_UNLESS(os::CreateThread(std::addressof(m_thread), ThreadEntry, this, thread_stack, thread_stack_size, AMS_GET_SYSTEM_THREAD_PRIORITY(TioServer, FileServerHtcsServer)));
+
+ /* Set our thread name pointer. */
+ os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(TioServer, FileServerHtcsServer));
+ }
+
+ void FileServerHtcsServer::Start() {
+ os::StartThread(std::addressof(m_thread));
+ }
+ void FileServerHtcsServer::Wait() {
+ os::WaitThread(std::addressof(m_thread));
+ }
+
+ void FileServerHtcsServer::ThreadFunc() {
+ /* Loop forever, servicing sockets. */
+ while (true) {
+ /* Get a socket. */
+ int fd;
+ while ((fd = htcs::Socket()) == -1) {
+ os::SleepThread(TimeSpan::FromSeconds(1));
+ }
+
+ /* Ensure we cleanup the socket when we're done with it. */
+ ON_SCOPE_EXIT {
+ htcs::Close(fd);
+ os::SleepThread(TimeSpan::FromSeconds(1));
+ };
+
+ /* Create a sock addr for our server. */
+ htcs::SockAddrHtcs addr;
+ addr.family = htcs::HTCS_AF_HTCS;
+ addr.peer_name = htcs::GetPeerNameAny();
+ addr.port_name = m_port_name;
+
+ /* Bind. */
+ if (htcs::Bind(fd, std::addressof(addr)) == -1) {
+ continue;
+ }
+
+ /* Listen on our port. */
+ while (htcs::Listen(fd, 0) == 0) {
+ /* Continue accepting clients, so long as we can. */
+ int client_fd;
+ while (true) {
+ /* Try to accept a client. */
+ if (client_fd = htcs::Accept(fd, std::addressof(addr)); client_fd < 0) {
+ break;
+ }
+
+ /* Handle the client. */
+ m_on_socket_accepted(client_fd);
+ }
+
+ /* NOTE: This seems unnecessary (client_fd guaranteed < 0 here), but Nintendo does it. */
+ htcs::Close(client_fd);
+ }
+ }
+ }
+
+ ssize_t FileServerHtcsServer::Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags) {
+ AMS_ASSERT(m_mutex.IsLockedByCurrentThread());
+
+ return htcs::Send(desc, buffer, buffer_size, flags);
+ }
+
+}
\ No newline at end of file
diff --git a/stratosphere/TioServer/source/tio_file_server_htcs_server.hpp b/stratosphere/TioServer/source/tio_file_server_htcs_server.hpp
new file mode 100644
index 000000000..b1ab62f2d
--- /dev/null
+++ b/stratosphere/TioServer/source/tio_file_server_htcs_server.hpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::tio {
+
+ using SocketAcceptedCallback = void(*)(s32 desc);
+
+ class FileServerHtcsServer {
+ private:
+ SocketAcceptedCallback m_on_socket_accepted;
+ htcs::HtcsPortName m_port_name;
+ os::ThreadType m_thread;
+ os::SdkMutex m_mutex;
+ public:
+ constexpr FileServerHtcsServer() : m_on_socket_accepted(nullptr), m_port_name{}, m_thread{}, m_mutex{} { /* ... */ }
+ private:
+ static void ThreadEntry(void *arg) {
+ static_cast(arg)->ThreadFunc();
+ }
+
+ void ThreadFunc();
+ public:
+ os::SdkMutex &GetMutex() { return m_mutex; }
+ public:
+ void Initialize(const char *port_name, void *thread_stack, size_t thread_stack_size, SocketAcceptedCallback on_socket_accepted);
+ void Start();
+ void Wait();
+
+ ssize_t Send(s32 desc, const void *buffer, size_t buffer_size, s32 flags);
+ };
+
+}
\ No newline at end of file
diff --git a/stratosphere/TioServer/source/tio_file_server_packet.hpp b/stratosphere/TioServer/source/tio_file_server_packet.hpp
new file mode 100644
index 000000000..17af28f70
--- /dev/null
+++ b/stratosphere/TioServer/source/tio_file_server_packet.hpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::tio {
+
+ enum class PacketType : u32 {
+ /* Control commands. */
+ Connect = 0,
+ Disconnect = 1,
+
+ /* Direct filesystem access. */
+ CreateDirectory = 500,
+ DeleteDirectory = 501,
+ DeleteDirectoryRecursively = 502,
+ OpenDirectory = 503,
+ CloseDirectory = 504,
+ RenameDirectory = 505,
+ CreateFile = 506,
+ DeleteFile = 507,
+ OpenFile = 508,
+ FlushFile = 509,
+ CloseFile = 510,
+ RenameFile = 511,
+ ReadFile = 512,
+ WriteFile = 513,
+ GetEntryType = 514,
+ ReadDirectory = 515,
+ GetFileSize = 516,
+ SetFileSize = 517,
+ GetTotalSpaceSize = 518,
+ GetFreeSpaceSize = 519,
+
+ /* Utilities. */
+ Stat = 1000,
+ ListDirectory = 1001,
+ };
+
+ struct FileServerRequestHeader {
+ u64 request_id;
+ PacketType packet_type;
+ u32 body_size;
+ };
+
+ struct FileServerResponseHeader {
+ u64 request_id;
+ Result result;
+ u32 body_size;
+ };
+ static_assert(sizeof(FileServerRequestHeader) == sizeof(FileServerResponseHeader));
+
+}
\ No newline at end of file
diff --git a/stratosphere/TioServer/source/tio_file_server_processor.cpp b/stratosphere/TioServer/source/tio_file_server_processor.cpp
new file mode 100644
index 000000000..5618f1854
--- /dev/null
+++ b/stratosphere/TioServer/source/tio_file_server_processor.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "tio_file_server_processor.hpp"
+
+namespace ams::tio {
+
+ namespace {
+
+ constexpr inline int ProtocolVersion = 1;
+
+ }
+
+ void FileServerProcessor::Unmount() {
+ /* Lock ourselves. */
+ std::scoped_lock lk(m_mutex);
+
+ /* Close all our directories. */
+ for (size_t i = 0; i < m_open_directory_count; ++i) {
+ fs::CloseDirectory(m_directories[i]);
+ m_directories[i] = {};
+ }
+
+ /* Close all our files. */
+ for (size_t i = 0; i < m_open_file_count; ++i) {
+ fs::CloseFile(m_files[i]);
+ m_files[i] = {};
+ }
+
+ /* If we're mounted, unmount the sd card. */
+ if (m_is_mounted) {
+ m_is_mounted = false;
+ fs::Unmount("sd");
+ }
+ }
+
+ bool FileServerProcessor::ProcessRequest(FileServerRequestHeader *header, u8 *body, int socket) {
+ /* Declare a response header for us to use. */
+ FileServerResponseHeader response_header = {
+ .request_id = header->request_id,
+ .result = ResultSuccess(),
+ .body_size = 0,
+ };
+
+ /* Handle the special control commands. */
+ if (header->packet_type == PacketType::Connect) {
+ /* If the SD card isn't already mounted, try to mount it. */
+ if (!m_is_mounted) {
+ /* Mount the sd card. */
+ m_is_mounted = !fs::ResultSdCardAccessFailed::Includes(fs::MountSdCard("sd"));
+
+ /* Prepare the response. */
+ char *response_body = reinterpret_cast(body);
+ util::SNPrintf(response_body, 0x100, "{\"bufferSize\":%zu, \"sdcardMounted\":%s, \"sdcardInserted\":%s, \"version\":%d}",
+ m_request_buffer_size,
+ m_is_mounted ? "true" : "false",
+ m_is_inserted ? "true" : "false",
+ ProtocolVersion);
+
+ /* Get the response length. */
+ response_header.body_size = std::strlen(response_body);
+ }
+
+ return this->SendResponse(response_header, body, socket);
+ } else if (header->packet_type == PacketType::Disconnect) {
+ /* If we need to, unmount the sd card. */
+ if (m_is_mounted) {
+ this->Unmount();
+ }
+
+ /* Send the response. */
+ return this->SendResponse(response_header, body, socket);
+ }
+
+ /* TODO: Handle remaining packet types. */
+ return false;
+ //
+ //switch (header->packet_type) {
+ // case PacketType::CreateDirectory:
+ // case PacketType::DeleteDirectory:
+ // case PacketType::DeleteDirectoryRecursively:
+ // case PacketType::OpenDirectory:
+ // case PacketType::CloseDirectory:
+ // case PacketType::RenameDirectory:
+ // case PacketType::CreateFile:
+ // case PacketType::DeleteFile:
+ // case PacketType::OpenFile:
+ // case PacketType::FlushFile:
+ // case PacketType::CloseFile:
+ // case PacketType::RenameFile:
+ // case PacketType::ReadFile:
+ // case PacketType::WriteFile:
+ // case PacketType::GetEntryType:
+ // case PacketType::ReadDirectory:
+ // case PacketType::GetFileSize:
+ // case PacketType::SetFileSize:
+ // case PacketType::GetTotalSpaceSize:
+ // case PacketType::GetFreeSpaceSize:
+ // case PacketType::Stat:
+ // case PacketType::ListDirectory:
+ // /* TODO */
+ // return false;
+ //}
+ }
+
+ bool FileServerProcessor::SendResponse(const FileServerResponseHeader &header, const void *body, int socket) {
+ /* Lock our server. */
+ std::scoped_lock lk(m_htcs_server.GetMutex());
+
+ /* Send the response header. */
+ if (m_htcs_server.Send(socket, std::addressof(header), sizeof(header), 0) != sizeof(header)) {
+ return false;
+ }
+
+ /* If we don't have a body, we're done. */
+ if (header.body_size == 0) {
+ return true;
+ }
+
+ /* Send the body. */
+ return m_htcs_server.Send(socket, body, header.body_size, 0) == header.body_size;
+ }
+
+}
\ No newline at end of file
diff --git a/stratosphere/TioServer/source/tio_file_server_processor.hpp b/stratosphere/TioServer/source/tio_file_server_processor.hpp
new file mode 100644
index 000000000..8ec5c1ac5
--- /dev/null
+++ b/stratosphere/TioServer/source/tio_file_server_processor.hpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+#include "tio_file_server_htcs_server.hpp"
+#include "tio_file_server_packet.hpp"
+
+namespace ams::tio {
+
+ class FileServerProcessor {
+ private:
+ bool m_is_inserted{};
+ bool m_is_mounted{};
+ size_t m_request_buffer_size{};
+ FileServerHtcsServer &m_htcs_server;
+ size_t m_open_file_count{};
+ size_t m_open_directory_count{};
+ fs::FileHandle m_files[0x80]{};
+ fs::DirectoryHandle m_directories[0x80]{};
+ os::SdkMutex m_fs_mutex{};
+ os::SdkMutex m_mutex{};
+ public:
+ constexpr FileServerProcessor(FileServerHtcsServer &htcs_server) : m_htcs_server(htcs_server) { /* ... */ }
+
+ void SetInserted(bool ins) { m_is_inserted = ins; }
+ void SetRequestBufferSize(size_t size) { m_request_buffer_size = size; }
+ public:
+ bool ProcessRequest(FileServerRequestHeader *header, u8 *body, int socket);
+
+ void Unmount();
+ private:
+ bool SendResponse(const FileServerResponseHeader &header, const void *body, int socket);
+ };
+
+}
\ No newline at end of file
diff --git a/stratosphere/TioServer/source/tio_main.cpp b/stratosphere/TioServer/source/tio_main.cpp
index bd2844517..9bf97dac4 100644
--- a/stratosphere/TioServer/source/tio_main.cpp
+++ b/stratosphere/TioServer/source/tio_main.cpp
@@ -14,6 +14,7 @@
* along with this program. If not, see .
*/
#include
+#include "tio_file_server.hpp"
extern "C" {
extern u32 __start__;
@@ -61,14 +62,63 @@ void __libnx_exception_handler(ThreadExceptionDump *ctx) {
#endif
+namespace ams::tio {
+
+ namespace {
+
+ alignas(0x40) constinit u8 g_fs_heap_buffer[64_KB];
+ alignas(0x40) constinit u8 g_htcs_buffer[1_KB];
+ lmem::HeapHandle g_fs_heap_handle;
+
+ void *AllocateForFs(size_t size) {
+ return lmem::AllocateFromExpHeap(g_fs_heap_handle, size);
+ }
+
+ void DeallocateForFs(void *p, size_t size) {
+ return lmem::FreeToExpHeap(g_fs_heap_handle, p);
+ }
+
+ void InitializeFsHeap() {
+ /* Setup fs allocator. */
+ g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_buffer, sizeof(g_fs_heap_buffer), lmem::CreateOption_ThreadSafe);
+ }
+
+ }
+
+}
+
+void __libnx_initheap(void) {
+ void* addr = nx_inner_heap;
+ size_t size = nx_inner_heap_size;
+
+ /* Newlib */
+ extern char* fake_heap_start;
+ extern char* fake_heap_end;
+
+ fake_heap_start = (char*)addr;
+ fake_heap_end = (char*)addr + size;
+
+ ams::tio::InitializeFsHeap();
+}
+
void __appInit(void) {
hos::InitializeForStratosphere();
- /* TODO */
+ /* Initialize FS heap. */
+ fs::SetAllocator(tio::AllocateForFs, tio::DeallocateForFs);
+
+ /* Disable FS auto-abort. */
+ fs::SetEnabledAutoAbort(false);
+
+ sm::DoWithSession([&]() {
+ R_ABORT_UNLESS(fsInitialize());
+ });
+
+ ams::CheckApiVersion();
}
void __appExit(void) {
- /* TODO */
+ fsExit();
}
namespace ams {
@@ -109,5 +159,20 @@ int main(int argc, char **argv)
os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(TioServer, Main));
AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(TioServer, Main));
+ /* Initialize htcs. */
+ constexpr auto HtcsSocketCountMax = 2;
+ const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax);
+ AMS_ABORT_UNLESS(sizeof(tio::g_htcs_buffer) >= buffer_size);
+ htcs::InitializeForSystem(tio::g_htcs_buffer, buffer_size, HtcsSocketCountMax);
+
+ /* Initialize the file server. */
+ tio::InitializeFileServer();
+
+ /* Start the file server. */
+ tio::StartFileServer();
+
+ /* Wait for the file server to finish. */
+ tio::WaitFileServer();
+
return 0;
}