From 1dd9d46415d6b31ebcfe84ed77865df197dcbc5d Mon Sep 17 00:00:00 2001
From: yellows8 <yellows8@users.noreply.github.com>
Date: Thu, 18 Feb 2021 11:05:47 -0500
Subject: [PATCH] uart.mitm: Implemented fs writing with a seperate thread.

---
 .../source/uart_mitm/uart_mitm_logger.cpp     | 252 ++++++++++++++++++
 .../source/uart_mitm/uart_mitm_logger.hpp     |  74 +++++
 .../source/uart_mitm/uart_mitm_service.cpp    | 149 ++++-------
 .../source/uart_mitm/uart_mitm_service.hpp    |  37 +--
 .../source/uart_mitm/uartmitm_module.cpp      |   5 +
 5 files changed, 398 insertions(+), 119 deletions(-)
 create mode 100644 stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.cpp
 create mode 100644 stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.hpp

diff --git a/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.cpp b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.cpp
new file mode 100644
index 000000000..34ff1dc9e
--- /dev/null
+++ b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#include <stratosphere.hpp>
+#include "uart_mitm_logger.hpp"
+#include "../amsmitm_fs_utils.hpp"
+
+namespace ams::mitm::uart {
+
+    alignas(os::ThreadStackAlignment) u8 g_logger_stack[0x4000];
+
+    std::shared_ptr<UartLogger> g_logger;
+
+    UartLogger::UartLogger() : m_request_event(os::EventClearMode_ManualClear), m_finish_event(os::EventClearMode_ManualClear), m_client_queue(m_client_queue_list, this->QueueSize), m_thread_queue(m_thread_queue_list, this->QueueSize) {
+        for (size_t i=0; i<this->QueueSize; i++) {
+            UartLogMessage *msg = &this->m_queue_list_msgs[i];
+            std::memset(msg, 0, sizeof(UartLogMessage));
+
+            msg->data = static_cast<u8 *>(std::malloc(this->QueueBufferSize));
+            if (msg->data != nullptr) {
+                std::memset(msg->data, 0, this->QueueBufferSize);
+            }
+
+            this->m_client_queue.Send(reinterpret_cast<uintptr_t>(msg));
+        }
+
+        /* Create and start the logger thread. */
+        R_ABORT_UNLESS(os::CreateThread(std::addressof(this->m_thread), this->ThreadEntry, this, g_logger_stack, sizeof(g_logger_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(uart, IpcServer) - 2));
+        os::StartThread(std::addressof(this->m_thread));
+    }
+
+    UartLogger::~UartLogger() {
+        /* Tell the logger thread to exit. */
+        UartLogMessage *msg=nullptr;
+        this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
+
+        msg->type = 0;
+
+        this->m_finish_event.Clear();
+        this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
+        this->m_request_event.Signal();
+
+        /* Wait on the logger thread, then destroy it. */
+        os::WaitThread(std::addressof(this->m_thread));
+        os::DestroyThread(std::addressof(this->m_thread));
+
+        for (size_t i=0; i<this->QueueSize; i++) {
+            UartLogMessage *msg = &this->m_queue_list_msgs[i];
+            std::free(msg->data);
+            msg->data = nullptr;
+        }
+    }
+
+    void UartLogger::ThreadFunction() {
+        bool exit_flag=false;
+
+        this->m_cache_count = 0;
+        this->m_cache_pos = 0;
+        std::memset(this->m_cache_list, 0, sizeof(this->m_cache_list));
+        std::memset(this->m_cache_buffer, 0, sizeof(this->m_cache_buffer));
+
+        while (!exit_flag) {
+            this->m_request_event.Wait();
+
+            /* Receive messages, process them, then Send them. */
+            UartLogMessage *msg=nullptr;
+            while (this->m_thread_queue.TryReceive(reinterpret_cast<uintptr_t *>(&msg))) {
+                if (msg->type==0) {
+                    exit_flag = true;
+                }
+                else if (msg->type==1) {
+                    this->WriteCache(msg);
+                }
+                else if (msg->type==2) {
+                    this->WriteCmdLog(reinterpret_cast<const char*>(msg->data), reinterpret_cast<const char*>(&msg->data[std::strlen((const char*)msg->data)+1]), msg->file_pos);
+                }
+                else if (msg->type==3) {
+                    this->FlushCache();
+                }
+                this->m_client_queue.Send(reinterpret_cast<uintptr_t>(msg));
+            }
+
+            this->m_request_event.Clear();
+            this->m_finish_event.Signal();
+        }
+    }
+
+    /* Wait for the thread to finish processing messages. */
+    void UartLogger::WaitFinished() {
+        /* Tell the thread to flush the cache. */
+        UartLogMessage *msg=nullptr;
+        this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
+
+        msg->type = 3;
+
+        this->m_finish_event.Clear();
+        this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
+        this->m_request_event.Signal();
+
+        /* Wait for processing to finish. */
+        m_finish_event.Wait();
+    }
+
+    /* Initialize the specified btsnoop log file. */
+    void UartLogger::InitializeDataLog(FsFile *f, size_t *datalog_pos) {
+        *datalog_pos = 0;
+
+        /* Setup the btsnoop header. */
+
+        struct {
+            char id[8];
+            u32 version;
+            u32 datalink_type;
+        } btsnoop_header = { .id = "btsnoop" };
+
+        u32 version = 1;
+        u32 datalink_type = 1002; /* HCI UART (H4) */
+        ams::util::StoreBigEndian(&btsnoop_header.version, version);
+        ams::util::StoreBigEndian(&btsnoop_header.datalink_type, datalink_type);
+
+        /* Write the btsnoop header to the datalog. */
+        this->WriteLog(f, datalog_pos, &btsnoop_header, sizeof(btsnoop_header));
+    }
+
+    /* Flush the cache into the file. */
+    void UartLogger::FlushCache() {
+        for (size_t i=0; i<this->m_cache_count; i++) {
+            UartLogMessage *cache_msg=&this->m_cache_list[i];
+            this->WriteLogPacket(cache_msg->datalog_file, cache_msg->file_pos, cache_msg->dir, cache_msg->data, cache_msg->size);
+        }
+
+        this->m_cache_count = 0;
+        this->m_cache_pos = 0;
+    }
+
+    /* Write the specified message into the cache. */
+    /* dir: false = Send (host->controller), true = Receive (controller->host). */
+    void UartLogger::WriteCache(UartLogMessage *msg) {
+        if (this->m_cache_count >= this->CacheListSize || this->m_cache_pos + msg->size >= this->CacheBufferSize) {
+            this->FlushCache();
+        }
+
+        UartLogMessage *cache_msg=&this->m_cache_list[this->m_cache_count];
+        *cache_msg = *msg;
+        cache_msg->data = &this->m_cache_buffer[this->m_cache_pos];
+        std::memcpy(cache_msg->data, msg->data, msg->size);
+        this->m_cache_count++;
+        this->m_cache_pos+= msg->size;
+    }
+
+    /* Append the specified string to the text file. */
+    void UartLogger::WriteCmdLog(const char *path, const char *str, size_t *file_pos) {
+        Result rc=0;
+        FsFile file={};
+        size_t len = std::strlen(str);
+        rc = ams::mitm::fs::OpenAtmosphereSdFile(&file, path, FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
+        if (R_SUCCEEDED(rc)) {
+            rc = fsFileWrite(&file, *file_pos, str, len, FsWriteOption_None);
+        }
+        if (R_SUCCEEDED(rc)) {
+            *file_pos += len;
+        }
+        fsFileClose(&file);
+    }
+
+    /* Append the specified data to the datalog file. */
+    void UartLogger::WriteLog(FsFile *f, size_t *datalog_pos, const void* buffer, size_t size) {
+        if (R_SUCCEEDED(fsFileWrite(f, *datalog_pos, buffer, size, FsWriteOption_None))) {
+            *datalog_pos += size;
+        }
+    }
+
+    /* Append the specified packet to the datalog via WriteLog. */
+    /* dir: false = Send (host->controller), true = Receive (controller->host). */
+    void UartLogger::WriteLogPacket(FsFile *f, size_t *datalog_pos, bool dir, const void* buffer, size_t size) {
+        struct {
+            u32 original_length;
+            u32 included_length;
+            u32 packet_flags;
+            u32 cumulative_drops;
+            s64 timestamp_microseconds;
+        } pkt_hdr = {};
+
+        u32 flags = 0;
+        if (dir) {
+            flags |= BIT(0);
+        }
+        ams::util::StoreBigEndian(&pkt_hdr.original_length, static_cast<u32>(size));
+        ams::util::StoreBigEndian(&pkt_hdr.included_length, static_cast<u32>(size));
+        ams::util::StoreBigEndian(&pkt_hdr.packet_flags, flags);
+
+        /* Currently we leave the timestamp at value 0. */
+
+        this->WriteLog(f, datalog_pos, &pkt_hdr, sizeof(pkt_hdr));
+        this->WriteLog(f, datalog_pos, buffer, size);
+    }
+
+    /* Send the specified data to the Logger thread. */
+    /* dir: false = Send (host->controller), true = Receive (controller->host). */
+    void UartLogger::SendLogData(FsFile *f, size_t *file_pos, bool dir, const void* buffer, size_t size) {
+        /* Ignore log data which is too large. */
+        if (size > this->QueueBufferSize) return;
+
+        UartLogMessage *msg=nullptr;
+        this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
+        if (msg->data == nullptr) return;
+
+        /* Setup the msg and send it. */
+        msg->type = 1;
+        msg->dir = dir;
+        msg->datalog_file = f;
+        msg->file_pos = file_pos;
+        msg->size = size;
+        std::memcpy(msg->data, buffer, size);
+
+        this->m_finish_event.Clear();
+        this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
+        this->m_request_event.Signal();
+    }
+
+    /* Send the specified text log to the Logger thread. */
+    void UartLogger::SendTextLogData(const char *path, size_t *file_pos, const char *str) {
+        /* Ignore log data which is too large. */
+        if (std::strlen(path)+1 + std::strlen(str)+1 > this->QueueBufferSize) return;
+
+        UartLogMessage *msg=nullptr;
+        this->m_client_queue.Receive(reinterpret_cast<uintptr_t *>(&msg));
+        if (msg->data == nullptr) return;
+
+        /* Setup the msg and send it. */
+        msg->type = 2;
+        msg->file_pos = file_pos;
+        std::memcpy(msg->data, path, std::strlen(path)+1);
+        std::memcpy(&msg->data[std::strlen(path)+1], str, std::strlen(str)+1);
+
+        this->m_finish_event.Clear();
+        this->m_thread_queue.Send(reinterpret_cast<uintptr_t>(msg));
+        this->m_request_event.Signal();
+    }
+}
diff --git a/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.hpp b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.hpp
new file mode 100644
index 000000000..db52c265f
--- /dev/null
+++ b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_logger.hpp
@@ -0,0 +1,74 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+#include <stratosphere.hpp>
+
+namespace ams::mitm::uart {
+
+    struct UartLogMessage {
+        u8 type;
+        bool dir;
+        FsFile *datalog_file;
+        size_t *file_pos;
+        size_t size;
+        u8 *data;
+    };
+
+    class UartLogger {
+        private:
+            ams::os::ThreadType m_thread;
+            os::Event m_request_event;
+            os::Event m_finish_event;
+            os::MessageQueue m_client_queue;
+            os::MessageQueue m_thread_queue;
+
+            static constexpr inline size_t QueueSize = 0x20;
+            static constexpr inline size_t QueueBufferSize = 0x400;
+            static constexpr inline size_t CacheListSize = 0x80;
+            static constexpr inline size_t CacheBufferSize = 0x1000;
+
+            uintptr_t m_client_queue_list[QueueSize];
+            uintptr_t m_thread_queue_list[QueueSize];
+            UartLogMessage m_queue_list_msgs[QueueSize];
+
+            size_t m_cache_count;
+            size_t m_cache_pos;
+            UartLogMessage m_cache_list[CacheListSize];
+            u8 m_cache_buffer[CacheBufferSize];
+
+            static void ThreadEntry(void *arg) { static_cast<UartLogger *>(arg)->ThreadFunction(); }
+            void ThreadFunction();
+
+            void FlushCache();
+            void WriteCache(UartLogMessage *msg);
+
+            void WriteCmdLog(const char *path, const char *str, size_t *file_pos);
+            void WriteLog(FsFile *f, size_t *datalog_pos, const void* buffer, size_t size);
+            void WriteLogPacket(FsFile *f, size_t *datalog_pos, bool dir, const void* buffer, size_t size);
+        public:
+            UartLogger();
+            ~UartLogger();
+
+            void WaitFinished();
+
+            void InitializeDataLog(FsFile *f, size_t *datalog_pos);
+
+            void SendLogData(FsFile *f, size_t *file_pos, bool dir, const void* buffer, size_t size);
+            void SendTextLogData(const char *path, size_t *file_pos, const char *str);
+    };
+
+    extern std::shared_ptr<UartLogger> g_logger;
+}
diff --git a/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.cpp b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.cpp
index 14a165feb..1fb3a5773 100644
--- a/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.cpp
+++ b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.cpp
@@ -15,10 +15,9 @@
  */
 #include <stratosphere.hpp>
 #include "uart_mitm_service.hpp"
+#include "uart_mitm_logger.hpp"
 #include "../amsmitm_fs_utils.hpp"
 
-/* TODO: This should really use async fs-writing, there's a slowdown with bluetooth communications with current fs-writing. */
-
 namespace ams::mitm::uart {
 
     /* Helper functions. */
@@ -41,7 +40,7 @@ namespace ams::mitm::uart {
         }
     }
 
-    UartPortService::UartPortService(const sm::MitmProcessInfo &cl, std::unique_ptr<::UartPortSession> s) : client_info(cl), srv(std::move(s)) {
+    UartPortService::UartPortService(const sm::MitmProcessInfo &cl, std::unique_ptr<::UartPortSession> s) : m_client_info(cl), m_srv(std::move(s)) {
         Result rc=0;
         /* Get a timestamp. */
         u64 timestamp0=0, timestamp1;
@@ -49,122 +48,66 @@ namespace ams::mitm::uart {
         timestamp1 = svcGetSystemTick();
 
         /* Setup/create the logging directory. */
-        std::snprintf(this->base_path, sizeof(this->base_path), "uart_logs/%011lu_%011lu_%016lx", timestamp0, timestamp1, static_cast<u64>(this->client_info.program_id));
+        std::snprintf(this->m_base_path, sizeof(this->m_base_path), "uart_logs/%011lu_%011lu_%016lx", timestamp0, timestamp1, static_cast<u64>(this->m_client_info.program_id));
         ams::mitm::fs::CreateAtmosphereSdDirectory("uart_logs");
-        ams::mitm::fs::CreateAtmosphereSdDirectory(this->base_path);
+        ams::mitm::fs::CreateAtmosphereSdDirectory(this->m_base_path);
 
         /* Create/initialize the text cmd_log. */
         char tmp_path[256];
-        std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->base_path, "cmd_log");
+        std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->m_base_path, "cmd_log");
         ams::mitm::fs::CreateAtmosphereSdFile(tmp_path, 0, 0);
-        this->cmdlog_pos = 0;
+        this->m_cmdlog_pos = 0;
 
         /* Initialize the Send cache-buffer. */
-        this->send_cache_buffer = static_cast<u8 *>(std::malloc(this->CacheBufferSize));
-        if (this->send_cache_buffer != nullptr) {
-            std::memset(this->send_cache_buffer, 0, this->CacheBufferSize);
+        this->m_send_cache_buffer = static_cast<u8 *>(std::malloc(this->CacheBufferSize));
+        if (this->m_send_cache_buffer != nullptr) {
+            std::memset(this->m_send_cache_buffer, 0, this->CacheBufferSize);
         }
-        this->send_cache_pos = 0;
+        this->m_send_cache_pos = 0;
 
         /* Initialize the Receive cache-buffer. */
-        this->receive_cache_buffer = static_cast<u8 *>(std::malloc(this->CacheBufferSize));
-        if (this->receive_cache_buffer != nullptr) {
-            std::memset(this->receive_cache_buffer, 0, this->CacheBufferSize);
+        this->m_receive_cache_buffer = static_cast<u8 *>(std::malloc(this->CacheBufferSize));
+        if (this->m_receive_cache_buffer != nullptr) {
+            std::memset(this->m_receive_cache_buffer, 0, this->CacheBufferSize);
         }
-        this->receive_cache_pos = 0;
+        this->m_receive_cache_pos = 0;
+
+        this->m_datalog_ready = false;
 
         /* When the above is successful, initialize the datalog. */
-        if (this->send_cache_buffer != nullptr && this->receive_cache_buffer != nullptr) {
-            std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->base_path, "btsnoop_hci.log");
+        if (this->m_send_cache_buffer != nullptr && this->m_receive_cache_buffer != nullptr) {
+            std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->m_base_path, "btsnoop_hci.log");
             ams::mitm::fs::CreateAtmosphereSdFile(tmp_path, 0, 0);
-            rc = ams::mitm::fs::OpenAtmosphereSdFile(&this->datalog_file, tmp_path, FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
+            rc = ams::mitm::fs::OpenAtmosphereSdFile(&this->m_datalog_file, tmp_path, FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
             /* Set datalog_ready to whether initialization was successful. */
-            this->datalog_ready = R_SUCCEEDED(rc);
+            this->m_datalog_ready = R_SUCCEEDED(rc);
         }
-        this->datalog_pos = 0;
 
-        /* Setup the btsnoop header. */
+        if (this->m_datalog_ready) {
+            std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
+            logger->InitializeDataLog(&this->m_datalog_file, &this->m_datalog_pos);
+        }
 
-        struct {
-            char id[8];
-            u32 version;
-            u32 datalink_type;
-        } btsnoop_header = { .id = "btsnoop" };
-
-        u32 version = 1;
-        u32 datalink_type = 1002; /* HCI UART (H4) */
-        ams::util::StoreBigEndian(&btsnoop_header.version, version);
-        ams::util::StoreBigEndian(&btsnoop_header.datalink_type, datalink_type);
-
-        /* Enable data-logging, required for WriteLog() to write anything. */
-        this->data_logging_enabled = true;
-
-        /* Write the btsnoop header to the datalog. */
-        this->WriteLog(&btsnoop_header, sizeof(btsnoop_header));
-
-        /* This will be re-enabled by WriteUartData once a certain command is detected. */
-        /* If you want to log all HCI traffic during system-boot initialization, you can comment out the below line, however there will be a slowdown. */
-        this->data_logging_enabled = false;
+        /* This will be enabled by WriteUartData once a certain command is detected. */
+        /* If you want to log all HCI traffic during system-boot initialization, you can change this field to true. */
+        /* When changed to true, qlaunch will hang at a black-screen during system-boot, due to the bluetooth slowdown. */
+        this->m_data_logging_enabled = false;
     }
 
     /* Append the specified string to the text cmd_log file. */
     void UartPortService::WriteCmdLog(const char *str) {
-        Result rc=0;
-        FsFile file={};
         char tmp_path[256];
-        size_t len = strlen(str);
-        std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->base_path, "cmd_log");
-        rc = ams::mitm::fs::OpenAtmosphereSdFile(&file, tmp_path, FsOpenMode_Read | FsOpenMode_Write | FsOpenMode_Append);
-        if (R_SUCCEEDED(rc)) {
-            rc = fsFileWrite(&file, this->cmdlog_pos, str, len, FsWriteOption_None);
-        }
-        if (R_SUCCEEDED(rc)) {
-            this->cmdlog_pos += len;
-        }
-        fsFileClose(&file);
-    }
-
-    /* Append the specified data to the datalog file. */
-    void UartPortService::WriteLog(const void* buffer, size_t size) {
-        /* Only write to the file if data-logging is enabled and initialized. */
-        if (this->data_logging_enabled && this->datalog_ready) {
-            if (R_SUCCEEDED(fsFileWrite(&this->datalog_file, this->datalog_pos, buffer, size, FsWriteOption_None))) {
-                this->datalog_pos += size;
-            }
-        }
-    }
-
-    /* Append the specified packet to the datalog via WriteLog. */
-    /* dir: false = Send (host->controller), true = Receive (controller->host). */
-    void UartPortService::WriteLogPacket(bool dir, const void* buffer, size_t size) {
-        struct {
-            u32 original_length;
-            u32 included_length;
-            u32 packet_flags;
-            u32 cumulative_drops;
-            s64 timestamp_microseconds;
-        } pkt_hdr = {};
-
-        u32 flags = 0;
-        if (dir) {
-            flags |= BIT(0);
-        }
-        ams::util::StoreBigEndian(&pkt_hdr.original_length, static_cast<u32>(size));
-        ams::util::StoreBigEndian(&pkt_hdr.included_length, static_cast<u32>(size));
-        ams::util::StoreBigEndian(&pkt_hdr.packet_flags, flags);
-
-        /* Currently we leave the timestamp at value 0. */
-
-        this->WriteLog(&pkt_hdr, sizeof(pkt_hdr));
-        this->WriteLog(buffer, size);
+        std::snprintf(tmp_path, sizeof(tmp_path), "%s/%s", this->m_base_path, "cmd_log");
+        std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
+        logger->SendTextLogData(tmp_path, &this->m_cmdlog_pos, str);
     }
 
     /* Log data from Send/Receive. */
     /* dir: false = Send (host->controller), true = Receive (controller->host). */
     void UartPortService::WriteUartData(bool dir, const void* buffer, size_t size) {
         /* Select which cache buffer/pos to use via dir. */
-        u8 *cache_buffer = !dir ? this->send_cache_buffer : this->receive_cache_buffer;
-        size_t *cache_pos = !dir ? &this->send_cache_pos : &this->receive_cache_pos;
+        u8 *cache_buffer = !dir ? this->m_send_cache_buffer : this->m_receive_cache_buffer;
+        size_t *cache_pos = !dir ? &this->m_send_cache_pos : &this->m_receive_cache_pos;
 
         /* Verify that the input size is non-zero, and within cache buffer bounds. */
         if (size && *cache_pos + size <= this->CacheBufferSize) {
@@ -217,8 +160,8 @@ namespace ams::mitm::uart {
                         /* Check for the first command used in the port which is opened last by bluetooth-sysmodule. */
                         /* This is a vendor command. */
                         /* Once detected, data-logging will be enabled. */
-                        if (!this->data_logging_enabled && hci_cmd->opcode[1] == 0xFC && hci_cmd->opcode[0] == 0x16) {
-                            this->data_logging_enabled = true;
+                        if (!this->m_data_logging_enabled && hci_cmd->opcode[1] == 0xFC && hci_cmd->opcode[0] == 0x16) {
+                            this->m_data_logging_enabled = true;
                         }
                     }
                 }
@@ -258,7 +201,11 @@ namespace ams::mitm::uart {
 
                 /* If a packet is available, log it and update the cache. */
                 if (pkt_len>0x1) {
-                    this->WriteLogPacket(dir, cache_buffer, pkt_len);
+                    /* Only write to the file if data-logging is enabled and initialized. */
+                    if (this->m_data_logging_enabled && this->m_datalog_ready) {
+                        std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
+                        logger->SendLogData(&this->m_datalog_file, &this->m_datalog_pos, dir, cache_buffer, pkt_len);
+                    }
                     (*cache_pos)-= pkt_len;
                     if (*cache_pos) {
                         std::memmove(cache_buffer, &cache_buffer[pkt_len], *cache_pos);
@@ -272,7 +219,7 @@ namespace ams::mitm::uart {
 
     /* Forward OpenPort and write to the cmd_log. */
     Result UartPortService::OpenPort(sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length) {
-        Result rc = uartPortSessionOpenPortFwd(this->srv.get(), reinterpret_cast<bool *>(out.GetPointer()), port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle.GetValue(), receive_handle.GetValue(), send_buffer_length, receive_buffer_length);
+        Result rc = uartPortSessionOpenPortFwd(this->m_srv.get(), reinterpret_cast<bool *>(out.GetPointer()), port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle.GetValue(), receive_handle.GetValue(), send_buffer_length, receive_buffer_length);
         svcCloseHandle(send_handle.GetValue());
         svcCloseHandle(receive_handle.GetValue());
 
@@ -284,7 +231,7 @@ namespace ams::mitm::uart {
 
     /* Forward OpenPortForDev and write to the cmd_log. */
     Result UartPortService::OpenPortForDev(sf::Out<bool> out, u32 port, u32 baud_rate, UartFlowControlMode flow_control_mode, u32 device_variation, bool is_invert_tx, bool is_invert_rx, bool is_invert_rts, bool is_invert_cts, sf::CopyHandle send_handle, sf::CopyHandle receive_handle, u64 send_buffer_length, u64 receive_buffer_length) {
-        Result rc = uartPortSessionOpenPortForDevFwd(this->srv.get(), reinterpret_cast<bool *>(out.GetPointer()), port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle.GetValue(), receive_handle.GetValue(), send_buffer_length, receive_buffer_length);
+        Result rc = uartPortSessionOpenPortForDevFwd(this->m_srv.get(), reinterpret_cast<bool *>(out.GetPointer()), port, baud_rate, flow_control_mode, device_variation, is_invert_tx, is_invert_rx, is_invert_rts, is_invert_cts, send_handle.GetValue(), receive_handle.GetValue(), send_buffer_length, receive_buffer_length);
         svcCloseHandle(send_handle.GetValue());
         svcCloseHandle(receive_handle.GetValue());
 
@@ -296,7 +243,7 @@ namespace ams::mitm::uart {
 
     /* Forward GetWritableLength and write to the cmd_log. */
     Result UartPortService::GetWritableLength(sf::Out<u64> out) {
-        Result rc = uartPortSessionGetWritableLength(this->srv.get(), reinterpret_cast<u64 *>(out.GetPointer()));
+        Result rc = uartPortSessionGetWritableLength(this->m_srv.get(), reinterpret_cast<u64 *>(out.GetPointer()));
 
         char str[256];
         std::snprintf(str, sizeof(str), "GetWritableLength(): rc = 0x%x, out = 0x%lx\n", rc.GetValue(), out.GetValue());
@@ -307,7 +254,7 @@ namespace ams::mitm::uart {
 
     /* Forward Send and log the data if the out_size is non-zero. */
     Result UartPortService::Send(sf::Out<u64> out_size, const sf::InAutoSelectBuffer &data) {
-        Result rc = uartPortSessionSend(this->srv.get(), data.GetPointer(), data.GetSize(), reinterpret_cast<u64 *>(out_size.GetPointer()));
+        Result rc = uartPortSessionSend(this->m_srv.get(), data.GetPointer(), data.GetSize(), reinterpret_cast<u64 *>(out_size.GetPointer()));
 
         if (R_SUCCEEDED(rc) && out_size.GetValue()) {
             this->WriteUartData(false, data.GetPointer(), out_size.GetValue());
@@ -317,7 +264,7 @@ namespace ams::mitm::uart {
 
     /* Forward GetReadableLength and write to the cmd_log. */
     Result UartPortService::GetReadableLength(sf::Out<u64> out) {
-        Result rc = uartPortSessionGetReadableLength(this->srv.get(), reinterpret_cast<u64 *>(out.GetPointer()));
+        Result rc = uartPortSessionGetReadableLength(this->m_srv.get(), reinterpret_cast<u64 *>(out.GetPointer()));
 
         char str[256];
         std::snprintf(str, sizeof(str), "GetReadableLength(): rc = 0x%x, out = 0x%lx\n", rc.GetValue(), out.GetValue());
@@ -328,7 +275,7 @@ namespace ams::mitm::uart {
 
     /* Forward Receive and log the data if the out_size is non-zero. */
     Result UartPortService::Receive(sf::Out<u64> out_size, const sf::OutAutoSelectBuffer &data) {
-        Result rc = uartPortSessionReceive(this->srv.get(), data.GetPointer(), data.GetSize(), reinterpret_cast<u64 *>(out_size.GetPointer()));
+        Result rc = uartPortSessionReceive(this->m_srv.get(), data.GetPointer(), data.GetSize(), reinterpret_cast<u64 *>(out_size.GetPointer()));
 
         if (R_SUCCEEDED(rc) && out_size.GetValue()) {
             this->WriteUartData(true, data.GetPointer(), out_size.GetValue());
@@ -338,7 +285,7 @@ namespace ams::mitm::uart {
 
     /* Forward BindPortEvent and write to the cmd_log. */
     Result UartPortService::BindPortEvent(sf::Out<bool> out, sf::OutCopyHandle out_event_handle, UartPortEventType port_event_type, s64 threshold) {
-        Result rc = uartPortSessionBindPortEventFwd(this->srv.get(), port_event_type, threshold, reinterpret_cast<bool *>(out.GetPointer()), out_event_handle.GetHandlePointer());
+        Result rc = uartPortSessionBindPortEventFwd(this->m_srv.get(), port_event_type, threshold, reinterpret_cast<bool *>(out.GetPointer()), out_event_handle.GetHandlePointer());
 
         char str[256];
         std::snprintf(str, sizeof(str), "BindPortEvent(port_event_type = 0x%x, threshold = 0x%lx): rc = 0x%x, out = %d\n", port_event_type, threshold, rc.GetValue(), out.GetValue());
@@ -348,7 +295,7 @@ namespace ams::mitm::uart {
 
     /* Forward UnbindPortEvent and write to the cmd_log. */
     Result UartPortService::UnbindPortEvent(sf::Out<bool> out, UartPortEventType port_event_type) {
-        Result rc = uartPortSessionUnbindPortEvent(this->srv.get(), port_event_type, reinterpret_cast<bool *>(out.GetPointer()));
+        Result rc = uartPortSessionUnbindPortEvent(this->m_srv.get(), port_event_type, reinterpret_cast<bool *>(out.GetPointer()));
 
         char str[256];
         std::snprintf(str, sizeof(str), "UnbindPortEvent(port_event_type = 0x%x): rc = 0x%x, out = %d\n", port_event_type, rc.GetValue(), out.GetValue());
diff --git a/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.hpp b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.hpp
index 0b0b4471b..2a9c0917d 100644
--- a/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.hpp
+++ b/stratosphere/ams_mitm/source/uart_mitm/uart_mitm_service.hpp
@@ -16,6 +16,7 @@
 #pragma once
 #include <stratosphere.hpp>
 
+#include "uart_mitm_logger.hpp"
 #include "uart_shim.h"
 
 #define AMS_UART_IPORTSESSION_MITM_INTERFACE_INFO(C, H)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 \
@@ -39,39 +40,39 @@ namespace ams::mitm::uart {
 
     class UartPortService {
         private:
-            sm::MitmProcessInfo client_info;
-            std::unique_ptr<::UartPortSession> srv;
+            sm::MitmProcessInfo m_client_info;
+            std::unique_ptr<::UartPortSession> m_srv;
 
             static constexpr inline size_t CacheBufferSize = 0x1000;
 
-            char base_path[256];
+            char m_base_path[256];
 
-            size_t cmdlog_pos;
-            size_t datalog_pos;
+            size_t m_cmdlog_pos;
+            size_t m_datalog_pos;
 
-            bool datalog_ready;
-            bool data_logging_enabled;
+            bool m_datalog_ready;
+            bool m_data_logging_enabled;
 
-            FsFile datalog_file;
+            FsFile m_datalog_file;
 
-            u8 *send_cache_buffer;
-            u8 *receive_cache_buffer;
-            size_t send_cache_pos;
-            size_t receive_cache_pos;
+            u8 *m_send_cache_buffer;
+            u8 *m_receive_cache_buffer;
+            size_t m_send_cache_pos;
+            size_t m_receive_cache_pos;
 
             bool TryGetCurrentTimestamp(u64 *out);
             void WriteCmdLog(const char *str);
-            void WriteLog(const void* buffer, size_t size);
-            void WriteLogPacket(bool dir, const void* buffer, size_t size);
             void WriteUartData(bool dir, const void* buffer, size_t size);
         public:
             UartPortService(const sm::MitmProcessInfo &cl, std::unique_ptr<::UartPortSession> s);
 
             virtual ~UartPortService() {
-                uartPortSessionClose(this->srv.get());
-                fsFileClose(&this->datalog_file);
-                std::free(this->send_cache_buffer);
-                std::free(this->receive_cache_buffer);
+                std::shared_ptr<UartLogger> logger = mitm::uart::g_logger;
+                logger->WaitFinished();
+                uartPortSessionClose(this->m_srv.get());
+                fsFileClose(&this->m_datalog_file);
+                std::free(this->m_send_cache_buffer);
+                std::free(this->m_receive_cache_buffer);
             }
         public:
             /* Actual command API. */
diff --git a/stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.cpp b/stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.cpp
index dfe75342f..4229f6e3b 100644
--- a/stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.cpp
+++ b/stratosphere/ams_mitm/source/uart_mitm/uartmitm_module.cpp
@@ -17,6 +17,7 @@
 #include "../amsmitm_initialization.hpp"
 #include "uartmitm_module.hpp"
 #include "uart_mitm_service.hpp"
+#include "uart_mitm_logger.hpp"
 
 namespace ams::mitm::uart {
 
@@ -84,8 +85,12 @@ namespace ams::mitm::uart {
         /* Create mitm servers. */
         R_ABORT_UNLESS((g_server_manager.RegisterMitmServer<UartMitmService>(PortIndex_Mitm, UartMitmServiceName)));
 
+        mitm::uart::g_logger = std::make_shared<UartLogger>();
+
         /* Loop forever, servicing our services. */
         g_server_manager.LoopProcess();
+
+        mitm::uart::g_logger.reset();
     }
 
 }