From 6940c99ed65c64f462efc082d31f238eac13ae25 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 6 Aug 2019 15:59:31 +0100
Subject: [PATCH 001/129] Added boost serialization

---
 .gitmodules                      |  2 +-
 CMakeLists.txt                   |  9 +++++++++
 externals/boost                  |  2 +-
 src/common/archives.h            | 11 +++++++++++
 src/core/CMakeLists.txt          |  2 +-
 src/core/hle/kernel/vm_manager.h | 26 ++++++++++++++++++++++++++
 src/core/memory.cpp              | 31 +++++++++++++++++++++++++++++++
 src/core/memory.h                |  9 +++++++++
 8 files changed, 89 insertions(+), 3 deletions(-)
 create mode 100644 src/common/archives.h

diff --git a/.gitmodules b/.gitmodules
index b247ccdbe..b0bfcaee8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
 [submodule "boost"]
     path = externals/boost
-    url = https://github.com/citra-emu/ext-boost.git
+    url = https://github.com/hamish-milne/ext-boost.git
 [submodule "nihstro"]
     path = externals/nihstro
     url = https://github.com/neobrain/nihstro.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 41d55f375..df8081f05 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -124,6 +124,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
 # System imported libraries
 # ======================
 
+add_library(boost_libs INTERFACE)
+
 find_package(Boost 1.66.0 QUIET)
 if (NOT Boost_FOUND)
     message(STATUS "Boost 1.66.0 or newer not found, falling back to externals")
@@ -131,7 +133,14 @@ if (NOT Boost_FOUND)
     set(BOOST_ROOT "${PROJECT_SOURCE_DIR}/externals/boost")
     set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
     set(Boost_NO_SYSTEM_PATHS OFF)
+    add_definitions( -DBOOST_ALL_NO_LIB )
     find_package(Boost QUIET REQUIRED)
+
+    # Boost external libraries
+    file(GLOB boost_serialization_SRC "externals/boost/libs/serialization/src/*.cpp")
+    add_library(boost_serialization STATIC ${boost_serialization_SRC})
+    target_link_libraries(boost_serialization PUBLIC Boost::boost)
+    target_link_libraries(boost_libs INTERFACE boost_serialization)
 endif()
 
 # Prefer the -pthread flag on Linux.
diff --git a/externals/boost b/externals/boost
index 502437b2a..1acb9699a 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 502437b2ae3f1da821aa7d5d5174ec356fa89269
+Subproject commit 1acb9699ac8e91654331504cf3524b26463eeee4
diff --git a/src/common/archives.h b/src/common/archives.h
new file mode 100644
index 000000000..76aa71054
--- /dev/null
+++ b/src/common/archives.h
@@ -0,0 +1,11 @@
+#include "boost/archive/binary_iarchive.hpp"
+#include "boost/archive/binary_oarchive.hpp"
+
+#define SERIALIZE_IMPL(A) template void A::serialize<boost::archive::binary_iarchive>( \
+    boost::archive::binary_iarchive & ar, \
+    const unsigned int file_version \
+); \
+template void A::serialize<boost::archive::binary_oarchive>( \
+    boost::archive::binary_oarchive & ar, \
+    const unsigned int file_version \
+);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 064e44f94..ed2642431 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -465,7 +465,7 @@ endif()
 create_target_directory_groups(core)
 
 target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
-target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives)
+target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives boost_libs)
 if (ENABLE_WEB_SERVICE)
     target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
     target_link_libraries(core PRIVATE web_service)
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index fbd9bf09b..0d3ae1e44 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <utility>
 #include <vector>
+#include "boost/serialization/split_member.hpp"
 #include "common/common_types.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
@@ -193,6 +194,31 @@ public:
     Memory::PageTable page_table;
 
 private:
+    friend class boost::serialization::access;
+    template<class Archive>
+    void save(Archive & ar, const unsigned int file_version)
+    {
+        for (int i = 0; i < page_table.pointers.size(); i++) {
+            ar << memory.GetFCRAMOffset(page_table.pointers[i]);
+        }
+        ar & page_table.special_regions;
+        ar & page_table.attributes;
+    }
+
+    template<class Archive>
+    void load(Archive & ar, const unsigned int file_version)
+    {
+        for (int i = 0; i < page_table.pointers.size(); i++) {
+            u32 offset{};
+            ar >> offset;
+            page_table.pointers[i] = memory.GetFCRAMPointer(offset);
+        }
+        ar & page_table.special_regions;
+        ar & page_table.attributes;
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
+
     using VMAIter = decltype(vma_map)::iterator;
 
     /// Converts a VMAHandle to a mutable VMAIter.
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 096f4c697..e5fb83f5a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -4,7 +4,9 @@
 
 #include <array>
 #include <cstring>
+#include "boost/serialization/split_member.hpp"
 #include "audio_core/dsp_interface.h"
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
@@ -67,8 +69,37 @@ public:
     std::vector<PageTable*> page_table_list;
 
     AudioCore::DspInterface* dsp = nullptr;
+
+private:
+    friend class boost::serialization::access;
+    template<class Archive>
+    void save(Archive & ar, const unsigned int file_version) const
+    {
+        // TODO: Skip n3ds ram when not used?
+        ar.save_binary(fcram.get(), Memory::FCRAM_N3DS_SIZE);
+        ar.save_binary(vram.get(), Memory::VRAM_SIZE);
+        ar.save_binary(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
+        // ar & cache_marker;
+        // ar & page_table_list;
+        // ar & current_page_table;
+    }
+
+    template<class Archive>
+    void load(Archive & ar, const unsigned int file_version)
+    {
+        ar.load_binary(fcram.get(), Memory::FCRAM_N3DS_SIZE);
+        ar.load_binary(vram.get(), Memory::VRAM_SIZE);
+        ar.load_binary(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
+        // ar & cache_marker;
+        // ar & page_table_list;
+        // ar & current_page_table;
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
 };
 
+SERIALIZE_IMPL(MemorySystem::Impl)
+
 MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
 MemorySystem::~MemorySystem() = default;
 
diff --git a/src/core/memory.h b/src/core/memory.h
index 6caca5a2b..e5582d16d 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -9,6 +9,7 @@
 #include <memory>
 #include <string>
 #include <vector>
+#include "boost/serialization/split_member.hpp"
 #include "common/common_types.h"
 #include "core/mmio.h"
 
@@ -52,6 +53,14 @@ struct SpecialRegion {
     VAddr base;
     u32 size;
     MMIORegionPointer handler;
+
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & base;
+        ar & size;
+        ar & handler;
+    }
 };
 
 /**

From dc04774ece118757007fdf9e14b52585990e2554 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 6 Aug 2019 17:45:06 +0100
Subject: [PATCH 002/129] Added POD serialization

---
 externals/boost           |  2 +-
 src/common/CMakeLists.txt |  1 +
 src/common/pod.h          | 20 +++++++++++++++++
 src/core/core.h           |  9 ++++++++
 src/core/hle/result.h     |  3 +++
 src/core/hw/gpu.h         |  3 +++
 src/core/hw/lcd.h         |  3 +++
 src/core/memory.cpp       | 47 +++++++++++++++++++++++----------------
 8 files changed, 68 insertions(+), 20 deletions(-)
 create mode 100644 src/common/pod.h

diff --git a/externals/boost b/externals/boost
index 1acb9699a..d2a5baa1a 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 1acb9699ac8e91654331504cf3524b26463eeee4
+Subproject commit d2a5baa1ad701671a7ef547ef71cb0f0c80ce2cf
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index af07ac215..5abf93dbc 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -84,6 +84,7 @@ add_library(common STATIC
     misc.cpp
     param_package.cpp
     param_package.h
+    pod.h
     quaternion.h
     ring_buffer.h
     scm_rev.cpp
diff --git a/src/common/pod.h b/src/common/pod.h
new file mode 100644
index 000000000..e7224644a
--- /dev/null
+++ b/src/common/pod.h
@@ -0,0 +1,20 @@
+#include "boost/serialization/split_member.hpp"
+
+#define SERIALIZE_AS_POD                                             \
+    private:                                                         \
+    friend class boost::serialization::access;                       \
+    template<typename Archive>                                       \
+    void save(Archive & ar, const unsigned int file_version) const { \
+        ar.save_binary(this, sizeof(*this));                         \
+    }                                                                \
+    template<typename Archive>                                       \
+    void load(Archive & ar, const unsigned int file_version) {       \
+        ar.load_binary(this, sizeof(*this));                         \
+    }                                                                \
+    template<class Archive>                                          \
+    void serialize(                                                  \
+        Archive &ar,                                                 \
+        const unsigned int file_version                              \
+    ){                                                               \
+        boost::serialization::split_member(ar, *this, file_version); \
+    }
diff --git a/src/core/core.h b/src/core/core.h
index 5b7965453..333e4a76c 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -15,6 +15,7 @@
 #include "core/memory.h"
 #include "core/perf_stats.h"
 #include "core/telemetry_session.h"
+class boost::serialization::access;
 
 class ARM_Interface;
 
@@ -338,6 +339,14 @@ private:
 
     std::atomic<bool> reset_requested;
     std::atomic<bool> shutdown_requested;
+
+    friend class boost::serialization::access;
+    template<typename Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & GPU::g_regs;
+        ar & LCD::g_regs;
+    }
 };
 
 inline ARM_Interface& CPU() {
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 1543d7bd8..4168ce36c 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -10,6 +10,7 @@
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
+#include "common/pod.h"
 
 // All the constants in this file come from http://3dbrew.org/wiki/Error_codes
 
@@ -225,6 +226,8 @@ union ResultCode {
     constexpr bool IsError() const {
         return is_error.ExtractValue(raw) == 1;
     }
+
+    SERIALIZE_AS_POD
 };
 
 constexpr bool operator==(const ResultCode& a, const ResultCode& b) {
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 606ab9504..980b48cd7 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -10,6 +10,7 @@
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
+#include "common/pod.h"
 
 namespace Memory {
 class MemorySystem;
@@ -296,6 +297,8 @@ private:
     static inline u32 DecodeAddressRegister(u32 register_value) {
         return register_value * 8;
     }
+
+    SERIALIZE_AS_POD
 };
 static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
 
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index 5e37121f7..ecc9ecea4 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -9,6 +9,7 @@
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
+#include "common/pod.h"
 
 #define LCD_REG_INDEX(field_name) (offsetof(LCD::Regs, field_name) / sizeof(u32))
 
@@ -50,6 +51,8 @@ struct Regs {
         u32* content = reinterpret_cast<u32*>(this);
         return content[index];
     }
+
+    SERIALIZE_AS_POD
 };
 static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
 
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index e5fb83f5a..9ee279129 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -4,7 +4,8 @@
 
 #include <array>
 #include <cstring>
-#include "boost/serialization/split_member.hpp"
+#include "boost/serialization/array.hpp"
+#include "boost/serialization/nvp.hpp"
 #include "audio_core/dsp_interface.h"
 #include "common/archives.h"
 #include "common/assert.h"
@@ -54,6 +55,16 @@ private:
     std::array<bool, VRAM_SIZE / PAGE_SIZE> vram{};
     std::array<bool, LINEAR_HEAP_SIZE / PAGE_SIZE> linear_heap{};
     std::array<bool, NEW_LINEAR_HEAP_SIZE / PAGE_SIZE> new_linear_heap{};
+
+    static_assert(sizeof(bool) == 1); // TODO: Maybe this isn't true?
+    friend class boost::serialization::access;
+    template<typename Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & vram;
+        ar & linear_heap;
+        ar & new_linear_heap;
+    }
 };
 
 class MemorySystem::Impl {
@@ -71,31 +82,29 @@ public:
     AudioCore::DspInterface* dsp = nullptr;
 
 private:
+
+    template<class Archive>
+    void add_blob(Archive & ar, std::unique_ptr<u8[]> & var, const char *name, std::size_t size)
+    {
+        ar & boost::serialization::make_nvp(
+            name,
+            *static_cast<u8 (*)[Memory::FCRAM_N3DS_SIZE]>(static_cast<void *>(var.get()))
+        );
+    }
+
     friend class boost::serialization::access;
     template<class Archive>
-    void save(Archive & ar, const unsigned int file_version) const
+    void serialize(Archive & ar, const unsigned int file_version)
     {
         // TODO: Skip n3ds ram when not used?
-        ar.save_binary(fcram.get(), Memory::FCRAM_N3DS_SIZE);
-        ar.save_binary(vram.get(), Memory::VRAM_SIZE);
-        ar.save_binary(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
-        // ar & cache_marker;
+        add_blob(ar, fcram, "fcram", Memory::FCRAM_N3DS_SIZE);
+        add_blob(ar, vram, "vram", Memory::VRAM_SIZE);
+        add_blob(ar, n3ds_extra_ram, "n3ds_extra_ram", Memory::N3DS_EXTRA_RAM_SIZE);
+        ar & cache_marker;
+        // TODO: How the hell to do page tables..
         // ar & page_table_list;
         // ar & current_page_table;
     }
-
-    template<class Archive>
-    void load(Archive & ar, const unsigned int file_version)
-    {
-        ar.load_binary(fcram.get(), Memory::FCRAM_N3DS_SIZE);
-        ar.load_binary(vram.get(), Memory::VRAM_SIZE);
-        ar.load_binary(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
-        // ar & cache_marker;
-        // ar & page_table_list;
-        // ar & current_page_table;
-    }
-
-    BOOST_SERIALIZATION_SPLIT_MEMBER()
 };
 
 SERIALIZE_IMPL(MemorySystem::Impl)

From ee2cae20931114fb0b6fc7733e70e48930fa80a9 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 7 Aug 2019 02:53:56 +0100
Subject: [PATCH 003/129] Added core serialization

---
 src/audio_core/dsp_interface.h |  1 +
 src/core/core.cpp              | 26 ++++++++++++++++++++++++++
 src/core/core.h                | 12 ++++++------
 src/core/memory.cpp            | 11 +++++++++--
 src/core/memory.h              |  6 +++++-
 5 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h
index fc3d7cab2..29ec13d61 100644
--- a/src/audio_core/dsp_interface.h
+++ b/src/audio_core/dsp_interface.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <vector>
+#include "boost/serialization/array.hpp"
 #include "audio_core/audio_types.h"
 #include "audio_core/time_stretch.h"
 #include "common/common_types.h"
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ebaee4f87..cee6a3866 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -4,9 +4,12 @@
 
 #include <memory>
 #include <utility>
+#include "boost/serialization/array.hpp"
+#include "boost/serialization/unique_ptr.hpp"
 #include "audio_core/dsp_interface.h"
 #include "audio_core/hle/hle.h"
 #include "audio_core/lle/lle.h"
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "common/texture.h"
 #include "core/arm/arm_interface.h"
@@ -30,7 +33,9 @@
 #include "core/hle/service/fs/archive.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/sm/sm.h"
+#include "core/hw/gpu.h"
 #include "core/hw/hw.h"
+#include "core/hw/lcd.h"
 #include "core/loader/loader.h"
 #include "core/movie.h"
 #include "core/rpc/rpc_server.h"
@@ -389,4 +394,25 @@ void System::Reset() {
     Load(*m_emu_window, m_filepath);
 }
 
+template<class Archive>
+void System::serialize(Archive & ar, const unsigned int file_version)
+{
+    ar & memory;
+    ar & GPU::g_regs;
+    ar & LCD::g_regs;
+    ar & dsp_core->GetDspMemory();
+}
+
+void System::Save(std::ostream &stream) const
+{
+    boost::archive::binary_oarchive oa{stream};
+    oa & *this;
+}
+
+void System::Load(std::istream &stream)
+{
+    boost::archive::binary_iarchive ia{stream};
+    ia & *this;
+}
+
 } // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index 333e4a76c..b811badba 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include "boost/serialization/access.hpp"
 #include "common/common_types.h"
 #include "core/custom_tex_cache.h"
 #include "core/frontend/applets/mii_selector.h"
@@ -15,7 +16,6 @@
 #include "core/memory.h"
 #include "core/perf_stats.h"
 #include "core/telemetry_session.h"
-class boost::serialization::access;
 
 class ARM_Interface;
 
@@ -272,6 +272,10 @@ public:
         return registered_image_interface;
     }
 
+    void Save(std::ostream &stream) const;
+
+    void Load(std::istream &stream);
+
 private:
     /**
      * Initialize the emulated system.
@@ -342,11 +346,7 @@ private:
 
     friend class boost::serialization::access;
     template<typename Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & GPU::g_regs;
-        ar & LCD::g_regs;
-    }
+    void serialize(Archive & ar, const unsigned int file_version);
 };
 
 inline ARM_Interface& CPU() {
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 9ee279129..fe33cf767 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -6,6 +6,7 @@
 #include <cstring>
 #include "boost/serialization/array.hpp"
 #include "boost/serialization/nvp.hpp"
+#include "boost/serialization/unique_ptr.hpp"
 #include "audio_core/dsp_interface.h"
 #include "common/archives.h"
 #include "common/assert.h"
@@ -107,11 +108,17 @@ private:
     }
 };
 
-SERIALIZE_IMPL(MemorySystem::Impl)
-
 MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
 MemorySystem::~MemorySystem() = default;
 
+template<class Archive>
+void MemorySystem::serialize(Archive & ar, const unsigned int file_version)
+{
+    ar & impl;
+}
+
+SERIALIZE_IMPL(MemorySystem)
+
 void MemorySystem::SetCurrentPageTable(PageTable* page_table) {
     impl->current_page_table = page_table;
 }
diff --git a/src/core/memory.h b/src/core/memory.h
index e5582d16d..9c1455a80 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -9,7 +9,7 @@
 #include <memory>
 #include <string>
 #include <vector>
-#include "boost/serialization/split_member.hpp"
+#include "boost/serialization/access.hpp"
 #include "common/common_types.h"
 #include "core/mmio.h"
 
@@ -324,6 +324,10 @@ private:
     class Impl;
 
     std::unique_ptr<Impl> impl;
+
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version);
 };
 
 /// Determines if the given VAddr is valid for the specified process.

From 6f00976ab59c8e8960c11a43e5d746146aa2884a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 7 Aug 2019 17:08:52 +0100
Subject: [PATCH 004/129] video_core serialization

---
 src/common/archives.h                | 11 ++--
 src/core/core.cpp                    | 16 +++--
 src/core/hw/gpu.cpp                  |  9 +--
 src/video_core/CMakeLists.txt        |  2 +-
 src/video_core/command_processor.cpp | 13 +++-
 src/video_core/command_processor.h   |  2 +-
 src/video_core/pica_state.h          | 90 ++++++++++++++++++++++++++++
 src/video_core/video_core.cpp        | 16 +++++
 src/video_core/video_core.h          |  4 ++
 9 files changed, 142 insertions(+), 21 deletions(-)

diff --git a/src/common/archives.h b/src/common/archives.h
index 76aa71054..490710d3c 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -1,11 +1,14 @@
 #include "boost/archive/binary_iarchive.hpp"
 #include "boost/archive/binary_oarchive.hpp"
 
-#define SERIALIZE_IMPL(A) template void A::serialize<boost::archive::binary_iarchive>( \
-    boost::archive::binary_iarchive & ar, \
+using iarchive = boost::archive::binary_iarchive;
+using oarchive = boost::archive::binary_oarchive;
+
+#define SERIALIZE_IMPL(A) template void A::serialize<iarchive>( \
+    iarchive & ar, \
     const unsigned int file_version \
 ); \
-template void A::serialize<boost::archive::binary_oarchive>( \
-    boost::archive::binary_oarchive & ar, \
+template void A::serialize<oarchive>( \
+    oarchive & ar, \
     const unsigned int file_version \
 );
diff --git a/src/core/core.cpp b/src/core/core.cpp
index cee6a3866..63730214f 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -397,22 +397,28 @@ void System::Reset() {
 template<class Archive>
 void System::serialize(Archive & ar, const unsigned int file_version)
 {
-    ar & memory;
     ar & GPU::g_regs;
     ar & LCD::g_regs;
     ar & dsp_core->GetDspMemory();
+    ar & memory;
 }
 
 void System::Save(std::ostream &stream) const
 {
-    boost::archive::binary_oarchive oa{stream};
-    oa & *this;
+    {
+        oarchive oa{stream};
+        oa & *this;
+    }
+    VideoCore::Save(stream);
 }
 
 void System::Load(std::istream &stream)
 {
-    boost::archive::binary_iarchive ia{stream};
-    ia & *this;
+    {
+        iarchive ia{stream};
+        ia & *this;
+    }
+    VideoCore::Load(stream);
 }
 
 } // namespace Core
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index fcb60e6fe..b283b7d91 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -472,14 +472,7 @@ inline void Write(u32 addr, const T data) {
         if (config.trigger & 1) {
             MICROPROFILE_SCOPE(GPU_CmdlistProcessing);
 
-            u32* buffer = (u32*)g_memory->GetPhysicalPointer(config.GetPhysicalAddress());
-
-            if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
-                Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size,
-                                                                config.GetPhysicalAddress());
-            }
-
-            Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
+            Pica::CommandProcessor::ProcessCommandList(config.GetPhysicalAddress(), config.size);
 
             g_regs.command_processor_config.trigger = 0;
         }
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 4cb976354..8dbf5d8e0 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -94,7 +94,7 @@ endif()
 create_target_directory_groups(video_core)
 
 target_link_libraries(video_core PUBLIC common core)
-target_link_libraries(video_core PRIVATE glad nihstro-headers)
+target_link_libraries(video_core PRIVATE glad nihstro-headers boost_libs)
 
 if (ARCHITECTURE_x86_64)
     target_link_libraries(video_core PUBLIC xbyak)
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 72f6f2161..3a5b35236 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -640,8 +640,17 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
                                  reinterpret_cast<void*>(&id));
 }
 
-void ProcessCommandList(const u32* list, u32 size) {
-    g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list;
+void ProcessCommandList(PAddr list, u32 size) {
+
+    u32* buffer = (u32*)VideoCore::g_memory->GetPhysicalPointer(list);
+
+    if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
+        Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, size,
+                                                        list);
+    }
+
+    g_state.cmd_list.addr = list;
+    g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = buffer;
     g_state.cmd_list.length = size / sizeof(u32);
 
     while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) {
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
index 82b154327..3b4e05519 100644
--- a/src/video_core/command_processor.h
+++ b/src/video_core/command_processor.h
@@ -32,6 +32,6 @@ static_assert(std::is_standard_layout<CommandHeader>::value == true,
               "CommandHeader does not use standard layout");
 static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
 
-void ProcessCommandList(const u32* list, u32 size);
+void ProcessCommandList(PAddr list, u32 size);
 
 } // namespace Pica::CommandProcessor
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 5a97ae952..1e5b1ecd2 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <array>
+#include "boost/serialization/split_member.hpp"
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "common/vector_math.h"
@@ -13,6 +14,18 @@
 #include "video_core/regs.h"
 #include "video_core/shader/shader.h"
 
+// NB, by defining this we can't use the built-in std::array serializer in this file
+namespace boost::serialization {
+
+template<class Archive, typename Value, size_t Size>
+void serialize(Archive & ar, std::array<Value, Size> &array, const unsigned int version)
+{
+    static_assert(sizeof(Value) == sizeof(u32));
+    ar & *static_cast<u32 (*)[Size]>(static_cast<void *>(array.data()));
+}
+
+}
+
 namespace Pica {
 
 /// Struct used to describe current Pica state
@@ -79,6 +92,18 @@ struct State {
         std::array<ValueEntry, 128> alpha_map_table;
         std::array<ColorEntry, 256> color_table;
         std::array<ColorDifferenceEntry, 256> color_diff_table;
+
+    private:
+        friend class boost::serialization::access;
+        template<class Archive>
+        void serialize(Archive & ar, const unsigned int file_version)
+        {
+            ar & noise_table;
+            ar & color_map_table;
+            ar & alpha_map_table;
+            ar & color_table;
+            ar & color_diff_table;
+        }
     } proctex;
 
     struct Lighting {
@@ -101,6 +126,12 @@ struct State {
                 float diff = static_cast<float>(difference) / 2047.f;
                 return neg_difference ? -diff : diff;
             }
+
+            template<class Archive>
+            void serialize(Archive & ar, const unsigned int file_version)
+            {
+                ar & raw;
+            }
         };
 
         std::array<std::array<LutEntry, 256>, 24> luts;
@@ -126,8 +157,11 @@ struct State {
         std::array<LutEntry, 128> lut;
     } fog;
 
+#undef SERIALIZE_RAW
+
     /// Current Pica command list
     struct {
+        PAddr addr; // This exists only for serialization
         const u32* head_ptr;
         const u32* current_ptr;
         u32 length;
@@ -141,6 +175,17 @@ struct State {
         u32 current_attribute = 0;
         // Indicates the immediate mode just started and the geometry pipeline needs to reconfigure
         bool reset_geometry_pipeline = true;
+
+    private:
+        friend class boost::serialization::access;
+        template<class Archive>
+        void serialize(Archive & ar, const unsigned int file_version)
+        {
+            // ar & input_vertex;
+            ar & current_attribute;
+            ar & reset_geometry_pipeline;
+        }
+
     } immediate;
 
     // the geometry shader needs to be kept in the global state because some shaders relie on
@@ -161,6 +206,51 @@ struct State {
 
     int default_attr_counter = 0;
     u32 default_attr_write_buffer[3]{};
+
+private:
+
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & regs.reg_array;
+        // ar & vs;
+        // ar & gs;
+        // ar & input_default_attributes;
+        ar & proctex;
+        for (auto i = 0; i < lighting.luts.size(); i++) {
+            ar & lighting.luts[i];
+        }
+        ar & fog.lut;
+        ar & cmd_list.addr;
+        ar & cmd_list.length;
+        ar & immediate;
+        // ar & gs_unit;
+        // ar & geometry_pipeline;
+        // ar & primitive_assembler;
+        ar & vs_float_regs_counter;
+        ar & vs_uniform_write_buffer;
+        ar & gs_float_regs_counter;
+        ar & gs_uniform_write_buffer;
+        ar & default_attr_counter;
+        ar & default_attr_write_buffer;
+        boost::serialization::split_member(ar, *this, file_version);
+    }
+
+    template<class Archive>
+    void save(Archive & ar, const unsigned int file_version) const
+    {
+        ar << static_cast<u32>(cmd_list.current_ptr - cmd_list.head_ptr);
+    }
+
+    template<class Archive>
+    void load(Archive & ar, const unsigned int file_version)
+    {
+        u32 offset{};
+        ar >> offset;
+        cmd_list.head_ptr = (u32*)VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr);
+        cmd_list.current_ptr = cmd_list.head_ptr + offset;
+    }
 };
 
 extern State g_state; ///< Current Pica state
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index b7e1d4885..5bc1e8702 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -3,9 +3,11 @@
 // Refer to the license.txt file included.
 
 #include <memory>
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/settings.h"
 #include "video_core/pica.h"
+#include "video_core/pica_state.h"
 #include "video_core/renderer_base.h"
 #include "video_core/renderer_opengl/gl_vars.h"
 #include "video_core/renderer_opengl/renderer_opengl.h"
@@ -85,4 +87,18 @@ u16 GetResolutionScaleFactor() {
     }
 }
 
+void Save(std::ostream &stream)
+{
+    oarchive oa{stream};
+    oa & Pica::g_state;
+}
+
+void Load(std::istream &stream)
+{
+    iarchive ia{stream};
+    ia & Pica::g_state;
+    // TODO: Flush/reset things
+
+}
+
 } // namespace VideoCore
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index f11b67839..1ec69f802 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <iostream>
 #include <atomic>
 #include <memory>
 #include "core/frontend/emu_window.h"
@@ -61,4 +62,7 @@ void RequestScreenshot(void* data, std::function<void()> callback,
 
 u16 GetResolutionScaleFactor();
 
+void Save(std::ostream &stream);
+void Load(std::istream &stream);
+
 } // namespace VideoCore

From 45788b9c825c5361cca5614465fdec64ab7a5cd5 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 8 Aug 2019 05:25:24 +0100
Subject: [PATCH 005/129] Added shader state serialization

---
 src/common/vector_math.h       | 28 ++++++++++++++++++++++++++++
 src/video_core/pica_state.h    | 30 ++++++++++++++++--------------
 src/video_core/pica_types.h    |  8 ++++++++
 src/video_core/shader/shader.h | 24 ++++++++++++++++++++++++
 4 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index ba36744fc..171d4ebfd 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -32,6 +32,7 @@
 
 #include <cmath>
 #include <type_traits>
+#include <boost/serialization/access.hpp>
 
 namespace Common {
 
@@ -44,6 +45,14 @@ class Vec4;
 
 template <typename T>
 class Vec2 {
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & x;
+        ar & y;
+    }
+
 public:
     T x;
     T y;
@@ -191,6 +200,15 @@ inline float Vec2<float>::Normalize() {
 
 template <typename T>
 class Vec3 {
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & x;
+        ar & y;
+        ar & z;
+    }
+
 public:
     T x;
     T y;
@@ -399,6 +417,16 @@ using Vec3f = Vec3<float>;
 
 template <typename T>
 class Vec4 {
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & x;
+        ar & y;
+        ar & z;
+        ar & w;
+    }
+
 public:
     T x;
     T y;
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 1e5b1ecd2..10d1e637b 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -14,11 +14,15 @@
 #include "video_core/regs.h"
 #include "video_core/shader/shader.h"
 
-// NB, by defining this we can't use the built-in std::array serializer in this file
+// Boost::serialization doesn't like union types for some reason,
+// so we need to mark arrays of union values with a special serialization method
+template<typename Value, size_t Size>
+struct UnionArray : public std::array<Value, Size> { };
+
 namespace boost::serialization {
 
 template<class Archive, typename Value, size_t Size>
-void serialize(Archive & ar, std::array<Value, Size> &array, const unsigned int version)
+void serialize(Archive& ar, UnionArray<Value, Size>& array, const unsigned int version)
 {
     static_assert(sizeof(Value) == sizeof(u32));
     ar & *static_cast<u32 (*)[Size]>(static_cast<void *>(array.data()));
@@ -87,11 +91,11 @@ struct State {
             }
         };
 
-        std::array<ValueEntry, 128> noise_table;
-        std::array<ValueEntry, 128> color_map_table;
-        std::array<ValueEntry, 128> alpha_map_table;
-        std::array<ColorEntry, 256> color_table;
-        std::array<ColorDifferenceEntry, 256> color_diff_table;
+        UnionArray<ValueEntry, 128> noise_table;
+        UnionArray<ValueEntry, 128> color_map_table;
+        UnionArray<ValueEntry, 128> alpha_map_table;
+        UnionArray<ColorEntry, 256> color_table;
+        UnionArray<ColorDifferenceEntry, 256> color_diff_table;
 
     private:
         friend class boost::serialization::access;
@@ -134,7 +138,7 @@ struct State {
             }
         };
 
-        std::array<std::array<LutEntry, 256>, 24> luts;
+        std::array<UnionArray<LutEntry, 256>, 24> luts;
     } lighting;
 
     struct {
@@ -154,7 +158,7 @@ struct State {
             }
         };
 
-        std::array<LutEntry, 128> lut;
+        UnionArray<LutEntry, 128> lut;
     } fog;
 
 #undef SERIALIZE_RAW
@@ -214,13 +218,11 @@ private:
     void serialize(Archive & ar, const unsigned int file_version)
     {
         ar & regs.reg_array;
-        // ar & vs;
-        // ar & gs;
+        ar & vs;
+        ar & gs;
         // ar & input_default_attributes;
         ar & proctex;
-        for (auto i = 0; i < lighting.luts.size(); i++) {
-            ar & lighting.luts[i];
-        }
+        ar & lighting.luts;
         ar & fog.lut;
         ar & cmd_list.addr;
         ar & cmd_list.length;
diff --git a/src/video_core/pica_types.h b/src/video_core/pica_types.h
index 5aca37b69..bef256e13 100644
--- a/src/video_core/pica_types.h
+++ b/src/video_core/pica_types.h
@@ -6,6 +6,7 @@
 
 #include <cmath>
 #include <cstring>
+#include <boost/serialization/access.hpp>
 #include "common/common_types.h"
 
 namespace Pica {
@@ -140,6 +141,13 @@ private:
     // Stored as a regular float, merely for convenience
     // TODO: Perform proper arithmetic on this!
     float value;
+
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & value;
+    }
 };
 
 using float24 = Float<16, 7>;
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index bb6a5fae7..3f55d3064 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -9,6 +9,7 @@
 #include <functional>
 #include <type_traits>
 #include <nihstro/shader_bytecode.h>
+#include <boost/serialization/array.hpp>
 #include "common/assert.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
@@ -193,6 +194,16 @@ struct Uniforms {
     static std::size_t GetIntUniformOffset(unsigned index) {
         return offsetof(Uniforms, i) + index * sizeof(Common::Vec4<u8>);
     }
+
+private:
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & f;
+        ar & b;
+        ar & i;
+    }
 };
 
 struct ShaderSetup {
@@ -237,6 +248,19 @@ private:
     bool swizzle_data_hash_dirty = true;
     u64 program_code_hash = 0xDEADC0DE;
     u64 swizzle_data_hash = 0xDEADC0DE;
+
+    friend class boost::serialization::access;
+    template<class Archive>
+    void serialize(Archive & ar, const unsigned int file_version)
+    {
+        ar & uniforms;
+        ar & program_code;
+        ar & swizzle_data;
+        ar & program_code_hash_dirty;
+        ar & swizzle_data_hash_dirty;
+        ar & program_code_hash;
+        ar & swizzle_data_hash;
+    }
 };
 
 class ShaderEngine {

From f79c9668a3a271a5038bb9d55bf32e701c678a11 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 11 Aug 2019 00:20:09 +0100
Subject: [PATCH 006/129] Added shader state; WIP kernel objects

---
 externals/boost                           |   2 +-
 src/common/CMakeLists.txt                 |   2 +
 src/common/serialization/atomic.h         |  28 ++++
 src/common/serialization/boost_vector.hpp | 189 ++++++++++++++++++++++
 src/core/core.cpp                         |   6 +-
 src/core/hle/kernel/client_port.cpp       |   5 +-
 src/core/hle/kernel/client_port.h         |  16 +-
 src/core/hle/kernel/event.h               |  10 ++
 src/core/hle/kernel/handle_table.h        |  12 ++
 src/core/hle/kernel/kernel.cpp            |  23 +++
 src/core/hle/kernel/kernel.h              |   9 ++
 src/core/hle/kernel/memory.h              |  11 ++
 src/core/hle/kernel/mutex.h               |  12 ++
 src/core/hle/kernel/object.cpp            |  12 +-
 src/core/hle/kernel/object.h              |  11 ++
 src/core/hle/kernel/process.cpp           |  14 +-
 src/core/hle/kernel/process.h             |  65 +++++++-
 src/core/hle/kernel/resource_limit.cpp    |   6 +-
 src/core/hle/kernel/resource_limit.h      |  40 ++++-
 src/core/hle/kernel/semaphore.h           |  11 ++
 src/core/hle/kernel/server_port.cpp       |   9 +-
 src/core/hle/kernel/server_port.h         |   2 -
 src/core/hle/kernel/server_session.cpp    |   5 +-
 src/core/hle/kernel/server_session.h      |   2 +-
 src/core/hle/kernel/thread.cpp            |   9 +-
 src/core/hle/kernel/thread.h              |   2 +-
 src/core/hle/kernel/vm_manager.h          |  28 +++-
 src/core/hle/kernel/wait_object.h         |  14 ++
 src/core/hle/service/err_f.cpp            |   1 +
 src/core/memory.cpp                       |  23 +--
 src/core/mmio.h                           |   7 +
 src/video_core/pica_state.h               |   6 +-
 src/video_core/shader/shader.h            |  52 ++++++
 33 files changed, 576 insertions(+), 68 deletions(-)
 create mode 100644 src/common/serialization/atomic.h
 create mode 100644 src/common/serialization/boost_vector.hpp

diff --git a/externals/boost b/externals/boost
index d2a5baa1a..48130d387 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit d2a5baa1ad701671a7ef547ef71cb0f0c80ce2cf
+Subproject commit 48130d387975d17aed1b34ef75c21020f2d710a8
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 5abf93dbc..b0577f9d9 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -90,6 +90,8 @@ add_library(common STATIC
     scm_rev.cpp
     scm_rev.h
     scope_exit.h
+    serialization/atomic.h
+    serialization/boost_vector.hpp
     string_util.cpp
     string_util.h
     swap.h
diff --git a/src/common/serialization/atomic.h b/src/common/serialization/atomic.h
new file mode 100644
index 000000000..ef33202ff
--- /dev/null
+++ b/src/common/serialization/atomic.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <atomic>
+#include <boost/serialization/split_free.hpp>
+
+namespace boost::serialization
+{
+    template <class Archive, class T>
+    void serialize(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
+    {
+        boost::serialization::split_free(ar, value, file_version);
+    }
+
+    template <class Archive, class T>
+    void save(Archive& ar, const std::atomic<T>& value, const unsigned int file_version)
+    {
+        ar << value.load();
+    }
+
+    template <class Archive, class T>
+    void load(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
+    {
+        T tmp;
+        ar >> tmp;
+        value.store(tmp);
+    }
+
+} // namespace boost::serialization
diff --git a/src/common/serialization/boost_vector.hpp b/src/common/serialization/boost_vector.hpp
new file mode 100644
index 000000000..d97ebd208
--- /dev/null
+++ b/src/common/serialization/boost_vector.hpp
@@ -0,0 +1,189 @@
+#ifndef  BOOST_SERIALIZATION_BOOST_VECTOR_HPP
+#define BOOST_SERIALIZATION_BOOST_VECTOR_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// boost_vector.hpp: serialization for boost vector templates
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
+// fast array serialization (C) Copyright 2005 Matthias Troyer
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <boost/container/vector.hpp>
+
+#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
+
+#include <boost/archive/detail/basic_iarchive.hpp>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/serialization/collection_size_type.hpp>
+#include <boost/serialization/item_version_type.hpp>
+
+#include <boost/serialization/collections_save_imp.hpp>
+#include <boost/serialization/collections_load_imp.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/array_wrapper.hpp>
+#include <boost/mpl/bool_fwd.hpp>
+#include <boost/mpl/if.hpp>
+
+// default is being compatible with version 1.34.1 files, not 1.35 files
+#ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
+#define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V==4 || V==5)
+#endif
+
+namespace boost {
+namespace serialization {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// vector< T >
+
+// the default versions
+
+template<class Archive, class U, class Allocator>
+inline void save(
+    Archive & ar,
+    const boost::container::vector<U, Allocator> &t,
+    const unsigned int /* file_version */,
+    mpl::false_
+){
+    boost::serialization::stl::save_collection<Archive, boost::container::vector<U, Allocator> >(
+        ar, t
+    );
+}
+
+template<class Archive, class U, class Allocator>
+inline void load(
+    Archive & ar,
+    boost::container::vector<U, Allocator> &t,
+    const unsigned int /* file_version */,
+    mpl::false_
+){
+    const boost::archive::library_version_type library_version(
+        ar.get_library_version()
+    );
+    // retrieve number of elements
+    item_version_type item_version(0);
+    collection_size_type count;
+    ar >> BOOST_SERIALIZATION_NVP(count);
+    if(boost::archive::library_version_type(3) < library_version){
+        ar >> BOOST_SERIALIZATION_NVP(item_version);
+    }
+    t.reserve(count);
+    stl::collection_load_impl(ar, t, count, item_version);
+}
+
+// the optimized versions
+
+template<class Archive, class U, class Allocator>
+inline void save(
+    Archive & ar,
+    const boost::container::vector<U, Allocator> &t,
+    const unsigned int /* file_version */,
+    mpl::true_
+){
+    const collection_size_type count(t.size());
+    ar << BOOST_SERIALIZATION_NVP(count);
+    if (!t.empty())
+        // explict template arguments to pass intel C++ compiler
+        ar << serialization::make_array<const U, collection_size_type>(
+            static_cast<const U *>(&t[0]),
+            count
+        );
+}
+
+template<class Archive, class U, class Allocator>
+inline void load(
+    Archive & ar,
+    boost::container::vector<U, Allocator> &t,
+    const unsigned int /* file_version */,
+    mpl::true_
+){
+    collection_size_type count(t.size());
+    ar >> BOOST_SERIALIZATION_NVP(count);
+    t.resize(count);
+    unsigned int item_version=0;
+    if(BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) {
+        ar >> BOOST_SERIALIZATION_NVP(item_version);
+    }
+    if (!t.empty())
+        // explict template arguments to pass intel C++ compiler
+        ar >> serialization::make_array<U, collection_size_type>(
+            static_cast<U *>(&t[0]),
+            count
+        );
+  }
+
+// dispatch to either default or optimized versions
+
+template<class Archive, class U, class Allocator>
+inline void save(
+    Archive & ar,
+    const boost::container::vector<U, Allocator> &t,
+    const unsigned int file_version
+){
+    typedef typename
+    boost::serialization::use_array_optimization<Archive>::template apply<
+        typename remove_const<U>::type
+    >::type use_optimized;
+    save(ar,t,file_version, use_optimized());
+}
+
+template<class Archive, class U, class Allocator>
+inline void load(
+    Archive & ar,
+    boost::container::vector<U, Allocator> &t,
+    const unsigned int file_version
+){
+#ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
+    if (ar.get_library_version()==boost::archive::library_version_type(5))
+    {
+      load(ar,t,file_version, boost::is_arithmetic<U>());
+      return;
+    }
+#endif
+    typedef typename
+    boost::serialization::use_array_optimization<Archive>::template apply<
+        typename remove_const<U>::type
+    >::type use_optimized;
+    load(ar,t,file_version, use_optimized());
+}
+
+// split non-intrusive serialization function member into separate
+// non intrusive save/load member functions
+template<class Archive, class U, class Allocator>
+inline void serialize(
+    Archive & ar,
+    boost::container::vector<U, Allocator> & t,
+    const unsigned int file_version
+){
+    boost::serialization::split_free(ar, t, file_version);
+}
+
+// split non-intrusive serialization function member into separate
+// non intrusive save/load member functions
+template<class Archive, class Allocator>
+inline void serialize(
+    Archive & ar,
+    boost::container::vector<bool, Allocator> & t,
+    const unsigned int file_version
+){
+    boost::serialization::split_free(ar, t, file_version);
+}
+
+} // serialization
+} // namespace boost
+
+#include <boost/serialization/collection_traits.hpp>
+
+BOOST_SERIALIZATION_COLLECTION_TRAITS(boost::container::vector)
+
+#endif // BOOST_SERIALIZATION_VECTOR_HPP
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 63730214f..902340d41 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -5,7 +5,6 @@
 #include <memory>
 #include <utility>
 #include "boost/serialization/array.hpp"
-#include "boost/serialization/unique_ptr.hpp"
 #include "audio_core/dsp_interface.h"
 #include "audio_core/hle/hle.h"
 #include "audio_core/lle/lle.h"
@@ -205,6 +204,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
                                                     [this] { PrepareReschedule(); }, system_mode);
+    Kernel::g_kernel = kernel.get();
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -368,6 +368,7 @@ void System::Shutdown() {
     service_manager.reset();
     dsp_core.reset();
     cpu_core.reset();
+    Kernel::g_kernel = nullptr;
     kernel.reset();
     timing.reset();
     app_loader.reset();
@@ -400,7 +401,8 @@ void System::serialize(Archive & ar, const unsigned int file_version)
     ar & GPU::g_regs;
     ar & LCD::g_regs;
     ar & dsp_core->GetDspMemory();
-    ar & memory;
+    ar & *memory.get();
+    ar & *kernel.get();
 }
 
 void System::Save(std::ostream &stream) const
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index d217dfb7c..dc0e08d9d 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -13,9 +13,6 @@
 
 namespace Kernel {
 
-ClientPort::ClientPort(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
-ClientPort::~ClientPort() = default;
-
 ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
     // Note: Threads do not wait for the server endpoint to call
     // AcceptSession before returning from this call.
@@ -26,7 +23,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
     active_sessions++;
 
     // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
-    auto [server, client] = kernel.CreateSessionPair(server_port->GetName(), SharedFrom(this));
+    auto [server, client] = g_kernel->CreateSessionPair(server_port->GetName(), SharedFrom(this));
 
     if (server_port->hle_handler)
         server_port->hle_handler->ClientConnected(server);
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 423db0172..35544e37e 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -17,8 +17,6 @@ class ClientSession;
 
 class ClientPort final : public Object {
 public:
-    explicit ClientPort(KernelSystem& kernel);
-    ~ClientPort() override;
 
     friend class ServerPort;
     std::string GetTypeName() const override {
@@ -52,13 +50,25 @@ public:
     void ConnectionClosed();
 
 private:
-    KernelSystem& kernel;
     std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
     u32 max_sessions = 0;    ///< Maximum number of simultaneous sessions the port can have
     u32 active_sessions = 0; ///< Number of currently open sessions to this port
     std::string name;        ///< Name of client port (optional)
 
     friend class KernelSystem;
+
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        ar & server_port;
+        ar & max_sessions;
+        ar & active_sessions;
+        ar & name;
+    }
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index efc4a0c28..9e9da267a 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -49,6 +49,16 @@ private:
     std::string name; ///< Name of event (optional)
 
     friend class KernelSystem;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<WaitObject>(*this);
+        ar & reset_type;
+        ar & signaled;
+        ar & name;
+    }
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index bd5a5df6a..eabf06c26 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -7,6 +7,8 @@
 #include <array>
 #include <cstddef>
 #include <memory>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/result.h"
@@ -116,6 +118,16 @@ private:
     u16 next_free_slot;
 
     KernelSystem& kernel;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & objects;
+        ar & generations;
+        ar & next_generation;
+        ar & next_free_slot;
+    }
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index ceb2f14f5..d8bd0f034 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
+#include "common/serialization/atomic.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/config_mem.h"
 #include "core/hle/kernel/handle_table.h"
@@ -16,6 +18,8 @@
 
 namespace Kernel {
 
+KernelSystem* g_kernel;
+
 /// Initialize the kernel
 KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
                            std::function<void()> prepare_reschedule_callback, u32 system_mode)
@@ -101,4 +105,23 @@ void KernelSystem::AddNamedPort(std::string name, std::shared_ptr<ClientPort> po
     named_ports.emplace(std::move(name), std::move(port));
 }
 
+template <class Archive>
+void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
+{
+    ar & named_ports;
+    // TODO: CPU
+    // NB: subsystem references and prepare_reschedule_callback are constant
+    ar & *resource_limits.get();
+    ar & next_object_id;
+    //ar & *timer_manager.get();
+    ar & next_process_id;
+    ar & process_list;
+    ar & current_process;
+    // ar & *thread_manager.get();
+    //ar & *config_mem_handler.get();
+    //ar & *shared_page_handler.get();
+}
+
+SERIALIZE_IMPL(KernelSystem)
+
 } // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 58f63938b..c662882f5 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,6 +11,9 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unordered_map.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/result.h"
@@ -283,6 +286,12 @@ private:
     std::unique_ptr<SharedPage::Handler> shared_page_handler;
 
     std::unique_ptr<IPCDebugger::Recorder> ipc_recorder;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 
+extern KernelSystem* g_kernel;
+
 } // namespace Kernel
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
index bb4e174f7..9e9fe5eb4 100644
--- a/src/core/hle/kernel/memory.h
+++ b/src/core/hle/kernel/memory.h
@@ -60,6 +60,17 @@ struct MemoryRegionInfo {
      * @param size the size of the region to free.
      */
     void Free(u32 offset, u32 size);
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & base;
+        ar & size;
+        ar & used;
+        // TODO: boost icl / free_blocks
+    }
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 1f6358909..618685451 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -58,6 +58,18 @@ public:
 
 private:
     KernelSystem& kernel;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<WaitObject>(*this);
+        ar & lock_count;
+        ar & priority;
+        ar & name;
+        ar & holding_thread;
+        ar & kernel; // TODO: Check that this works!
+    }
 };
 
 /**
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index f9ca68218..6ab1b1769 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -8,7 +8,17 @@
 
 namespace Kernel {
 
-Object::Object(KernelSystem& kernel) : object_id{kernel.GenerateObjectID()} {}
+// TODO: Remove this
+Object::Object(KernelSystem& kernel)
+{
+}
+
+Object::Object() = default;
+
+void Object::Init(KernelSystem& kernel)
+{
+    object_id = kernel.GenerateObjectID();
+}
 
 Object::~Object() = default;
 
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index 9547a83ed..8998cb88d 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -7,6 +7,7 @@
 #include <atomic>
 #include <memory>
 #include <string>
+#include <boost/serialization/access.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
 
@@ -41,8 +42,11 @@ enum {
 class Object : NonCopyable, public std::enable_shared_from_this<Object> {
 public:
     explicit Object(KernelSystem& kernel);
+    Object();
     virtual ~Object();
 
+    virtual void Init(KernelSystem& kernel);
+
     /// Returns a unique identifier for the object. For debugging purposes only.
     u32 GetObjectId() const {
         return object_id.load(std::memory_order_relaxed);
@@ -64,6 +68,13 @@ public:
 
 private:
     std::atomic<u32> object_id;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & object_id;
+    }
 };
 
 template <typename T>
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index c6aa2b895..63a5c3b68 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -18,7 +18,8 @@
 namespace Kernel {
 
 std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
-    auto codeset{std::make_shared<CodeSet>(*this)};
+    auto codeset{std::make_shared<CodeSet>()};
+    codeset->Init(*this);
 
     codeset->name = std::move(name);
     codeset->program_id = program_id;
@@ -26,11 +27,9 @@ std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 progr
     return codeset;
 }
 
-CodeSet::CodeSet(KernelSystem& kernel) : Object(kernel) {}
-CodeSet::~CodeSet() {}
-
 std::shared_ptr<Process> KernelSystem::CreateProcess(std::shared_ptr<CodeSet> code_set) {
-    auto process{std::make_shared<Process>(*this)};
+    auto process{std::make_shared<Process>()};
+    process->Init(*this);
 
     process->codeset = std::move(code_set);
     process->flags.raw = 0;
@@ -401,9 +400,8 @@ ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission pe
     return RESULT_SUCCESS;
 }
 
-Kernel::Process::Process(KernelSystem& kernel)
-    : Object(kernel), handle_table(kernel), vm_manager(kernel.memory), kernel(kernel) {
-
+Kernel::Process::Process() : kernel(*g_kernel), handle_table(*g_kernel), vm_manager(g_kernel->memory)
+{
     kernel.memory.RegisterPageTable(&vm_manager.page_table);
 }
 Kernel::Process::~Process() {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index dc2c878b8..6defd42c6 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -11,8 +11,13 @@
 #include <string>
 #include <vector>
 #include <boost/container/static_vector.hpp>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/bitset.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
+#include "common/serialization/boost_vector.hpp"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/vm_manager.h"
@@ -25,6 +30,17 @@ struct AddressMapping {
     u32 size;
     bool read_only;
     bool unk_flag;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & address;
+        ar & size;
+        ar & read_only;
+        ar & unk_flag;
+    }
 };
 
 union ProcessFlags {
@@ -52,13 +68,20 @@ struct MemoryRegionInfo;
 
 class CodeSet final : public Object {
 public:
-    explicit CodeSet(KernelSystem& kernel);
-    ~CodeSet() override;
-
     struct Segment {
         std::size_t offset = 0;
         VAddr addr = 0;
         u32 size = 0;
+
+    private:
+        friend class boost::serialization::access;
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int file_version)
+        {
+            ar & offset;
+            ar & addr;
+            ar & size;
+        }
     };
 
     std::string GetTypeName() const override {
@@ -106,11 +129,24 @@ public:
     std::string name;
     /// Title ID corresponding to the process
     u64 program_id;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        // TODO: memory reference
+        ar & segments;
+        ar & entrypoint;
+        ar & name;
+        ar & program_id;
+    }
 };
 
 class Process final : public Object {
 public:
-    explicit Process(Kernel::KernelSystem& kernel);
+    explicit Process();
     ~Process() override;
 
     std::string GetTypeName() const override {
@@ -195,5 +231,26 @@ public:
 
 private:
     KernelSystem& kernel;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        ar & handle_table;
+        ar & codeset;
+        ar & resource_limit;
+        ar & svc_access_mask;
+        ar & handle_table_size;
+        ar & (boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8> >&)address_mappings;
+        ar & flags.raw;
+        ar & kernel_version;
+        ar & ideal_processor;
+        ar & process_id;
+        ar & vm_manager;
+        ar & memory_used;
+        ar & memory_region;
+        ar & tls_slots;
+    }
 };
 } // namespace Kernel
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 8691c142e..fe19caff9 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -9,11 +9,9 @@
 
 namespace Kernel {
 
-ResourceLimit::ResourceLimit(KernelSystem& kernel) : Object(kernel) {}
-ResourceLimit::~ResourceLimit() {}
-
 std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelSystem& kernel, std::string name) {
-    auto resource_limit{std::make_shared<ResourceLimit>(kernel)};
+    auto resource_limit{std::make_shared<ResourceLimit>()};
+    resource_limit->Init(kernel);
 
     resource_limit->name = std::move(name);
     return resource_limit;
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 99ae8f2cf..06fe71587 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -6,6 +6,8 @@
 
 #include <array>
 #include <memory>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 
@@ -33,8 +35,6 @@ enum ResourceTypes {
 
 class ResourceLimit final : public Object {
 public:
-    explicit ResourceLimit(KernelSystem& kernel);
-    ~ResourceLimit() override;
 
     /**
      * Creates a resource limit object.
@@ -110,6 +110,35 @@ public:
 
     /// Current CPU time that the processes in this category are utilizing
     s32 current_cpu_time = 0;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        // NB most of these aren't used at all currently, but we're adding them here for forwards compatibility
+        ar & name;
+        ar & max_priority;
+        ar & max_commit;
+        ar & max_threads;
+        ar & max_events;
+        ar & max_mutexes;
+        ar & max_semaphores;
+        ar & max_timers;
+        ar & max_shared_mems;
+        ar & max_address_arbiters;
+        ar & max_cpu_time;
+        ar & current_commit;
+        ar & current_threads;
+        ar & current_events;
+        ar & current_mutexes;
+        ar & current_semaphores;
+        ar & current_timers;
+        ar & current_shared_mems;
+        ar & current_address_arbiters;
+        ar & current_cpu_time;
+    }
 };
 
 class ResourceLimitList {
@@ -126,6 +155,13 @@ public:
 
 private:
     std::array<std::shared_ptr<ResourceLimit>, 4> resource_limits;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & resource_limits;
+    }
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index 47b3eabf1..526be6812 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -43,6 +43,17 @@ public:
      * @return The number of free slots the semaphore had before this call
      */
     ResultVal<s32> Release(s32 release_count);
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<WaitObject>(*this);
+        ar & max_count;
+        ar & available_count;
+        ar & name;
+    }
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index a69b42778..ca4cded3d 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -13,9 +13,6 @@
 
 namespace Kernel {
 
-ServerPort::ServerPort(KernelSystem& kernel) : WaitObject(kernel) {}
-ServerPort::~ServerPort() {}
-
 ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
     if (pending_sessions.empty()) {
         return ERR_NO_PENDING_SESSIONS;
@@ -36,8 +33,10 @@ void ServerPort::Acquire(Thread* thread) {
 }
 
 KernelSystem::PortPair KernelSystem::CreatePortPair(u32 max_sessions, std::string name) {
-    auto server_port{std::make_shared<ServerPort>(*this)};
-    auto client_port{std::make_shared<ClientPort>(*this)};
+    auto server_port{std::make_shared<ServerPort>()};
+    server_port->Init(*this);
+    auto client_port{std::make_shared<ClientPort>()};
+    client_port->Init(*this);
 
     server_port->name = name + "_Server";
     client_port->name = name + "_Client";
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 9b0f13480..c500fd1b2 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -20,8 +20,6 @@ class SessionRequestHandler;
 
 class ServerPort final : public WaitObject {
 public:
-    explicit ServerPort(KernelSystem& kernel);
-    ~ServerPort() override;
 
     std::string GetTypeName() const override {
         return "ServerPort";
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 5855d83a5..c6a6261a5 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -13,7 +13,7 @@
 
 namespace Kernel {
 
-ServerSession::ServerSession(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
+ServerSession::ServerSession() : kernel(*g_kernel) {}
 ServerSession::~ServerSession() {
     // This destructor will be called automatically when the last ServerSession handle is closed by
     // the emulated application.
@@ -30,7 +30,8 @@ ServerSession::~ServerSession() {
 
 ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelSystem& kernel,
                                                                 std::string name) {
-    auto server_session{std::make_shared<ServerSession>(kernel)};
+    auto server_session{std::make_shared<ServerSession>()};
+    server_session->Init(kernel);
 
     server_session->name = std::move(name);
     server_session->parent = nullptr;
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 940f38f9b..3536bcbd1 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -38,7 +38,7 @@ class Thread;
 class ServerSession final : public WaitObject {
 public:
     ~ServerSession() override;
-    explicit ServerSession(KernelSystem& kernel);
+    explicit ServerSession();
 
     std::string GetName() const override {
         return name;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 3b15ec35e..4c2344dcb 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -37,9 +37,9 @@ u32 ThreadManager::NewThreadId() {
     return next_thread_id++;
 }
 
-Thread::Thread(KernelSystem& kernel)
-    : WaitObject(kernel), context(kernel.GetThreadManager().NewContext()),
-      thread_manager(kernel.GetThreadManager()) {}
+Thread::Thread()
+    : context(g_kernel->GetThreadManager().NewContext()),
+      thread_manager(g_kernel->GetThreadManager()) {}
 Thread::~Thread() {}
 
 Thread* ThreadManager::GetCurrentThread() const {
@@ -309,7 +309,8 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
                           ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
     }
 
-    auto thread{std::make_shared<Thread>(*this)};
+    auto thread{std::make_shared<Thread>()};
+    thread->Init(*this);
 
     thread_manager->thread_list.push_back(thread);
     thread_manager->ready_queue.prepare(priority);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index f2ef767ef..2db5dda91 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -149,7 +149,7 @@ private:
 
 class Thread final : public WaitObject {
 public:
-    explicit Thread(KernelSystem&);
+    explicit Thread();
     ~Thread() override;
 
     std::string GetName() const override {
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 0d3ae1e44..6711c9b4d 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -8,7 +8,8 @@
 #include <memory>
 #include <utility>
 #include <vector>
-#include "boost/serialization/split_member.hpp"
+#include <boost/serialization/map.hpp>
+#include <boost/serialization/split_member.hpp>
 #include "common/common_types.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
@@ -81,6 +82,21 @@ struct VirtualMemoryArea {
 
     /// Tests if this area can be merged to the right with `next`.
     bool CanBeMergedWith(const VirtualMemoryArea& next) const;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & base;
+        ar & size;
+        ar & type;
+        ar & permissions;
+        ar & meminfo_state;
+        // TODO: backing memory ref
+        ar & paddr;
+        ar & mmio_handler;
+    }
 };
 
 /**
@@ -195,9 +211,10 @@ public:
 
 private:
     friend class boost::serialization::access;
-    template<class Archive>
-    void save(Archive & ar, const unsigned int file_version)
+    template <class Archive>
+    void save(Archive& ar, const unsigned int file_version) const
     {
+        ar & vma_map;
         for (int i = 0; i < page_table.pointers.size(); i++) {
             ar << memory.GetFCRAMOffset(page_table.pointers[i]);
         }
@@ -205,9 +222,10 @@ private:
         ar & page_table.attributes;
     }
 
-    template<class Archive>
-    void load(Archive & ar, const unsigned int file_version)
+    template <class Archive>
+    void load(Archive& ar, const unsigned int file_version)
     {
+        ar & vma_map;
         for (int i = 0; i < page_table.pointers.size(); i++) {
             u32 offset{};
             ar >> offset;
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index 41e803515..e08997721 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -7,6 +7,9 @@
 #include <functional>
 #include <memory>
 #include <vector>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 
@@ -62,6 +65,17 @@ private:
 
     /// Function to call when this object becomes available
     std::function<void()> hle_notifier;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        ar & waiting_threads;
+        // NB: hle_notifier *not* serialized since it's a callback!
+        // Fortunately it's only used in one place (DSP) so we can reconstruct it there
+    }
 };
 
 // Specialization of DynamicObjectCast for WaitObjects
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 13b2c7e46..b218eb793 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -14,6 +14,7 @@
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/result.h"
 #include "core/hle/service/err_f.h"
+#undef exception_info
 
 namespace Service::ERR {
 
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index fe33cf767..a07cc2e13 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -5,8 +5,7 @@
 #include <array>
 #include <cstring>
 #include "boost/serialization/array.hpp"
-#include "boost/serialization/nvp.hpp"
-#include "boost/serialization/unique_ptr.hpp"
+#include "boost/serialization/binary_object.hpp"
 #include "audio_core/dsp_interface.h"
 #include "common/archives.h"
 #include "common/assert.h"
@@ -84,23 +83,17 @@ public:
 
 private:
 
-    template<class Archive>
-    void add_blob(Archive & ar, std::unique_ptr<u8[]> & var, const char *name, std::size_t size)
-    {
-        ar & boost::serialization::make_nvp(
-            name,
-            *static_cast<u8 (*)[Memory::FCRAM_N3DS_SIZE]>(static_cast<void *>(var.get()))
-        );
-    }
-
     friend class boost::serialization::access;
     template<class Archive>
     void serialize(Archive & ar, const unsigned int file_version)
     {
         // TODO: Skip n3ds ram when not used?
-        add_blob(ar, fcram, "fcram", Memory::FCRAM_N3DS_SIZE);
-        add_blob(ar, vram, "vram", Memory::VRAM_SIZE);
-        add_blob(ar, n3ds_extra_ram, "n3ds_extra_ram", Memory::N3DS_EXTRA_RAM_SIZE);
+        auto s_fcram = boost::serialization::binary_object(fcram.get(), Memory::FCRAM_N3DS_SIZE);
+        auto s_vram = boost::serialization::binary_object(vram.get(), Memory::VRAM_SIZE);
+        auto s_extra = boost::serialization::binary_object(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
+        ar & s_fcram;
+        ar & s_vram;
+        ar & s_extra;
         ar & cache_marker;
         // TODO: How the hell to do page tables..
         // ar & page_table_list;
@@ -114,7 +107,7 @@ MemorySystem::~MemorySystem() = default;
 template<class Archive>
 void MemorySystem::serialize(Archive & ar, const unsigned int file_version)
 {
-    ar & impl;
+    ar & *impl.get();
 }
 
 SERIALIZE_IMPL(MemorySystem)
diff --git a/src/core/mmio.h b/src/core/mmio.h
index 30bafaf5f..0a8249c9a 100644
--- a/src/core/mmio.h
+++ b/src/core/mmio.h
@@ -32,6 +32,13 @@ public:
     virtual void Write64(VAddr addr, u64 data) = 0;
 
     virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+    }
 };
 
 using MMIORegionPointer = std::shared_ptr<MMIORegion>;
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 10d1e637b..376865397 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -161,8 +161,6 @@ struct State {
         UnionArray<LutEntry, 128> lut;
     } fog;
 
-#undef SERIALIZE_RAW
-
     /// Current Pica command list
     struct {
         PAddr addr; // This exists only for serialization
@@ -185,7 +183,7 @@ struct State {
         template<class Archive>
         void serialize(Archive & ar, const unsigned int file_version)
         {
-            // ar & input_vertex;
+            ar & input_vertex;
             ar & current_attribute;
             ar & reset_geometry_pipeline;
         }
@@ -220,7 +218,7 @@ private:
         ar & regs.reg_array;
         ar & vs;
         ar & gs;
-        // ar & input_default_attributes;
+        ar & input_default_attributes;
         ar & proctex;
         ar & lighting.luts;
         ar & fog.lut;
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 3f55d3064..1a0f6ef8a 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -10,6 +10,7 @@
 #include <type_traits>
 #include <nihstro/shader_bytecode.h>
 #include <boost/serialization/array.hpp>
+#include <boost/serialization/base_object.hpp>
 #include "common/assert.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
@@ -32,6 +33,14 @@ using SwizzleData = std::array<u32, MAX_SWIZZLE_DATA_LENGTH>;
 
 struct AttributeBuffer {
     alignas(16) Common::Vec4<float24> attr[16];
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & attr;
+    }
 };
 
 /// Handler type for receiving vertex outputs from vertex shader or geometry shader
@@ -91,6 +100,19 @@ struct GSEmitter {
     GSEmitter();
     ~GSEmitter();
     void Emit(Common::Vec4<float24> (&output_regs)[16]);
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & buffer;
+        ar & vertex_id;
+        ar & prim_emit;
+        ar & winding;
+        ar & output_mask;
+        // Handlers are ignored because they're constant
+    }
 };
 static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type");
 
@@ -108,6 +130,16 @@ struct UnitState {
         alignas(16) Common::Vec4<float24> input[16];
         alignas(16) Common::Vec4<float24> temporary[16];
         alignas(16) Common::Vec4<float24> output[16];
+
+    private:
+        friend class boost::serialization::access;
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int file_version)
+        {
+            ar & input;
+            ar & temporary;
+            ar & output;
+        }
     } registers;
     static_assert(std::is_pod<Registers>::value, "Structure is not POD");
 
@@ -160,6 +192,17 @@ struct UnitState {
     void LoadInput(const ShaderRegs& config, const AttributeBuffer& input);
 
     void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & registers;
+        ar & conditional_code;
+        ar & address_registers;
+        // TODO: emitter_ptr
+    }
 };
 
 /**
@@ -173,6 +216,15 @@ struct GSUnitState : public UnitState {
     void ConfigOutput(const ShaderRegs& config);
 
     GSEmitter emitter;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<UnitState>(*this);
+        ar & emitter;
+    }
 };
 
 struct Uniforms {

From 5035e68dadbdef6c8e6d5b856f8d15462a515faf Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 11 Aug 2019 15:19:45 +0100
Subject: [PATCH 007/129] Added derived kernel objects

---
 externals/boost                         |  2 +-
 src/common/archives.h                   |  5 +++++
 src/core/hle/kernel/address_arbiter.cpp |  8 ++++++--
 src/core/hle/kernel/address_arbiter.h   | 17 ++++++++++++++++-
 src/core/hle/kernel/object.h            |  1 +
 5 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/externals/boost b/externals/boost
index 48130d387..19ccdcc6f 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 48130d387975d17aed1b34ef75c21020f2d710a8
+Subproject commit 19ccdcc6fbd026f98ed83dea32ff0398120fbb32
diff --git a/src/common/archives.h b/src/common/archives.h
index 490710d3c..f30886d90 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -12,3 +12,8 @@ template void A::serialize<oarchive>( \
     oarchive & ar, \
     const unsigned int file_version \
 );
+
+#define SERIALIZE_EXPORT_IMPL(A) \
+BOOST_SERIALIZATION_REGISTER_ARCHIVE(iarchive) \
+BOOST_SERIALIZATION_REGISTER_ARCHIVE(oarchive) \
+BOOST_CLASS_EXPORT_IMPLEMENT(A)
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index e52c0f272..c4fb4fd99 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "core/hle/kernel/address_arbiter.h"
@@ -14,6 +15,8 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Kernel namespace
 
+SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter)
+
 namespace Kernel {
 
 void AddressArbiter::WaitThread(std::shared_ptr<Thread> thread, VAddr wait_address) {
@@ -65,11 +68,12 @@ std::shared_ptr<Thread> AddressArbiter::ResumeHighestPriorityThread(VAddr addres
     return thread;
 }
 
-AddressArbiter::AddressArbiter(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
+AddressArbiter::AddressArbiter() : kernel(*g_kernel) {}
 AddressArbiter::~AddressArbiter() {}
 
 std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string name) {
-    auto address_arbiter{std::make_shared<AddressArbiter>(*this)};
+    auto address_arbiter{std::make_shared<AddressArbiter>()};
+    address_arbiter->Init(*this);
 
     address_arbiter->name = std::move(name);
 
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index a4aff6a6e..3b29a84a4 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -6,6 +6,10 @@
 
 #include <memory>
 #include <vector>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/result.h"
@@ -32,7 +36,7 @@ enum class ArbitrationType : u32 {
 
 class AddressArbiter final : public Object {
 public:
-    explicit AddressArbiter(KernelSystem& kernel);
+    explicit AddressArbiter();
     ~AddressArbiter() override;
 
     std::string GetTypeName() const override {
@@ -67,6 +71,17 @@ private:
 
     /// Threads waiting for the address arbiter to be signaled.
     std::vector<std::shared_ptr<Thread>> waiting_threads;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        ar & name;
+        ar & waiting_threads;
+    }
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter)
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index 8998cb88d..6adba034e 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 #include <boost/serialization/access.hpp>
+#include "common/serialization/atomic.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
 

From 06891d94542fcf5ec6e1c45435df097d48b8ca77 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 11 Aug 2019 22:29:00 +0100
Subject: [PATCH 008/129] Added client/server objects

---
 src/core/CMakeLists.txt                |  1 +
 src/core/hle/kernel/client_port.cpp    |  3 +++
 src/core/hle/kernel/client_port.h      |  3 +++
 src/core/hle/kernel/client_session.cpp |  6 ++++--
 src/core/hle/kernel/client_session.h   | 17 ++++++++++++++++-
 src/core/hle/kernel/server_port.cpp    |  3 +++
 src/core/hle/kernel/server_port.h      | 18 ++++++++++++++++++
 src/core/hle/kernel/server_session.cpp |  7 +++++--
 src/core/hle/kernel/server_session.h   | 19 +++++++++++++++++++
 src/core/hle/kernel/session.cpp        | 18 +++++++++++++++---
 src/core/hle/kernel/session.h          |  6 ++++++
 11 files changed, 93 insertions(+), 8 deletions(-)

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index ed2642431..9ed9a856d 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -162,6 +162,7 @@ add_library(core STATIC
     hle/kernel/server_session.cpp
     hle/kernel/server_session.h
     hle/kernel/session.h
+    hle/kernel/session.cpp
     hle/kernel/shared_memory.cpp
     hle/kernel/shared_memory.h
     hle/kernel/shared_page.cpp
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index dc0e08d9d..3334a278b 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "common/assert.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/client_session.h"
@@ -11,6 +12,8 @@
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::ClientPort)
+
 namespace Kernel {
 
 ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 35544e37e..72cae85c3 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
@@ -72,3 +73,5 @@ private:
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::ClientPort)
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 3e76f1a4e..ba9c2ec50 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -3,7 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "common/assert.h"
-
+#include "common/archives.h"
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/hle_ipc.h"
@@ -11,9 +11,11 @@
 #include "core/hle/kernel/session.h"
 #include "core/hle/kernel/thread.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::ClientSession)
+
 namespace Kernel {
 
-ClientSession::ClientSession(KernelSystem& kernel) : Object(kernel) {}
+ClientSession::ClientSession() = default;
 ClientSession::~ClientSession() {
     // This destructor will be called automatically when the last ClientSession handle is closed by
     // the emulated application.
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index de2c7b0ba..2ffe68f8b 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -6,6 +6,9 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/result.h"
@@ -17,7 +20,7 @@ class Thread;
 
 class ClientSession final : public Object {
 public:
-    explicit ClientSession(KernelSystem& kernel);
+    explicit ClientSession();
     ~ClientSession() override;
 
     friend class KernelSystem;
@@ -46,6 +49,18 @@ public:
 
     /// The parent session, which links to the server endpoint.
     std::shared_ptr<Session> parent;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        ar & name;
+        ar & parent;
+    }
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::ClientSession)
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index ca4cded3d..191b43ea8 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <tuple>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/errors.h"
@@ -11,6 +12,8 @@
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/thread.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::ServerPort)
+
 namespace Kernel {
 
 ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index c500fd1b2..e0014ee7c 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -7,8 +7,13 @@
 #include <memory>
 #include <string>
 #include <tuple>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
+#include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/wait_object.h"
 #include "core/hle/result.h"
 
@@ -58,6 +63,19 @@ public:
 
     bool ShouldWait(const Thread* thread) const override;
     void Acquire(Thread* thread) override;
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        ar & name;
+        ar & pending_sessions;
+        //ar & hle_handler;
+    }
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::ServerPort)
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index c6a6261a5..f2ceb899e 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -3,7 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <tuple>
-
+#include "common/archives.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/hle_ipc.h"
@@ -11,6 +11,8 @@
 #include "core/hle/kernel/session.h"
 #include "core/hle/kernel/thread.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::ServerSession)
+
 namespace Kernel {
 
 ServerSession::ServerSession() : kernel(*g_kernel) {}
@@ -124,7 +126,8 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
 KernelSystem::SessionPair KernelSystem::CreateSessionPair(const std::string& name,
                                                           std::shared_ptr<ClientPort> port) {
     auto server_session = ServerSession::Create(*this, name + "_Server").Unwrap();
-    auto client_session{std::make_shared<ClientSession>(*this)};
+    auto client_session{std::make_shared<ClientSession>()};
+    client_session->Init(*this);
     client_session->name = name + "_Client";
 
     std::shared_ptr<Session> parent(new Session);
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 3536bcbd1..6112eefac 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -6,10 +6,14 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/ipc.h"
 #include "core/hle/kernel/object.h"
+#include "core/hle/kernel/session.h"
 #include "core/hle/kernel/wait_object.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
@@ -103,6 +107,21 @@ private:
 
     friend class KernelSystem;
     KernelSystem& kernel;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & boost::serialization::base_object<Object>(*this);
+        ar & name;
+        ar & parent;
+        //ar & hle_handler;
+        ar & pending_requesting_threads;
+        ar & currently_handling;
+        //ar & mapped_buffer_context;
+    }
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::ServerSession)
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index 642914744..f264c49bd 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -2,11 +2,23 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/shared_ptr.hpp>
+#include "common/archives.h"
 #include "core/hle/kernel/session.h"
-#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/client_port.h"
+
+SERIALIZE_IMPL(Kernel::Session)
 
 namespace Kernel {
 
-Session::Session() {}
-Session::~Session() {}
+template <class Archive>
+void Session::serialize(Archive& ar, const unsigned int file_version)
+{
+    ar & client;
+    ar & server;
+    ar & port;
+}
+
 } // namespace Kernel
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 17bb4d6c6..eca1a9252 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/access.hpp>
 #include "core/hle/kernel/object.h"
 
 namespace Kernel {
@@ -24,5 +25,10 @@ public:
     ClientSession* client = nullptr;  ///< The client endpoint of the session.
     ServerSession* server = nullptr;  ///< The server endpoint of the session.
     std::shared_ptr<ClientPort> port; ///< The port that this session is associated with (optional).
+
+private:
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 } // namespace Kernel

From f557d26b40d4cc034bd9599b801ef5bf524d537c Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 12 Aug 2019 17:01:33 +0100
Subject: [PATCH 009/129] Added CPU, mutex, process, thread, timer

---
 externals/boost                           |   2 +-
 src/common/CMakeLists.txt                 |   1 +
 src/common/serialization/boost_flat_set.h |  37 ++++++++
 src/common/thread_queue_list.h            |  31 +++++++
 src/core/arm/arm_interface.h              | 102 +++++++++++++++++++++-
 src/core/arm/dynarmic/arm_dynarmic.cpp    |   2 +-
 src/core/arm/dynarmic/arm_dynarmic.h      |   2 +-
 src/core/arm/dyncom/arm_dyncom.cpp        |   2 +-
 src/core/arm/dyncom/arm_dyncom.h          |   2 +-
 src/core/hle/kernel/config_mem.h          |   9 ++
 src/core/hle/kernel/kernel.cpp            |  10 +--
 src/core/hle/kernel/mutex.cpp             |   5 +-
 src/core/hle/kernel/mutex.h               |   3 +-
 src/core/hle/kernel/process.cpp           |  26 ++++++
 src/core/hle/kernel/process.h             |  24 +----
 src/core/hle/kernel/shared_page.h         |   9 ++
 src/core/hle/kernel/thread.cpp            |  26 ++++++
 src/core/hle/kernel/thread.h              |  18 ++++
 src/core/hle/kernel/timer.cpp             |   6 +-
 src/core/hle/kernel/timer.h               |  23 ++++-
 20 files changed, 299 insertions(+), 41 deletions(-)
 create mode 100644 src/common/serialization/boost_flat_set.h

diff --git a/externals/boost b/externals/boost
index 19ccdcc6f..f4850c297 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 19ccdcc6fbd026f98ed83dea32ff0398120fbb32
+Subproject commit f4850c2975a0d977b7479664b8d4a6f03300a042
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index b0577f9d9..c0182ed48 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -91,6 +91,7 @@ add_library(common STATIC
     scm_rev.h
     scope_exit.h
     serialization/atomic.h
+    serialization/boost_flat_set.h
     serialization/boost_vector.hpp
     string_util.cpp
     string_util.h
diff --git a/src/common/serialization/boost_flat_set.h b/src/common/serialization/boost_flat_set.h
new file mode 100644
index 000000000..9a0ae77b0
--- /dev/null
+++ b/src/common/serialization/boost_flat_set.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "common/common_types.h"
+#include <boost/container/flat_set.hpp>
+#include <boost/serialization/split_free.hpp>
+
+namespace boost::serialization {
+
+template <class Archive, class T>
+void save(Archive& ar, const boost::container::flat_set<T>& set, const unsigned int file_version)
+{
+    ar << static_cast<u64>(set.size());
+    for (auto &v : set) {
+        ar << v;
+    }
+}
+
+template <class Archive, class T>
+void load(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version)
+{
+    u64 count{};
+    ar >> count;
+    set.clear();
+    for (auto i = 0; i < count; i++) {
+        T value{};
+        ar >> value;
+        set.insert(value);
+    }
+}
+
+template <class Archive, class T>
+void serialize(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version)
+{
+    boost::serialization::split_free(ar, set, file_version);
+}
+
+}
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 3e3d04b4d..ce57c01e9 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -6,6 +6,9 @@
 
 #include <array>
 #include <deque>
+#include <boost/serialization/deque.hpp>
+#include <boost/serialization/split_member.hpp>
+#include "common/common_types.h"
 
 namespace Common {
 
@@ -156,6 +159,34 @@ private:
     Queue* first;
     // The priority level queues of thread ids.
     std::array<Queue, NUM_QUEUES> queues;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void save(Archive& ar, const unsigned int file_version) const
+    {
+        s32 idx = first == UnlinkedTag() ? -1 : static_cast<s32>(first - &queues[0]);
+        ar << idx;
+        for (auto i = 0; i < NUM_QUEUES; i++) {
+            s32 idx1 = first == UnlinkedTag() ? -1 : static_cast<s32>(queues[i].next_nonempty - &queues[0]);
+            ar << idx1;
+            ar << queues[i].data;
+        }
+    }
+
+    template <class Archive>
+    void load(Archive& ar, const unsigned int file_version)
+    {
+        s32 idx;
+        ar >> idx;
+        first = idx < 0 ? UnlinkedTag() : &queues[idx];
+        for (auto i = 0; i < NUM_QUEUES; i++) {
+            ar >> idx;
+            queues[i].next_nonempty = idx < 0 ? UnlinkedTag() : &queues[idx];
+            ar >> queues[i].data;
+        }
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
 };
 
 } // namespace Common
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 6e6da8626..483ba4371 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -6,6 +6,7 @@
 
 #include <cstddef>
 #include <memory>
+#include <boost/serialization/split_member.hpp>
 #include "common/common_types.h"
 #include "core/arm/skyeye_common/arm_regformat.h"
 #include "core/arm/skyeye_common/vfp/asm_vfp.h"
@@ -16,6 +17,48 @@ public:
     virtual ~ARM_Interface() {}
 
     class ThreadContext {
+        friend class boost::serialization::access;
+
+        template <class Archive>
+        void save(Archive& ar, const unsigned int file_version) const
+        {
+            for (auto i = 0; i < 16; i++) {
+                auto r = GetCpuRegister(i);
+                ar << r;
+            }
+            for (auto i = 0; i < 16; i++) {
+                auto r = GetFpuRegister(i);
+                ar << r;
+            }
+            auto r1 = GetCpsr();
+            ar << r1;
+            auto r2 = GetFpscr();
+            ar << r2;
+            auto r3 = GetFpexc();
+            ar << r3;
+        }
+
+        template <class Archive>
+        void load(Archive& ar, const unsigned int file_version)
+        {
+            u32 r;
+            for (auto i = 0; i < 16; i++) {
+                ar >> r;
+                SetCpuRegister(i, r);
+            }
+            for (auto i = 0; i < 16; i++) {
+                ar >> r;
+                SetFpuRegister(i, r);
+            }
+            ar >> r;
+            SetCpsr(r);
+            ar >> r;
+            SetFpscr(r);
+            ar >> r;
+            SetFpexc(r);
+        }
+
+        BOOST_SERIALIZATION_SPLIT_MEMBER()
     public:
         virtual ~ThreadContext() = default;
 
@@ -143,7 +186,7 @@ public:
      * @param reg The CP15 register to retrieve the value from.
      * @return the value stored in the given CP15 register.
      */
-    virtual u32 GetCP15Register(CP15Register reg) = 0;
+    virtual u32 GetCP15Register(CP15Register reg) const = 0;
 
     /**
      * Stores the given value into the indicated CP15 register.
@@ -172,4 +215,61 @@ public:
 
     /// Prepare core for thread reschedule (if needed to correctly handle state)
     virtual void PrepareReschedule() = 0;
+
+private:
+    friend class boost::serialization::access;
+
+    template <class Archive>
+    void save(Archive& ar, const unsigned int file_version) const
+    {
+        for (auto i = 0; i < 15; i++) {
+            auto r = GetReg(i);
+            ar << r;
+        }
+        auto pc = GetPC();
+        ar << pc;
+        auto cpsr = GetCPSR();
+        ar << cpsr;
+        for (auto i = 0; i < 32; i++) {
+            auto r = GetVFPReg(i);
+            ar << r;
+        }
+        for (auto i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
+            auto r = GetVFPSystemReg(static_cast<VFPSystemRegister>(i));
+            ar << r;
+        }
+        for (auto i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
+            auto r = GetCP15Register(static_cast<CP15Register>(i));
+            ar << r;
+        }
+    }
+
+    template <class Archive>
+    void load(Archive& ar, const unsigned int file_version)
+    {
+        u32 r;
+        for (auto i = 0; i < 15; i++) {
+            ar >> r;
+            SetReg(i, r);
+        }
+        ar >> r;
+        SetPC(r);
+        ar >> r;
+        SetCPSR(r);
+        for (auto i = 0; i < 32; i++) {
+            ar >> r;
+            SetVFPReg(i, r);
+        }
+        for (auto i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
+            ar >> r;
+            SetVFPSystemReg(static_cast<VFPSystemRegister>(i), r);
+        }
+        for (auto i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
+            ar >> r;
+            SetCP15Register(static_cast<CP15Register>(i), r);
+        }
+        // TODO: Clear caches etc?
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
 };
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index f494b5228..a422db6af 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -235,7 +235,7 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) {
     jit->SetCpsr(cpsr);
 }
 
-u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) {
+u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const {
     return interpreter_state->CP15[reg];
 }
 
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 559dbf5a8..ff9a104b5 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -40,7 +40,7 @@ public:
     void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override;
     u32 GetCPSR() const override;
     void SetCPSR(u32 cpsr) override;
-    u32 GetCP15Register(CP15Register reg) override;
+    u32 GetCP15Register(CP15Register reg) const override;
     void SetCP15Register(CP15Register reg, u32 value) override;
 
     std::unique_ptr<ThreadContext> NewContext() const override;
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index d54b0cb95..6b67644e7 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -138,7 +138,7 @@ void ARM_DynCom::SetCPSR(u32 cpsr) {
     state->Cpsr = cpsr;
 }
 
-u32 ARM_DynCom::GetCP15Register(CP15Register reg) {
+u32 ARM_DynCom::GetCP15Register(CP15Register reg) const {
     return state->CP15[reg];
 }
 
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 99c6ab460..7497b765f 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -41,7 +41,7 @@ public:
     void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override;
     u32 GetCPSR() const override;
     void SetCPSR(u32 cpsr) override;
-    u32 GetCP15Register(CP15Register reg) override;
+    u32 GetCP15Register(CP15Register reg) const override;
     void SetCP15Register(CP15Register reg, u32 value) override;
 
     std::unique_ptr<ThreadContext> NewContext() const override;
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index ecb97c6bd..26fc0bccb 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -9,6 +9,7 @@
 // bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm
 // putting this as a subset of HLE for now.
 
+#include <boost/serialization/binary_object.hpp>
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/swap.h"
@@ -56,6 +57,14 @@ public:
 
 private:
     ConfigMemDef config_mem;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        auto o_config_mem = boost::serialization::binary_object(&config_mem, sizeof(config_mem));
+        ar & o_config_mem;
+    }
 };
 
 } // namespace ConfigMem
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index d8bd0f034..32d76d0d3 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -109,17 +109,17 @@ template <class Archive>
 void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
 {
     ar & named_ports;
-    // TODO: CPU
+    ar & *current_cpu.get();
     // NB: subsystem references and prepare_reschedule_callback are constant
     ar & *resource_limits.get();
     ar & next_object_id;
-    //ar & *timer_manager.get();
+    ar & *timer_manager.get();
     ar & next_process_id;
     ar & process_list;
     ar & current_process;
-    // ar & *thread_manager.get();
-    //ar & *config_mem_handler.get();
-    //ar & *shared_page_handler.get();
+    ar & *thread_manager.get();
+    ar & *config_mem_handler.get();
+    ar & *shared_page_handler.get();
 }
 
 SERIALIZE_IMPL(KernelSystem)
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 467b1ae1e..b9a32ef23 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -23,11 +23,12 @@ void ReleaseThreadMutexes(Thread* thread) {
     thread->held_mutexes.clear();
 }
 
-Mutex::Mutex(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
+Mutex::Mutex() : kernel(*g_kernel) {}
 Mutex::~Mutex() {}
 
 std::shared_ptr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::string name) {
-    auto mutex{std::make_shared<Mutex>(*this)};
+    auto mutex{std::make_shared<Mutex>()};
+    mutex->Init(*this);
 
     mutex->lock_count = 0;
     mutex->name = std::move(name);
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 618685451..4f0c2c2b5 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -17,7 +17,7 @@ class Thread;
 
 class Mutex final : public WaitObject {
 public:
-    explicit Mutex(KernelSystem& kernel);
+    explicit Mutex();
     ~Mutex() override;
 
     std::string GetTypeName() const override {
@@ -68,7 +68,6 @@ private:
         ar & priority;
         ar & name;
         ar & holding_thread;
-        ar & kernel; // TODO: Check that this works!
     }
 };
 
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 63a5c3b68..49de1e69e 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -4,9 +4,13 @@
 
 #include <algorithm>
 #include <memory>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/bitset.hpp>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_funcs.h"
 #include "common/logging/log.h"
+#include "common/serialization/boost_vector.hpp"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/process.h"
@@ -17,6 +21,28 @@
 
 namespace Kernel {
 
+template <class Archive>
+void Process::serialize(Archive& ar, const unsigned int file_version)
+{
+    ar & boost::serialization::base_object<Object>(*this);
+    ar & handle_table;
+    ar & codeset;
+    ar & resource_limit;
+    ar & svc_access_mask;
+    ar & handle_table_size;
+    ar & (boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8> >&)address_mappings;
+    ar & flags.raw;
+    ar & kernel_version;
+    ar & ideal_processor;
+    ar & process_id;
+    ar & vm_manager;
+    ar & memory_used;
+    ar & memory_region;
+    ar & tls_slots;
+}
+
+SERIALIZE_IMPL(Process)
+
 std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
     auto codeset{std::make_shared<CodeSet>()};
     codeset->Init(*this);
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 6defd42c6..edda20c1f 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -11,13 +11,10 @@
 #include <string>
 #include <vector>
 #include <boost/container/static_vector.hpp>
-#include <boost/serialization/array.hpp>
-#include <boost/serialization/bitset.hpp>
-#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/vector.hpp>
+#include <boost/serialization/base_object.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
-#include "common/serialization/boost_vector.hpp"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/vm_manager.h"
@@ -234,23 +231,6 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        ar & handle_table;
-        ar & codeset;
-        ar & resource_limit;
-        ar & svc_access_mask;
-        ar & handle_table_size;
-        ar & (boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8> >&)address_mappings;
-        ar & flags.raw;
-        ar & kernel_version;
-        ar & ideal_processor;
-        ar & process_id;
-        ar & vm_manager;
-        ar & memory_used;
-        ar & memory_region;
-        ar & tls_slots;
-    }
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 } // namespace Kernel
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index 5092b4869..58cd46334 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -13,6 +13,7 @@
 #include <chrono>
 #include <ctime>
 #include <memory>
+#include <boost/serialization/binary_object.hpp>
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
@@ -104,6 +105,14 @@ private:
     std::chrono::seconds init_time;
 
     SharedPageDef shared_page;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        auto o_shared_page = boost::serialization::binary_object(&shared_page, sizeof(shared_page));
+        ar & o_shared_page;
+    }
 };
 
 } // namespace SharedPage
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 4c2344dcb..9fa5df33a 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -6,10 +6,12 @@
 #include <list>
 #include <unordered_map>
 #include <vector>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "common/math_util.h"
+#include "common/serialization/boost_flat_set.h"
 #include "core/arm/arm_interface.h"
 #include "core/arm/skyeye_common/armstate.h"
 #include "core/core.h"
@@ -25,6 +27,30 @@
 
 namespace Kernel {
 
+template <class Archive>
+void Thread::serialize(Archive& ar, const unsigned int file_version)
+{
+    ar & *context.get();
+    ar & thread_id;
+    ar & status;
+    ar & entry_point;
+    ar & stack_top;
+    ar & nominal_priority;
+    ar & current_priority;
+    ar & last_running_ticks;
+    ar & processor_id;
+    ar & tls_address;
+    ar & held_mutexes;
+    ar & pending_mutexes;
+    ar & owner_process;
+    ar & wait_objects;
+    ar & wait_address;
+    ar & name;
+    // TODO: How the hell to do wakeup_callback
+}
+
+SERIALIZE_IMPL(Thread)
+
 bool Thread::ShouldWait(const Thread* thread) const {
     return status != ThreadStatus::Dead;
 }
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 2db5dda91..fc9170675 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -9,6 +9,9 @@
 #include <unordered_map>
 #include <vector>
 #include <boost/container/flat_set.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unordered_map.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "common/thread_queue_list.h"
 #include "core/arm/arm_interface.h"
@@ -145,6 +148,17 @@ private:
 
     friend class Thread;
     friend class KernelSystem;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & next_thread_id;
+        ar & current_thread;
+        ar & ready_queue;
+        ar & wakeup_callback_table;
+        ar & thread_list;
+    }
 };
 
 class Thread final : public WaitObject {
@@ -305,6 +319,10 @@ public:
 
 private:
     ThreadManager& thread_manager;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 
 /**
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 9c3d0f725..f073c3312 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -14,15 +14,15 @@
 
 namespace Kernel {
 
-Timer::Timer(KernelSystem& kernel)
-    : WaitObject(kernel), kernel(kernel), timer_manager(kernel.GetTimerManager()) {}
+Timer::Timer() : kernel(*g_kernel), timer_manager(g_kernel->GetTimerManager()) {}
 Timer::~Timer() {
     Cancel();
     timer_manager.timer_callback_table.erase(callback_id);
 }
 
 std::shared_ptr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string name) {
-    auto timer{std::make_shared<Timer>(*this)};
+    auto timer{std::make_shared<Timer>()};
+    timer->Init(*this);
 
     timer->reset_type = reset_type;
     timer->signaled = false;
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index 6865f5243..690350611 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <boost/serialization/unordered_map.hpp>
 #include "common/common_types.h"
 #include "core/core_timing.h"
 #include "core/hle/kernel/object.h"
@@ -33,11 +34,19 @@ private:
 
     friend class Timer;
     friend class KernelSystem;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & next_timer_callback_id;
+        ar & timer_callback_table;
+    }
 };
 
 class Timer final : public WaitObject {
 public:
-    explicit Timer(KernelSystem& kernel);
+    explicit Timer();
     ~Timer() override;
 
     std::string GetTypeName() const override {
@@ -103,6 +112,18 @@ private:
     TimerManager& timer_manager;
 
     friend class KernelSystem;
+
+    friend class boost::serialization::access;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & reset_type;
+        ar & initial_delay;
+        ar & interval_delay;
+        ar & signaled;
+        ar & name;
+        ar & callback_id;
+    }
 };
 
 } // namespace Kernel

From dc0d1ebc95fbaa04034b96db9523470a161f4ed4 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 13 Aug 2019 17:37:04 +0100
Subject: [PATCH 010/129] Added a TODO

---
 TODO                           | 80 ++++++++++++++++++++++++++++++++++
 src/video_core/pica_state.h    |  2 +-
 src/video_core/shader/shader.h |  2 +-
 3 files changed, 82 insertions(+), 2 deletions(-)
 create mode 100644 TODO

diff --git a/TODO b/TODO
new file mode 100644
index 000000000..3f15f3fb5
--- /dev/null
+++ b/TODO
@@ -0,0 +1,80 @@
+☐ Save/load UI
+✔ CPU @done(19-08-13 15:41)
+✔ Memory @done(19-08-13 15:41)
+✔ DSP @done(19-08-13 15:41)
+☐ MMIO
+☐ Movie
+☐ Perf stats
+☐ Settings
+☐ Telemetry session
+✔ HW @done(19-08-13 15:41)
+    ✔ GPU regs @done(19-08-13 15:41)
+    ✔ LCD regs @done(19-08-13 15:41)
+☐ Video core @started(19-08-13 16:43)
+    ☐ Geometry pipeline
+    ✔ PICA state @done(19-08-13 15:41)
+    ☐ Primitive assembly
+    ✔ Shader @done(19-08-13 16:03)
+☐ HLE @started(19-08-13 16:43)
+    ☐ Kernel @started(19-08-13 16:43)
+        ✔ Address arbiter @done(19-08-13 16:40)
+        ✔ Client port @done(19-08-13 16:40)
+        ✔ Client session @done(19-08-13 16:40)
+        ✔ Config mem @done(19-08-13 16:40)
+        ☐ Event
+        ✔ Handle table @done(19-08-13 16:42)
+        ☐ HLE IPC
+        ☐ IPC
+        ☐ Memory @started(19-08-13 16:43)
+        ☐ Mutex @started(19-08-13 16:43)
+        ✔ Object @done(19-08-13 15:41)
+        ☐ Process @started(19-08-13 16:43)
+        ✔ Resource limit @done(19-08-13 16:43)
+        ☐ Semaphore @started(19-08-13 16:44)
+        ✔ Server port @done(19-08-13 16:44)
+        ✔ Server session @done(19-08-13 16:44)
+        ✔ Session @done(19-08-13 16:44)
+        ☐ Shared memory
+        ☐ Shared page @started(19-08-13 16:44)
+        ☐ SVC
+        ☐ Thread @started(19-08-13 16:45)
+        ✔ Timer @done(19-08-13 16:45)
+        ☐ VM Manager @started(19-08-13 16:46)
+        ✔ Wait object @done(19-08-13 16:46)
+    ☐ Service
+        ☐ AC
+        ☐ ACT
+        ☐ AM
+        ☐ APT
+        ☐ BOSS
+        ☐ CAM
+        ☐ CECD
+        ☐ CGF
+        ☐ CSND
+        ☐ DLP
+        ☐ DSP
+        ☐ ERR
+        ☐ FRD
+        ☐ FS
+        ☐ GSP
+        ☐ HID
+        ☐ HTTP
+        ☐ IR
+        ☐ LDR_RO
+        ☐ MIC
+        ☐ MVD
+        ☐ NDM
+        ☐ NEWS
+        ☐ NFC
+        ☐ NIM
+        ☐ NS
+        ☐ NWM
+        ☐ PM
+        ☐ PS
+        ☐ PTM
+        ☐ PXI
+        ☐ QTM
+        ☐ SM
+        ☐ SOC
+        ☐ SSL
+        ☐ Y2R
\ No newline at end of file
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 376865397..f0a9a119d 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -225,7 +225,7 @@ private:
         ar & cmd_list.addr;
         ar & cmd_list.length;
         ar & immediate;
-        // ar & gs_unit;
+        ar & gs_unit;
         // ar & geometry_pipeline;
         // ar & primitive_assembler;
         ar & vs_float_regs_counter;
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 1a0f6ef8a..ffa60f3b5 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -201,7 +201,7 @@ private:
         ar & registers;
         ar & conditional_code;
         ar & address_registers;
-        // TODO: emitter_ptr
+        // emitter_ptr is only set by GSUnitState and is serialized there
     }
 };
 

From acc89b22514d4ab61ef9d2b9f6be4143fd07ee7c Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 21 Dec 2019 23:37:41 +0000
Subject: [PATCH 011/129] Fixed an include

---
 src/video_core/pica_state.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index f0a9a119d..ba9f8235e 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -9,6 +9,7 @@
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "common/vector_math.h"
+#include "video_core/video_core.h"
 #include "video_core/geometry_pipeline.h"
 #include "video_core/primitive_assembly.h"
 #include "video_core/regs.h"

From c284192a87ae7fe2ec4ff0e3b5e86863a44a445c Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 22 Dec 2019 15:53:04 +0000
Subject: [PATCH 012/129] Serialize geometry_pipeline

---
 TODO                                 |   6 +-
 externals/boost                      |   2 +-
 src/core/hle/kernel/kernel.cpp       |   3 +-
 src/video_core/geometry_pipeline.cpp | 139 +++++++++++++++++++++++++--
 src/video_core/geometry_pipeline.h   |   5 +
 src/video_core/pica_state.h          |   2 +-
 6 files changed, 144 insertions(+), 13 deletions(-)

diff --git a/TODO b/TODO
index 3f15f3fb5..840caba1b 100644
--- a/TODO
+++ b/TODO
@@ -11,7 +11,7 @@
     ✔ GPU regs @done(19-08-13 15:41)
     ✔ LCD regs @done(19-08-13 15:41)
 ☐ Video core @started(19-08-13 16:43)
-    ☐ Geometry pipeline
+    ✔ Geometry pipeline @done(19-12-22 15:52)
     ✔ PICA state @done(19-08-13 15:41)
     ☐ Primitive assembly
     ✔ Shader @done(19-08-13 16:03)
@@ -35,9 +35,11 @@
         ✔ Server session @done(19-08-13 16:44)
         ✔ Session @done(19-08-13 16:44)
         ☐ Shared memory
-        ☐ Shared page @started(19-08-13 16:44)
+        ✘ Shared page @started(19-08-13 16:44) @cancelled(19-12-22 11:19)
+            Not needed right now as shared_page is read-only and derived from other data
         ☐ SVC
         ☐ Thread @started(19-08-13 16:45)
+            This requires refactoring wakeup_callback to be an object ref
         ✔ Timer @done(19-08-13 16:45)
         ☐ VM Manager @started(19-08-13 16:46)
         ✔ Wait object @done(19-08-13 16:46)
diff --git a/externals/boost b/externals/boost
index f4850c297..55725b779 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit f4850c2975a0d977b7479664b8d4a6f03300a042
+Subproject commit 55725b7796c7faa0a4af869e412d0410bd47612d
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 32d76d0d3..2dd0a34bf 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -119,7 +119,8 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
     ar & current_process;
     ar & *thread_manager.get();
     ar & *config_mem_handler.get();
-    ar & *shared_page_handler.get();
+    // Shared page data is read-only at the moment, so doesn't need serializing
+    //ar & *shared_page_handler.get();
 }
 
 SERIALIZE_IMPL(KernelSystem)
diff --git a/src/video_core/geometry_pipeline.cpp b/src/video_core/geometry_pipeline.cpp
index 3a24b71c9..44a2fd6da 100644
--- a/src/video_core/geometry_pipeline.cpp
+++ b/src/video_core/geometry_pipeline.cpp
@@ -2,6 +2,10 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/unique_ptr.hpp>
+#include "common/archives.h"
 #include "video_core/geometry_pipeline.h"
 #include "video_core/pica_state.h"
 #include "video_core/regs.h"
@@ -30,6 +34,13 @@ public:
      * @return if the buffer is full and the geometry shader should be invoked
      */
     virtual bool SubmitVertex(const Shader::AttributeBuffer& input) = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+    }
+    friend class boost::serialization::access;
 };
 
 // In the Point mode, vertex attributes are sent to the input registers in the geometry shader unit.
@@ -40,7 +51,7 @@ public:
 // TODO: what happens when the input size is not divisible by the output size?
 class GeometryPipeline_Point : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_Point(const Regs& regs, Shader::GSUnitState& unit) : regs(regs), unit(unit) {
+    GeometryPipeline_Point() : regs(g_state.regs), unit(g_state.gs_unit) {
         ASSERT(regs.pipeline.variable_primitive == 0);
         ASSERT(regs.gs.input_to_uniform == 0);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -79,6 +90,39 @@ private:
     Common::Vec4<float24>* buffer_cur;
     Common::Vec4<float24>* buffer_end;
     unsigned int vs_output_num;
+
+    template <typename Class, class Archive>
+    static void serialize_common(Class* self, Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
+        ar & self->attribute_buffer;
+        ar & self->vs_output_num;
+    }
+
+    template<class Archive>
+    void save(Archive & ar, const unsigned int version) const
+    {
+        serialize_common(this, ar, version);
+        auto buffer_idx = static_cast<u32>(buffer_cur - attribute_buffer.attr);
+        auto buffer_size = static_cast<u32>(buffer_end - attribute_buffer.attr);
+        ar << buffer_idx;
+        ar << buffer_size;
+    }
+
+    template<class Archive>
+    void load(Archive & ar, const unsigned int version)
+    {
+        serialize_common(this, ar, version);
+        u32 buffer_idx, buffer_size;
+        ar >> buffer_idx;
+        ar >> buffer_size;
+        buffer_cur = attribute_buffer.attr + buffer_idx;
+        buffer_end = attribute_buffer.attr + buffer_size;
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
+
+    friend class boost::serialization::access;
 };
 
 // In VariablePrimitive mode, vertex attributes are buffered into the uniform registers in the
@@ -86,8 +130,8 @@ private:
 // value in the batch. This mode is usually used for subdivision.
 class GeometryPipeline_VariablePrimitive : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_VariablePrimitive(const Regs& regs, Shader::ShaderSetup& setup)
-        : regs(regs), setup(setup) {
+    GeometryPipeline_VariablePrimitive()
+        : regs(g_state.regs), setup(g_state.gs) {
         ASSERT(regs.pipeline.variable_primitive == 1);
         ASSERT(regs.gs.input_to_uniform == 1);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -144,6 +188,37 @@ private:
     unsigned int total_vertex_num;
     Common::Vec4<float24>* buffer_cur;
     unsigned int vs_output_num;
+
+    template <typename Class, class Archive>
+    static void serialize_common(Class* self, Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
+        ar & self->need_index;
+        ar & self->main_vertex_num;
+        ar & self->total_vertex_num;
+        ar & self->vs_output_num;
+    }
+
+    template<class Archive>
+    void save(Archive & ar, const unsigned int version) const
+    {
+        serialize_common(this, ar, version);
+        auto buffer_idx = static_cast<u32>(buffer_cur - setup.uniforms.f);
+        ar << buffer_idx;
+    }
+
+    template<class Archive>
+    void load(Archive & ar, const unsigned int version)
+    {
+        serialize_common(this, ar, version);
+        u32 buffer_idx;
+        ar >> buffer_idx;
+        buffer_cur = setup.uniforms.f + buffer_idx;
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
+
+    friend class boost::serialization::access;
 };
 
 // In FixedPrimitive mode, vertex attributes are buffered into the uniform registers in the geometry
@@ -151,8 +226,8 @@ private:
 // particle system.
 class GeometryPipeline_FixedPrimitive : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_FixedPrimitive(const Regs& regs, Shader::ShaderSetup& setup)
-        : regs(regs), setup(setup) {
+    GeometryPipeline_FixedPrimitive()
+        : regs(g_state.regs), setup(g_state.gs) {
         ASSERT(regs.pipeline.variable_primitive == 0);
         ASSERT(regs.gs.input_to_uniform == 1);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -190,6 +265,42 @@ private:
     Common::Vec4<float24>* buffer_cur;
     Common::Vec4<float24>* buffer_end;
     unsigned int vs_output_num;
+
+    template <typename Class, class Archive>
+    static void serialize_common(Class* self, Archive& ar, const unsigned int version)
+    {
+        ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
+        ar & self->vs_output_num;
+    }
+
+    template<class Archive>
+    void save(Archive & ar, const unsigned int version) const
+    {
+        serialize_common(this, ar, version);
+        auto buffer_offset = static_cast<u32>(buffer_begin - setup.uniforms.f);
+        auto buffer_idx = static_cast<u32>(buffer_cur - setup.uniforms.f);
+        auto buffer_size = static_cast<u32>(buffer_end - setup.uniforms.f);
+        ar << buffer_offset;
+        ar << buffer_idx;
+        ar << buffer_size;
+    }
+
+    template<class Archive>
+    void load(Archive & ar, const unsigned int version)
+    {
+        serialize_common(this, ar, version);
+        u32 buffer_offset, buffer_idx, buffer_size;
+        ar >> buffer_offset;
+        ar >> buffer_idx;
+        ar >> buffer_size;
+        buffer_begin = setup.uniforms.f + buffer_offset;
+        buffer_cur = setup.uniforms.f + buffer_idx;
+        buffer_end = setup.uniforms.f + buffer_size;
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
+
+    friend class boost::serialization::access;
 };
 
 GeometryPipeline::GeometryPipeline(State& state) : state(state) {}
@@ -231,13 +342,13 @@ void GeometryPipeline::Reconfigure() {
 
     switch (state.regs.pipeline.gs_config.mode) {
     case PipelineRegs::GSMode::Point:
-        backend = std::make_unique<GeometryPipeline_Point>(state.regs, state.gs_unit);
+        backend = std::make_unique<GeometryPipeline_Point>();
         break;
     case PipelineRegs::GSMode::VariablePrimitive:
-        backend = std::make_unique<GeometryPipeline_VariablePrimitive>(state.regs, state.gs);
+        backend = std::make_unique<GeometryPipeline_VariablePrimitive>();
         break;
     case PipelineRegs::GSMode::FixedPrimitive:
-        backend = std::make_unique<GeometryPipeline_FixedPrimitive>(state.regs, state.gs);
+        backend = std::make_unique<GeometryPipeline_FixedPrimitive>();
         break;
     default:
         UNREACHABLE();
@@ -271,4 +382,16 @@ void GeometryPipeline::SubmitVertex(const Shader::AttributeBuffer& input) {
     }
 }
 
+template <class Archive>
+void GeometryPipeline::serialize(Archive& ar, const unsigned int version) {
+    // vertex_handler and shader_engine are always set to the same value
+    ar & backend;
+}
+
 } // namespace Pica
+
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(Pica::GeometryPipelineBackend)
+SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_Point)
+SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_VariablePrimitive)
+SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_FixedPrimitive)
+SERIALIZE_IMPL(Pica::GeometryPipeline)
diff --git a/src/video_core/geometry_pipeline.h b/src/video_core/geometry_pipeline.h
index 91fdd3192..1ca2d00c4 100644
--- a/src/video_core/geometry_pipeline.h
+++ b/src/video_core/geometry_pipeline.h
@@ -45,5 +45,10 @@ private:
     Shader::ShaderEngine* shader_engine;
     std::unique_ptr<GeometryPipelineBackend> backend;
     State& state;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int version);
+
+    friend class boost::serialization::access;
 };
 } // namespace Pica
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index ba9f8235e..d7ae04c1b 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -227,7 +227,7 @@ private:
         ar & cmd_list.length;
         ar & immediate;
         ar & gs_unit;
-        // ar & geometry_pipeline;
+        ar & geometry_pipeline;
         // ar & primitive_assembler;
         ar & vs_float_regs_counter;
         ar & vs_uniform_write_buffer;

From 050c3bdee59a41858cfc69f03adf5f14698090a3 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 22 Dec 2019 16:06:26 +0000
Subject: [PATCH 013/129] Serialize primitive_assembly

---
 TODO                                |  5 ++++-
 src/video_core/pica_state.h         |  2 +-
 src/video_core/primitive_assembly.h | 12 ++++++++++++
 src/video_core/shader/shader.h      |  3 +++
 4 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index 840caba1b..95bdaa926 100644
--- a/TODO
+++ b/TODO
@@ -7,16 +7,19 @@
 ☐ Perf stats
 ☐ Settings
 ☐ Telemetry session
+☐ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
     ✔ LCD regs @done(19-08-13 15:41)
 ☐ Video core @started(19-08-13 16:43)
     ✔ Geometry pipeline @done(19-12-22 15:52)
+        Required more use of g_state
     ✔ PICA state @done(19-08-13 15:41)
-    ☐ Primitive assembly
+    ✔ Primitive assembly @done(19-12-22 16:05)
     ✔ Shader @done(19-08-13 16:03)
 ☐ HLE @started(19-08-13 16:43)
     ☐ Kernel @started(19-08-13 16:43)
+        Most of these require adding g_kernel
         ✔ Address arbiter @done(19-08-13 16:40)
         ✔ Client port @done(19-08-13 16:40)
         ✔ Client session @done(19-08-13 16:40)
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index d7ae04c1b..95ee77662 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -228,7 +228,7 @@ private:
         ar & immediate;
         ar & gs_unit;
         ar & geometry_pipeline;
-        // ar & primitive_assembler;
+        ar & primitive_assembler;
         ar & vs_float_regs_counter;
         ar & vs_uniform_write_buffer;
         ar & gs_float_regs_counter;
diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h
index fd5445aa8..1545a6b4c 100644
--- a/src/video_core/primitive_assembly.h
+++ b/src/video_core/primitive_assembly.h
@@ -6,6 +6,7 @@
 
 #include <functional>
 #include "video_core/regs_pipeline.h"
+namespace boost::serialization { class access; }
 
 namespace Pica {
 
@@ -62,6 +63,17 @@ private:
     VertexType buffer[2];
     bool strip_ready = false;
     bool winding = false;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int version)
+    {
+        ar & topology;
+        ar & buffer_index;
+        ar & buffer;
+        ar & strip_ready;
+        ar & winding;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Pica
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index ffa60f3b5..f20e08d98 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -16,6 +16,7 @@
 #include "common/common_types.h"
 #include "common/hash.h"
 #include "common/vector_math.h"
+#include "common/pod.h"
 #include "video_core/pica_types.h"
 #include "video_core/regs_rasterizer.h"
 #include "video_core/regs_shader.h"
@@ -64,6 +65,8 @@ struct OutputVertex {
     static void ValidateSemantics(const RasterizerRegs& regs);
     static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs,
                                             const AttributeBuffer& output);
+
+    SERIALIZE_AS_POD
 };
 #define ASSERT_POS(var, pos)                                                                       \
     static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong "       \

From 8c81500deec2e8368c112fbce98770c7b518f40e Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 22 Dec 2019 18:35:03 +0000
Subject: [PATCH 014/129] Serialize kernel/hle/memory

---
 TODO                                          |  4 +--
 .../serialization/boost_discrete_interval.hpp | 33 +++++++++++++++++++
 src/core/hle/kernel/kernel.cpp                |  2 +-
 src/core/hle/kernel/memory.h                  |  5 ++-
 4 files changed, 40 insertions(+), 4 deletions(-)
 create mode 100644 src/common/serialization/boost_discrete_interval.hpp

diff --git a/TODO b/TODO
index 95bdaa926..cad91b958 100644
--- a/TODO
+++ b/TODO
@@ -11,7 +11,7 @@
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
     ✔ LCD regs @done(19-08-13 15:41)
-☐ Video core @started(19-08-13 16:43)
+✔ Video core @started(19-08-13 16:43) @done(19-12-22 16:06)
     ✔ Geometry pipeline @done(19-12-22 15:52)
         Required more use of g_state
     ✔ PICA state @done(19-08-13 15:41)
@@ -28,7 +28,7 @@
         ✔ Handle table @done(19-08-13 16:42)
         ☐ HLE IPC
         ☐ IPC
-        ☐ Memory @started(19-08-13 16:43)
+        ✔ Memory @started(19-08-13 16:43) @done(19-12-22 18:34)
         ☐ Mutex @started(19-08-13 16:43)
         ✔ Object @done(19-08-13 15:41)
         ☐ Process @started(19-08-13 16:43)
diff --git a/src/common/serialization/boost_discrete_interval.hpp b/src/common/serialization/boost_discrete_interval.hpp
new file mode 100644
index 000000000..dc920e439
--- /dev/null
+++ b/src/common/serialization/boost_discrete_interval.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "common/common_types.h"
+#include <boost/icl/discrete_interval.hpp>
+
+namespace boost::serialization {
+
+template <class Archive, class DomainT, ICL_COMPARE Compare>
+void save(Archive& ar, const boost::icl::discrete_interval<DomainT, Compare>& obj, const unsigned int file_version)
+{
+    ar << obj.lower();
+    ar << obj.upper();
+    ar << obj.bounds()._bits;
+}
+
+template <class Archive, class DomainT, ICL_COMPARE Compare>
+void load(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj, const unsigned int file_version)
+{
+    DomainT upper, lower;
+    boost::icl::bound_type bounds;
+    ar >> upper;
+    ar >> lower;
+    ar >> bounds;
+    obj = boost::icl::discrete_interval(upper, lower, boost::icl::interval_bounds(bounds));
+}
+
+template <class Archive, class DomainT, ICL_COMPARE Compare>
+void serialize(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj, const unsigned int file_version)
+{
+    boost::serialization::split_free(ar, obj, file_version);
+}
+
+}
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 2dd0a34bf..6248311b9 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -108,6 +108,7 @@ void KernelSystem::AddNamedPort(std::string name, std::shared_ptr<ClientPort> po
 template <class Archive>
 void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
 {
+    ar & memory_regions;
     ar & named_ports;
     ar & *current_cpu.get();
     // NB: subsystem references and prepare_reschedule_callback are constant
@@ -120,7 +121,6 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
     ar & *thread_manager.get();
     ar & *config_mem_handler.get();
     // Shared page data is read-only at the moment, so doesn't need serializing
-    //ar & *shared_page_handler.get();
 }
 
 SERIALIZE_IMPL(KernelSystem)
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
index 9e9fe5eb4..ed4ea1296 100644
--- a/src/core/hle/kernel/memory.h
+++ b/src/core/hle/kernel/memory.h
@@ -6,6 +6,8 @@
 
 #include <optional>
 #include <boost/icl/interval_set.hpp>
+#include <boost/serialization/set.hpp>
+#include "common/serialization/boost_discrete_interval.hpp"
 #include "common/common_types.h"
 
 namespace Kernel {
@@ -69,7 +71,8 @@ private:
         ar & base;
         ar & size;
         ar & used;
-        // TODO: boost icl / free_blocks
+        // This works because interval_set has exactly one member of type ImplSetT
+        ar & *(reinterpret_cast<IntervalSet::ImplSetT*>(&free_blocks));
     }
 };
 

From 4f95575d418195d833a61704c54df29f4c58ec86 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 22 Dec 2019 23:37:17 +0000
Subject: [PATCH 015/129] Serialize some more kernel objects

---
 TODO                                | 21 +++++++++++++++------
 src/common/archives.h               |  1 +
 src/core/core.cpp                   |  2 ++
 src/core/hle/kernel/event.cpp       |  7 +++++--
 src/core/hle/kernel/event.h         |  5 ++++-
 src/core/hle/kernel/kernel.cpp      |  1 +
 src/core/hle/kernel/mutex.cpp       |  3 +++
 src/core/hle/kernel/mutex.h         |  3 +++
 src/core/hle/kernel/process.cpp     |  1 +
 src/core/hle/kernel/semaphore.cpp   |  7 +++++--
 src/core/hle/kernel/semaphore.h     |  5 ++++-
 src/core/hle/kernel/shared_memory.h | 16 ++++++++++++++++
 src/core/hle/kernel/thread.cpp      |  2 ++
 src/core/hle/kernel/thread.h        |  3 +++
 src/core/hle/kernel/vm_manager.h    |  1 +
 15 files changed, 66 insertions(+), 12 deletions(-)

diff --git a/TODO b/TODO
index cad91b958..6397b4ba9 100644
--- a/TODO
+++ b/TODO
@@ -2,6 +2,10 @@
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
 ✔ DSP @done(19-08-13 15:41)
+☐ Service manager
+☐ App loader
+☐ Archive manager
+☐ Custom texture cache
 ☐ MMIO
 ☐ Movie
 ☐ Perf stats
@@ -24,27 +28,32 @@
         ✔ Client port @done(19-08-13 16:40)
         ✔ Client session @done(19-08-13 16:40)
         ✔ Config mem @done(19-08-13 16:40)
-        ☐ Event
+        ✔ Event @done(19-12-22 18:44)
         ✔ Handle table @done(19-08-13 16:42)
         ☐ HLE IPC
         ☐ IPC
         ✔ Memory @started(19-08-13 16:43) @done(19-12-22 18:34)
-        ☐ Mutex @started(19-08-13 16:43)
+        ✔ Mutex @done(19-08-13 16:43)
         ✔ Object @done(19-08-13 15:41)
-        ☐ Process @started(19-08-13 16:43)
+        ✔ Process @started(19-08-13 16:43) @done(19-12-22 18:41)
+        ☐ Code set @started(19-12-22 18:41)
+            Needs a way to reference loaded images (so we don't serialize the entire ROM as well)
         ✔ Resource limit @done(19-08-13 16:43)
-        ☐ Semaphore @started(19-08-13 16:44)
+        ✔ Semaphore @done(19-08-13 16:44)
         ✔ Server port @done(19-08-13 16:44)
         ✔ Server session @done(19-08-13 16:44)
         ✔ Session @done(19-08-13 16:44)
-        ☐ Shared memory
+        ☐ Shared memory @started(19-12-22 21:20)
+            Need to figure out backing memory (a u8*)
         ✘ Shared page @started(19-08-13 16:44) @cancelled(19-12-22 11:19)
             Not needed right now as shared_page is read-only and derived from other data
-        ☐ SVC
+        ✔ SVC @done(19-12-22 21:32)
+            Nothing to do - all data is constant
         ☐ Thread @started(19-08-13 16:45)
             This requires refactoring wakeup_callback to be an object ref
         ✔ Timer @done(19-08-13 16:45)
         ☐ VM Manager @started(19-08-13 16:46)
+            Just need to figure out backing_mem (a u8*)
         ✔ Wait object @done(19-08-13 16:46)
     ☐ Service
         ☐ AC
diff --git a/src/common/archives.h b/src/common/archives.h
index f30886d90..a27afe80c 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -1,5 +1,6 @@
 #include "boost/archive/binary_iarchive.hpp"
 #include "boost/archive/binary_oarchive.hpp"
+#include "boost/serialization/export.hpp"
 
 using iarchive = boost::archive::binary_iarchive;
 using oarchive = boost::archive::binary_oarchive;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 902340d41..9aecf84c9 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -398,6 +398,8 @@ void System::Reset() {
 template<class Archive>
 void System::serialize(Archive & ar, const unsigned int file_version)
 {
+    ar & *cpu_core.get();
+    //ar & *service_manager.get();
     ar & GPU::g_regs;
     ar & LCD::g_regs;
     ar & dsp_core->GetDspMemory();
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index f31162e35..7af667739 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -6,17 +6,20 @@
 #include <map>
 #include <vector>
 #include "common/assert.h"
+#include "common/archives.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/thread.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::Event)
+
 namespace Kernel {
 
-Event::Event(KernelSystem& kernel) : WaitObject(kernel) {}
+Event::Event() : WaitObject() {}
 Event::~Event() {}
 
 std::shared_ptr<Event> KernelSystem::CreateEvent(ResetType reset_type, std::string name) {
-    auto evt{std::make_shared<Event>(*this)};
+    auto evt{std::make_shared<Event>()};
 
     evt->signaled = false;
     evt->reset_type = reset_type;
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 9e9da267a..bb97f6eb1 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/wait_object.h"
@@ -12,7 +13,7 @@ namespace Kernel {
 
 class Event final : public WaitObject {
 public:
-    explicit Event(KernelSystem& kernel);
+    explicit Event();
     ~Event() override;
 
     std::string GetTypeName() const override {
@@ -62,3 +63,5 @@ private:
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::Event)
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 6248311b9..4f9a02410 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -121,6 +121,7 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
     ar & *thread_manager.get();
     ar & *config_mem_handler.get();
     // Shared page data is read-only at the moment, so doesn't need serializing
+    // Deliberately don't include debugger info to allow debugging through loads
 }
 
 SERIALIZE_IMPL(KernelSystem)
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index b9a32ef23..b8a3d143b 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -4,6 +4,7 @@
 
 #include <map>
 #include <vector>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "core/core.h"
 #include "core/hle/kernel/errors.h"
@@ -12,6 +13,8 @@
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::Mutex)
+
 namespace Kernel {
 
 void ReleaseThreadMutexes(Thread* thread) {
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 4f0c2c2b5..f4449c0f2 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/wait_object.h"
@@ -78,3 +79,5 @@ private:
 void ReleaseThreadMutexes(Thread* thread);
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::Mutex)
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 49de1e69e..5fad4fd85 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -34,6 +34,7 @@ void Process::serialize(Archive& ar, const unsigned int file_version)
     ar & flags.raw;
     ar & kernel_version;
     ar & ideal_processor;
+    ar & status;
     ar & process_id;
     ar & vm_manager;
     ar & memory_used;
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index bbc8a385f..f60a653e5 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -3,14 +3,17 @@
 // Refer to the license.txt file included.
 
 #include "common/assert.h"
+#include "common/archives.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/semaphore.h"
 #include "core/hle/kernel/thread.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::Semaphore)
+
 namespace Kernel {
 
-Semaphore::Semaphore(KernelSystem& kernel) : WaitObject(kernel) {}
+Semaphore::Semaphore() : WaitObject() {}
 Semaphore::~Semaphore() {}
 
 ResultVal<std::shared_ptr<Semaphore>> KernelSystem::CreateSemaphore(s32 initial_count,
@@ -20,7 +23,7 @@ ResultVal<std::shared_ptr<Semaphore>> KernelSystem::CreateSemaphore(s32 initial_
     if (initial_count > max_count)
         return ERR_INVALID_COMBINATION_KERNEL;
 
-    auto semaphore{std::make_shared<Semaphore>(*this)};
+    auto semaphore{std::make_shared<Semaphore>()};
 
     // When the semaphore is created, some slots are reserved for other threads,
     // and the rest is reserved for the caller thread
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index 526be6812..ff6a4434a 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -6,6 +6,7 @@
 
 #include <string>
 #include <queue>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/wait_object.h"
@@ -15,7 +16,7 @@ namespace Kernel {
 
 class Semaphore final : public WaitObject {
 public:
-    explicit Semaphore(KernelSystem& kernel);
+    explicit Semaphore();
     ~Semaphore() override;
 
     std::string GetTypeName() const override {
@@ -57,3 +58,5 @@ private:
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::Semaphore)
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 0d781cfcc..42d783513 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -6,6 +6,7 @@
 
 #include <string>
 #include <utility>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
@@ -104,6 +105,21 @@ private:
 
     friend class KernelSystem;
     KernelSystem& kernel;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & linear_heap_phys_offset;
+        // TODO: backing blocks u8* (this is always FCRAM I think)
+        ar & size;
+        ar & permissions;
+        ar & other_permissions;
+        ar & owner_process;
+        ar & base_address;
+        ar & name;
+        ar & *(reinterpret_cast<MemoryRegionInfo::IntervalSet::ImplSetT*>(&holding_memory));;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 9fa5df33a..409dcc886 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -25,6 +25,8 @@
 #include "core/hle/result.h"
 #include "core/memory.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::Thread)
+
 namespace Kernel {
 
 template <class Archive>
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index fc9170675..b423392e3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -12,6 +12,7 @@
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/unordered_map.hpp>
 #include <boost/serialization/vector.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "common/thread_queue_list.h"
 #include "core/arm/arm_interface.h"
@@ -337,3 +338,5 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
                                         std::shared_ptr<Process> owner_process);
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::Thread)
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 6711c9b4d..e930fc64a 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -94,6 +94,7 @@ private:
         ar & permissions;
         ar & meminfo_state;
         // TODO: backing memory ref
+        // backing memory can be: Physical/FCRAM pointer, config mem, shared page
         ar & paddr;
         ar & mmio_handler;
     }

From 7a5bde0b44b86d4d64e049ede824286942408fad Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 23 Dec 2019 11:41:07 +0000
Subject: [PATCH 016/129] Serialize service manager, server prt

---
 TODO                                 |  9 ++++++---
 src/core/core.cpp                    |  4 ++--
 src/core/core.h                      |  2 +-
 src/core/hle/kernel/hle_ipc.h        | 26 ++++++++++++++++++++++++++
 src/core/hle/kernel/ipc.h            | 15 +++++++++++++++
 src/core/hle/kernel/server_port.cpp  | 11 +++++++++++
 src/core/hle/kernel/server_port.h    |  8 +-------
 src/core/hle/kernel/server_session.h |  4 ++--
 src/core/hle/kernel/session.cpp      |  1 +
 src/core/hle/kernel/shared_memory.h  |  2 +-
 src/core/hle/service/sm/sm.h         | 11 +++++++++++
 11 files changed, 77 insertions(+), 16 deletions(-)

diff --git a/TODO b/TODO
index 6397b4ba9..f3e1ea943 100644
--- a/TODO
+++ b/TODO
@@ -2,7 +2,8 @@
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
 ✔ DSP @done(19-08-13 15:41)
-☐ Service manager
+✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
+    ☐ Fix or ignore inverse map
 ☐ App loader
 ☐ Archive manager
 ☐ Custom texture cache
@@ -30,8 +31,8 @@
         ✔ Config mem @done(19-08-13 16:40)
         ✔ Event @done(19-12-22 18:44)
         ✔ Handle table @done(19-08-13 16:42)
-        ☐ HLE IPC
-        ☐ IPC
+        ✔ HLE IPC @done(19-12-23 00:36)
+        ✔ IPC @done(19-12-23 00:36)
         ✔ Memory @started(19-08-13 16:43) @done(19-12-22 18:34)
         ✔ Mutex @done(19-08-13 16:43)
         ✔ Object @done(19-08-13 15:41)
@@ -42,6 +43,8 @@
         ✔ Semaphore @done(19-08-13 16:44)
         ✔ Server port @done(19-08-13 16:44)
         ✔ Server session @done(19-08-13 16:44)
+            ☐ Mapped buffer context
+                This may not be needed!
         ✔ Session @done(19-08-13 16:44)
         ☐ Shared memory @started(19-12-22 21:20)
             Need to figure out backing memory (a u8*)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 9aecf84c9..8ca3a2ab5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -235,7 +235,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     rpc_server = std::make_unique<RPC::RPCServer>();
 
-    service_manager = std::make_shared<Service::SM::ServiceManager>(*this);
+    service_manager = std::make_unique<Service::SM::ServiceManager>(*this);
     archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this);
 
     HW::Init(*memory);
@@ -399,7 +399,7 @@ template<class Archive>
 void System::serialize(Archive & ar, const unsigned int file_version)
 {
     ar & *cpu_core.get();
-    //ar & *service_manager.get();
+    ar & *service_manager.get();
     ar & GPU::g_regs;
     ar & LCD::g_regs;
     ar & dsp_core->GetDspMemory();
diff --git a/src/core/core.h b/src/core/core.h
index b811badba..8bf04d365 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -305,7 +305,7 @@ private:
     std::unique_ptr<Core::TelemetrySession> telemetry_session;
 
     /// Service manager
-    std::shared_ptr<Service::SM::ServiceManager> service_manager;
+    std::unique_ptr<Service::SM::ServiceManager> service_manager;
 
     /// Frontend applets
     std::shared_ptr<Frontend::MiiSelector> registered_mii_selector;
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 26942fe6b..be3a20e79 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -11,12 +11,19 @@
 #include <string>
 #include <vector>
 #include <boost/container/small_vector.hpp>
+#include <boost/serialization/unique_ptr.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/assume_abstract.hpp>
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_session.h"
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::SessionRequestHandler)
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::SessionRequestHandler::SessionDataBase)
+
 namespace Service {
 class ServiceFrameworkBase;
 }
@@ -90,12 +97,31 @@ protected:
 
         std::shared_ptr<ServerSession> session;
         std::unique_ptr<SessionDataBase> data;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int file_version)
+        {
+            ar & session;
+            ar & data;
+        }
+        friend class boost::serialization::access;
     };
     /// List of sessions that are connected to this handler. A ServerSession whose server endpoint
     /// is an HLE implementation is kept alive by this list for the duration of the connection.
     std::vector<SessionInfo> connected_sessions;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & connected_sessions;
+    }
+    friend class boost::serialization::access;
 };
 
+// NOTE: The below classes are ephemeral and don't need serialization
+
 class MappedBuffer {
 public:
     MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
diff --git a/src/core/hle/kernel/ipc.h b/src/core/hle/kernel/ipc.h
index b06079958..46d86a528 100644
--- a/src/core/hle/kernel/ipc.h
+++ b/src/core/hle/kernel/ipc.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <vector>
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/common_types.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/thread.h"
@@ -26,6 +27,20 @@ struct MappedBufferContext {
 
     std::unique_ptr<u8[]> buffer;
     std::unique_ptr<u8[]> reserve_buffer;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & permissions;
+        ar & size;
+        ar & source_address;
+        ar & target_address;
+        // TODO: Check whether we need these. If we do, add a field for the size and/or change to a 'vector'
+        //ar & buffer;
+        //ar & reserve_buffer;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Performs IPC command buffer translation from one process to another.
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 191b43ea8..0aeb86a78 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -11,6 +11,7 @@
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/hle_ipc.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::ServerPort)
 
@@ -50,4 +51,14 @@ KernelSystem::PortPair KernelSystem::CreatePortPair(u32 max_sessions, std::strin
     return std::make_pair(std::move(server_port), std::move(client_port));
 }
 
+template <class Archive>
+void ServerPort::serialize(Archive& ar, const unsigned int file_version)
+{
+    ar & boost::serialization::base_object<WaitObject>(*this);
+    ar & name;
+    ar & pending_sessions;
+    ar & hle_handler;
+}
+SERIALIZE_IMPL(ServerPort)
+
 } // namespace Kernel
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index e0014ee7c..f055cd267 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -67,13 +67,7 @@ public:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        ar & name;
-        ar & pending_sessions;
-        //ar & hle_handler;
-    }
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 6112eefac..05b469c38 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -115,10 +115,10 @@ private:
         ar & boost::serialization::base_object<Object>(*this);
         ar & name;
         ar & parent;
-        //ar & hle_handler;
+        ar & hle_handler;
         ar & pending_requesting_threads;
         ar & currently_handling;
-        //ar & mapped_buffer_context;
+        ar & mapped_buffer_context;
     }
 };
 
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index f264c49bd..a2a1f90f9 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -8,6 +8,7 @@
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/hle_ipc.h"
 
 SERIALIZE_IMPL(Kernel::Session)
 
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 42d783513..8aaf3df1f 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -117,7 +117,7 @@ private:
         ar & owner_process;
         ar & base_address;
         ar & name;
-        ar & *(reinterpret_cast<MemoryRegionInfo::IntervalSet::ImplSetT*>(&holding_memory));;
+        ar & *(reinterpret_cast<MemoryRegionInfo::IntervalSet::ImplSetT*>(&holding_memory));
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 6e47fd152..9cdaff72d 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -8,6 +8,9 @@
 #include <string>
 #include <type_traits>
 #include <unordered_map>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/unordered_map.hpp>
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
@@ -80,6 +83,14 @@ private:
     // For IPC Recorder
     /// client port Object id -> service name
     std::unordered_map<u32, std::string> registered_services_inverse;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & registered_services;
+        ar & registered_services_inverse; // TODO: Instead, compute this from registered_services
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::SM

From ac0337d8dfcd1a95090b5a8a6982d3bc91218e32 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 24 Dec 2019 17:49:56 +0000
Subject: [PATCH 017/129] Started IPC services serialization

---
 TODO                           |  8 +++---
 src/common/construct.h         | 35 ++++++++++++++++++++++++++
 src/core/hle/kernel/hle_ipc.h  |  5 ++++
 src/core/hle/service/ac/ac.cpp |  3 +++
 src/core/hle/service/ac/ac.h   | 46 ++++++++++++++++++++++++++++++++++
 src/core/hle/service/service.h |  1 +
 src/core/hle/service/sm/sm.h   | 19 +++++++++++---
 src/core/memory.cpp            |  2 +-
 8 files changed, 112 insertions(+), 7 deletions(-)
 create mode 100644 src/common/construct.h

diff --git a/TODO b/TODO
index f3e1ea943..bc62720d6 100644
--- a/TODO
+++ b/TODO
@@ -1,9 +1,11 @@
 ☐ Save/load UI
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
+    ☐ Page tables
+    ☐ Skip N3DS RAM if unused
 ✔ DSP @done(19-08-13 15:41)
 ✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
-    ☐ Fix or ignore inverse map
+    ✔ Fix or ignore inverse map @done(19-12-23 12:46)
 ☐ App loader
 ☐ Archive manager
 ☐ Custom texture cache
@@ -58,8 +60,8 @@
         ☐ VM Manager @started(19-08-13 16:46)
             Just need to figure out backing_mem (a u8*)
         ✔ Wait object @done(19-08-13 16:46)
-    ☐ Service
-        ☐ AC
+    ☐ Service @started(19-12-23 12:49)
+        ☐ AC @started(19-12-23 12:48)
         ☐ ACT
         ☐ AM
         ☐ APT
diff --git a/src/common/construct.h b/src/common/construct.h
new file mode 100644
index 000000000..28f4cc349
--- /dev/null
+++ b/src/common/construct.h
@@ -0,0 +1,35 @@
+#include <boost/serialization/serialization.hpp>
+
+#define BOOST_SERIALIZATION_FRIENDS \
+    friend class boost::serialization::access; \
+    friend class construct_access;
+
+class construct_access {
+public:
+    template<class Archive, class T>
+    static inline void save_construct(Archive & ar, const T * t, const unsigned int file_version) {
+        t->save_construct(ar, file_version);
+    }
+    template<class Archive, class T>
+    static inline void load_construct(Archive & ar, T * t, const unsigned int file_version) {
+        T::load_construct(ar, t, file_version);
+    }
+};
+
+#define BOOST_SERIALIZATION_CONSTRUCT(T) \
+namespace boost { namespace serialization { \
+\
+    template<class Archive> \
+    inline void save_construct_data( \
+        Archive & ar, const T * t, const unsigned int file_version \
+    ){ \
+        construct_access::save_construct(ar, t, file_version); \
+    } \
+\
+    template<class Archive> \
+    inline void load_construct_data( \
+        Archive & ar, T * t, const unsigned int file_version \
+    ){ \
+        construct_access::load_construct(ar, t, file_version); \
+    } \
+}}
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index be3a20e79..da89ad39a 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -75,6 +75,10 @@ public:
     /// in each service must inherit from this.
     struct SessionDataBase {
         virtual ~SessionDataBase() = default;
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int file_version) { }
+        friend class boost::serialization::access;
     };
 
 protected:
@@ -94,6 +98,7 @@ protected:
 
     struct SessionInfo {
         SessionInfo(std::shared_ptr<ServerSession> session, std::unique_ptr<SessionDataBase> data);
+        SessionInfo() = default;
 
         std::shared_ptr<ServerSession> session;
         std::unique_ptr<SessionDataBase> data;
diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp
index 9d40b9661..acae47fd5 100644
--- a/src/core/hle/service/ac/ac.cpp
+++ b/src/core/hle/service/ac/ac.cpp
@@ -5,6 +5,7 @@
 #include <vector>
 #include "common/common_types.h"
 #include "common/logging/log.h"
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/hle/ipc.h"
 #include "core/hle/ipc_helpers.h"
@@ -16,6 +17,8 @@
 #include "core/hle/service/ac/ac_u.h"
 #include "core/memory.h"
 
+SERIALIZE_EXPORT_IMPL(Service::AC::Module::Interface)
+
 namespace Service::AC {
 void Module::Interface::CreateDefaultConfig(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx, 0x1, 0, 0);
diff --git a/src/core/hle/service/ac/ac.h b/src/core/hle/service/ac/ac.h
index f3554c876..12e304f59 100644
--- a/src/core/hle/service/ac/ac.h
+++ b/src/core/hle/service/ac/ac.h
@@ -6,6 +6,9 @@
 
 #include <array>
 #include <memory>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include "common/construct.h"
 #include "core/hle/service/service.h"
 
 namespace Core {
@@ -139,6 +142,34 @@ public:
 
     protected:
         std::shared_ptr<Module> ac;
+
+    private:
+        template <class Archive>
+        void save_construct(Archive& ar, const unsigned int file_version) const
+        {
+            ar << ac;
+            ar << GetServiceName();
+            ar << GetMaxSessions();
+        }
+
+        template <class Archive>
+        static void load_construct(Archive& ar, Interface* t, const unsigned int file_version)
+        {
+            std::shared_ptr<Module> ac;
+            std::string name;
+            u32 max_sessions;
+            ar >> ac;
+            ar >> name;
+            ar >> max_sessions;
+            ::new(t)Interface(ac, name.c_str(), max_sessions);
+        }
+
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int file_version)
+        {
+            ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        }
+        BOOST_SERIALIZATION_FRIENDS
     };
 
 protected:
@@ -153,8 +184,23 @@ protected:
     std::shared_ptr<Kernel::Event> close_event;
     std::shared_ptr<Kernel::Event> connect_event;
     std::shared_ptr<Kernel::Event> disconnect_event;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version)
+    {
+        ar & ac_connected;
+        ar & close_event;
+        ar & connect_event;
+        ar & disconnect_event;
+        // default_config is never written to
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::AC
+
+BOOST_SERIALIZATION_CONSTRUCT(Service::AC::Module::Interface)
+BOOST_CLASS_EXPORT_KEY(Service::AC::Module::Interface)
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index db6a0ad23..f05c15f23 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -85,6 +85,7 @@ private:
     using InvokerFn = void(ServiceFrameworkBase* object, HandlerFnP<ServiceFrameworkBase> member,
                            Kernel::HLERequestContext& ctx);
 
+    // TODO: Replace all these with virtual functions!
     ServiceFrameworkBase(const char* service_name, u32 max_sessions, InvokerFn* handler_invoker);
     ~ServiceFrameworkBase() override;
 
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 9cdaff72d..d91732da9 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -11,6 +11,7 @@
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/string.hpp>
 #include <boost/serialization/unordered_map.hpp>
+#include <boost/serialization/split_member.hpp>
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
@@ -85,11 +86,23 @@ private:
     std::unordered_map<u32, std::string> registered_services_inverse;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
+    void save(Archive& ar, const unsigned int file_version) const
     {
-        ar & registered_services;
-        ar & registered_services_inverse; // TODO: Instead, compute this from registered_services
+        ar << registered_services;
     }
+
+    template <class Archive>
+    void load(Archive& ar, const unsigned int file_version)
+    {
+        ar >> registered_services;
+        registered_services_inverse.clear();
+        for (const auto& pair : registered_services) {
+            registered_services_inverse.emplace(pair.second->GetObjectId(), pair.first);
+        }
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
+
     friend class boost::serialization::access;
 };
 
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index a07cc2e13..7264e1ec4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -56,7 +56,7 @@ private:
     std::array<bool, LINEAR_HEAP_SIZE / PAGE_SIZE> linear_heap{};
     std::array<bool, NEW_LINEAR_HEAP_SIZE / PAGE_SIZE> new_linear_heap{};
 
-    static_assert(sizeof(bool) == 1); // TODO: Maybe this isn't true?
+    static_assert(sizeof(bool) == 1);
     friend class boost::serialization::access;
     template<typename Archive>
     void serialize(Archive & ar, const unsigned int file_version)

From 3fd5c431f157964bd08fcde73b0352979ff15f91 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 24 Dec 2019 22:39:02 +0000
Subject: [PATCH 018/129] Service serialization framework; done AC

---
 TODO                             |  2 +-
 src/common/construct.h           |  4 ---
 src/core/hle/service/ac/ac.cpp   | 14 +++++++++--
 src/core/hle/service/ac/ac.h     | 43 +++-----------------------------
 src/core/hle/service/ac/ac_i.cpp |  3 +++
 src/core/hle/service/ac/ac_i.h   |  7 ++++++
 src/core/hle/service/service.h   | 25 +++++++++++++++++++
 7 files changed, 51 insertions(+), 47 deletions(-)

diff --git a/TODO b/TODO
index bc62720d6..b9f4fe46b 100644
--- a/TODO
+++ b/TODO
@@ -61,7 +61,7 @@
             Just need to figure out backing_mem (a u8*)
         ✔ Wait object @done(19-08-13 16:46)
     ☐ Service @started(19-12-23 12:49)
-        ☐ AC @started(19-12-23 12:48)
+        ✔ AC @started(19-12-23 12:48) @done(19-12-24 22:38) @lasted(1d9h50m3s)
         ☐ ACT
         ☐ AM
         ☐ APT
diff --git a/src/common/construct.h b/src/common/construct.h
index 28f4cc349..6ef9af1ef 100644
--- a/src/common/construct.h
+++ b/src/common/construct.h
@@ -1,9 +1,5 @@
 #include <boost/serialization/serialization.hpp>
 
-#define BOOST_SERIALIZATION_FRIENDS \
-    friend class boost::serialization::access; \
-    friend class construct_access;
-
 class construct_access {
 public:
     template<class Archive, class T>
diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp
index acae47fd5..356df5a63 100644
--- a/src/core/hle/service/ac/ac.cpp
+++ b/src/core/hle/service/ac/ac.cpp
@@ -17,8 +17,6 @@
 #include "core/hle/service/ac/ac_u.h"
 #include "core/memory.h"
 
-SERIALIZE_EXPORT_IMPL(Service::AC::Module::Interface)
-
 namespace Service::AC {
 void Module::Interface::CreateDefaultConfig(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx, 0x1, 0, 0);
@@ -182,4 +180,16 @@ void InstallInterfaces(Core::System& system) {
     std::make_shared<AC_U>(ac)->InstallAsService(service_manager);
 }
 
+template <class Archive>
+void Module::serialize(Archive& ar, const unsigned int)
+{
+    ar & ac_connected;
+    ar & close_event;
+    ar & connect_event;
+    ar & disconnect_event;
+    // default_config is never written to
+}
+
 } // namespace Service::AC
+
+SERIALIZE_IMPL(Service::AC::Module)
diff --git a/src/core/hle/service/ac/ac.h b/src/core/hle/service/ac/ac.h
index 12e304f59..b7a079b33 100644
--- a/src/core/hle/service/ac/ac.h
+++ b/src/core/hle/service/ac/ac.h
@@ -8,7 +8,6 @@
 #include <memory>
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/shared_ptr.hpp>
-#include "common/construct.h"
 #include "core/hle/service/service.h"
 
 namespace Core {
@@ -19,6 +18,8 @@ namespace Kernel {
 class Event;
 }
 
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(Service::AC::Module::Interface)
+
 namespace Service::AC {
 class Module final {
 public:
@@ -142,34 +143,6 @@ public:
 
     protected:
         std::shared_ptr<Module> ac;
-
-    private:
-        template <class Archive>
-        void save_construct(Archive& ar, const unsigned int file_version) const
-        {
-            ar << ac;
-            ar << GetServiceName();
-            ar << GetMaxSessions();
-        }
-
-        template <class Archive>
-        static void load_construct(Archive& ar, Interface* t, const unsigned int file_version)
-        {
-            std::shared_ptr<Module> ac;
-            std::string name;
-            u32 max_sessions;
-            ar >> ac;
-            ar >> name;
-            ar >> max_sessions;
-            ::new(t)Interface(ac, name.c_str(), max_sessions);
-        }
-
-        template <class Archive>
-        void serialize(Archive& ar, const unsigned int file_version)
-        {
-            ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-        }
-        BOOST_SERIALIZATION_FRIENDS
     };
 
 protected:
@@ -187,20 +160,10 @@ protected:
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & ac_connected;
-        ar & close_event;
-        ar & connect_event;
-        ar & disconnect_event;
-        // default_config is never written to
-    }
+    void serialize(Archive& ar, const unsigned int file_version);
     friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::AC
-
-BOOST_SERIALIZATION_CONSTRUCT(Service::AC::Module::Interface)
-BOOST_CLASS_EXPORT_KEY(Service::AC::Module::Interface)
diff --git a/src/core/hle/service/ac/ac_i.cpp b/src/core/hle/service/ac/ac_i.cpp
index 0dde7bf90..e4cc4c1f1 100644
--- a/src/core/hle/service/ac/ac_i.cpp
+++ b/src/core/hle/service/ac/ac_i.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/ac/ac_i.h"
+#include "common/archives.h"
 
 namespace Service::AC {
 
@@ -33,3 +34,5 @@ AC_I::AC_I(std::shared_ptr<Module> ac) : Module::Interface(std::move(ac), "ac:i"
 }
 
 } // namespace Service::AC
+
+SERIALIZE_EXPORT_IMPL(Service::AC::AC_I)
diff --git a/src/core/hle/service/ac/ac_i.h b/src/core/hle/service/ac/ac_i.h
index bca91aabe..d7ab22b25 100644
--- a/src/core/hle/service/ac/ac_i.h
+++ b/src/core/hle/service/ac/ac_i.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/base_object.hpp>
 #include "core/hle/service/ac/ac.h"
 
 namespace Service::AC {
@@ -12,6 +13,12 @@ namespace Service::AC {
 class AC_I final : public Module::Interface {
 public:
     explicit AC_I(std::shared_ptr<Module> ac);
+
+private:
+    SERVICE_SERIALIZATION(AC_I, ac)
 };
 
 } // namespace Service::AC
+
+BOOST_CLASS_EXPORT_KEY(Service::AC::AC_I)
+BOOST_SERIALIZATION_CONSTRUCT(Service::AC::AC_I)
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index f05c15f23..d124b0070 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -10,7 +10,9 @@
 #include <memory>
 #include <string>
 #include <boost/container/flat_map.hpp>
+#include <boost/serialization/assume_abstract.hpp>
 #include "common/common_types.h"
+#include "common/construct.h"
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/service/sm/sm.h"
@@ -194,3 +196,26 @@ struct ServiceModuleInfo {
 extern const std::array<ServiceModuleInfo, 40> service_module_map;
 
 } // namespace Service
+
+#define SERVICE_SERIALIZATION(T, MFIELD) \
+    template <class Archive> \
+    void save_construct(Archive& ar, const unsigned int file_version) const \
+    { \
+        ar << MFIELD; \
+    } \
+ \
+    template <class Archive> \
+    static void load_construct(Archive& ar, T* t, const unsigned int file_version) \
+    { \
+        std::shared_ptr<Module> MFIELD; \
+        ar >> MFIELD; \
+        ::new(t)T(MFIELD); \
+    } \
+ \
+    template <class Archive> \
+    void serialize(Archive& ar, const unsigned int) \
+    { \
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this); \
+    } \
+    friend class boost::serialization::access; \
+    friend class construct_access;

From 89e4e49a63e53d7ed73170091037067a5c137be1 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 24 Dec 2019 23:17:24 +0000
Subject: [PATCH 019/129] Finished AC and ACT service serialization

---
 TODO                               | 2 +-
 src/core/hle/service/ac/ac.h       | 2 --
 src/core/hle/service/ac/ac_i.h     | 1 -
 src/core/hle/service/ac/ac_u.cpp   | 3 +++
 src/core/hle/service/ac/ac_u.h     | 6 ++++++
 src/core/hle/service/act/act.h     | 6 +++++-
 src/core/hle/service/act/act_a.cpp | 3 +++
 src/core/hle/service/act/act_a.h   | 5 +++++
 src/core/hle/service/act/act_u.cpp | 3 +++
 src/core/hle/service/act/act_u.h   | 5 +++++
 src/core/hle/service/service.h     | 2 ++
 11 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/TODO b/TODO
index b9f4fe46b..a7488a20f 100644
--- a/TODO
+++ b/TODO
@@ -62,7 +62,7 @@
         ✔ Wait object @done(19-08-13 16:46)
     ☐ Service @started(19-12-23 12:49)
         ✔ AC @started(19-12-23 12:48) @done(19-12-24 22:38) @lasted(1d9h50m3s)
-        ☐ ACT
+        ✔ ACT @done(19-12-24 23:17)
         ☐ AM
         ☐ APT
         ☐ BOSS
diff --git a/src/core/hle/service/ac/ac.h b/src/core/hle/service/ac/ac.h
index b7a079b33..0f31ca1b4 100644
--- a/src/core/hle/service/ac/ac.h
+++ b/src/core/hle/service/ac/ac.h
@@ -6,8 +6,6 @@
 
 #include <array>
 #include <memory>
-#include <boost/serialization/base_object.hpp>
-#include <boost/serialization/shared_ptr.hpp>
 #include "core/hle/service/service.h"
 
 namespace Core {
diff --git a/src/core/hle/service/ac/ac_i.h b/src/core/hle/service/ac/ac_i.h
index d7ab22b25..e05bac803 100644
--- a/src/core/hle/service/ac/ac_i.h
+++ b/src/core/hle/service/ac/ac_i.h
@@ -5,7 +5,6 @@
 #pragma once
 
 #include <memory>
-#include <boost/serialization/base_object.hpp>
 #include "core/hle/service/ac/ac.h"
 
 namespace Service::AC {
diff --git a/src/core/hle/service/ac/ac_u.cpp b/src/core/hle/service/ac/ac_u.cpp
index d62d7ccb6..429942f7d 100644
--- a/src/core/hle/service/ac/ac_u.cpp
+++ b/src/core/hle/service/ac/ac_u.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/ac/ac_u.h"
+#include "common/archives.h"
 
 namespace Service::AC {
 
@@ -33,3 +34,5 @@ AC_U::AC_U(std::shared_ptr<Module> ac) : Module::Interface(std::move(ac), "ac:u"
 }
 
 } // namespace Service::AC
+
+SERIALIZE_EXPORT_IMPL(Service::AC::AC_U)
diff --git a/src/core/hle/service/ac/ac_u.h b/src/core/hle/service/ac/ac_u.h
index 18efcd1e6..c15870b51 100644
--- a/src/core/hle/service/ac/ac_u.h
+++ b/src/core/hle/service/ac/ac_u.h
@@ -12,6 +12,12 @@ namespace Service::AC {
 class AC_U final : public Module::Interface {
 public:
     explicit AC_U(std::shared_ptr<Module> ac);
+
+private:
+    SERVICE_SERIALIZATION(AC_U, ac)
 };
 
 } // namespace Service::AC
+
+BOOST_CLASS_EXPORT_KEY(Service::AC::AC_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::AC::AC_U)
diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h
index 884678890..c327cdaef 100644
--- a/src/core/hle/service/act/act.h
+++ b/src/core/hle/service/act/act.h
@@ -20,9 +20,13 @@ public:
         Interface(std::shared_ptr<Module> act, const char* name);
         ~Interface();
 
-    private:
+    protected:
         std::shared_ptr<Module> act;
     };
+private:
+    template <class Archive>
+    inline void serialize(Archive& ar, const unsigned int file_version) { }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
diff --git a/src/core/hle/service/act/act_a.cpp b/src/core/hle/service/act/act_a.cpp
index 7a33f9175..b4bf750f7 100644
--- a/src/core/hle/service/act/act_a.cpp
+++ b/src/core/hle/service/act/act_a.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/act/act_a.h"
+#include "common/archives.h"
 
 namespace Service::ACT {
 
@@ -24,3 +25,5 @@ ACT_A::ACT_A(std::shared_ptr<Module> act) : Module::Interface(std::move(act), "a
 }
 
 } // namespace Service::ACT
+
+SERIALIZE_EXPORT_IMPL(Service::ACT::ACT_A)
diff --git a/src/core/hle/service/act/act_a.h b/src/core/hle/service/act/act_a.h
index 48a79aab7..036a96182 100644
--- a/src/core/hle/service/act/act_a.h
+++ b/src/core/hle/service/act/act_a.h
@@ -11,6 +11,11 @@ namespace Service::ACT {
 class ACT_A final : public Module::Interface {
 public:
     explicit ACT_A(std::shared_ptr<Module> act);
+private:
+    SERVICE_SERIALIZATION(ACT_A, act)
 };
 
 } // namespace Service::ACT
+
+BOOST_CLASS_EXPORT_KEY(Service::ACT::ACT_A)
+BOOST_SERIALIZATION_CONSTRUCT(Service::ACT::ACT_A)
diff --git a/src/core/hle/service/act/act_u.cpp b/src/core/hle/service/act/act_u.cpp
index 99978d9ca..599bec18a 100644
--- a/src/core/hle/service/act/act_u.cpp
+++ b/src/core/hle/service/act/act_u.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/act/act_u.h"
+#include "common/archives.h"
 
 namespace Service::ACT {
 
@@ -20,3 +21,5 @@ ACT_U::ACT_U(std::shared_ptr<Module> act) : Module::Interface(std::move(act), "a
 }
 
 } // namespace Service::ACT
+
+SERIALIZE_EXPORT_IMPL(Service::ACT::ACT_U)
diff --git a/src/core/hle/service/act/act_u.h b/src/core/hle/service/act/act_u.h
index 3aca428e6..14d924025 100644
--- a/src/core/hle/service/act/act_u.h
+++ b/src/core/hle/service/act/act_u.h
@@ -11,6 +11,11 @@ namespace Service::ACT {
 class ACT_U final : public Module::Interface {
 public:
     explicit ACT_U(std::shared_ptr<Module> act);
+private:
+    SERVICE_SERIALIZATION(ACT_U, act)
 };
 
 } // namespace Service::ACT
+
+BOOST_CLASS_EXPORT_KEY(Service::ACT::ACT_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::ACT::ACT_U)
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index d124b0070..bdad47ea8 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -11,6 +11,8 @@
 #include <string>
 #include <boost/container/flat_map.hpp>
 #include <boost/serialization/assume_abstract.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/base_object.hpp>
 #include "common/common_types.h"
 #include "common/construct.h"
 #include "core/hle/kernel/hle_ipc.h"

From e707685c2a1cfbede81e30594d865b11268a5362 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 24 Dec 2019 23:53:51 +0000
Subject: [PATCH 020/129] Serialize AM services

---
 TODO                                |  2 +-
 src/core/hle/service/am/am.cpp      |  8 +++++---
 src/core/hle/service/am/am.h        | 26 ++++++++++++++++++++++++--
 src/core/hle/service/am/am_app.cpp  |  3 +++
 src/core/hle/service/am/am_app.h    |  5 +++++
 src/core/hle/service/am/am_net.cpp  |  3 +++
 src/core/hle/service/am/am_net.h    |  5 +++++
 src/core/hle/service/am/am_sys.cpp  |  3 +++
 src/core/hle/service/am/am_sys.h    |  5 +++++
 src/core/hle/service/am/am_u.cpp    |  3 +++
 src/core/hle/service/am/am_u.h      |  5 +++++
 src/core/hle/service/fs/archive.cpp |  3 ++-
 src/core/hle/service/fs/file.cpp    | 10 +++++-----
 src/core/hle/service/fs/file.h      |  4 ++--
 14 files changed, 71 insertions(+), 14 deletions(-)

diff --git a/TODO b/TODO
index a7488a20f..673ef0a14 100644
--- a/TODO
+++ b/TODO
@@ -63,7 +63,7 @@
     ☐ Service @started(19-12-23 12:49)
         ✔ AC @started(19-12-23 12:48) @done(19-12-24 22:38) @lasted(1d9h50m3s)
         ✔ ACT @done(19-12-24 23:17)
-        ☐ AM
+        ✔ AM @started(19-12-24 23:17) @done(19-12-24 23:53) @lasted(36m8s)
         ☐ APT
         ☐ BOSS
         ☐ CAM
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 65b9c3e01..45ed29e6c 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1021,7 +1021,7 @@ void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) {
     // Citra will store contents out to sdmc/nand
     const FileSys::Path cia_path = {};
     auto file = std::make_shared<Service::FS::File>(
-        am->system, std::make_unique<CIAFile>(media_type), cia_path);
+        am->kernel, std::make_unique<CIAFile>(media_type), cia_path);
 
     am->cia_installing = true;
 
@@ -1048,7 +1048,7 @@ void Module::Interface::BeginImportProgramTemporarily(Kernel::HLERequestContext&
     // contents out to sdmc/nand
     const FileSys::Path cia_path = {};
     auto file = std::make_shared<Service::FS::File>(
-        am->system, std::make_unique<CIAFile>(FS::MediaType::NAND), cia_path);
+        am->kernel, std::make_unique<CIAFile>(FS::MediaType::NAND), cia_path);
 
     am->cia_installing = true;
 
@@ -1450,11 +1450,13 @@ void Module::Interface::GetMetaDataFromCia(Kernel::HLERequestContext& ctx) {
     rb.PushMappedBuffer(output_buffer);
 }
 
-Module::Module(Core::System& system) : system(system) {
+Module::Module(Core::System& system) : kernel(system.Kernel()) {
     ScanForAllTitles();
     system_updater_mutex = system.Kernel().CreateMutex(false, "AM::SystemUpdaterMutex");
 }
 
+Module::Module(Kernel::KernelSystem& kernel) : kernel(kernel) { }
+
 Module::~Module() = default;
 
 void InstallInterfaces(Core::System& system) {
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 0912dde40..88a70bf10 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -9,6 +9,9 @@
 #include <memory>
 #include <string>
 #include <vector>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/cia_container.h"
 #include "core/file_sys/file_backend.h"
@@ -150,6 +153,8 @@ std::string GetMediaTitlePath(Service::FS::MediaType media_type);
 class Module final {
 public:
     explicit Module(Core::System& system);
+    explicit Module(Kernel::KernelSystem& kernel);
+    Module() = default;
     ~Module();
 
     class Interface : public ServiceFramework<Interface> {
@@ -557,7 +562,7 @@ public:
          */
         void GetMetaDataFromCia(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> am;
     };
 
@@ -573,12 +578,29 @@ private:
      */
     void ScanForAllTitles();
 
-    Core::System& system;
+    Kernel::KernelSystem& kernel;
     bool cia_installing = false;
     std::array<std::vector<u64_le>, 3> am_title_list;
     std::shared_ptr<Kernel::Mutex> system_updater_mutex;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & cia_installing;
+        ar & am_title_list;
+        ar & system_updater_mutex;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::AM
+
+namespace boost::serialization {
+    template <class Archive>
+    inline void load_construct_data(Archive& ar, Service::AM::Module* t, const unsigned int)
+    {
+        ::new(t)Service::AM::Module(*Kernel::g_kernel);
+    }
+}
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index cee1aa81b..52d256ca2 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/am/am_app.h"
+#include "common/archives.h"
 
 namespace Service::AM {
 
@@ -26,3 +27,5 @@ AM_APP::AM_APP(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
 }
 
 } // namespace Service::AM
+
+SERIALIZE_EXPORT_IMPL(Service::AM::AM_APP)
diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h
index 67cf8ba2e..e78b5ef70 100644
--- a/src/core/hle/service/am/am_app.h
+++ b/src/core/hle/service/am/am_app.h
@@ -11,6 +11,11 @@ namespace Service::AM {
 class AM_APP final : public Module::Interface {
 public:
     explicit AM_APP(std::shared_ptr<Module> am);
+private:
+    SERVICE_SERIALIZATION(AM_APP, am)
 };
 
 } // namespace Service::AM
+
+BOOST_CLASS_EXPORT_KEY(Service::AM::AM_APP)
+BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_APP)
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index 120ee53e7..44c852c19 100644
--- a/src/core/hle/service/am/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/am/am_net.h"
+#include "common/archives.h"
 
 namespace Service::AM {
 
@@ -123,3 +124,5 @@ AM_NET::AM_NET(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
 }
 
 } // namespace Service::AM
+
+SERIALIZE_EXPORT_IMPL(Service::AM::AM_NET)
diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h
index a5adbd7e5..74e335b76 100644
--- a/src/core/hle/service/am/am_net.h
+++ b/src/core/hle/service/am/am_net.h
@@ -11,6 +11,11 @@ namespace Service::AM {
 class AM_NET final : public Module::Interface {
 public:
     explicit AM_NET(std::shared_ptr<Module> am);
+private:
+    SERVICE_SERIALIZATION(AM_NET, am)
 };
 
 } // namespace Service::AM
+
+BOOST_CLASS_EXPORT_KEY(Service::AM::AM_NET)
+BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_NET)
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp
index ca4affbc2..c6817fe87 100644
--- a/src/core/hle/service/am/am_sys.cpp
+++ b/src/core/hle/service/am/am_sys.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/am/am_sys.h"
+#include "common/archives.h"
 
 namespace Service::AM {
 
@@ -71,3 +72,5 @@ AM_SYS::AM_SYS(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "a
 }
 
 } // namespace Service::AM
+
+SERIALIZE_EXPORT_IMPL(Service::AM::AM_SYS)
diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h
index b142916ca..028837f3d 100644
--- a/src/core/hle/service/am/am_sys.h
+++ b/src/core/hle/service/am/am_sys.h
@@ -11,6 +11,11 @@ namespace Service::AM {
 class AM_SYS final : public Module::Interface {
 public:
     explicit AM_SYS(std::shared_ptr<Module> am);
+private:
+    SERVICE_SERIALIZATION(AM_SYS, am)
 };
 
 } // namespace Service::AM
+
+BOOST_CLASS_EXPORT_KEY(Service::AM::AM_SYS)
+BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_SYS)
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp
index 840860ec0..c9b80bf06 100644
--- a/src/core/hle/service/am/am_u.cpp
+++ b/src/core/hle/service/am/am_u.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/am/am_u.h"
+#include "common/archives.h"
 
 namespace Service::AM {
 
@@ -83,3 +84,5 @@ AM_U::AM_U(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "am:u"
 }
 
 } // namespace Service::AM
+
+SERIALIZE_EXPORT_IMPL(Service::AM::AM_U)
diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h
index 1d732c90a..b19d48167 100644
--- a/src/core/hle/service/am/am_u.h
+++ b/src/core/hle/service/am/am_u.h
@@ -11,6 +11,11 @@ namespace Service::AM {
 class AM_U final : public Module::Interface {
 public:
     explicit AM_U(std::shared_ptr<Module> am);
+private:
+    SERVICE_SERIALIZATION(AM_U, am)
 };
 
 } // namespace Service::AM
+
+BOOST_CLASS_EXPORT_KEY(Service::AM::AM_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::AM::AM_U)
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 6e179978b..90dfad62f 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -27,6 +27,7 @@
 #include "core/file_sys/file_backend.h"
 #include "core/hle/result.h"
 #include "core/hle/service/fs/archive.h"
+#include "core/core.h"
 
 namespace Service::FS {
 
@@ -90,7 +91,7 @@ ArchiveManager::OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys:
     if (backend.Failed())
         return std::make_tuple(backend.Code(), open_timeout_ns);
 
-    auto file = std::shared_ptr<File>(new File(system, std::move(backend).Unwrap(), path));
+    auto file = std::shared_ptr<File>(new File(system.Kernel(), std::move(backend).Unwrap(), path));
     return std::make_tuple(MakeResult<std::shared_ptr<File>>(std::move(file)), open_timeout_ns);
 }
 
diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp
index e31f89d0e..946e27211 100644
--- a/src/core/hle/service/fs/file.cpp
+++ b/src/core/hle/service/fs/file.cpp
@@ -15,9 +15,9 @@
 
 namespace Service::FS {
 
-File::File(Core::System& system, std::unique_ptr<FileSys::FileBackend>&& backend,
+File::File(Kernel::KernelSystem& kernel, std::unique_ptr<FileSys::FileBackend>&& backend,
            const FileSys::Path& path)
-    : ServiceFramework("", 1), path(path), backend(std::move(backend)), system(system) {
+    : ServiceFramework("", 1), path(path), backend(std::move(backend)), kernel(kernel) {
     static const FunctionInfo functions[] = {
         {0x08010100, &File::OpenSubFile, "OpenSubFile"},
         {0x080200C2, &File::Read, "Read"},
@@ -197,7 +197,7 @@ void File::OpenLinkFile(Kernel::HLERequestContext& ctx) {
     using Kernel::ServerSession;
     IPC::RequestParser rp(ctx, 0x080C, 0, 0);
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
-    auto [server, client] = system.Kernel().CreateSessionPair(GetName());
+    auto [server, client] = kernel.CreateSessionPair(GetName());
     ClientConnected(server);
 
     FileSessionSlot* slot = GetSessionData(server);
@@ -243,7 +243,7 @@ void File::OpenSubFile(Kernel::HLERequestContext& ctx) {
 
     using Kernel::ClientSession;
     using Kernel::ServerSession;
-    auto [server, client] = system.Kernel().CreateSessionPair(GetName());
+    auto [server, client] = kernel.CreateSessionPair(GetName());
     ClientConnected(server);
 
     FileSessionSlot* slot = GetSessionData(server);
@@ -257,7 +257,7 @@ void File::OpenSubFile(Kernel::HLERequestContext& ctx) {
 }
 
 std::shared_ptr<Kernel::ClientSession> File::Connect() {
-    auto [server, client] = system.Kernel().CreateSessionPair(GetName());
+    auto [server, client] = kernel.CreateSessionPair(GetName());
     ClientConnected(server);
 
     FileSessionSlot* slot = GetSessionData(server);
diff --git a/src/core/hle/service/fs/file.h b/src/core/hle/service/fs/file.h
index 062fcd5e7..ff4a5670a 100644
--- a/src/core/hle/service/fs/file.h
+++ b/src/core/hle/service/fs/file.h
@@ -25,7 +25,7 @@ struct FileSessionSlot : public Kernel::SessionRequestHandler::SessionDataBase {
 // Consider splitting ServiceFramework interface.
 class File final : public ServiceFramework<File, FileSessionSlot> {
 public:
-    File(Core::System& system, std::unique_ptr<FileSys::FileBackend>&& backend,
+    File(Kernel::KernelSystem& kernel, std::unique_ptr<FileSys::FileBackend>&& backend,
          const FileSys::Path& path);
     ~File() = default;
 
@@ -59,7 +59,7 @@ private:
     void OpenLinkFile(Kernel::HLERequestContext& ctx);
     void OpenSubFile(Kernel::HLERequestContext& ctx);
 
-    Core::System& system;
+    Kernel::KernelSystem& kernel;
 };
 
 } // namespace Service::FS

From 3e752002c4245746b4c1bf47f75af48ed866cd97 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 25 Dec 2019 18:51:56 +0000
Subject: [PATCH 021/129] Replace g_kernel with Core::Global etc.

---
 TODO                                    | 2 +-
 src/core/core.cpp                       | 9 +++++++--
 src/core/global.h                       | 6 ++++++
 src/core/hle/kernel/address_arbiter.cpp | 3 ++-
 src/core/hle/kernel/client_port.cpp     | 3 ++-
 src/core/hle/kernel/kernel.cpp          | 2 --
 src/core/hle/kernel/kernel.h            | 2 --
 src/core/hle/kernel/mutex.cpp           | 3 ++-
 src/core/hle/kernel/process.cpp         | 7 ++++++-
 src/core/hle/kernel/process.h           | 3 ++-
 src/core/hle/kernel/server_session.cpp  | 3 ++-
 src/core/hle/kernel/thread.cpp          | 5 +++--
 src/core/hle/kernel/timer.cpp           | 3 ++-
 src/core/hle/service/am/am.h            | 3 ++-
 src/video_core/pica.cpp                 | 6 ++++++
 15 files changed, 43 insertions(+), 17 deletions(-)
 create mode 100644 src/core/global.h

diff --git a/TODO b/TODO
index 673ef0a14..7309acb1a 100644
--- a/TODO
+++ b/TODO
@@ -26,7 +26,7 @@
     ✔ Shader @done(19-08-13 16:03)
 ☐ HLE @started(19-08-13 16:43)
     ☐ Kernel @started(19-08-13 16:43)
-        Most of these require adding g_kernel
+        Most of these require adding Core::Global
         ✔ Address arbiter @done(19-08-13 16:40)
         ✔ Client port @done(19-08-13 16:40)
         ✔ Client session @done(19-08-13 16:40)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 8ca3a2ab5..055eadae2 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -25,6 +25,7 @@
 #endif
 #include "core/custom_tex_cache.h"
 #include "core/gdbstub/gdbstub.h"
+#include "core/global.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
@@ -46,6 +47,12 @@ namespace Core {
 
 /*static*/ System System::s_instance;
 
+template <>
+Core::System& Global() { return System::GetInstance(); }
+
+template <>
+Kernel::KernelSystem& Global() { return System::GetInstance().Kernel(); }
+
 System::ResultStatus System::RunLoop(bool tight_loop) {
     status = ResultStatus::Success;
     if (!cpu_core) {
@@ -204,7 +211,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
                                                     [this] { PrepareReschedule(); }, system_mode);
-    Kernel::g_kernel = kernel.get();
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -368,7 +374,6 @@ void System::Shutdown() {
     service_manager.reset();
     dsp_core.reset();
     cpu_core.reset();
-    Kernel::g_kernel = nullptr;
     kernel.reset();
     timing.reset();
     app_loader.reset();
diff --git a/src/core/global.h b/src/core/global.h
new file mode 100644
index 000000000..8dfd022d8
--- /dev/null
+++ b/src/core/global.h
@@ -0,0 +1,6 @@
+namespace Core {
+
+template <class T>
+T& Global();
+
+} // namespace Core
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index c4fb4fd99..ca120e6f9 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -11,6 +11,7 @@
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/thread.h"
 #include "core/memory.h"
+#include "core/global.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Kernel namespace
@@ -68,7 +69,7 @@ std::shared_ptr<Thread> AddressArbiter::ResumeHighestPriorityThread(VAddr addres
     return thread;
 }
 
-AddressArbiter::AddressArbiter() : kernel(*g_kernel) {}
+AddressArbiter::AddressArbiter() : kernel(Core::Global<KernelSystem>()) {}
 AddressArbiter::~AddressArbiter() {}
 
 std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string name) {
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index 3334a278b..f9202035c 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -11,6 +11,7 @@
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
+#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::ClientPort)
 
@@ -26,7 +27,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
     active_sessions++;
 
     // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
-    auto [server, client] = g_kernel->CreateSessionPair(server_port->GetName(), SharedFrom(this));
+    auto [server, client] = Core::Global<KernelSystem>().CreateSessionPair(server_port->GetName(), SharedFrom(this));
 
     if (server_port->hle_handler)
         server_port->hle_handler->ClientConnected(server);
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4f9a02410..a45973968 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -18,8 +18,6 @@
 
 namespace Kernel {
 
-KernelSystem* g_kernel;
-
 /// Initialize the kernel
 KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
                            std::function<void()> prepare_reschedule_callback, u32 system_mode)
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index c662882f5..6ca3267fb 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -292,6 +292,4 @@ private:
     void serialize(Archive& ar, const unsigned int file_version);
 };
 
-extern KernelSystem* g_kernel;
-
 } // namespace Kernel
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index b8a3d143b..16bcd3af2 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -12,6 +12,7 @@
 #include "core/hle/kernel/mutex.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
+#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::Mutex)
 
@@ -26,7 +27,7 @@ void ReleaseThreadMutexes(Thread* thread) {
     thread->held_mutexes.clear();
 }
 
-Mutex::Mutex() : kernel(*g_kernel) {}
+Mutex::Mutex() : kernel(Core::Global<KernelSystem>()) {}
 Mutex::~Mutex() {}
 
 std::shared_ptr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::string name) {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 5fad4fd85..72f882c56 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -18,6 +18,7 @@
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/vm_manager.h"
 #include "core/memory.h"
+#include "core/global.h"
 
 namespace Kernel {
 
@@ -427,7 +428,11 @@ ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission pe
     return RESULT_SUCCESS;
 }
 
-Kernel::Process::Process() : kernel(*g_kernel), handle_table(*g_kernel), vm_manager(g_kernel->memory)
+Kernel::Process::Process() : Kernel::Process::Process(Core::Global<KernelSystem>())
+{
+}
+
+Kernel::Process::Process(KernelSystem& kernel) : kernel(kernel), handle_table(kernel), vm_manager(kernel.memory)
 {
     kernel.memory.RegisterPageTable(&vm_manager.page_table);
 }
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index edda20c1f..70a5f212b 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -143,7 +143,8 @@ private:
 
 class Process final : public Object {
 public:
-    explicit Process();
+    Process();
+    explicit Process(KernelSystem& kernel);
     ~Process() override;
 
     std::string GetTypeName() const override {
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index f2ceb899e..146142f08 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -10,12 +10,13 @@
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/session.h"
 #include "core/hle/kernel/thread.h"
+#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::ServerSession)
 
 namespace Kernel {
 
-ServerSession::ServerSession() : kernel(*g_kernel) {}
+ServerSession::ServerSession() : kernel(Core::Global<KernelSystem>()) {}
 ServerSession::~ServerSession() {
     // This destructor will be called automatically when the last ServerSession handle is closed by
     // the emulated application.
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 409dcc886..98fe85175 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -24,6 +24,7 @@
 #include "core/hle/kernel/thread.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
+#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::Thread)
 
@@ -66,8 +67,8 @@ u32 ThreadManager::NewThreadId() {
 }
 
 Thread::Thread()
-    : context(g_kernel->GetThreadManager().NewContext()),
-      thread_manager(g_kernel->GetThreadManager()) {}
+    : context(Core::Global<KernelSystem>().GetThreadManager().NewContext()),
+      thread_manager(Core::Global<KernelSystem>().GetThreadManager()) {}
 Thread::~Thread() {}
 
 Thread* ThreadManager::GetCurrentThread() const {
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index f073c3312..422cf990c 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -11,10 +11,11 @@
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/timer.h"
+#include "core/global.h"
 
 namespace Kernel {
 
-Timer::Timer() : kernel(*g_kernel), timer_manager(g_kernel->GetTimerManager()) {}
+Timer::Timer() : kernel(Core::Global<KernelSystem>()), timer_manager(Core::Global<KernelSystem>().GetTimerManager()) {}
 Timer::~Timer() {
     Cancel();
     timer_manager.timer_callback_table.erase(callback_id);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 88a70bf10..771bbfb53 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -18,6 +18,7 @@
 #include "core/hle/kernel/mutex.h"
 #include "core/hle/result.h"
 #include "core/hle/service/service.h"
+#include "core/global.h"
 
 namespace Core {
 class System;
@@ -601,6 +602,6 @@ namespace boost::serialization {
     template <class Archive>
     inline void load_construct_data(Archive& ar, Service::AM::Module* t, const unsigned int)
     {
-        ::new(t)Service::AM::Module(*Kernel::g_kernel);
+        ::new(t)Service::AM::Module(Core::Global<Kernel::KernelSystem>());
     }
 }
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index 1475e3a92..0b5aaa682 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -8,6 +8,12 @@
 #include "video_core/pica_state.h"
 #include "video_core/renderer_base.h"
 #include "video_core/video_core.h"
+#include "core/global.h"
+
+namespace Core {
+    template <>
+    Pica::State& Global() { return Pica::g_state; }
+}
 
 namespace Pica {
 

From 5265c79056c4e3546b3550018f0f1cfc4b7d4414 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 25 Dec 2019 21:43:51 +0000
Subject: [PATCH 022/129] APT service serialization

---
 TODO                                      |  2 +-
 src/common/serialization/optional.h       | 91 +++++++++++++++++++++++
 src/core/global.h                         |  5 ++
 src/core/hle/kernel/shared_memory.cpp     |  7 +-
 src/core/hle/kernel/shared_memory.h       |  2 +-
 src/core/hle/service/ac/ac_i.h            |  2 +-
 src/core/hle/service/ac/ac_u.h            |  2 +-
 src/core/hle/service/act/act_a.h          |  2 +-
 src/core/hle/service/act/act_u.h          |  2 +-
 src/core/hle/service/am/am_app.h          |  2 +-
 src/core/hle/service/am/am_net.h          |  2 +-
 src/core/hle/service/am/am_sys.h          |  2 +-
 src/core/hle/service/am/am_u.h            |  2 +-
 src/core/hle/service/apt/applet_manager.h | 60 +++++++++++++++
 src/core/hle/service/apt/apt.cpp          | 28 +++++++
 src/core/hle/service/apt/apt.h            | 17 ++++-
 src/core/hle/service/apt/apt_a.cpp        |  3 +
 src/core/hle/service/apt/apt_a.h          |  5 ++
 src/core/hle/service/apt/apt_s.cpp        |  3 +
 src/core/hle/service/apt/apt_s.h          |  5 ++
 src/core/hle/service/apt/apt_u.cpp        |  3 +
 src/core/hle/service/apt/apt_u.h          |  5 ++
 src/core/hle/service/apt/ns_s.cpp         |  3 +
 src/core/hle/service/apt/ns_s.h           |  5 ++
 src/core/hle/service/service.h            |  4 +-
 25 files changed, 247 insertions(+), 17 deletions(-)
 create mode 100644 src/common/serialization/optional.h

diff --git a/TODO b/TODO
index 7309acb1a..9e591af8d 100644
--- a/TODO
+++ b/TODO
@@ -64,7 +64,7 @@
         ✔ AC @started(19-12-23 12:48) @done(19-12-24 22:38) @lasted(1d9h50m3s)
         ✔ ACT @done(19-12-24 23:17)
         ✔ AM @started(19-12-24 23:17) @done(19-12-24 23:53) @lasted(36m8s)
-        ☐ APT
+        ✔ APT @done(19-12-25 21:41)
         ☐ BOSS
         ☐ CAM
         ☐ CECD
diff --git a/src/common/serialization/optional.h b/src/common/serialization/optional.h
new file mode 100644
index 000000000..5ab6af9b8
--- /dev/null
+++ b/src/common/serialization/optional.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include <boost/config.hpp>
+
+#include <boost/archive/detail/basic_iarchive.hpp>
+
+#include <optional>
+#include <boost/move/utility_core.hpp>
+
+#include <boost/serialization/item_version_type.hpp>
+#include <boost/serialization/split_free.hpp>
+#include <boost/serialization/level.hpp>
+#include <boost/serialization/nvp.hpp>
+#include <boost/serialization/version.hpp>
+#include <boost/type_traits/is_pointer.hpp>
+#include <boost/serialization/detail/stack_constructor.hpp>
+#include <boost/serialization/detail/is_default_constructible.hpp>
+#include <boost/serialization/force_include.hpp>
+
+// function specializations must be defined in the appropriate
+// namespace - boost::serialization
+namespace boost {
+namespace serialization {
+
+template<class Archive, class T>
+void save(
+    Archive & ar,
+    const std::optional< T > & t,
+    const unsigned int /*version*/
+){
+    // It is an inherent limitation to the serialization of optional.hpp
+    // that the underlying type must be either a pointer or must have a
+    // default constructor.  It's possible that this could change sometime
+    // in the future, but for now, one will have to work around it.  This can
+    // be done by serialization the optional<T> as optional<T *>
+    #if ! defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
+        BOOST_STATIC_ASSERT(
+            boost::serialization::detail::is_default_constructible<T>::value
+            || boost::is_pointer<T>::value
+        );
+    #endif
+    const bool tflag = t.has_value();
+    ar << boost::serialization::make_nvp("initialized", tflag);
+    if (tflag){
+        ar << boost::serialization::make_nvp("value", *t);
+    }
+}
+
+template<class Archive, class T>
+void load(
+    Archive & ar,
+    std::optional< T > & t,
+    const unsigned int version
+){
+    bool tflag;
+    ar >> boost::serialization::make_nvp("initialized", tflag);
+    if(! tflag){
+        t.reset();
+        return;
+    }
+
+    if(0 == version){
+        boost::serialization::item_version_type item_version(0);
+        boost::archive::library_version_type library_version(
+            ar.get_library_version()
+        );
+        if(boost::archive::library_version_type(3) < library_version){
+            ar >> BOOST_SERIALIZATION_NVP(item_version);
+        }
+    }
+    if(! t.has_value())
+        t = T();
+    ar >> boost::serialization::make_nvp("value", *t);
+}
+
+template<class Archive, class T>
+void serialize(
+    Archive & ar,
+    std::optional< T > & t,
+    const unsigned int version
+){
+    boost::serialization::split_free(ar, t, version);
+}
+
+template<class T>
+struct version<std::optional<T> > {
+    BOOST_STATIC_CONSTANT(int, value = 1);
+};
+
+} // serialization
+} // boost
diff --git a/src/core/global.h b/src/core/global.h
index 8dfd022d8..d2e1cd97d 100644
--- a/src/core/global.h
+++ b/src/core/global.h
@@ -3,4 +3,9 @@ namespace Core {
 template <class T>
 T& Global();
 
+// Declare explicit specialisation to prevent im
+class System;
+template <>
+System& Global();
+
 } // namespace Core
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 4cd305508..c76cdfa19 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -8,10 +8,11 @@
 #include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/memory.h"
+#include "core/global.h"
 
 namespace Kernel {
 
-SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
+SharedMemory::SharedMemory() : Object(Core::Global<KernelSystem>()), kernel(Core::Global<KernelSystem>()) {}
 SharedMemory::~SharedMemory() {
     for (const auto& interval : holding_memory) {
         kernel.GetMemoryRegion(MemoryRegion::SYSTEM)
@@ -27,7 +28,7 @@ SharedMemory::~SharedMemory() {
 ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
     Process* owner_process, u32 size, MemoryPermission permissions,
     MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
-    auto shared_memory{std::make_shared<SharedMemory>(*this)};
+    auto shared_memory{std::make_shared<SharedMemory>()};
 
     shared_memory->owner_process = owner_process;
     shared_memory->name = std::move(name);
@@ -72,7 +73,7 @@ ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
 std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
     u32 offset, u32 size, MemoryPermission permissions, MemoryPermission other_permissions,
     std::string name) {
-    auto shared_memory{std::make_shared<SharedMemory>(*this)};
+    auto shared_memory{std::make_shared<SharedMemory>()};
 
     // Allocate memory in heap
     MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 8aaf3df1f..925f7783c 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -16,7 +16,7 @@ namespace Kernel {
 
 class SharedMemory final : public Object {
 public:
-    explicit SharedMemory(KernelSystem& kernel);
+    explicit SharedMemory();
     ~SharedMemory() override;
 
     std::string GetTypeName() const override {
diff --git a/src/core/hle/service/ac/ac_i.h b/src/core/hle/service/ac/ac_i.h
index e05bac803..8e852fb9b 100644
--- a/src/core/hle/service/ac/ac_i.h
+++ b/src/core/hle/service/ac/ac_i.h
@@ -14,7 +14,7 @@ public:
     explicit AC_I(std::shared_ptr<Module> ac);
 
 private:
-    SERVICE_SERIALIZATION(AC_I, ac)
+    SERVICE_SERIALIZATION(AC_I, ac, Module)
 };
 
 } // namespace Service::AC
diff --git a/src/core/hle/service/ac/ac_u.h b/src/core/hle/service/ac/ac_u.h
index c15870b51..117269f1f 100644
--- a/src/core/hle/service/ac/ac_u.h
+++ b/src/core/hle/service/ac/ac_u.h
@@ -14,7 +14,7 @@ public:
     explicit AC_U(std::shared_ptr<Module> ac);
 
 private:
-    SERVICE_SERIALIZATION(AC_U, ac)
+    SERVICE_SERIALIZATION(AC_U, ac, Module)
 };
 
 } // namespace Service::AC
diff --git a/src/core/hle/service/act/act_a.h b/src/core/hle/service/act/act_a.h
index 036a96182..1e37c9bde 100644
--- a/src/core/hle/service/act/act_a.h
+++ b/src/core/hle/service/act/act_a.h
@@ -12,7 +12,7 @@ class ACT_A final : public Module::Interface {
 public:
     explicit ACT_A(std::shared_ptr<Module> act);
 private:
-    SERVICE_SERIALIZATION(ACT_A, act)
+    SERVICE_SERIALIZATION(ACT_A, act, Module)
 };
 
 } // namespace Service::ACT
diff --git a/src/core/hle/service/act/act_u.h b/src/core/hle/service/act/act_u.h
index 14d924025..820aa862a 100644
--- a/src/core/hle/service/act/act_u.h
+++ b/src/core/hle/service/act/act_u.h
@@ -12,7 +12,7 @@ class ACT_U final : public Module::Interface {
 public:
     explicit ACT_U(std::shared_ptr<Module> act);
 private:
-    SERVICE_SERIALIZATION(ACT_U, act)
+    SERVICE_SERIALIZATION(ACT_U, act, Module)
 };
 
 } // namespace Service::ACT
diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h
index e78b5ef70..fae22d96f 100644
--- a/src/core/hle/service/am/am_app.h
+++ b/src/core/hle/service/am/am_app.h
@@ -12,7 +12,7 @@ class AM_APP final : public Module::Interface {
 public:
     explicit AM_APP(std::shared_ptr<Module> am);
 private:
-    SERVICE_SERIALIZATION(AM_APP, am)
+    SERVICE_SERIALIZATION(AM_APP, am, Module)
 };
 
 } // namespace Service::AM
diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h
index 74e335b76..4a50c6c07 100644
--- a/src/core/hle/service/am/am_net.h
+++ b/src/core/hle/service/am/am_net.h
@@ -12,7 +12,7 @@ class AM_NET final : public Module::Interface {
 public:
     explicit AM_NET(std::shared_ptr<Module> am);
 private:
-    SERVICE_SERIALIZATION(AM_NET, am)
+    SERVICE_SERIALIZATION(AM_NET, am, Module)
 };
 
 } // namespace Service::AM
diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h
index 028837f3d..c67052302 100644
--- a/src/core/hle/service/am/am_sys.h
+++ b/src/core/hle/service/am/am_sys.h
@@ -12,7 +12,7 @@ class AM_SYS final : public Module::Interface {
 public:
     explicit AM_SYS(std::shared_ptr<Module> am);
 private:
-    SERVICE_SERIALIZATION(AM_SYS, am)
+    SERVICE_SERIALIZATION(AM_SYS, am, Module)
 };
 
 } // namespace Service::AM
diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h
index b19d48167..c09e27c09 100644
--- a/src/core/hle/service/am/am_u.h
+++ b/src/core/hle/service/am/am_u.h
@@ -12,7 +12,7 @@ class AM_U final : public Module::Interface {
 public:
     explicit AM_U(std::shared_ptr<Module> am);
 private:
-    SERVICE_SERIALIZATION(AM_U, am)
+    SERVICE_SERIALIZATION(AM_U, am, Module)
 };
 
 } // namespace Service::AM
diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h
index 6bc880bd4..9410b6b54 100644
--- a/src/core/hle/service/apt/applet_manager.h
+++ b/src/core/hle/service/apt/applet_manager.h
@@ -8,9 +8,12 @@
 #include <memory>
 #include <optional>
 #include <vector>
+#include <boost/serialization/array.hpp>
+#include "common/serialization/optional.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/result.h"
 #include "core/hle/service/fs/archive.h"
+#include "core/global.h"
 
 namespace Core {
 class System;
@@ -84,6 +87,18 @@ struct MessageParameter {
     SignalType signal = SignalType::None;
     std::shared_ptr<Kernel::Object> object = nullptr;
     std::vector<u8> buffer;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & sender_id;
+        ar & destination_id;
+        ar & signal;
+        ar & object;
+        ar & buffer;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Holds information about the parameters used in StartLibraryApplet
@@ -161,6 +176,17 @@ public:
 
         u64 current_title_id;
         FS::MediaType current_media_type;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int)
+        {
+            ar & next_title_id;
+            ar & next_media_type;
+            ar & current_title_id;
+            ar & current_media_type;
+        }
+        friend class boost::serialization::access;
     };
 
     ApplicationJumpParameters GetApplicationJumpParameters() const {
@@ -199,6 +225,21 @@ private:
             title_id = 0;
             attributes.raw = 0;
         }
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int)
+        {
+            ar & applet_id;
+            ar & slot;
+            ar & title_id;
+            ar & registered;
+            ar & loaded;
+            ar & attributes.raw;
+            ar & notification_event;
+            ar & parameter_event;
+        }
+        friend class boost::serialization::access;
     };
 
     ApplicationJumpParameters app_jump_parameters{};
@@ -216,6 +257,25 @@ private:
     SignalType library_applet_closing_command;
 
     Core::System& system;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & next_parameter;
+        ar & app_jump_parameters;
+        ar & applet_slots;
+        ar & library_applet_closing_command;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::APT
+
+namespace boost::serialization {
+    template <class Archive>
+    inline void load_construct_data(Archive& ar, Service::APT::AppletManager* t, const unsigned int)
+    {
+        ::new(t)Service::APT::AppletManager(Core::Global<Core::System>());
+    }
+}
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index f7fb0660f..8e02d2bd4 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -5,6 +5,7 @@
 #include "common/common_paths.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/file_sys/archive_ncch.h"
 #include "core/file_sys/file_backend.h"
@@ -26,8 +27,35 @@
 #include "core/hw/aes/ccm.h"
 #include "core/hw/aes/key.h"
 
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::APT::Module* t, const unsigned int)
+    {
+        ::new(t)Service::APT::Module(Core::Global<Core::System>());
+    }
+
+    template
+    void load_construct_data<iarchive>(iarchive& ar, Service::APT::Module* t, const unsigned int);
+}
+
 namespace Service::APT {
 
+template <class Archive>
+void Module::serialize(Archive& ar, const unsigned int)
+{
+    ar & shared_font_mem;
+    ar & shared_font_loaded;
+    ar & shared_font_relocated;
+    ar & lock;
+    ar & cpu_percent;
+    ar & unknown_ns_state_field;
+    ar & screen_capture_buffer;
+    ar & screen_capture_post_permission;
+    ar & applet_manager;
+}
+
+SERIALIZE_IMPL(Module)
+
 Module::NSInterface::NSInterface(std::shared_ptr<Module> apt, const char* name, u32 max_session)
     : ServiceFramework(name, max_session), apt(std::move(apt)) {}
 
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 2e2c219cd..c12dc3f55 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -6,11 +6,15 @@
 
 #include <memory>
 #include <vector>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
+#include "common/archives.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/service/service.h"
+#include "core/global.h"
 
 namespace Core {
 class System;
@@ -65,7 +69,7 @@ public:
         NSInterface(std::shared_ptr<Module> apt, const char* name, u32 max_session);
         ~NSInterface();
 
-    private:
+    protected:
         std::shared_ptr<Module> apt;
     };
 
@@ -601,7 +605,7 @@ public:
          */
         void CheckNew3DS(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         bool application_reset_prepared{};
         std::shared_ptr<Module> apt;
     };
@@ -630,8 +634,17 @@ private:
         ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
 
     std::shared_ptr<AppletManager> applet_manager;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::APT
+
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::APT::Module* t, const unsigned int);
+}
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 7d5c96139..db49c57d8 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/apt/apt_a.h"
+#include "common/archives.h"
 
 namespace Service::APT {
 
@@ -105,3 +106,5 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
 }
 
 } // namespace Service::APT
+
+SERIALIZE_EXPORT_IMPL(Service::APT::APT_A)
diff --git a/src/core/hle/service/apt/apt_a.h b/src/core/hle/service/apt/apt_a.h
index f481fa1c9..1b81022df 100644
--- a/src/core/hle/service/apt/apt_a.h
+++ b/src/core/hle/service/apt/apt_a.h
@@ -11,6 +11,11 @@ namespace Service::APT {
 class APT_A final : public Module::APTInterface {
 public:
     explicit APT_A(std::shared_ptr<Module> apt);
+private:
+    SERVICE_SERIALIZATION(APT_A, apt, Module)
 };
 
 } // namespace Service::APT
+
+BOOST_CLASS_EXPORT_KEY(Service::APT::APT_A)
+BOOST_SERIALIZATION_CONSTRUCT(Service::APT::APT_A)
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index 1843bdd9a..4d151fb3d 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/apt/apt_s.h"
+#include "common/archives.h"
 
 namespace Service::APT {
 
@@ -105,3 +106,5 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
 }
 
 } // namespace Service::APT
+
+SERIALIZE_EXPORT_IMPL(Service::APT::APT_S)
diff --git a/src/core/hle/service/apt/apt_s.h b/src/core/hle/service/apt/apt_s.h
index 7e041cbda..ef1c235b0 100644
--- a/src/core/hle/service/apt/apt_s.h
+++ b/src/core/hle/service/apt/apt_s.h
@@ -18,6 +18,11 @@ namespace Service::APT {
 class APT_S final : public Module::APTInterface {
 public:
     explicit APT_S(std::shared_ptr<Module> apt);
+private:
+    SERVICE_SERIALIZATION(APT_S, apt, Module)
 };
 
 } // namespace Service::APT
+
+BOOST_CLASS_EXPORT_KEY(Service::APT::APT_S)
+BOOST_SERIALIZATION_CONSTRUCT(Service::APT::APT_S)
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index 0ecbd65da..7ebaf86e3 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/apt/apt_u.h"
+#include "common/archives.h"
 
 namespace Service::APT {
 
@@ -102,3 +103,5 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
 }
 
 } // namespace Service::APT
+
+SERIALIZE_EXPORT_IMPL(Service::APT::APT_U)
diff --git a/src/core/hle/service/apt/apt_u.h b/src/core/hle/service/apt/apt_u.h
index 3b342ed55..79d2df651 100644
--- a/src/core/hle/service/apt/apt_u.h
+++ b/src/core/hle/service/apt/apt_u.h
@@ -18,6 +18,11 @@ namespace Service::APT {
 class APT_U final : public Module::APTInterface {
 public:
     explicit APT_U(std::shared_ptr<Module> apt);
+private:
+    SERVICE_SERIALIZATION(APT_U, apt, Module)
 };
 
 } // namespace Service::APT
+
+BOOST_CLASS_EXPORT_KEY(Service::APT::APT_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::APT::APT_U)
diff --git a/src/core/hle/service/apt/ns_s.cpp b/src/core/hle/service/apt/ns_s.cpp
index e9eb87174..b556845d3 100644
--- a/src/core/hle/service/apt/ns_s.cpp
+++ b/src/core/hle/service/apt/ns_s.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/apt/ns_s.h"
+#include "common/archives.h"
 
 namespace Service::NS {
 
@@ -29,3 +30,5 @@ NS_S::NS_S(std::shared_ptr<Service::APT::Module> apt)
 }
 
 } // namespace Service::NS
+
+SERIALIZE_EXPORT_IMPL(Service::NS::NS_S)
diff --git a/src/core/hle/service/apt/ns_s.h b/src/core/hle/service/apt/ns_s.h
index 5a5b311b0..8f023e204 100644
--- a/src/core/hle/service/apt/ns_s.h
+++ b/src/core/hle/service/apt/ns_s.h
@@ -14,6 +14,11 @@ namespace Service::NS {
 class NS_S final : public Service::APT::Module::NSInterface {
 public:
     explicit NS_S(std::shared_ptr<Service::APT::Module> apt);
+private:
+    SERVICE_SERIALIZATION(NS_S, apt, Service::APT::Module)
 };
 
 } // namespace Service::NS
+
+BOOST_CLASS_EXPORT_KEY(Service::NS::NS_S)
+BOOST_SERIALIZATION_CONSTRUCT(Service::NS::NS_S)
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index bdad47ea8..c0c48892a 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -199,7 +199,7 @@ extern const std::array<ServiceModuleInfo, 40> service_module_map;
 
 } // namespace Service
 
-#define SERVICE_SERIALIZATION(T, MFIELD) \
+#define SERVICE_SERIALIZATION(T, MFIELD, TMODULE) \
     template <class Archive> \
     void save_construct(Archive& ar, const unsigned int file_version) const \
     { \
@@ -209,7 +209,7 @@ extern const std::array<ServiceModuleInfo, 40> service_module_map;
     template <class Archive> \
     static void load_construct(Archive& ar, T* t, const unsigned int file_version) \
     { \
-        std::shared_ptr<Module> MFIELD; \
+        std::shared_ptr<TMODULE> MFIELD; \
         ar >> MFIELD; \
         ::new(t)T(MFIELD); \
     } \

From 1185d627924b9bd5dd13461e7581850a777e9d22 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 25 Dec 2019 23:19:01 +0000
Subject: [PATCH 023/129] BOSS service serialization

---
 TODO                                 |  2 +-
 src/core/hle/service/apt/apt.h       |  8 ++++++++
 src/core/hle/service/boss/boss.h     | 30 +++++++++++++++++++++++++++-
 src/core/hle/service/boss/boss_p.cpp |  3 +++
 src/core/hle/service/boss/boss_p.h   |  6 ++++++
 src/core/hle/service/boss/boss_u.cpp |  3 +++
 src/core/hle/service/boss/boss_u.h   |  6 ++++++
 7 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index 9e591af8d..c6e3366e3 100644
--- a/TODO
+++ b/TODO
@@ -65,7 +65,7 @@
         ✔ ACT @done(19-12-24 23:17)
         ✔ AM @started(19-12-24 23:17) @done(19-12-24 23:53) @lasted(36m8s)
         ✔ APT @done(19-12-25 21:41)
-        ☐ BOSS
+        ✔ BOSS @started(19-12-25 21:48) @done(19-12-25 23:18) @lasted(1h30m14s)
         ☐ CAM
         ☐ CECD
         ☐ CGF
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index c12dc3f55..45a93b350 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -608,6 +608,14 @@ public:
     protected:
         bool application_reset_prepared{};
         std::shared_ptr<Module> apt;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int)
+        {
+            ar & application_reset_prepared;
+        }
+        friend class boost::serialization::access;
     };
 
 private:
diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h
index e0cb39b37..7017ce2b6 100644
--- a/src/core/hle/service/boss/boss.h
+++ b/src/core/hle/service/boss/boss.h
@@ -5,8 +5,10 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/shared_ptr.hpp>
 #include "core/hle/kernel/event.h"
 #include "core/hle/service/service.h"
+#include "core/global.h"
 
 namespace Core {
 class System;
@@ -952,19 +954,45 @@ public:
          */
         void GetNsDataNewFlagPrivileged(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> boss;
 
+    private:
         u8 new_arrival_flag;
         u8 ns_data_new_flag;
         u8 ns_data_new_flag_privileged;
         u8 output_flag;
+
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int)
+        {
+            ar & new_arrival_flag;
+            ar & ns_data_new_flag;
+            ar & ns_data_new_flag_privileged;
+            ar & output_flag;
+        }
+        friend class boost::serialization::access;
     };
 
 private:
     std::shared_ptr<Kernel::Event> task_finish_event;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & task_finish_event;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::BOSS
+
+namespace boost::serialization {
+    template <class Archive>
+    inline void load_construct_data(Archive& ar, Service::BOSS::Module* t, const unsigned int)
+    {
+        ::new(t)Service::BOSS::Module(Core::Global<Core::System>());
+    }
+}
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp
index cdc8f1036..4e48fe8f3 100644
--- a/src/core/hle/service/boss/boss_p.cpp
+++ b/src/core/hle/service/boss/boss_p.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/boss/boss_p.h"
+#include "common/archives.h"
 
 namespace Service::BOSS {
 
@@ -84,3 +85,5 @@ BOSS_P::BOSS_P(std::shared_ptr<Module> boss)
 }
 
 } // namespace Service::BOSS
+
+SERIALIZE_EXPORT_IMPL(Service::BOSS::BOSS_P)
diff --git a/src/core/hle/service/boss/boss_p.h b/src/core/hle/service/boss/boss_p.h
index 9c84a1e9d..56f0cd4fc 100644
--- a/src/core/hle/service/boss/boss_p.h
+++ b/src/core/hle/service/boss/boss_p.h
@@ -11,6 +11,12 @@ namespace Service::BOSS {
 class BOSS_P final : public Module::Interface {
 public:
     explicit BOSS_P(std::shared_ptr<Module> boss);
+
+private:
+    SERVICE_SERIALIZATION(BOSS_P, boss, Module)
 };
 
 } // namespace Service::BOSS
+
+BOOST_CLASS_EXPORT_KEY(Service::BOSS::BOSS_P)
+BOOST_SERIALIZATION_CONSTRUCT(Service::BOSS::BOSS_P)
diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp
index c6aaba888..f839e9292 100644
--- a/src/core/hle/service/boss/boss_u.cpp
+++ b/src/core/hle/service/boss/boss_u.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/boss/boss_u.h"
+#include "common/archives.h"
 
 namespace Service::BOSS {
 
@@ -72,3 +73,5 @@ BOSS_U::BOSS_U(std::shared_ptr<Module> boss)
 }
 
 } // namespace Service::BOSS
+
+SERIALIZE_EXPORT_IMPL(Service::BOSS::BOSS_U)
diff --git a/src/core/hle/service/boss/boss_u.h b/src/core/hle/service/boss/boss_u.h
index a93b4e502..195783b40 100644
--- a/src/core/hle/service/boss/boss_u.h
+++ b/src/core/hle/service/boss/boss_u.h
@@ -11,6 +11,12 @@ namespace Service::BOSS {
 class BOSS_U final : public Module::Interface {
 public:
     explicit BOSS_U(std::shared_ptr<Module> boss);
+
+private:
+    SERVICE_SERIALIZATION(BOSS_U, boss, Module)
 };
 
 } // namespace Service::BOSS
+
+BOOST_CLASS_EXPORT_KEY(Service::BOSS::BOSS_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::BOSS::BOSS_U)

From 17b9cbefef78aa006075d69855c328e569af280d Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 26 Dec 2019 10:37:43 +0000
Subject: [PATCH 024/129] CAM service serialization

---
 TODO                               |  3 +-
 src/core/hle/service/cam/cam.cpp   | 11 +++++
 src/core/hle/service/cam/cam.h     | 79 +++++++++++++++++++++++++++++-
 src/core/hle/service/cam/cam_c.cpp |  3 ++
 src/core/hle/service/cam/cam_c.h   |  6 +++
 src/core/hle/service/cam/cam_q.cpp |  3 ++
 src/core/hle/service/cam/cam_q.h   |  9 ++++
 src/core/hle/service/cam/cam_s.cpp |  3 ++
 src/core/hle/service/cam/cam_s.h   |  6 +++
 src/core/hle/service/cam/cam_u.cpp |  3 ++
 src/core/hle/service/cam/cam_u.h   |  6 +++
 11 files changed, 129 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index c6e3366e3..354e61a2f 100644
--- a/TODO
+++ b/TODO
@@ -66,7 +66,8 @@
         ✔ AM @started(19-12-24 23:17) @done(19-12-24 23:53) @lasted(36m8s)
         ✔ APT @done(19-12-25 21:41)
         ✔ BOSS @started(19-12-25 21:48) @done(19-12-25 23:18) @lasted(1h30m14s)
-        ☐ CAM
+        ☐ CAM @started(19-12-26 10:37)
+            Need to check capture_result
         ☐ CECD
         ☐ CGF
         ☐ CSND
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index bf1bab8c0..b7acd307c 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include "common/archives.h"
 #include "common/bit_set.h"
 #include "common/logging/log.h"
 #include "core/core.h"
@@ -22,6 +23,16 @@
 
 namespace Service::CAM {
 
+template <class Archive>
+void Module::serialize(Archive& ar, const unsigned int)
+{
+    ar & cameras;
+    ar & ports;
+    ar & is_camera_reload_pending;
+}
+
+SERIALIZE_IMPL(Module)
+
 // built-in resolution parameters
 constexpr std::array<Resolution, 8> PRESET_RESOLUTION{{
     {640, 480, 0, 0, 639, 479},  // VGA
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 9f3d81990..229c882b5 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -12,6 +12,7 @@
 #include "common/swap.h"
 #include "core/hle/result.h"
 #include "core/hle/service/service.h"
+#include "core/global.h"
 
 namespace Core {
 class System;
@@ -179,6 +180,19 @@ struct Resolution {
     u16 crop_y0;
     u16 crop_x1;
     u16 crop_y1;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & width;
+        ar & height;
+        ar & crop_x0;
+        ar & crop_y0;
+        ar & crop_x1;
+        ar & crop_y1;
+    }
+    friend class boost::serialization::access;
 };
 
 struct PackageParameterWithoutContext {
@@ -710,7 +724,7 @@ public:
          */
         void DriverFinalize(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> cam;
     };
 
@@ -738,6 +752,17 @@ private:
         Effect effect{Effect::None};
         OutputFormat format{OutputFormat::YUV422};
         Resolution resolution = {0, 0, 0, 0, 0, 0};
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int)
+        {
+            ar & flip;
+            ar & effect;
+            ar & format;
+            ar & resolution;
+        }
+        friend class boost::serialization::access;
     };
 
     struct CameraConfig {
@@ -745,6 +770,17 @@ private:
         std::array<ContextConfig, 2> contexts;
         int current_context{0};
         FrameRate frame_rate{FrameRate::Rate_5};
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int)
+        {
+            ar & impl;
+            ar & contexts;
+            ar & current_context;
+            ar & frame_rate;
+        }
+        friend class boost::serialization::access;
     };
 
     struct PortConfig {
@@ -779,6 +815,32 @@ private:
         u32 dest_size{0}; // the destination size of the receiving process
 
         void Clear();
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int)
+        {
+            ar & camera_id;
+            ar & is_active;
+            ar & is_pending_receiving;
+            ar & is_busy;
+            ar & is_receiving;
+            ar & is_trimming;
+            ar & x0;
+            ar & y0;
+            ar & x1;
+            ar & y1;
+            ar & transfer_bytes;
+            ar & completion_event;
+            ar & buffer_error_interrupt_event;
+            ar & vsync_interrupt_event;
+            // TODO: Check if this is ever needed:
+            //ar & capture_result;
+            ar & dest_process;
+            ar & dest;
+            ar & dest_size;
+        }
+        friend class boost::serialization::access;
     };
 
     void LoadCameraImplementation(CameraConfig& camera, int camera_id);
@@ -786,8 +848,13 @@ private:
     Core::System& system;
     std::array<CameraConfig, NumCameras> cameras;
     std::array<PortConfig, 2> ports;
-    Core::TimingEventType* completion_event_callback;
+    // TODO: Make this *const
+    const Core::TimingEventType* completion_event_callback;
     std::atomic<bool> is_camera_reload_pending{false};
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 std::shared_ptr<Module> GetModule(Core::System& system);
@@ -795,3 +862,11 @@ std::shared_ptr<Module> GetModule(Core::System& system);
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::CAM
+
+namespace boost::serialization {
+    template <class Archive>
+    inline void load_construct_data(Archive& ar, Service::CAM::Module* t, const unsigned int)
+    {
+        ::new(t)Service::CAM::Module(Core::Global<Core::System>());
+    }
+}
diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp
index 80816c923..a29e9db3e 100644
--- a/src/core/hle/service/cam/cam_c.cpp
+++ b/src/core/hle/service/cam/cam_c.cpp
@@ -4,6 +4,7 @@
 
 #include "core/hle/service/cam/cam.h"
 #include "core/hle/service/cam/cam_c.h"
+#include "common/archives.h"
 
 namespace Service::CAM {
 
@@ -79,3 +80,5 @@ CAM_C::CAM_C(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
 }
 
 } // namespace Service::CAM
+
+SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_C)
diff --git a/src/core/hle/service/cam/cam_c.h b/src/core/hle/service/cam/cam_c.h
index d6dfcd6c5..c1ed355ac 100644
--- a/src/core/hle/service/cam/cam_c.h
+++ b/src/core/hle/service/cam/cam_c.h
@@ -11,6 +11,12 @@ namespace Service::CAM {
 class CAM_C final : public Module::Interface {
 public:
     explicit CAM_C(std::shared_ptr<Module> cam);
+
+private:
+    SERVICE_SERIALIZATION(CAM_C, cam, Module)
 };
 
 } // namespace Service::CAM
+
+BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_C)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CAM::CAM_C)
diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp
index 71fc127d2..ac477bf04 100644
--- a/src/core/hle/service/cam/cam_q.cpp
+++ b/src/core/hle/service/cam/cam_q.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/cam/cam_q.h"
+#include "common/archives.h"
 
 namespace Service::CAM {
 
@@ -13,3 +14,5 @@ CAM_Q::CAM_Q() : ServiceFramework("cam:q", 1 /*TODO: find the true value*/) {
 }
 
 } // namespace Service::CAM
+
+SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_Q)
diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h
index d1124493b..33943ca21 100644
--- a/src/core/hle/service/cam/cam_q.h
+++ b/src/core/hle/service/cam/cam_q.h
@@ -11,6 +11,15 @@ namespace Service::CAM {
 class CAM_Q : public ServiceFramework<CAM_Q> {
 public:
     CAM_Q();
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::CAM
+
+BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_Q)
diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp
index c4936f9b5..0797ed4e1 100644
--- a/src/core/hle/service/cam/cam_s.cpp
+++ b/src/core/hle/service/cam/cam_s.cpp
@@ -4,6 +4,7 @@
 
 #include "core/hle/service/cam/cam.h"
 #include "core/hle/service/cam/cam_s.h"
+#include "common/archives.h"
 
 namespace Service::CAM {
 
@@ -79,3 +80,5 @@ CAM_S::CAM_S(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
 }
 
 } // namespace Service::CAM
+
+SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_S)
diff --git a/src/core/hle/service/cam/cam_s.h b/src/core/hle/service/cam/cam_s.h
index 0c9d26644..cceb99b87 100644
--- a/src/core/hle/service/cam/cam_s.h
+++ b/src/core/hle/service/cam/cam_s.h
@@ -11,6 +11,12 @@ namespace Service::CAM {
 class CAM_S final : public Module::Interface {
 public:
     explicit CAM_S(std::shared_ptr<Module> cam);
+
+private:
+    SERVICE_SERIALIZATION(CAM_S, cam, Module)
 };
 
 } // namespace Service::CAM
+
+BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_S)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CAM::CAM_S)
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp
index 3c3c4b17d..16c652a26 100644
--- a/src/core/hle/service/cam/cam_u.cpp
+++ b/src/core/hle/service/cam/cam_u.cpp
@@ -4,6 +4,7 @@
 
 #include "core/hle/service/cam/cam.h"
 #include "core/hle/service/cam/cam_u.h"
+#include "common/archives.h"
 
 namespace Service::CAM {
 
@@ -79,3 +80,5 @@ CAM_U::CAM_U(std::shared_ptr<Module> cam) : Module::Interface(std::move(cam), "c
 }
 
 } // namespace Service::CAM
+
+SERIALIZE_EXPORT_IMPL(Service::CAM::CAM_U)
diff --git a/src/core/hle/service/cam/cam_u.h b/src/core/hle/service/cam/cam_u.h
index 85b12559a..2b775a035 100644
--- a/src/core/hle/service/cam/cam_u.h
+++ b/src/core/hle/service/cam/cam_u.h
@@ -11,6 +11,12 @@ namespace Service::CAM {
 class CAM_U final : public Module::Interface {
 public:
     explicit CAM_U(std::shared_ptr<Module> cam);
+
+private:
+    SERVICE_SERIALIZATION(CAM_U, cam, Module)
 };
 
 } // namespace Service::CAM
+
+BOOST_CLASS_EXPORT_KEY(Service::CAM::CAM_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CAM::CAM_U)

From a0c3b9178525df5d192048d266e3e1d0f8c1e3ef Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 26 Dec 2019 17:56:44 +0000
Subject: [PATCH 025/129] Added CSND serialization

---
 TODO                                   |  7 +++-
 src/core/hle/service/csnd/csnd_snd.cpp | 14 +++++++
 src/core/hle/service/csnd/csnd_snd.h   | 56 ++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index 354e61a2f..e485f33a7 100644
--- a/TODO
+++ b/TODO
@@ -15,6 +15,7 @@
 ☐ Settings
 ☐ Telemetry session
 ☐ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE
+☐ Review constructor/initialization code
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
     ✔ LCD regs @done(19-08-13 15:41)
@@ -69,8 +70,10 @@
         ☐ CAM @started(19-12-26 10:37)
             Need to check capture_result
         ☐ CECD
-        ☐ CGF
-        ☐ CSND
+            ☐ Archive backend / file handles
+        ☐ CFG
+            Also needs archive backend..
+        ✔ CSND @started(19-12-26 17:51) @done(19-12-26 17:56) @lasted(5m30s)
         ☐ DLP
         ☐ DSP
         ☐ ERR
diff --git a/src/core/hle/service/csnd/csnd_snd.cpp b/src/core/hle/service/csnd/csnd_snd.cpp
index 5c9fa13e9..d011a1c66 100644
--- a/src/core/hle/service/csnd/csnd_snd.cpp
+++ b/src/core/hle/service/csnd/csnd_snd.cpp
@@ -3,11 +3,25 @@
 // Refer to the license.txt file included.
 
 #include "common/alignment.h"
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/result.h"
 #include "core/hle/service/csnd/csnd_snd.h"
 
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::CSND::CSND_SND* t, const unsigned int)
+    {
+        ::new(t)Service::CSND::CSND_SND(Core::Global<Core::System>());
+    }
+
+    template
+    void load_construct_data<iarchive>(iarchive& ar, Service::CSND::CSND_SND* t, const unsigned int);
+}
+
+SERIALIZE_EXPORT_IMPL(Service::CSND::CSND_SND)
+
 namespace Service::CSND {
 
 enum class CommandId : u16 {
diff --git a/src/core/hle/service/csnd/csnd_snd.h b/src/core/hle/service/csnd/csnd_snd.h
index afdc3b1a8..0e2dd8cd8 100644
--- a/src/core/hle/service/csnd/csnd_snd.h
+++ b/src/core/hle/service/csnd/csnd_snd.h
@@ -5,6 +5,8 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "core/hle/kernel/mutex.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/service/service.h"
@@ -33,6 +35,15 @@ enum class LoopMode : u8 {
 struct AdpcmState {
     s16 predictor = 0;
     u8 step_index = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & predictor;
+        ar & step_index;
+    }
+    friend class boost::serialization::access;
 };
 
 struct Channel {
@@ -52,6 +63,29 @@ struct Channel {
     LoopMode loop_mode = LoopMode::Manual;
     Encoding encoding = Encoding::Pcm8;
     u8 psg_duty = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & block1_address;
+        ar & block2_address;
+        ar & block1_size;
+        ar & block2_size;
+        ar & block1_adpcm_state;
+        ar & block2_adpcm_state;
+        ar & block2_adpcm_reload;
+        ar & left_channel_volume;
+        ar & right_channel_volume;
+        ar & left_capture_volume;
+        ar & right_capture_volume;
+        ar & sample_rate;
+        ar & linear_interpolation;
+        ar & loop_mode;
+        ar & encoding;
+        ar & psg_duty;
+    }
+    friend class boost::serialization::access;
 };
 
 class CSND_SND final : public ServiceFramework<CSND_SND> {
@@ -222,9 +256,31 @@ private:
     u32 type1_command_offset = 0;
 
     u32 acquired_channel_mask = 0;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & mutex;
+        ar & shared_memory;
+        ar & capture_units;
+        ar & channels;
+        ar & master_state_offset;
+        ar & channel_state_offset;
+        ar & capture_state_offset;
+        ar & type1_command_offset;
+        ar & acquired_channel_mask;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Initializes the CSND_SND Service
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::CSND
+
+BOOST_CLASS_EXPORT_KEY(Service::CSND::CSND_SND)
+
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::CSND::CSND_SND* t, const unsigned int);
+}

From 30fe2bfe38fb251989acb50df561ba512d9f27b6 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 26 Dec 2019 18:02:59 +0000
Subject: [PATCH 026/129] Added DLP service serialization

---
 TODO                                  | 2 +-
 src/core/hle/service/dlp/dlp_clnt.cpp | 3 +++
 src/core/hle/service/dlp/dlp_clnt.h   | 9 +++++++++
 src/core/hle/service/dlp/dlp_fkcl.cpp | 3 +++
 src/core/hle/service/dlp/dlp_fkcl.h   | 9 +++++++++
 src/core/hle/service/dlp/dlp_srvr.cpp | 3 +++
 src/core/hle/service/dlp/dlp_srvr.h   | 9 +++++++++
 7 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/TODO b/TODO
index e485f33a7..27f720dca 100644
--- a/TODO
+++ b/TODO
@@ -74,7 +74,7 @@
         ☐ CFG
             Also needs archive backend..
         ✔ CSND @started(19-12-26 17:51) @done(19-12-26 17:56) @lasted(5m30s)
-        ☐ DLP
+        ✔ DLP @done(19-12-26 18:02)
         ☐ DSP
         ☐ ERR
         ☐ FRD
diff --git a/src/core/hle/service/dlp/dlp_clnt.cpp b/src/core/hle/service/dlp/dlp_clnt.cpp
index 63308f57e..df5b755e1 100644
--- a/src/core/hle/service/dlp/dlp_clnt.cpp
+++ b/src/core/hle/service/dlp/dlp_clnt.cpp
@@ -4,6 +4,9 @@
 
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/dlp/dlp_clnt.h"
+#include "common/archives.h"
+
+SERIALIZE_EXPORT_IMPL(Service::DLP::DLP_CLNT)
 
 namespace Service::DLP {
 
diff --git a/src/core/hle/service/dlp/dlp_clnt.h b/src/core/hle/service/dlp/dlp_clnt.h
index db506b985..3f9020863 100644
--- a/src/core/hle/service/dlp/dlp_clnt.h
+++ b/src/core/hle/service/dlp/dlp_clnt.h
@@ -12,6 +12,15 @@ class DLP_CLNT final : public ServiceFramework<DLP_CLNT> {
 public:
     DLP_CLNT();
     ~DLP_CLNT() = default;
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::DLP
+
+BOOST_CLASS_EXPORT_KEY(Service::DLP::DLP_CLNT)
diff --git a/src/core/hle/service/dlp/dlp_fkcl.cpp b/src/core/hle/service/dlp/dlp_fkcl.cpp
index 30a98c4bf..607c211d4 100644
--- a/src/core/hle/service/dlp/dlp_fkcl.cpp
+++ b/src/core/hle/service/dlp/dlp_fkcl.cpp
@@ -4,6 +4,9 @@
 
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/dlp/dlp_fkcl.h"
+#include "common/archives.h"
+
+SERIALIZE_EXPORT_IMPL(Service::DLP::DLP_FKCL)
 
 namespace Service::DLP {
 
diff --git a/src/core/hle/service/dlp/dlp_fkcl.h b/src/core/hle/service/dlp/dlp_fkcl.h
index a3b2ac86d..ae26b6220 100644
--- a/src/core/hle/service/dlp/dlp_fkcl.h
+++ b/src/core/hle/service/dlp/dlp_fkcl.h
@@ -12,6 +12,15 @@ class DLP_FKCL final : public ServiceFramework<DLP_FKCL> {
 public:
     DLP_FKCL();
     ~DLP_FKCL() = default;
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::DLP
+
+BOOST_CLASS_EXPORT_KEY(Service::DLP::DLP_FKCL)
diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp
index 9d7405941..0cff2e2bc 100644
--- a/src/core/hle/service/dlp/dlp_srvr.cpp
+++ b/src/core/hle/service/dlp/dlp_srvr.cpp
@@ -7,6 +7,9 @@
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/result.h"
 #include "core/hle/service/dlp/dlp_srvr.h"
+#include "common/archives.h"
+
+SERIALIZE_EXPORT_IMPL(Service::DLP::DLP_SRVR)
 
 namespace Service::DLP {
 
diff --git a/src/core/hle/service/dlp/dlp_srvr.h b/src/core/hle/service/dlp/dlp_srvr.h
index 50d8d92b2..6af350c8e 100644
--- a/src/core/hle/service/dlp/dlp_srvr.h
+++ b/src/core/hle/service/dlp/dlp_srvr.h
@@ -15,6 +15,15 @@ public:
 
 private:
     void IsChild(Kernel::HLERequestContext& ctx);
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::DLP
+
+BOOST_CLASS_EXPORT_KEY(Service::DLP::DLP_SRVR)

From 452ae2e3714ba6f8de7902c8b6046e22a8f2f957 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 26 Dec 2019 18:10:38 +0000
Subject: [PATCH 027/129] Added DSP service serialization

---
 TODO                                 |  2 +-
 src/core/hle/service/dsp/dsp_dsp.cpp | 14 ++++++++++++++
 src/core/hle/service/dsp/dsp_dsp.h   | 19 +++++++++++++++++++
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/TODO b/TODO
index 27f720dca..c3e8a57d7 100644
--- a/TODO
+++ b/TODO
@@ -75,7 +75,7 @@
             Also needs archive backend..
         ✔ CSND @started(19-12-26 17:51) @done(19-12-26 17:56) @lasted(5m30s)
         ✔ DLP @done(19-12-26 18:02)
-        ☐ DSP
+        ✔ DSP @done(19-12-26 18:10)
         ☐ ERR
         ☐ FRD
         ☐ FS
diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp
index 37682edcc..519d39b0c 100644
--- a/src/core/hle/service/dsp/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp/dsp_dsp.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "audio_core/audio_types.h"
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "core/core.h"
@@ -13,6 +14,19 @@
 using DspPipe = AudioCore::DspPipe;
 using InterruptType = Service::DSP::DSP_DSP::InterruptType;
 
+SERIALIZE_EXPORT_IMPL(Service::DSP::DSP_DSP)
+
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::DSP::DSP_DSP* t, const unsigned int)
+    {
+        ::new(t)Service::DSP::DSP_DSP(Core::Global<Core::System>());
+    }
+
+    template
+    void load_construct_data<iarchive>(iarchive& ar, Service::DSP::DSP_DSP* t, const unsigned int);
+}
+
 namespace AudioCore {
 enum class DspPipe;
 }
diff --git a/src/core/hle/service/dsp/dsp_dsp.h b/src/core/hle/service/dsp/dsp_dsp.h
index ef1f0b76d..b4c727091 100644
--- a/src/core/hle/service/dsp/dsp_dsp.h
+++ b/src/core/hle/service/dsp/dsp_dsp.h
@@ -264,8 +264,27 @@ private:
 
     /// Each DSP pipe has an associated interrupt
     std::array<std::shared_ptr<Kernel::Event>, AudioCore::num_dsp_pipe> pipes = {{}};
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar & semaphore_event;
+        ar & preset_semaphore;
+        ar & interrupt_zero;
+        ar & interrupt_one;
+        ar & pipes;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::DSP
+
+BOOST_CLASS_EXPORT_KEY(Service::DSP::DSP_DSP)
+
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::DSP::DSP_DSP* t, const unsigned int);
+}

From 4354179156e38bac0819ba6c10c1a2245ba879d7 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 26 Dec 2019 18:14:22 +0000
Subject: [PATCH 028/129] Added ERR service serialization

---
 TODO                           |  2 +-
 src/core/hle/service/err_f.cpp | 14 ++++++++++++++
 src/core/hle/service/err_f.h   | 14 ++++++++++++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/TODO b/TODO
index c3e8a57d7..4a07c0608 100644
--- a/TODO
+++ b/TODO
@@ -76,7 +76,7 @@
         ✔ CSND @started(19-12-26 17:51) @done(19-12-26 17:56) @lasted(5m30s)
         ✔ DLP @done(19-12-26 18:02)
         ✔ DSP @done(19-12-26 18:10)
-        ☐ ERR
+        ✔ ERR @done(19-12-26 18:14)
         ☐ FRD
         ☐ FS
         ☐ GSP
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index b218eb793..0efc600e8 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -6,6 +6,7 @@
 #include <chrono>
 #include <iomanip>
 #include <sstream>
+#include "common/archives.h"
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
@@ -16,6 +17,19 @@
 #include "core/hle/service/err_f.h"
 #undef exception_info
 
+SERIALIZE_EXPORT_IMPL(Service::ERR::ERR_F)
+
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int)
+    {
+        ::new(t)Service::ERR::ERR_F(Core::Global<Core::System>());
+    }
+
+    template
+    void load_construct_data<iarchive>(iarchive& ar, Service::ERR::ERR_F* t, const unsigned int);
+}
+
 namespace Service::ERR {
 
 enum class FatalErrType : u32 {
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
index 4a1684caf..a3d0cf11e 100644
--- a/src/core/hle/service/err_f.h
+++ b/src/core/hle/service/err_f.h
@@ -34,8 +34,22 @@ private:
     void ThrowFatalError(Kernel::HLERequestContext& ctx);
 
     Core::System& system;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::ERR
+
+BOOST_CLASS_EXPORT_KEY(Service::ERR::ERR_F)
+
+namespace boost::serialization {
+    template <class Archive>
+    void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int);
+}

From d1096de24525aa00b1cbdd490e4b4b76b6c8d915 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 26 Dec 2019 19:09:55 +0000
Subject: [PATCH 029/129] Added FRD service serialization

---
 TODO                               |  2 +-
 src/core/hle/service/frd/frd.h     | 28 +++++++++++++++++++++++++++-
 src/core/hle/service/frd/frd_a.cpp |  3 +++
 src/core/hle/service/frd/frd_a.h   |  5 +++++
 src/core/hle/service/frd/frd_u.cpp |  3 +++
 src/core/hle/service/frd/frd_u.h   |  5 +++++
 6 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index 4a07c0608..5a483dc84 100644
--- a/TODO
+++ b/TODO
@@ -77,7 +77,7 @@
         ✔ DLP @done(19-12-26 18:02)
         ✔ DSP @done(19-12-26 18:10)
         ✔ ERR @done(19-12-26 18:14)
-        ☐ FRD
+        ✔ FRD @done(19-12-26 19:09)
         ☐ FS
         ☐ GSP
         ☐ HID
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h
index 200b51ebe..46dc96cad 100644
--- a/src/core/hle/service/frd/frd.h
+++ b/src/core/hle/service/frd/frd.h
@@ -18,10 +18,28 @@ struct FriendKey {
     u32 friend_id;
     u32 unknown;
     u64 friend_code;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & friend_id;
+        ar & unknown;
+        ar & friend_code;
+    }
+    friend class boost::serialization::access;
 };
 
 struct MyPresence {
     u8 unknown[0x12C];
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & unknown;
+    }
+    friend class boost::serialization::access;
 };
 
 struct Profile {
@@ -130,13 +148,21 @@ public:
          */
         void SetClientSdkVersion(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> frd;
     };
 
 private:
     FriendKey my_friend_key = {0, 0, 0ull};
     MyPresence my_presence = {};
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & my_friend_key;
+        ar & my_presence;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp
index c68689cc0..6248891af 100644
--- a/src/core/hle/service/frd/frd_a.cpp
+++ b/src/core/hle/service/frd/frd_a.cpp
@@ -3,6 +3,9 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/frd/frd_a.h"
+#include "common/archives.h"
+
+SERIALIZE_EXPORT_IMPL(Service::FRD::FRD_A)
 
 namespace Service::FRD {
 
diff --git a/src/core/hle/service/frd/frd_a.h b/src/core/hle/service/frd/frd_a.h
index 97657a072..133d40dc1 100644
--- a/src/core/hle/service/frd/frd_a.h
+++ b/src/core/hle/service/frd/frd_a.h
@@ -11,6 +11,11 @@ namespace Service::FRD {
 class FRD_A final : public Module::Interface {
 public:
     explicit FRD_A(std::shared_ptr<Module> frd);
+private:
+    SERVICE_SERIALIZATION(FRD_A, frd, Module)
 };
 
 } // namespace Service::FRD
+
+BOOST_CLASS_EXPORT_KEY(Service::FRD::FRD_A)
+BOOST_SERIALIZATION_CONSTRUCT(Service::FRD::FRD_A)
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 2cbc64243..ba499dd2b 100644
--- a/src/core/hle/service/frd/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -3,6 +3,9 @@
 // Refer to the license.txt file included.
 
 #include "core/hle/service/frd/frd_u.h"
+#include "common/archives.h"
+
+SERIALIZE_EXPORT_IMPL(Service::FRD::FRD_U)
 
 namespace Service::FRD {
 
diff --git a/src/core/hle/service/frd/frd_u.h b/src/core/hle/service/frd/frd_u.h
index 5704d5e11..281334f51 100644
--- a/src/core/hle/service/frd/frd_u.h
+++ b/src/core/hle/service/frd/frd_u.h
@@ -11,6 +11,11 @@ namespace Service::FRD {
 class FRD_U final : public Module::Interface {
 public:
     explicit FRD_U(std::shared_ptr<Module> frd);
+private:
+    SERVICE_SERIALIZATION(FRD_U, frd, Module)
 };
 
 } // namespace Service::FRD
+
+BOOST_CLASS_EXPORT_KEY(Service::FRD::FRD_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::FRD::FRD_U)

From 3ed8d95866eeebc8edfe3d886b4e24f84148563d Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 27 Dec 2019 11:46:10 +0000
Subject: [PATCH 030/129] Serialize FS service; some compiler fixes

---
 src/core/hle/kernel/hle_ipc.h          |  3 ++-
 src/core/hle/service/apt/apt.cpp       | 11 +----------
 src/core/hle/service/csnd/csnd_snd.cpp | 12 +-----------
 src/core/hle/service/csnd/csnd_snd.h   |  1 +
 src/core/hle/service/dsp/dsp_dsp.cpp   | 12 +-----------
 src/core/hle/service/fs/fs_user.cpp    |  5 +++++
 src/core/hle/service/fs/fs_user.h      | 20 ++++++++++++++++++++
 src/core/hle/service/service.h         | 19 ++++++++++++++++++-
 src/tests/core/hle/kernel/hle_ipc.cpp  |  3 +++
 src/video_core/pica_state.h            | 21 ++++++++++-----------
 10 files changed, 62 insertions(+), 45 deletions(-)

diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index da89ad39a..162a2eb39 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -22,7 +22,6 @@
 #include "core/hle/kernel/server_session.h"
 
 BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::SessionRequestHandler)
-BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::SessionRequestHandler::SessionDataBase)
 
 namespace Service {
 class ServiceFrameworkBase;
@@ -282,3 +281,5 @@ private:
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::SessionRequestHandler::SessionDataBase)
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 8e02d2bd4..d5a7fb001 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -27,16 +27,7 @@
 #include "core/hw/aes/ccm.h"
 #include "core/hw/aes/key.h"
 
-namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::APT::Module* t, const unsigned int)
-    {
-        ::new(t)Service::APT::Module(Core::Global<Core::System>());
-    }
-
-    template
-    void load_construct_data<iarchive>(iarchive& ar, Service::APT::Module* t, const unsigned int);
-}
+SERVICE_CONSTRUCT_IMPL(Service::APT::Module)
 
 namespace Service::APT {
 
diff --git a/src/core/hle/service/csnd/csnd_snd.cpp b/src/core/hle/service/csnd/csnd_snd.cpp
index d011a1c66..1a7a00964 100644
--- a/src/core/hle/service/csnd/csnd_snd.cpp
+++ b/src/core/hle/service/csnd/csnd_snd.cpp
@@ -9,17 +9,7 @@
 #include "core/hle/result.h"
 #include "core/hle/service/csnd/csnd_snd.h"
 
-namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::CSND::CSND_SND* t, const unsigned int)
-    {
-        ::new(t)Service::CSND::CSND_SND(Core::Global<Core::System>());
-    }
-
-    template
-    void load_construct_data<iarchive>(iarchive& ar, Service::CSND::CSND_SND* t, const unsigned int);
-}
-
+SERVICE_CONSTRUCT_IMPL(Service::CSND::CSND_SND)
 SERIALIZE_EXPORT_IMPL(Service::CSND::CSND_SND)
 
 namespace Service::CSND {
diff --git a/src/core/hle/service/csnd/csnd_snd.h b/src/core/hle/service/csnd/csnd_snd.h
index 0e2dd8cd8..44e4c030c 100644
--- a/src/core/hle/service/csnd/csnd_snd.h
+++ b/src/core/hle/service/csnd/csnd_snd.h
@@ -260,6 +260,7 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int)
     {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
         ar & mutex;
         ar & shared_memory;
         ar & capture_units;
diff --git a/src/core/hle/service/dsp/dsp_dsp.cpp b/src/core/hle/service/dsp/dsp_dsp.cpp
index 519d39b0c..9b0ef8986 100644
--- a/src/core/hle/service/dsp/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp/dsp_dsp.cpp
@@ -15,17 +15,7 @@ using DspPipe = AudioCore::DspPipe;
 using InterruptType = Service::DSP::DSP_DSP::InterruptType;
 
 SERIALIZE_EXPORT_IMPL(Service::DSP::DSP_DSP)
-
-namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::DSP::DSP_DSP* t, const unsigned int)
-    {
-        ::new(t)Service::DSP::DSP_DSP(Core::Global<Core::System>());
-    }
-
-    template
-    void load_construct_data<iarchive>(iarchive& ar, Service::DSP::DSP_DSP* t, const unsigned int);
-}
+SERVICE_CONSTRUCT_IMPL(Service::DSP::DSP_DSP)
 
 namespace AudioCore {
 enum class DspPipe;
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index bca8e77e5..e027e837f 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <cinttypes>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/file_util.h"
@@ -25,6 +26,10 @@
 #include "core/hle/service/fs/fs_user.h"
 #include "core/settings.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::FS::FS_USER)
+SERIALIZE_EXPORT_IMPL(Service::FS::FS_USER)
+SERIALIZE_EXPORT_IMPL(Service::FS::ClientSlot)
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Namespace FS_User
 
diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h
index 97b45714b..c001be0c5 100644
--- a/src/core/hle/service/fs/fs_user.h
+++ b/src/core/hle/service/fs/fs_user.h
@@ -22,6 +22,14 @@ struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
     // behaviour is modified. Since we don't emulate fs:REG mechanism, we assume the program ID is
     // the same as codeset ID and fetch from there directly.
     u64 program_id = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & program_id;
+    }
+    friend class boost::serialization::access;
 };
 
 class FS_USER final : public ServiceFramework<FS_USER, ClientSlot> {
@@ -545,8 +553,20 @@ private:
 
     Core::System& system;
     ArchiveManager& archives;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar & priority;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::FS
+
+SERVICE_CONSTRUCT(Service::FS::FS_USER)
+BOOST_CLASS_EXPORT_KEY(Service::FS::FS_USER)
+BOOST_CLASS_EXPORT_KEY(Service::FS::ClientSlot)
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index c0c48892a..4961678df 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -220,4 +220,21 @@ extern const std::array<ServiceModuleInfo, 40> service_module_map;
         ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this); \
     } \
     friend class boost::serialization::access; \
-    friend class construct_access;
+    friend class ::construct_access;
+
+#define SERVICE_CONSTRUCT(T) \
+namespace boost::serialization { \
+    template <class Archive> \
+    void load_construct_data(Archive& ar, T* t, const unsigned int); \
+}
+
+#define SERVICE_CONSTRUCT_IMPL(T) \
+namespace boost::serialization { \
+    template <class Archive> \
+    void load_construct_data(Archive& ar, T* t, const unsigned int) \
+    { \
+        ::new(t)T(Core::Global<Core::System>()); \
+    } \
+    template \
+    void load_construct_data<iarchive>(iarchive& ar, T* t, const unsigned int); \
+}
\ No newline at end of file
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index fb549f829..e405f6729 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <catch2/catch.hpp>
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/hle/ipc.h"
@@ -14,6 +15,8 @@
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/server_session.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::SessionRequestHandler::SessionDataBase)
+
 namespace Kernel {
 
 static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) {
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 95ee77662..30cef3496 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -18,18 +18,17 @@
 // Boost::serialization doesn't like union types for some reason,
 // so we need to mark arrays of union values with a special serialization method
 template<typename Value, size_t Size>
-struct UnionArray : public std::array<Value, Size> { };
-
-namespace boost::serialization {
-
-template<class Archive, typename Value, size_t Size>
-void serialize(Archive& ar, UnionArray<Value, Size>& array, const unsigned int version)
+struct UnionArray : public std::array<Value, Size>
 {
-    static_assert(sizeof(Value) == sizeof(u32));
-    ar & *static_cast<u32 (*)[Size]>(static_cast<void *>(array.data()));
-}
-
-}
+private:
+    template<class Archive>
+    void serialize(Archive& ar, const unsigned int)
+    {
+        static_assert(sizeof(Value) == sizeof(u32));
+        ar & *static_cast<u32 (*)[Size]>(static_cast<void *>(this->data()));
+    }
+    friend class boost::serialization::access;
+};
 
 namespace Pica {
 

From 6917eaf53b0260cf9ef0d1311a59d460f6329715 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 27 Dec 2019 18:52:33 +0000
Subject: [PATCH 031/129] Use load_construct_data for kernel objects

---
 TODO                                    |  5 ++--
 src/audio_core/dsp_interface.h          |  1 -
 src/common/CMakeLists.txt               |  4 +++
 src/common/archives.h                   | 12 ++++-----
 src/common/construct.h                  | 30 ++++++++++-----------
 src/common/serialization/atomic.h       | 36 ++++++++++++-------------
 src/core/core.cpp                       |  2 +-
 src/core/hle/kernel/address_arbiter.cpp |  5 ++--
 src/core/hle/kernel/address_arbiter.h   |  3 ++-
 src/core/hle/kernel/client_port.cpp     |  5 +++-
 src/core/hle/kernel/client_port.h       |  4 +++
 src/core/hle/kernel/client_session.cpp  |  2 +-
 src/core/hle/kernel/client_session.h    |  3 ++-
 src/core/hle/kernel/event.cpp           |  4 +--
 src/core/hle/kernel/event.h             |  3 ++-
 src/core/hle/kernel/mutex.cpp           |  5 ++--
 src/core/hle/kernel/mutex.h             |  3 ++-
 src/core/hle/kernel/object.cpp          | 12 +--------
 src/core/hle/kernel/object.h            | 17 +++++++++---
 src/core/hle/kernel/process.cpp         | 20 +++++++-------
 src/core/hle/kernel/process.h           | 11 ++++++--
 src/core/hle/kernel/resource_limit.cpp  |  9 +++++--
 src/core/hle/kernel/resource_limit.h    |  5 ++++
 src/core/hle/kernel/semaphore.cpp       |  4 +--
 src/core/hle/kernel/semaphore.h         |  3 ++-
 src/core/hle/kernel/server_port.cpp     |  9 ++++---
 src/core/hle/kernel/server_port.h       |  3 +++
 src/core/hle/kernel/server_session.cpp  |  8 +++---
 src/core/hle/kernel/server_session.h    |  3 ++-
 src/core/hle/kernel/shared_memory.cpp   |  9 ++++---
 src/core/hle/kernel/shared_memory.h     |  5 +++-
 src/core/hle/kernel/thread.cpp          |  9 +++----
 src/core/hle/kernel/thread.h            |  3 ++-
 src/core/hle/kernel/timer.cpp           |  9 ++++---
 src/core/hle/kernel/timer.h             |  5 +++-
 35 files changed, 158 insertions(+), 113 deletions(-)

diff --git a/TODO b/TODO
index 5a483dc84..be118365d 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,7 @@
 ✔ Memory @done(19-08-13 15:41)
     ☐ Page tables
     ☐ Skip N3DS RAM if unused
-✔ DSP @done(19-08-13 15:41)
+☐ DSP
 ✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
     ✔ Fix or ignore inverse map @done(19-12-23 12:46)
 ☐ App loader
@@ -16,6 +16,7 @@
 ☐ Telemetry session
 ☐ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE
 ☐ Review constructor/initialization code
+☐ Fix CI
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
     ✔ LCD regs @done(19-08-13 15:41)
@@ -78,7 +79,7 @@
         ✔ DSP @done(19-12-26 18:10)
         ✔ ERR @done(19-12-26 18:14)
         ✔ FRD @done(19-12-26 19:09)
-        ☐ FS
+        ✔ FS @done(19-12-27 11:46)
         ☐ GSP
         ☐ HID
         ☐ HTTP
diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h
index 29ec13d61..fc3d7cab2 100644
--- a/src/audio_core/dsp_interface.h
+++ b/src/audio_core/dsp_interface.h
@@ -6,7 +6,6 @@
 
 #include <memory>
 #include <vector>
-#include "boost/serialization/array.hpp"
 #include "audio_core/audio_types.h"
 #include "audio_core/time_stretch.h"
 #include "common/common_types.h"
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index c0182ed48..ac745d868 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -54,6 +54,7 @@ add_custom_command(OUTPUT scm_rev.cpp
 add_library(common STATIC
     alignment.h
     announce_multiplayer_room.h
+    archives.h
     assert.h
     detached_tasks.cpp
     detached_tasks.h
@@ -66,6 +67,7 @@ add_library(common STATIC
     common_funcs.h
     common_paths.h
     common_types.h
+    construct.h
     file_util.cpp
     file_util.h
     hash.h
@@ -91,8 +93,10 @@ add_library(common STATIC
     scm_rev.h
     scope_exit.h
     serialization/atomic.h
+    serialization/boost_discrete_interval.hpp
     serialization/boost_flat_set.h
     serialization/boost_vector.hpp
+    serialization/optional.h
     string_util.cpp
     string_util.h
     swap.h
diff --git a/src/common/archives.h b/src/common/archives.h
index a27afe80c..74cd9e08f 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -6,12 +6,12 @@ using iarchive = boost::archive::binary_iarchive;
 using oarchive = boost::archive::binary_oarchive;
 
 #define SERIALIZE_IMPL(A) template void A::serialize<iarchive>( \
-    iarchive & ar, \
-    const unsigned int file_version \
-); \
-template void A::serialize<oarchive>( \
-    oarchive & ar, \
-    const unsigned int file_version \
+    iarchive & ar,                                              \
+    const unsigned int file_version                             \
+);                                                              \
+template void A::serialize<oarchive>(                           \
+    oarchive & ar,                                              \
+    const unsigned int file_version                             \
 );
 
 #define SERIALIZE_EXPORT_IMPL(A) \
diff --git a/src/common/construct.h b/src/common/construct.h
index 6ef9af1ef..4e230ca43 100644
--- a/src/common/construct.h
+++ b/src/common/construct.h
@@ -12,20 +12,18 @@ public:
     }
 };
 
-#define BOOST_SERIALIZATION_CONSTRUCT(T) \
-namespace boost { namespace serialization { \
-\
-    template<class Archive> \
-    inline void save_construct_data( \
-        Archive & ar, const T * t, const unsigned int file_version \
-    ){ \
-        construct_access::save_construct(ar, t, file_version); \
-    } \
-\
-    template<class Archive> \
-    inline void load_construct_data( \
-        Archive & ar, T * t, const unsigned int file_version \
-    ){ \
-        construct_access::load_construct(ar, t, file_version); \
-    } \
+#define BOOST_SERIALIZATION_CONSTRUCT(T)                          \
+namespace boost { namespace serialization {                       \
+template<class Archive>                                           \
+inline void save_construct_data(                                  \
+    Archive & ar, const T * t, const unsigned int file_version    \
+){                                                                \
+    construct_access::save_construct(ar, t, file_version);        \
+}                                                                 \
+template<class Archive>                                           \
+inline void load_construct_data(                                  \
+    Archive & ar, T * t, const unsigned int file_version          \
+){                                                                \
+    construct_access::load_construct(ar, t, file_version);        \
+}                                                                 \
 }}
diff --git a/src/common/serialization/atomic.h b/src/common/serialization/atomic.h
index ef33202ff..665914df3 100644
--- a/src/common/serialization/atomic.h
+++ b/src/common/serialization/atomic.h
@@ -3,26 +3,26 @@
 #include <atomic>
 #include <boost/serialization/split_free.hpp>
 
-namespace boost::serialization
+namespace boost::serialization {
+
+template <class Archive, class T>
+void serialize(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
 {
-    template <class Archive, class T>
-    void serialize(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
-    {
-        boost::serialization::split_free(ar, value, file_version);
-    }
+    boost::serialization::split_free(ar, value, file_version);
+}
 
-    template <class Archive, class T>
-    void save(Archive& ar, const std::atomic<T>& value, const unsigned int file_version)
-    {
-        ar << value.load();
-    }
+template <class Archive, class T>
+void save(Archive& ar, const std::atomic<T>& value, const unsigned int file_version)
+{
+    ar << value.load();
+}
 
-    template <class Archive, class T>
-    void load(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
-    {
-        T tmp;
-        ar >> tmp;
-        value.store(tmp);
-    }
+template <class Archive, class T>
+void load(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
+{
+    T tmp;
+    ar >> tmp;
+    value.store(tmp);
+}
 
 } // namespace boost::serialization
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 055eadae2..2df38f3ed 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -4,7 +4,7 @@
 
 #include <memory>
 #include <utility>
-#include "boost/serialization/array.hpp"
+#include <boost/serialization/array.hpp>
 #include "audio_core/dsp_interface.h"
 #include "audio_core/hle/hle.h"
 #include "audio_core/lle/lle.h"
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index ca120e6f9..e5e017daa 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -69,12 +69,11 @@ std::shared_ptr<Thread> AddressArbiter::ResumeHighestPriorityThread(VAddr addres
     return thread;
 }
 
-AddressArbiter::AddressArbiter() : kernel(Core::Global<KernelSystem>()) {}
+AddressArbiter::AddressArbiter(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
 AddressArbiter::~AddressArbiter() {}
 
 std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string name) {
-    auto address_arbiter{std::make_shared<AddressArbiter>()};
-    address_arbiter->Init(*this);
+    auto address_arbiter{std::make_shared<AddressArbiter>(*this)};
 
     address_arbiter->name = std::move(name);
 
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 3b29a84a4..793d274ca 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -36,7 +36,7 @@ enum class ArbitrationType : u32 {
 
 class AddressArbiter final : public Object {
 public:
-    explicit AddressArbiter();
+    explicit AddressArbiter(KernelSystem& kernel);
     ~AddressArbiter() override;
 
     std::string GetTypeName() const override {
@@ -85,3 +85,4 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter)
+CONSTRUCT_KERNEL_OBJECT(Kernel::AddressArbiter)
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index f9202035c..618c7d0d7 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -17,6 +17,9 @@ SERIALIZE_EXPORT_IMPL(Kernel::ClientPort)
 
 namespace Kernel {
 
+ClientPort::ClientPort(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
+ClientPort::~ClientPort() = default;
+
 ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
     // Note: Threads do not wait for the server endpoint to call
     // AcceptSession before returning from this call.
@@ -27,7 +30,7 @@ ResultVal<std::shared_ptr<ClientSession>> ClientPort::Connect() {
     active_sessions++;
 
     // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
-    auto [server, client] = Core::Global<KernelSystem>().CreateSessionPair(server_port->GetName(), SharedFrom(this));
+    auto [server, client] = kernel.CreateSessionPair(server_port->GetName(), SharedFrom(this));
 
     if (server_port->hle_handler)
         server_port->hle_handler->ClientConnected(server);
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 72cae85c3..c5b032f1f 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -18,6 +18,8 @@ class ClientSession;
 
 class ClientPort final : public Object {
 public:
+    explicit ClientPort(KernelSystem& kernel);
+    ~ClientPort() override;
 
     friend class ServerPort;
     std::string GetTypeName() const override {
@@ -51,6 +53,7 @@ public:
     void ConnectionClosed();
 
 private:
+    KernelSystem& kernel;
     std::shared_ptr<ServerPort> server_port; ///< ServerPort associated with this client port.
     u32 max_sessions = 0;    ///< Maximum number of simultaneous sessions the port can have
     u32 active_sessions = 0; ///< Number of currently open sessions to this port
@@ -75,3 +78,4 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::ClientPort)
+CONSTRUCT_KERNEL_OBJECT(Kernel::ClientPort)
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index ba9c2ec50..0b00576d3 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -15,7 +15,7 @@ SERIALIZE_EXPORT_IMPL(Kernel::ClientSession)
 
 namespace Kernel {
 
-ClientSession::ClientSession() = default;
+ClientSession::ClientSession(KernelSystem& kernel) : Object(kernel) {}
 ClientSession::~ClientSession() {
     // This destructor will be called automatically when the last ClientSession handle is closed by
     // the emulated application.
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 2ffe68f8b..1ddbfb348 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -20,7 +20,7 @@ class Thread;
 
 class ClientSession final : public Object {
 public:
-    explicit ClientSession();
+    explicit ClientSession(KernelSystem& kernel);
     ~ClientSession() override;
 
     friend class KernelSystem;
@@ -64,3 +64,4 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::ClientSession)
+CONSTRUCT_KERNEL_OBJECT(Kernel::ClientSession)
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 7af667739..2375d6733 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -15,11 +15,11 @@ SERIALIZE_EXPORT_IMPL(Kernel::Event)
 
 namespace Kernel {
 
-Event::Event() : WaitObject() {}
+Event::Event(KernelSystem& kernel) : WaitObject(kernel) {}
 Event::~Event() {}
 
 std::shared_ptr<Event> KernelSystem::CreateEvent(ResetType reset_type, std::string name) {
-    auto evt{std::make_shared<Event>()};
+    auto evt{std::make_shared<Event>(*this)};
 
     evt->signaled = false;
     evt->reset_type = reset_type;
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index bb97f6eb1..509ab5c6c 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -13,7 +13,7 @@ namespace Kernel {
 
 class Event final : public WaitObject {
 public:
-    explicit Event();
+    explicit Event(KernelSystem& kernel);
     ~Event() override;
 
     std::string GetTypeName() const override {
@@ -65,3 +65,4 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::Event)
+CONSTRUCT_KERNEL_OBJECT(Kernel::Event)
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 16bcd3af2..4badd88ce 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -27,12 +27,11 @@ void ReleaseThreadMutexes(Thread* thread) {
     thread->held_mutexes.clear();
 }
 
-Mutex::Mutex() : kernel(Core::Global<KernelSystem>()) {}
+Mutex::Mutex(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
 Mutex::~Mutex() {}
 
 std::shared_ptr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::string name) {
-    auto mutex{std::make_shared<Mutex>()};
-    mutex->Init(*this);
+    auto mutex{std::make_shared<Mutex>(*this)};
 
     mutex->lock_count = 0;
     mutex->name = std::move(name);
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index f4449c0f2..a164b70da 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -18,7 +18,7 @@ class Thread;
 
 class Mutex final : public WaitObject {
 public:
-    explicit Mutex();
+    explicit Mutex(KernelSystem& kernel);
     ~Mutex() override;
 
     std::string GetTypeName() const override {
@@ -81,3 +81,4 @@ void ReleaseThreadMutexes(Thread* thread);
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::Mutex)
+CONSTRUCT_KERNEL_OBJECT(Kernel::Mutex)
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index 6ab1b1769..f9ca68218 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -8,17 +8,7 @@
 
 namespace Kernel {
 
-// TODO: Remove this
-Object::Object(KernelSystem& kernel)
-{
-}
-
-Object::Object() = default;
-
-void Object::Init(KernelSystem& kernel)
-{
-    object_id = kernel.GenerateObjectID();
-}
+Object::Object(KernelSystem& kernel) : object_id{kernel.GenerateObjectID()} {}
 
 Object::~Object() = default;
 
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index 6adba034e..a61e47c17 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -8,9 +8,12 @@
 #include <memory>
 #include <string>
 #include <boost/serialization/access.hpp>
+#include <boost/serialization/assume_abstract.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/serialization/atomic.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/global.h"
 
 namespace Kernel {
 
@@ -43,11 +46,8 @@ enum {
 class Object : NonCopyable, public std::enable_shared_from_this<Object> {
 public:
     explicit Object(KernelSystem& kernel);
-    Object();
     virtual ~Object();
 
-    virtual void Init(KernelSystem& kernel);
-
     /// Returns a unique identifier for the object. For debugging purposes only.
     u32 GetObjectId() const {
         return object_id.load(std::memory_order_relaxed);
@@ -99,3 +99,14 @@ inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) {
 }
 
 } // namespace Kernel
+
+BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::Object)
+
+#define CONSTRUCT_KERNEL_OBJECT(T)                                \
+namespace boost::serialization {                                  \
+template<class Archive>                                           \
+inline void load_construct_data(                                  \
+    Archive & ar, T * t, const unsigned int file_version          \
+){                                                                \
+    ::new(t)T(Core::Global<Kernel::KernelSystem>());              \
+}}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 72f882c56..12afe1f89 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -20,6 +20,9 @@
 #include "core/memory.h"
 #include "core/global.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::Process)
+SERIALIZE_EXPORT_IMPL(Kernel::CodeSet)
+
 namespace Kernel {
 
 template <class Archive>
@@ -46,8 +49,7 @@ void Process::serialize(Archive& ar, const unsigned int file_version)
 SERIALIZE_IMPL(Process)
 
 std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
-    auto codeset{std::make_shared<CodeSet>()};
-    codeset->Init(*this);
+    auto codeset{std::make_shared<CodeSet>(*this)};
 
     codeset->name = std::move(name);
     codeset->program_id = program_id;
@@ -55,9 +57,11 @@ std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 progr
     return codeset;
 }
 
+CodeSet::CodeSet(KernelSystem& kernel) : Object(kernel) {}
+CodeSet::~CodeSet() {}
+
 std::shared_ptr<Process> KernelSystem::CreateProcess(std::shared_ptr<CodeSet> code_set) {
-    auto process{std::make_shared<Process>()};
-    process->Init(*this);
+    auto process{std::make_shared<Process>(*this)};
 
     process->codeset = std::move(code_set);
     process->flags.raw = 0;
@@ -428,12 +432,8 @@ ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission pe
     return RESULT_SUCCESS;
 }
 
-Kernel::Process::Process() : Kernel::Process::Process(Core::Global<KernelSystem>())
-{
-}
-
-Kernel::Process::Process(KernelSystem& kernel) : kernel(kernel), handle_table(kernel), vm_manager(kernel.memory)
-{
+Kernel::Process::Process(KernelSystem& kernel)
+    : Object(kernel), handle_table(kernel), vm_manager(kernel.memory), kernel(kernel) {
     kernel.memory.RegisterPageTable(&vm_manager.page_table);
 }
 Kernel::Process::~Process() {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 70a5f212b..5746a1c6a 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -65,6 +65,9 @@ struct MemoryRegionInfo;
 
 class CodeSet final : public Object {
 public:
+    explicit CodeSet(KernelSystem& kernel);
+    ~CodeSet() override;
+
     struct Segment {
         std::size_t offset = 0;
         VAddr addr = 0;
@@ -143,8 +146,7 @@ private:
 
 class Process final : public Object {
 public:
-    Process();
-    explicit Process(KernelSystem& kernel);
+    explicit Process(Kernel::KernelSystem& kernel);
     ~Process() override;
 
     std::string GetTypeName() const override {
@@ -235,3 +237,8 @@ private:
     void serialize(Archive& ar, const unsigned int file_version);
 };
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::CodeSet)
+BOOST_CLASS_EXPORT_KEY(Kernel::Process)
+CONSTRUCT_KERNEL_OBJECT(Kernel::CodeSet)
+CONSTRUCT_KERNEL_OBJECT(Kernel::Process)
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index fe19caff9..9affa685a 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -3,15 +3,20 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "core/hle/kernel/resource_limit.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::ResourceLimit)
+
 namespace Kernel {
 
+ResourceLimit::ResourceLimit(KernelSystem& kernel) : Object(kernel) {}
+ResourceLimit::~ResourceLimit() {}
+
 std::shared_ptr<ResourceLimit> ResourceLimit::Create(KernelSystem& kernel, std::string name) {
-    auto resource_limit{std::make_shared<ResourceLimit>()};
-    resource_limit->Init(kernel);
+    auto resource_limit{std::make_shared<ResourceLimit>(kernel)};
 
     resource_limit->name = std::move(name);
     return resource_limit;
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 06fe71587..0d64f1216 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -35,6 +35,8 @@ enum ResourceTypes {
 
 class ResourceLimit final : public Object {
 public:
+    explicit ResourceLimit(KernelSystem& kernel);
+    ~ResourceLimit() override;
 
     /**
      * Creates a resource limit object.
@@ -165,3 +167,6 @@ private:
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::ResourceLimit)
+CONSTRUCT_KERNEL_OBJECT(Kernel::ResourceLimit)
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index f60a653e5..c637f5f4d 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -13,7 +13,7 @@ SERIALIZE_EXPORT_IMPL(Kernel::Semaphore)
 
 namespace Kernel {
 
-Semaphore::Semaphore() : WaitObject() {}
+Semaphore::Semaphore(KernelSystem& kernel) : WaitObject(kernel) {}
 Semaphore::~Semaphore() {}
 
 ResultVal<std::shared_ptr<Semaphore>> KernelSystem::CreateSemaphore(s32 initial_count,
@@ -23,7 +23,7 @@ ResultVal<std::shared_ptr<Semaphore>> KernelSystem::CreateSemaphore(s32 initial_
     if (initial_count > max_count)
         return ERR_INVALID_COMBINATION_KERNEL;
 
-    auto semaphore{std::make_shared<Semaphore>()};
+    auto semaphore{std::make_shared<Semaphore>(*this)};
 
     // When the semaphore is created, some slots are reserved for other threads,
     // and the rest is reserved for the caller thread
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index ff6a4434a..f28c30ec7 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -16,7 +16,7 @@ namespace Kernel {
 
 class Semaphore final : public WaitObject {
 public:
-    explicit Semaphore();
+    explicit Semaphore(KernelSystem& kernel);
     ~Semaphore() override;
 
     std::string GetTypeName() const override {
@@ -60,3 +60,4 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::Semaphore)
+CONSTRUCT_KERNEL_OBJECT(Kernel::Semaphore)
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 0aeb86a78..46aa8f758 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -17,6 +17,9 @@ SERIALIZE_EXPORT_IMPL(Kernel::ServerPort)
 
 namespace Kernel {
 
+ServerPort::ServerPort(KernelSystem& kernel) : WaitObject(kernel) {}
+ServerPort::~ServerPort() {}
+
 ResultVal<std::shared_ptr<ServerSession>> ServerPort::Accept() {
     if (pending_sessions.empty()) {
         return ERR_NO_PENDING_SESSIONS;
@@ -37,10 +40,8 @@ void ServerPort::Acquire(Thread* thread) {
 }
 
 KernelSystem::PortPair KernelSystem::CreatePortPair(u32 max_sessions, std::string name) {
-    auto server_port{std::make_shared<ServerPort>()};
-    server_port->Init(*this);
-    auto client_port{std::make_shared<ClientPort>()};
-    client_port->Init(*this);
+    auto server_port{std::make_shared<ServerPort>(*this)};
+    auto client_port{std::make_shared<ClientPort>(*this)};
 
     server_port->name = name + "_Server";
     client_port->name = name + "_Client";
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index f055cd267..2f00e586e 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -25,6 +25,8 @@ class SessionRequestHandler;
 
 class ServerPort final : public WaitObject {
 public:
+    explicit ServerPort(KernelSystem& kernel);
+    ~ServerPort() override;
 
     std::string GetTypeName() const override {
         return "ServerPort";
@@ -73,3 +75,4 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::ServerPort)
+CONSTRUCT_KERNEL_OBJECT(Kernel::ServerPort)
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 146142f08..e0c4087f1 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -16,7 +16,7 @@ SERIALIZE_EXPORT_IMPL(Kernel::ServerSession)
 
 namespace Kernel {
 
-ServerSession::ServerSession() : kernel(Core::Global<KernelSystem>()) {}
+ServerSession::ServerSession(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
 ServerSession::~ServerSession() {
     // This destructor will be called automatically when the last ServerSession handle is closed by
     // the emulated application.
@@ -33,8 +33,7 @@ ServerSession::~ServerSession() {
 
 ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelSystem& kernel,
                                                                 std::string name) {
-    auto server_session{std::make_shared<ServerSession>()};
-    server_session->Init(kernel);
+    auto server_session{std::make_shared<ServerSession>(kernel)};
 
     server_session->name = std::move(name);
     server_session->parent = nullptr;
@@ -127,8 +126,7 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
 KernelSystem::SessionPair KernelSystem::CreateSessionPair(const std::string& name,
                                                           std::shared_ptr<ClientPort> port) {
     auto server_session = ServerSession::Create(*this, name + "_Server").Unwrap();
-    auto client_session{std::make_shared<ClientSession>()};
-    client_session->Init(*this);
+    auto client_session{std::make_shared<ClientSession>(*this)};
     client_session->name = name + "_Client";
 
     std::shared_ptr<Session> parent(new Session);
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 05b469c38..6eb5673f6 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -42,7 +42,7 @@ class Thread;
 class ServerSession final : public WaitObject {
 public:
     ~ServerSession() override;
-    explicit ServerSession();
+    explicit ServerSession(KernelSystem& kernel);
 
     std::string GetName() const override {
         return name;
@@ -125,3 +125,4 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::ServerSession)
+CONSTRUCT_KERNEL_OBJECT(Kernel::ServerSession)
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index c76cdfa19..14c9751e8 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/memory.h"
@@ -10,9 +11,11 @@
 #include "core/memory.h"
 #include "core/global.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::SharedMemory)
+
 namespace Kernel {
 
-SharedMemory::SharedMemory() : Object(Core::Global<KernelSystem>()), kernel(Core::Global<KernelSystem>()) {}
+SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
 SharedMemory::~SharedMemory() {
     for (const auto& interval : holding_memory) {
         kernel.GetMemoryRegion(MemoryRegion::SYSTEM)
@@ -28,7 +31,7 @@ SharedMemory::~SharedMemory() {
 ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
     Process* owner_process, u32 size, MemoryPermission permissions,
     MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
-    auto shared_memory{std::make_shared<SharedMemory>()};
+    auto shared_memory{std::make_shared<SharedMemory>(*this)};
 
     shared_memory->owner_process = owner_process;
     shared_memory->name = std::move(name);
@@ -73,7 +76,7 @@ ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
 std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
     u32 offset, u32 size, MemoryPermission permissions, MemoryPermission other_permissions,
     std::string name) {
-    auto shared_memory{std::make_shared<SharedMemory>()};
+    auto shared_memory{std::make_shared<SharedMemory>(*this)};
 
     // Allocate memory in heap
     MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 925f7783c..88727be6d 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -16,7 +16,7 @@ namespace Kernel {
 
 class SharedMemory final : public Object {
 public:
-    explicit SharedMemory();
+    explicit SharedMemory(KernelSystem& kernel);
     ~SharedMemory() override;
 
     std::string GetTypeName() const override {
@@ -123,3 +123,6 @@ private:
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::SharedMemory)
+CONSTRUCT_KERNEL_OBJECT(Kernel::SharedMemory)
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 98fe85175..c824b58a6 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -66,9 +66,9 @@ u32 ThreadManager::NewThreadId() {
     return next_thread_id++;
 }
 
-Thread::Thread()
-    : context(Core::Global<KernelSystem>().GetThreadManager().NewContext()),
-      thread_manager(Core::Global<KernelSystem>().GetThreadManager()) {}
+Thread::Thread(KernelSystem& kernel)
+    : WaitObject(kernel), context(kernel.GetThreadManager().NewContext()),
+      thread_manager(kernel.GetThreadManager()) {}
 Thread::~Thread() {}
 
 Thread* ThreadManager::GetCurrentThread() const {
@@ -338,8 +338,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
                           ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
     }
 
-    auto thread{std::make_shared<Thread>()};
-    thread->Init(*this);
+    auto thread{std::make_shared<Thread>(*this)};
 
     thread_manager->thread_list.push_back(thread);
     thread_manager->ready_queue.prepare(priority);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index b423392e3..09341560a 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -164,7 +164,7 @@ private:
 
 class Thread final : public WaitObject {
 public:
-    explicit Thread();
+    explicit Thread(KernelSystem&);
     ~Thread() override;
 
     std::string GetName() const override {
@@ -340,3 +340,4 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::Thread)
+CONSTRUCT_KERNEL_OBJECT(Kernel::Thread)
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 422cf990c..f1a31cdf9 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -4,6 +4,7 @@
 
 #include <cinttypes>
 #include <unordered_map>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "core/core.h"
@@ -13,17 +14,19 @@
 #include "core/hle/kernel/timer.h"
 #include "core/global.h"
 
+SERIALIZE_EXPORT_IMPL(Kernel::Timer)
+
 namespace Kernel {
 
-Timer::Timer() : kernel(Core::Global<KernelSystem>()), timer_manager(Core::Global<KernelSystem>().GetTimerManager()) {}
+Timer::Timer(KernelSystem& kernel)
+    : WaitObject(kernel), kernel(kernel), timer_manager(kernel.GetTimerManager()) {}
 Timer::~Timer() {
     Cancel();
     timer_manager.timer_callback_table.erase(callback_id);
 }
 
 std::shared_ptr<Timer> KernelSystem::CreateTimer(ResetType reset_type, std::string name) {
-    auto timer{std::make_shared<Timer>()};
-    timer->Init(*this);
+    auto timer{std::make_shared<Timer>(*this)};
 
     timer->reset_type = reset_type;
     timer->signaled = false;
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index 690350611..f61ec1c11 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -46,7 +46,7 @@ private:
 
 class Timer final : public WaitObject {
 public:
-    explicit Timer();
+    explicit Timer(KernelSystem& kernel);
     ~Timer() override;
 
     std::string GetTypeName() const override {
@@ -127,3 +127,6 @@ private:
 };
 
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::Timer)
+CONSTRUCT_KERNEL_OBJECT(Kernel::Timer)

From d482fb359c306bf4301b1aa523afc514d4ed8217 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 27 Dec 2019 20:36:17 +0000
Subject: [PATCH 032/129] Attempting to fix mingw on windows

---
 src/core/hle/service/apt/apt.h | 1 +
 src/core/hle/service/service.h | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 45a93b350..14c07feb3 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -13,6 +13,7 @@
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/service/apt/applet_manager.h"
 #include "core/hle/service/service.h"
 #include "core/global.h"
 
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 4961678df..b16a4065f 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -237,4 +237,4 @@ namespace boost::serialization { \
     } \
     template \
     void load_construct_data<iarchive>(iarchive& ar, T* t, const unsigned int); \
-}
\ No newline at end of file
+}

From 7b846ffa9891fb86ad7f236cdc76bd63d6839f11 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 27 Dec 2019 21:07:29 +0000
Subject: [PATCH 033/129] clang-format fixes

---
 src/common/archives.h                     |  19 ++--
 src/common/construct.h                    |  36 ++++----
 src/common/pod.h                          |  31 +++----
 src/common/serialization/atomic.h         |   9 +-
 src/common/serialization/boost_flat_set.h |  15 ++--
 src/common/serialization/optional.h       |  75 +++++++---------
 src/common/thread_queue_list.h            |  10 +--
 src/common/vector_math.h                  |  33 ++++---
 src/core/arm/arm_interface.h              |  12 +--
 src/core/core.cpp                         |  39 +++++----
 src/core/core.h                           |   8 +-
 src/core/hle/kernel/address_arbiter.cpp   |   2 +-
 src/core/hle/kernel/address_arbiter.h     |   9 +-
 src/core/hle/kernel/client_port.cpp       |   2 +-
 src/core/hle/kernel/client_port.h         |  14 ++-
 src/core/hle/kernel/client_session.cpp    |   2 +-
 src/core/hle/kernel/client_session.h      |   9 +-
 src/core/hle/kernel/config_mem.h          |   5 +-
 src/core/hle/kernel/event.cpp             |   2 +-
 src/core/hle/kernel/event.h               |  11 ++-
 src/core/hle/kernel/handle_table.h        |  11 ++-
 src/core/hle/kernel/hle_ipc.h             |  21 +++--
 src/core/hle/kernel/ipc.h                 |  18 ++--
 src/core/hle/kernel/kernel.cpp            |  25 +++---
 src/core/hle/kernel/memory.h              |  13 ++-
 src/core/hle/kernel/mutex.cpp             |   2 +-
 src/core/hle/kernel/mutex.h               |  13 ++-
 src/core/hle/kernel/object.h              |  24 +++--
 src/core/hle/kernel/process.cpp           |  39 +++++----
 src/core/hle/kernel/process.h             |  35 ++++----
 src/core/hle/kernel/resource_limit.h      |  53 ++++++------
 src/core/hle/kernel/semaphore.cpp         |   2 +-
 src/core/hle/kernel/semaphore.h           |  13 ++-
 src/core/hle/kernel/server_port.cpp       |  13 ++-
 src/core/hle/kernel/server_session.cpp    |   2 +-
 src/core/hle/kernel/server_session.h      |  17 ++--
 src/core/hle/kernel/session.cpp           |  15 ++--
 src/core/hle/kernel/shared_memory.cpp     |   2 +-
 src/core/hle/kernel/shared_memory.h       |  19 ++--
 src/core/hle/kernel/shared_page.h         |   5 +-
 src/core/hle/kernel/thread.cpp            |  37 ++++----
 src/core/hle/kernel/thread.h              |  15 ++--
 src/core/hle/kernel/timer.cpp             |   2 +-
 src/core/hle/kernel/timer.h               |  22 +++--
 src/core/hle/kernel/vm_manager.h          |  35 ++++----
 src/core/hle/kernel/wait_object.h         |   7 +-
 src/core/hle/service/ac/ac.cpp            |  13 ++-
 src/core/hle/service/ac/ac_i.cpp          |   2 +-
 src/core/hle/service/ac/ac_u.cpp          |   2 +-
 src/core/hle/service/act/act.h            |   3 +-
 src/core/hle/service/act/act_a.cpp        |   2 +-
 src/core/hle/service/act/act_a.h          |   1 +
 src/core/hle/service/act/act_u.cpp        |   2 +-
 src/core/hle/service/act/act_u.h          |   1 +
 src/core/hle/service/am/am.cpp            |   2 +-
 src/core/hle/service/am/am.h              |  22 +++--
 src/core/hle/service/am/am_app.cpp        |   2 +-
 src/core/hle/service/am/am_app.h          |   1 +
 src/core/hle/service/am/am_net.cpp        |   2 +-
 src/core/hle/service/am/am_net.h          |   1 +
 src/core/hle/service/am/am_sys.cpp        |   2 +-
 src/core/hle/service/am/am_sys.h          |   1 +
 src/core/hle/service/am/am_u.cpp          |   2 +-
 src/core/hle/service/am/am_u.h            |   1 +
 src/core/hle/service/apt/applet_manager.h |  65 +++++++-------
 src/core/hle/service/apt/apt.cpp          |  23 +++--
 src/core/hle/service/apt/apt.h            |  14 ++-
 src/core/hle/service/apt/apt_a.cpp        |   2 +-
 src/core/hle/service/apt/apt_a.h          |   1 +
 src/core/hle/service/apt/apt_s.cpp        |   2 +-
 src/core/hle/service/apt/apt_s.h          |   1 +
 src/core/hle/service/apt/apt_u.cpp        |   2 +-
 src/core/hle/service/apt/apt_u.h          |   1 +
 src/core/hle/service/apt/ns_s.cpp         |   2 +-
 src/core/hle/service/apt/ns_s.h           |   1 +
 src/core/hle/service/boss/boss.h          |  27 +++---
 src/core/hle/service/boss/boss_p.cpp      |   2 +-
 src/core/hle/service/boss/boss_u.cpp      |   2 +-
 src/core/hle/service/cam/cam.cpp          |   9 +-
 src/core/hle/service/cam/cam.h            |  87 +++++++++----------
 src/core/hle/service/cam/cam_c.cpp        |   2 +-
 src/core/hle/service/cam/cam_q.cpp        |   2 +-
 src/core/hle/service/cam/cam_q.h          |   6 +-
 src/core/hle/service/cam/cam_s.cpp        |   2 +-
 src/core/hle/service/cam/cam_u.cpp        |   2 +-
 src/core/hle/service/csnd/csnd_snd.h      |  69 +++++++--------
 src/core/hle/service/dlp/dlp_clnt.cpp     |   2 +-
 src/core/hle/service/dlp/dlp_clnt.h       |   6 +-
 src/core/hle/service/dlp/dlp_fkcl.cpp     |   2 +-
 src/core/hle/service/dlp/dlp_fkcl.h       |   6 +-
 src/core/hle/service/dlp/dlp_srvr.cpp     |   2 +-
 src/core/hle/service/dlp/dlp_srvr.h       |   5 +-
 src/core/hle/service/dsp/dsp_dsp.h        |  19 ++--
 src/core/hle/service/err_f.cpp            |  15 ++--
 src/core/hle/service/err_f.h              |   9 +-
 src/core/hle/service/frd/frd.h            |  21 ++---
 src/core/hle/service/frd/frd_a.cpp        |   2 +-
 src/core/hle/service/frd/frd_a.h          |   1 +
 src/core/hle/service/frd/frd_u.cpp        |   2 +-
 src/core/hle/service/frd/frd_u.h          |   1 +
 src/core/hle/service/fs/archive.cpp       |   2 +-
 src/core/hle/service/fs/fs_user.h         |  12 ++-
 src/core/hle/service/service.h            |  69 +++++++--------
 src/core/hle/service/sm/sm.h              |   8 +-
 src/core/memory.cpp                       |  37 ++++----
 src/core/memory.h                         |  15 ++--
 src/core/mmio.h                           |   4 +-
 src/tests/core/hle/kernel/hle_ipc.cpp     |   6 +-
 src/video_core/command_processor.cpp      |   3 +-
 src/video_core/geometry_pipeline.cpp      |  57 +++++-------
 src/video_core/pica.cpp                   |   8 +-
 src/video_core/pica_state.h               | 101 ++++++++++------------
 src/video_core/pica_types.h               |   7 +-
 src/video_core/primitive_assembly.h       |  17 ++--
 src/video_core/shader/shader.h            |  77 ++++++++---------
 src/video_core/video_core.cpp             |  11 +--
 src/video_core/video_core.h               |   6 +-
 117 files changed, 797 insertions(+), 925 deletions(-)

diff --git a/src/common/archives.h b/src/common/archives.h
index 74cd9e08f..29f23865b 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -5,16 +5,11 @@
 using iarchive = boost::archive::binary_iarchive;
 using oarchive = boost::archive::binary_oarchive;
 
-#define SERIALIZE_IMPL(A) template void A::serialize<iarchive>( \
-    iarchive & ar,                                              \
-    const unsigned int file_version                             \
-);                                                              \
-template void A::serialize<oarchive>(                           \
-    oarchive & ar,                                              \
-    const unsigned int file_version                             \
-);
+#define SERIALIZE_IMPL(A)                                                                          \
+    template void A::serialize<iarchive>(iarchive & ar, const unsigned int file_version);          \
+    template void A::serialize<oarchive>(oarchive & ar, const unsigned int file_version);
 
-#define SERIALIZE_EXPORT_IMPL(A) \
-BOOST_SERIALIZATION_REGISTER_ARCHIVE(iarchive) \
-BOOST_SERIALIZATION_REGISTER_ARCHIVE(oarchive) \
-BOOST_CLASS_EXPORT_IMPLEMENT(A)
+#define SERIALIZE_EXPORT_IMPL(A)                                                                   \
+    BOOST_SERIALIZATION_REGISTER_ARCHIVE(iarchive)                                                 \
+    BOOST_SERIALIZATION_REGISTER_ARCHIVE(oarchive)                                                 \
+    BOOST_CLASS_EXPORT_IMPLEMENT(A)
diff --git a/src/common/construct.h b/src/common/construct.h
index 4e230ca43..6b2b3ceeb 100644
--- a/src/common/construct.h
+++ b/src/common/construct.h
@@ -2,28 +2,26 @@
 
 class construct_access {
 public:
-    template<class Archive, class T>
-    static inline void save_construct(Archive & ar, const T * t, const unsigned int file_version) {
+    template <class Archive, class T>
+    static inline void save_construct(Archive& ar, const T* t, const unsigned int file_version) {
         t->save_construct(ar, file_version);
     }
-    template<class Archive, class T>
-    static inline void load_construct(Archive & ar, T * t, const unsigned int file_version) {
+    template <class Archive, class T>
+    static inline void load_construct(Archive& ar, T* t, const unsigned int file_version) {
         T::load_construct(ar, t, file_version);
     }
 };
 
-#define BOOST_SERIALIZATION_CONSTRUCT(T)                          \
-namespace boost { namespace serialization {                       \
-template<class Archive>                                           \
-inline void save_construct_data(                                  \
-    Archive & ar, const T * t, const unsigned int file_version    \
-){                                                                \
-    construct_access::save_construct(ar, t, file_version);        \
-}                                                                 \
-template<class Archive>                                           \
-inline void load_construct_data(                                  \
-    Archive & ar, T * t, const unsigned int file_version          \
-){                                                                \
-    construct_access::load_construct(ar, t, file_version);        \
-}                                                                 \
-}}
+#define BOOST_SERIALIZATION_CONSTRUCT(T)                                                           \
+    namespace boost {                                                                              \
+    namespace serialization {                                                                      \
+    template <class Archive>                                                                       \
+    inline void save_construct_data(Archive& ar, const T* t, const unsigned int file_version) {    \
+        construct_access::save_construct(ar, t, file_version);                                     \
+    }                                                                                              \
+    template <class Archive>                                                                       \
+    inline void load_construct_data(Archive& ar, T* t, const unsigned int file_version) {          \
+        construct_access::load_construct(ar, t, file_version);                                     \
+    }                                                                                              \
+    }                                                                                              \
+    }
diff --git a/src/common/pod.h b/src/common/pod.h
index e7224644a..bb7095417 100644
--- a/src/common/pod.h
+++ b/src/common/pod.h
@@ -1,20 +1,17 @@
 #include "boost/serialization/split_member.hpp"
 
-#define SERIALIZE_AS_POD                                             \
-    private:                                                         \
-    friend class boost::serialization::access;                       \
-    template<typename Archive>                                       \
-    void save(Archive & ar, const unsigned int file_version) const { \
-        ar.save_binary(this, sizeof(*this));                         \
-    }                                                                \
-    template<typename Archive>                                       \
-    void load(Archive & ar, const unsigned int file_version) {       \
-        ar.load_binary(this, sizeof(*this));                         \
-    }                                                                \
-    template<class Archive>                                          \
-    void serialize(                                                  \
-        Archive &ar,                                                 \
-        const unsigned int file_version                              \
-    ){                                                               \
-        boost::serialization::split_member(ar, *this, file_version); \
+#define SERIALIZE_AS_POD                                                                           \
+private:                                                                                           \
+    friend class boost::serialization::access;                                                     \
+    template <typename Archive>                                                                    \
+    void save(Archive& ar, const unsigned int file_version) const {                                \
+        ar.save_binary(this, sizeof(*this));                                                       \
+    }                                                                                              \
+    template <typename Archive>                                                                    \
+    void load(Archive& ar, const unsigned int file_version) {                                      \
+        ar.load_binary(this, sizeof(*this));                                                       \
+    }                                                                                              \
+    template <class Archive>                                                                       \
+    void serialize(Archive& ar, const unsigned int file_version) {                                 \
+        boost::serialization::split_member(ar, *this, file_version);                               \
     }
diff --git a/src/common/serialization/atomic.h b/src/common/serialization/atomic.h
index 665914df3..dbc4c0dec 100644
--- a/src/common/serialization/atomic.h
+++ b/src/common/serialization/atomic.h
@@ -6,20 +6,17 @@
 namespace boost::serialization {
 
 template <class Archive, class T>
-void serialize(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
-{
+void serialize(Archive& ar, std::atomic<T>& value, const unsigned int file_version) {
     boost::serialization::split_free(ar, value, file_version);
 }
 
 template <class Archive, class T>
-void save(Archive& ar, const std::atomic<T>& value, const unsigned int file_version)
-{
+void save(Archive& ar, const std::atomic<T>& value, const unsigned int file_version) {
     ar << value.load();
 }
 
 template <class Archive, class T>
-void load(Archive& ar, std::atomic<T>& value, const unsigned int file_version)
-{
+void load(Archive& ar, std::atomic<T>& value, const unsigned int file_version) {
     T tmp;
     ar >> tmp;
     value.store(tmp);
diff --git a/src/common/serialization/boost_flat_set.h b/src/common/serialization/boost_flat_set.h
index 9a0ae77b0..7fe0fe097 100644
--- a/src/common/serialization/boost_flat_set.h
+++ b/src/common/serialization/boost_flat_set.h
@@ -1,23 +1,21 @@
 #pragma once
 
-#include "common/common_types.h"
 #include <boost/container/flat_set.hpp>
 #include <boost/serialization/split_free.hpp>
+#include "common/common_types.h"
 
 namespace boost::serialization {
 
 template <class Archive, class T>
-void save(Archive& ar, const boost::container::flat_set<T>& set, const unsigned int file_version)
-{
+void save(Archive& ar, const boost::container::flat_set<T>& set, const unsigned int file_version) {
     ar << static_cast<u64>(set.size());
-    for (auto &v : set) {
+    for (auto& v : set) {
         ar << v;
     }
 }
 
 template <class Archive, class T>
-void load(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version)
-{
+void load(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version) {
     u64 count{};
     ar >> count;
     set.clear();
@@ -29,9 +27,8 @@ void load(Archive& ar, boost::container::flat_set<T>& set, const unsigned int fi
 }
 
 template <class Archive, class T>
-void serialize(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version)
-{
+void serialize(Archive& ar, boost::container::flat_set<T>& set, const unsigned int file_version) {
     boost::serialization::split_free(ar, set, file_version);
 }
 
-}
+} // namespace boost::serialization
diff --git a/src/common/serialization/optional.h b/src/common/serialization/optional.h
index 5ab6af9b8..4e794058e 100644
--- a/src/common/serialization/optional.h
+++ b/src/common/serialization/optional.h
@@ -7,85 +7,70 @@
 #include <optional>
 #include <boost/move/utility_core.hpp>
 
+#include <boost/serialization/detail/is_default_constructible.hpp>
+#include <boost/serialization/detail/stack_constructor.hpp>
+#include <boost/serialization/force_include.hpp>
 #include <boost/serialization/item_version_type.hpp>
-#include <boost/serialization/split_free.hpp>
 #include <boost/serialization/level.hpp>
 #include <boost/serialization/nvp.hpp>
+#include <boost/serialization/split_free.hpp>
 #include <boost/serialization/version.hpp>
 #include <boost/type_traits/is_pointer.hpp>
-#include <boost/serialization/detail/stack_constructor.hpp>
-#include <boost/serialization/detail/is_default_constructible.hpp>
-#include <boost/serialization/force_include.hpp>
 
 // function specializations must be defined in the appropriate
 // namespace - boost::serialization
 namespace boost {
 namespace serialization {
 
-template<class Archive, class T>
-void save(
-    Archive & ar,
-    const std::optional< T > & t,
-    const unsigned int /*version*/
-){
-    // It is an inherent limitation to the serialization of optional.hpp
-    // that the underlying type must be either a pointer or must have a
-    // default constructor.  It's possible that this could change sometime
-    // in the future, but for now, one will have to work around it.  This can
-    // be done by serialization the optional<T> as optional<T *>
-    #if ! defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
-        BOOST_STATIC_ASSERT(
-            boost::serialization::detail::is_default_constructible<T>::value
-            || boost::is_pointer<T>::value
-        );
-    #endif
+template <class Archive, class T>
+void save(Archive& ar, const std::optional<T>& t, const unsigned int /*version*/
+) {
+// It is an inherent limitation to the serialization of optional.hpp
+// that the underlying type must be either a pointer or must have a
+// default constructor.  It's possible that this could change sometime
+// in the future, but for now, one will have to work around it.  This can
+// be done by serialization the optional<T> as optional<T *>
+#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
+    BOOST_STATIC_ASSERT(boost::serialization::detail::is_default_constructible<T>::value ||
+                        boost::is_pointer<T>::value);
+#endif
     const bool tflag = t.has_value();
     ar << boost::serialization::make_nvp("initialized", tflag);
-    if (tflag){
+    if (tflag) {
         ar << boost::serialization::make_nvp("value", *t);
     }
 }
 
-template<class Archive, class T>
-void load(
-    Archive & ar,
-    std::optional< T > & t,
-    const unsigned int version
-){
+template <class Archive, class T>
+void load(Archive& ar, std::optional<T>& t, const unsigned int version) {
     bool tflag;
     ar >> boost::serialization::make_nvp("initialized", tflag);
-    if(! tflag){
+    if (!tflag) {
         t.reset();
         return;
     }
 
-    if(0 == version){
+    if (0 == version) {
         boost::serialization::item_version_type item_version(0);
-        boost::archive::library_version_type library_version(
-            ar.get_library_version()
-        );
-        if(boost::archive::library_version_type(3) < library_version){
+        boost::archive::library_version_type library_version(ar.get_library_version());
+        if (boost::archive::library_version_type(3) < library_version) {
             ar >> BOOST_SERIALIZATION_NVP(item_version);
         }
     }
-    if(! t.has_value())
+    if (!t.has_value())
         t = T();
     ar >> boost::serialization::make_nvp("value", *t);
 }
 
-template<class Archive, class T>
-void serialize(
-    Archive & ar,
-    std::optional< T > & t,
-    const unsigned int version
-){
+template <class Archive, class T>
+void serialize(Archive& ar, std::optional<T>& t, const unsigned int version) {
     boost::serialization::split_free(ar, t, version);
 }
 
-template<class T>
-struct version<std::optional<T> > {
+template <class T>
+struct version<std::optional<T>> {
     BOOST_STATIC_CONSTANT(int, value = 1);
 };
 
-} // serialization
-} // boost
+} // namespace serialization
+} // namespace boost
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index ce57c01e9..093d86781 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -162,20 +162,20 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void save(Archive& ar, const unsigned int file_version) const
-    {
+    void save(Archive& ar, const unsigned int file_version) const {
         s32 idx = first == UnlinkedTag() ? -1 : static_cast<s32>(first - &queues[0]);
         ar << idx;
         for (auto i = 0; i < NUM_QUEUES; i++) {
-            s32 idx1 = first == UnlinkedTag() ? -1 : static_cast<s32>(queues[i].next_nonempty - &queues[0]);
+            s32 idx1 = first == UnlinkedTag()
+                           ? -1
+                           : static_cast<s32>(queues[i].next_nonempty - &queues[0]);
             ar << idx1;
             ar << queues[i].data;
         }
     }
 
     template <class Archive>
-    void load(Archive& ar, const unsigned int file_version)
-    {
+    void load(Archive& ar, const unsigned int file_version) {
         s32 idx;
         ar >> idx;
         first = idx < 0 ? UnlinkedTag() : &queues[idx];
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 171d4ebfd..ba7bd1aa7 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -46,11 +46,10 @@ class Vec4;
 template <typename T>
 class Vec2 {
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & x;
-        ar & y;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& x;
+        ar& y;
     }
 
 public:
@@ -201,12 +200,11 @@ inline float Vec2<float>::Normalize() {
 template <typename T>
 class Vec3 {
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & x;
-        ar & y;
-        ar & z;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& x;
+        ar& y;
+        ar& z;
     }
 
 public:
@@ -418,13 +416,12 @@ using Vec3f = Vec3<float>;
 template <typename T>
 class Vec4 {
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & x;
-        ar & y;
-        ar & z;
-        ar & w;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& x;
+        ar& y;
+        ar& z;
+        ar& w;
     }
 
 public:
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 483ba4371..be30499d1 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -20,8 +20,7 @@ public:
         friend class boost::serialization::access;
 
         template <class Archive>
-        void save(Archive& ar, const unsigned int file_version) const
-        {
+        void save(Archive& ar, const unsigned int file_version) const {
             for (auto i = 0; i < 16; i++) {
                 auto r = GetCpuRegister(i);
                 ar << r;
@@ -39,8 +38,7 @@ public:
         }
 
         template <class Archive>
-        void load(Archive& ar, const unsigned int file_version)
-        {
+        void load(Archive& ar, const unsigned int file_version) {
             u32 r;
             for (auto i = 0; i < 16; i++) {
                 ar >> r;
@@ -220,8 +218,7 @@ private:
     friend class boost::serialization::access;
 
     template <class Archive>
-    void save(Archive& ar, const unsigned int file_version) const
-    {
+    void save(Archive& ar, const unsigned int file_version) const {
         for (auto i = 0; i < 15; i++) {
             auto r = GetReg(i);
             ar << r;
@@ -245,8 +242,7 @@ private:
     }
 
     template <class Archive>
-    void load(Archive& ar, const unsigned int file_version)
-    {
+    void load(Archive& ar, const unsigned int file_version) {
         u32 r;
         for (auto i = 0; i < 15; i++) {
             ar >> r;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 2df38f3ed..6812a9474 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -48,10 +48,14 @@ namespace Core {
 /*static*/ System System::s_instance;
 
 template <>
-Core::System& Global() { return System::GetInstance(); }
+Core::System& Global() {
+    return System::GetInstance();
+}
 
 template <>
-Kernel::KernelSystem& Global() { return System::GetInstance().Kernel(); }
+Kernel::KernelSystem& Global() {
+    return System::GetInstance().Kernel();
+}
 
 System::ResultStatus System::RunLoop(bool tight_loop) {
     status = ResultStatus::Success;
@@ -209,8 +213,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
-                                                    [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(
+        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -400,32 +404,29 @@ void System::Reset() {
     Load(*m_emu_window, m_filepath);
 }
 
-template<class Archive>
-void System::serialize(Archive & ar, const unsigned int file_version)
-{
-    ar & *cpu_core.get();
-    ar & *service_manager.get();
-    ar & GPU::g_regs;
-    ar & LCD::g_regs;
+template <class Archive>
+void System::serialize(Archive& ar, const unsigned int file_version) {
+    ar&* cpu_core.get();
+    ar&* service_manager.get();
+    ar& GPU::g_regs;
+    ar& LCD::g_regs;
     ar & dsp_core->GetDspMemory();
-    ar & *memory.get();
-    ar & *kernel.get();
+    ar&* memory.get();
+    ar&* kernel.get();
 }
 
-void System::Save(std::ostream &stream) const
-{
+void System::Save(std::ostream& stream) const {
     {
         oarchive oa{stream};
-        oa & *this;
+        oa&* this;
     }
     VideoCore::Save(stream);
 }
 
-void System::Load(std::istream &stream)
-{
+void System::Load(std::istream& stream) {
     {
         iarchive ia{stream};
-        ia & *this;
+        ia&* this;
     }
     VideoCore::Load(stream);
 }
diff --git a/src/core/core.h b/src/core/core.h
index 8bf04d365..75e0e1a54 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -272,9 +272,9 @@ public:
         return registered_image_interface;
     }
 
-    void Save(std::ostream &stream) const;
+    void Save(std::ostream& stream) const;
 
-    void Load(std::istream &stream);
+    void Load(std::istream& stream);
 
 private:
     /**
@@ -345,8 +345,8 @@ private:
     std::atomic<bool> shutdown_requested;
 
     friend class boost::serialization::access;
-    template<typename Archive>
-    void serialize(Archive & ar, const unsigned int file_version);
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 
 inline ARM_Interface& CPU() {
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index e5e017daa..7b8329c4d 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -6,12 +6,12 @@
 #include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
+#include "core/global.h"
 #include "core/hle/kernel/address_arbiter.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/thread.h"
 #include "core/memory.h"
-#include "core/global.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Kernel namespace
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 793d274ca..19b80315f 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -74,11 +74,10 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        ar & name;
-        ar & waiting_threads;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
+        ar& name;
+        ar& waiting_threads;
     }
 };
 
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index 618c7d0d7..e7e8a8014 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -4,6 +4,7 @@
 
 #include "common/archives.h"
 #include "common/assert.h"
+#include "core/global.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/errors.h"
@@ -11,7 +12,6 @@
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
-#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::ClientPort)
 
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index c5b032f1f..1d0f5c024 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -61,17 +61,15 @@ private:
 
     friend class KernelSystem;
 
-
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        ar & server_port;
-        ar & max_sessions;
-        ar & active_sessions;
-        ar & name;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
+        ar& server_port;
+        ar& max_sessions;
+        ar& active_sessions;
+        ar& name;
     }
 };
 
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
index 0b00576d3..a47e6411b 100644
--- a/src/core/hle/kernel/client_session.cpp
+++ b/src/core/hle/kernel/client_session.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "common/assert.h"
 #include "common/archives.h"
+#include "common/assert.h"
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/hle_ipc.h"
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 1ddbfb348..38f39c299 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -53,11 +53,10 @@ public:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        ar & name;
-        ar & parent;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
+        ar& name;
+        ar& parent;
     }
 };
 
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index 26fc0bccb..e4e895516 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -60,10 +60,9 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
+    void serialize(Archive& ar, const unsigned int file_version) {
         auto o_config_mem = boost::serialization::binary_object(&config_mem, sizeof(config_mem));
-        ar & o_config_mem;
+        ar& o_config_mem;
     }
 };
 
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 2375d6733..9f26847b0 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -5,8 +5,8 @@
 #include <algorithm>
 #include <map>
 #include <vector>
-#include "common/assert.h"
 #include "common/archives.h"
+#include "common/assert.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/thread.h"
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 509ab5c6c..892718533 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -53,12 +53,11 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<WaitObject>(*this);
-        ar & reset_type;
-        ar & signaled;
-        ar & name;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<WaitObject>(*this);
+        ar& reset_type;
+        ar& signaled;
+        ar& name;
     }
 };
 
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index eabf06c26..728ab5fa3 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -121,12 +121,11 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & objects;
-        ar & generations;
-        ar & next_generation;
-        ar & next_free_slot;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& objects;
+        ar& generations;
+        ar& next_generation;
+        ar& next_free_slot;
     }
 };
 
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 162a2eb39..2177b733e 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -11,10 +11,10 @@
 #include <string>
 #include <vector>
 #include <boost/container/small_vector.hpp>
-#include <boost/serialization/unique_ptr.hpp>
-#include <boost/serialization/shared_ptr.hpp>
-#include <boost/serialization/vector.hpp>
 #include <boost/serialization/assume_abstract.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unique_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/hle/ipc.h"
@@ -74,9 +74,10 @@ public:
     /// in each service must inherit from this.
     struct SessionDataBase {
         virtual ~SessionDataBase() = default;
+
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int file_version) { }
+        void serialize(Archive& ar, const unsigned int file_version) {}
         friend class boost::serialization::access;
     };
 
@@ -104,10 +105,9 @@ protected:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int file_version)
-        {
-            ar & session;
-            ar & data;
+        void serialize(Archive& ar, const unsigned int file_version) {
+            ar& session;
+            ar& data;
         }
         friend class boost::serialization::access;
     };
@@ -117,9 +117,8 @@ protected:
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & connected_sessions;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& connected_sessions;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/kernel/ipc.h b/src/core/hle/kernel/ipc.h
index 46d86a528..2c69617d4 100644
--- a/src/core/hle/kernel/ipc.h
+++ b/src/core/hle/kernel/ipc.h
@@ -30,15 +30,15 @@ struct MappedBufferContext {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & permissions;
-        ar & size;
-        ar & source_address;
-        ar & target_address;
-        // TODO: Check whether we need these. If we do, add a field for the size and/or change to a 'vector'
-        //ar & buffer;
-        //ar & reserve_buffer;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& permissions;
+        ar& size;
+        ar& source_address;
+        ar& target_address;
+        // TODO: Check whether we need these. If we do, add a field for the size and/or change to a
+        // 'vector'
+        // ar & buffer;
+        // ar & reserve_buffer;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index a45973968..7edef2505 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -104,20 +104,19 @@ void KernelSystem::AddNamedPort(std::string name, std::shared_ptr<ClientPort> po
 }
 
 template <class Archive>
-void KernelSystem::serialize(Archive& ar, const unsigned int file_version)
-{
-    ar & memory_regions;
-    ar & named_ports;
-    ar & *current_cpu.get();
+void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
+    ar& memory_regions;
+    ar& named_ports;
+    ar&* current_cpu.get();
     // NB: subsystem references and prepare_reschedule_callback are constant
-    ar & *resource_limits.get();
-    ar & next_object_id;
-    ar & *timer_manager.get();
-    ar & next_process_id;
-    ar & process_list;
-    ar & current_process;
-    ar & *thread_manager.get();
-    ar & *config_mem_handler.get();
+    ar&* resource_limits.get();
+    ar& next_object_id;
+    ar&* timer_manager.get();
+    ar& next_process_id;
+    ar& process_list;
+    ar& current_process;
+    ar&* thread_manager.get();
+    ar&* config_mem_handler.get();
     // Shared page data is read-only at the moment, so doesn't need serializing
     // Deliberately don't include debugger info to allow debugging through loads
 }
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
index ed4ea1296..f4b0a6d98 100644
--- a/src/core/hle/kernel/memory.h
+++ b/src/core/hle/kernel/memory.h
@@ -7,8 +7,8 @@
 #include <optional>
 #include <boost/icl/interval_set.hpp>
 #include <boost/serialization/set.hpp>
-#include "common/serialization/boost_discrete_interval.hpp"
 #include "common/common_types.h"
+#include "common/serialization/boost_discrete_interval.hpp"
 
 namespace Kernel {
 
@@ -66,13 +66,12 @@ struct MemoryRegionInfo {
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & base;
-        ar & size;
-        ar & used;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& base;
+        ar& size;
+        ar& used;
         // This works because interval_set has exactly one member of type ImplSetT
-        ar & *(reinterpret_cast<IntervalSet::ImplSetT*>(&free_blocks));
+        ar&*(reinterpret_cast<IntervalSet::ImplSetT*>(&free_blocks));
     }
 };
 
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 4badd88ce..6aff80224 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -7,12 +7,12 @@
 #include "common/archives.h"
 #include "common/assert.h"
 #include "core/core.h"
+#include "core/global.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/mutex.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
-#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::Mutex)
 
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index a164b70da..4adf674c3 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -62,13 +62,12 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<WaitObject>(*this);
-        ar & lock_count;
-        ar & priority;
-        ar & name;
-        ar & holding_thread;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<WaitObject>(*this);
+        ar& lock_count;
+        ar& priority;
+        ar& name;
+        ar& holding_thread;
     }
 };
 
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index a61e47c17..57b208dc1 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -10,10 +10,10 @@
 #include <boost/serialization/access.hpp>
 #include <boost/serialization/assume_abstract.hpp>
 #include <boost/serialization/export.hpp>
-#include "common/serialization/atomic.h"
 #include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
+#include "common/serialization/atomic.h"
 #include "core/global.h"
+#include "core/hle/kernel/kernel.h"
 
 namespace Kernel {
 
@@ -72,9 +72,8 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & object_id;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& object_id;
     }
 };
 
@@ -102,11 +101,10 @@ inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) {
 
 BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::Object)
 
-#define CONSTRUCT_KERNEL_OBJECT(T)                                \
-namespace boost::serialization {                                  \
-template<class Archive>                                           \
-inline void load_construct_data(                                  \
-    Archive & ar, T * t, const unsigned int file_version          \
-){                                                                \
-    ::new(t)T(Core::Global<Kernel::KernelSystem>());              \
-}}
+#define CONSTRUCT_KERNEL_OBJECT(T)                                                                 \
+    namespace boost::serialization {                                                               \
+    template <class Archive>                                                                       \
+    inline void load_construct_data(Archive& ar, T* t, const unsigned int file_version) {          \
+        ::new (t) T(Core::Global<Kernel::KernelSystem>());                                         \
+    }                                                                                              \
+    }
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 12afe1f89..78b695e97 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -11,6 +11,7 @@
 #include "common/common_funcs.h"
 #include "common/logging/log.h"
 #include "common/serialization/boost_vector.hpp"
+#include "core/global.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/process.h"
@@ -18,7 +19,6 @@
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/vm_manager.h"
 #include "core/memory.h"
-#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::Process)
 SERIALIZE_EXPORT_IMPL(Kernel::CodeSet)
@@ -26,24 +26,25 @@ SERIALIZE_EXPORT_IMPL(Kernel::CodeSet)
 namespace Kernel {
 
 template <class Archive>
-void Process::serialize(Archive& ar, const unsigned int file_version)
-{
-    ar & boost::serialization::base_object<Object>(*this);
-    ar & handle_table;
-    ar & codeset;
-    ar & resource_limit;
-    ar & svc_access_mask;
-    ar & handle_table_size;
-    ar & (boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8> >&)address_mappings;
-    ar & flags.raw;
-    ar & kernel_version;
-    ar & ideal_processor;
-    ar & status;
-    ar & process_id;
-    ar & vm_manager;
-    ar & memory_used;
-    ar & memory_region;
-    ar & tls_slots;
+void Process::serialize(Archive& ar, const unsigned int file_version) {
+    ar& boost::serialization::base_object<Object>(*this);
+    ar& handle_table;
+    ar& codeset;
+    ar& resource_limit;
+    ar& svc_access_mask;
+    ar& handle_table_size;
+    ar&(boost::container::vector<
+        AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8>>&)
+        address_mappings;
+    ar& flags.raw;
+    ar& kernel_version;
+    ar& ideal_processor;
+    ar& status;
+    ar& process_id;
+    ar& vm_manager;
+    ar& memory_used;
+    ar& memory_region;
+    ar& tls_slots;
 }
 
 SERIALIZE_IMPL(Process)
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 5746a1c6a..f9aa76c67 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -11,8 +11,8 @@
 #include <string>
 #include <vector>
 #include <boost/container/static_vector.hpp>
-#include <boost/serialization/vector.hpp>
 #include <boost/serialization/base_object.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/handle_table.h"
@@ -31,12 +31,11 @@ struct AddressMapping {
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & address;
-        ar & size;
-        ar & read_only;
-        ar & unk_flag;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& address;
+        ar& size;
+        ar& read_only;
+        ar& unk_flag;
     }
 };
 
@@ -76,11 +75,10 @@ public:
     private:
         friend class boost::serialization::access;
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int file_version)
-        {
-            ar & offset;
-            ar & addr;
-            ar & size;
+        void serialize(Archive& ar, const unsigned int file_version) {
+            ar& offset;
+            ar& addr;
+            ar& size;
         }
     };
 
@@ -133,14 +131,13 @@ public:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
         // TODO: memory reference
-        ar & segments;
-        ar & entrypoint;
-        ar & name;
-        ar & program_id;
+        ar& segments;
+        ar& entrypoint;
+        ar& name;
+        ar& program_id;
     }
 };
 
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 0d64f1216..8593a03a3 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -116,30 +116,30 @@ public:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        // NB most of these aren't used at all currently, but we're adding them here for forwards compatibility
-        ar & name;
-        ar & max_priority;
-        ar & max_commit;
-        ar & max_threads;
-        ar & max_events;
-        ar & max_mutexes;
-        ar & max_semaphores;
-        ar & max_timers;
-        ar & max_shared_mems;
-        ar & max_address_arbiters;
-        ar & max_cpu_time;
-        ar & current_commit;
-        ar & current_threads;
-        ar & current_events;
-        ar & current_mutexes;
-        ar & current_semaphores;
-        ar & current_timers;
-        ar & current_shared_mems;
-        ar & current_address_arbiters;
-        ar & current_cpu_time;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
+        // NB most of these aren't used at all currently, but we're adding them here for forwards
+        // compatibility
+        ar& name;
+        ar& max_priority;
+        ar& max_commit;
+        ar& max_threads;
+        ar& max_events;
+        ar& max_mutexes;
+        ar& max_semaphores;
+        ar& max_timers;
+        ar& max_shared_mems;
+        ar& max_address_arbiters;
+        ar& max_cpu_time;
+        ar& current_commit;
+        ar& current_threads;
+        ar& current_events;
+        ar& current_mutexes;
+        ar& current_semaphores;
+        ar& current_timers;
+        ar& current_shared_mems;
+        ar& current_address_arbiters;
+        ar& current_cpu_time;
     }
 };
 
@@ -160,9 +160,8 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & resource_limits;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& resource_limits;
     }
 };
 
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index c637f5f4d..7aefc8605 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "common/assert.h"
 #include "common/archives.h"
+#include "common/assert.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/semaphore.h"
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index f28c30ec7..a7ab192a6 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -5,8 +5,8 @@
 #pragma once
 
 #include <string>
-#include <queue>
 #include <boost/serialization/export.hpp>
+#include <queue>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/wait_object.h"
@@ -48,12 +48,11 @@ public:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<WaitObject>(*this);
-        ar & max_count;
-        ar & available_count;
-        ar & name;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<WaitObject>(*this);
+        ar& max_count;
+        ar& available_count;
+        ar& name;
     }
 };
 
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 46aa8f758..077150222 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -7,11 +7,11 @@
 #include "common/assert.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/thread.h"
-#include "core/hle/kernel/hle_ipc.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::ServerPort)
 
@@ -53,12 +53,11 @@ KernelSystem::PortPair KernelSystem::CreatePortPair(u32 max_sessions, std::strin
 }
 
 template <class Archive>
-void ServerPort::serialize(Archive& ar, const unsigned int file_version)
-{
-    ar & boost::serialization::base_object<WaitObject>(*this);
-    ar & name;
-    ar & pending_sessions;
-    ar & hle_handler;
+void ServerPort::serialize(Archive& ar, const unsigned int file_version) {
+    ar& boost::serialization::base_object<WaitObject>(*this);
+    ar& name;
+    ar& pending_sessions;
+    ar& hle_handler;
 }
 SERIALIZE_IMPL(ServerPort)
 
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index e0c4087f1..4b393b63d 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -4,13 +4,13 @@
 
 #include <tuple>
 #include "common/archives.h"
+#include "core/global.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/session.h"
 #include "core/hle/kernel/thread.h"
-#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::ServerSession)
 
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 6eb5673f6..331ac8397 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -110,15 +110,14 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        ar & name;
-        ar & parent;
-        ar & hle_handler;
-        ar & pending_requesting_threads;
-        ar & currently_handling;
-        ar & mapped_buffer_context;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
+        ar& name;
+        ar& parent;
+        ar& hle_handler;
+        ar& pending_requesting_threads;
+        ar& currently_handling;
+        ar& mapped_buffer_context;
     }
 };
 
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index a2a1f90f9..1ec1039dc 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -4,22 +4,21 @@
 
 #include <boost/serialization/shared_ptr.hpp>
 #include "common/archives.h"
-#include "core/hle/kernel/session.h"
-#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/session.h"
 
 SERIALIZE_IMPL(Kernel::Session)
 
 namespace Kernel {
 
 template <class Archive>
-void Session::serialize(Archive& ar, const unsigned int file_version)
-{
-    ar & client;
-    ar & server;
-    ar & port;
+void Session::serialize(Archive& ar, const unsigned int file_version) {
+    ar& client;
+    ar& server;
+    ar& port;
 }
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 14c9751e8..55c374dc5 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -5,11 +5,11 @@
 #include <cstring>
 #include "common/archives.h"
 #include "common/logging/log.h"
+#include "core/global.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/memory.h"
-#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::SharedMemory)
 
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 88727be6d..f2fa1a728 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -107,17 +107,16 @@ private:
     KernelSystem& kernel;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & linear_heap_phys_offset;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& linear_heap_phys_offset;
         // TODO: backing blocks u8* (this is always FCRAM I think)
-        ar & size;
-        ar & permissions;
-        ar & other_permissions;
-        ar & owner_process;
-        ar & base_address;
-        ar & name;
-        ar & *(reinterpret_cast<MemoryRegionInfo::IntervalSet::ImplSetT*>(&holding_memory));
+        ar& size;
+        ar& permissions;
+        ar& other_permissions;
+        ar& owner_process;
+        ar& base_address;
+        ar& name;
+        ar&*(reinterpret_cast<MemoryRegionInfo::IntervalSet::ImplSetT*>(&holding_memory));
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index 58cd46334..b3e1a48b6 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -108,10 +108,9 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
+    void serialize(Archive& ar, const unsigned int file_version) {
         auto o_shared_page = boost::serialization::binary_object(&shared_page, sizeof(shared_page));
-        ar & o_shared_page;
+        ar& o_shared_page;
     }
 };
 
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index c824b58a6..c3c5da7d4 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -15,6 +15,7 @@
 #include "core/arm/arm_interface.h"
 #include "core/arm/skyeye_common/armstate.h"
 #include "core/core.h"
+#include "core/global.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/kernel.h"
@@ -24,31 +25,29 @@
 #include "core/hle/kernel/thread.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
-#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::Thread)
 
 namespace Kernel {
 
 template <class Archive>
-void Thread::serialize(Archive& ar, const unsigned int file_version)
-{
-    ar & *context.get();
-    ar & thread_id;
-    ar & status;
-    ar & entry_point;
-    ar & stack_top;
-    ar & nominal_priority;
-    ar & current_priority;
-    ar & last_running_ticks;
-    ar & processor_id;
-    ar & tls_address;
-    ar & held_mutexes;
-    ar & pending_mutexes;
-    ar & owner_process;
-    ar & wait_objects;
-    ar & wait_address;
-    ar & name;
+void Thread::serialize(Archive& ar, const unsigned int file_version) {
+    ar&* context.get();
+    ar& thread_id;
+    ar& status;
+    ar& entry_point;
+    ar& stack_top;
+    ar& nominal_priority;
+    ar& current_priority;
+    ar& last_running_ticks;
+    ar& processor_id;
+    ar& tls_address;
+    ar& held_mutexes;
+    ar& pending_mutexes;
+    ar& owner_process;
+    ar& wait_objects;
+    ar& wait_address;
+    ar& name;
     // TODO: How the hell to do wakeup_callback
 }
 
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 09341560a..219db9f2d 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -9,10 +9,10 @@
 #include <unordered_map>
 #include <vector>
 #include <boost/container/flat_set.hpp>
+#include <boost/serialization/export.hpp>
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/unordered_map.hpp>
 #include <boost/serialization/vector.hpp>
-#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "common/thread_queue_list.h"
 #include "core/arm/arm_interface.h"
@@ -152,13 +152,12 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & next_thread_id;
-        ar & current_thread;
-        ar & ready_queue;
-        ar & wakeup_callback_table;
-        ar & thread_list;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& next_thread_id;
+        ar& current_thread;
+        ar& ready_queue;
+        ar& wakeup_callback_table;
+        ar& thread_list;
     }
 };
 
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index f1a31cdf9..d29b25986 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -8,11 +8,11 @@
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "core/core.h"
+#include "core/global.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/timer.h"
-#include "core/global.h"
 
 SERIALIZE_EXPORT_IMPL(Kernel::Timer)
 
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index f61ec1c11..d2c513024 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -37,10 +37,9 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & next_timer_callback_id;
-        ar & timer_callback_table;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& next_timer_callback_id;
+        ar& timer_callback_table;
     }
 };
 
@@ -115,14 +114,13 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & reset_type;
-        ar & initial_delay;
-        ar & interval_delay;
-        ar & signaled;
-        ar & name;
-        ar & callback_id;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& reset_type;
+        ar& initial_delay;
+        ar& interval_delay;
+        ar& signaled;
+        ar& name;
+        ar& callback_id;
     }
 };
 
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index e930fc64a..5fd6d8740 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -86,17 +86,16 @@ struct VirtualMemoryArea {
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & base;
-        ar & size;
-        ar & type;
-        ar & permissions;
-        ar & meminfo_state;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& base;
+        ar& size;
+        ar& type;
+        ar& permissions;
+        ar& meminfo_state;
         // TODO: backing memory ref
         // backing memory can be: Physical/FCRAM pointer, config mem, shared page
-        ar & paddr;
-        ar & mmio_handler;
+        ar& paddr;
+        ar& mmio_handler;
     }
 };
 
@@ -213,27 +212,25 @@ public:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void save(Archive& ar, const unsigned int file_version) const
-    {
-        ar & vma_map;
+    void save(Archive& ar, const unsigned int file_version) const {
+        ar& vma_map;
         for (int i = 0; i < page_table.pointers.size(); i++) {
             ar << memory.GetFCRAMOffset(page_table.pointers[i]);
         }
-        ar & page_table.special_regions;
-        ar & page_table.attributes;
+        ar& page_table.special_regions;
+        ar& page_table.attributes;
     }
 
     template <class Archive>
-    void load(Archive& ar, const unsigned int file_version)
-    {
-        ar & vma_map;
+    void load(Archive& ar, const unsigned int file_version) {
+        ar& vma_map;
         for (int i = 0; i < page_table.pointers.size(); i++) {
             u32 offset{};
             ar >> offset;
             page_table.pointers[i] = memory.GetFCRAMPointer(offset);
         }
-        ar & page_table.special_regions;
-        ar & page_table.attributes;
+        ar& page_table.special_regions;
+        ar& page_table.attributes;
     }
 
     BOOST_SERIALIZATION_SPLIT_MEMBER()
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index e08997721..c07290e8a 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -69,10 +69,9 @@ private:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<Object>(*this);
-        ar & waiting_threads;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
+        ar& waiting_threads;
         // NB: hle_notifier *not* serialized since it's a callback!
         // Fortunately it's only used in one place (DSP) so we can reconstruct it there
     }
diff --git a/src/core/hle/service/ac/ac.cpp b/src/core/hle/service/ac/ac.cpp
index 356df5a63..d9f1085c8 100644
--- a/src/core/hle/service/ac/ac.cpp
+++ b/src/core/hle/service/ac/ac.cpp
@@ -3,9 +3,9 @@
 // Refer to the license.txt file included.
 
 #include <vector>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
-#include "common/archives.h"
 #include "core/core.h"
 #include "core/hle/ipc.h"
 #include "core/hle/ipc_helpers.h"
@@ -181,12 +181,11 @@ void InstallInterfaces(Core::System& system) {
 }
 
 template <class Archive>
-void Module::serialize(Archive& ar, const unsigned int)
-{
-    ar & ac_connected;
-    ar & close_event;
-    ar & connect_event;
-    ar & disconnect_event;
+void Module::serialize(Archive& ar, const unsigned int) {
+    ar& ac_connected;
+    ar& close_event;
+    ar& connect_event;
+    ar& disconnect_event;
     // default_config is never written to
 }
 
diff --git a/src/core/hle/service/ac/ac_i.cpp b/src/core/hle/service/ac/ac_i.cpp
index e4cc4c1f1..ff4fb954c 100644
--- a/src/core/hle/service/ac/ac_i.cpp
+++ b/src/core/hle/service/ac/ac_i.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/ac/ac_i.h"
 #include "common/archives.h"
+#include "core/hle/service/ac/ac_i.h"
 
 namespace Service::AC {
 
diff --git a/src/core/hle/service/ac/ac_u.cpp b/src/core/hle/service/ac/ac_u.cpp
index 429942f7d..e88cdd164 100644
--- a/src/core/hle/service/ac/ac_u.cpp
+++ b/src/core/hle/service/ac/ac_u.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/ac/ac_u.h"
 #include "common/archives.h"
+#include "core/hle/service/ac/ac_u.h"
 
 namespace Service::AC {
 
diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h
index c327cdaef..11812bcfe 100644
--- a/src/core/hle/service/act/act.h
+++ b/src/core/hle/service/act/act.h
@@ -23,9 +23,10 @@ public:
     protected:
         std::shared_ptr<Module> act;
     };
+
 private:
     template <class Archive>
-    inline void serialize(Archive& ar, const unsigned int file_version) { }
+    inline void serialize(Archive& ar, const unsigned int file_version) {}
     friend class boost::serialization::access;
 };
 
diff --git a/src/core/hle/service/act/act_a.cpp b/src/core/hle/service/act/act_a.cpp
index b4bf750f7..b85a17183 100644
--- a/src/core/hle/service/act/act_a.cpp
+++ b/src/core/hle/service/act/act_a.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/act/act_a.h"
 #include "common/archives.h"
+#include "core/hle/service/act/act_a.h"
 
 namespace Service::ACT {
 
diff --git a/src/core/hle/service/act/act_a.h b/src/core/hle/service/act/act_a.h
index 1e37c9bde..1454441d5 100644
--- a/src/core/hle/service/act/act_a.h
+++ b/src/core/hle/service/act/act_a.h
@@ -11,6 +11,7 @@ namespace Service::ACT {
 class ACT_A final : public Module::Interface {
 public:
     explicit ACT_A(std::shared_ptr<Module> act);
+
 private:
     SERVICE_SERIALIZATION(ACT_A, act, Module)
 };
diff --git a/src/core/hle/service/act/act_u.cpp b/src/core/hle/service/act/act_u.cpp
index 599bec18a..a0058d573 100644
--- a/src/core/hle/service/act/act_u.cpp
+++ b/src/core/hle/service/act/act_u.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/act/act_u.h"
 #include "common/archives.h"
+#include "core/hle/service/act/act_u.h"
 
 namespace Service::ACT {
 
diff --git a/src/core/hle/service/act/act_u.h b/src/core/hle/service/act/act_u.h
index 820aa862a..bcd2d653e 100644
--- a/src/core/hle/service/act/act_u.h
+++ b/src/core/hle/service/act/act_u.h
@@ -11,6 +11,7 @@ namespace Service::ACT {
 class ACT_U final : public Module::Interface {
 public:
     explicit ACT_U(std::shared_ptr<Module> act);
+
 private:
     SERVICE_SERIALIZATION(ACT_U, act, Module)
 };
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 45ed29e6c..b3bd037ea 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1455,7 +1455,7 @@ Module::Module(Core::System& system) : kernel(system.Kernel()) {
     system_updater_mutex = system.Kernel().CreateMutex(false, "AM::SystemUpdaterMutex");
 }
 
-Module::Module(Kernel::KernelSystem& kernel) : kernel(kernel) { }
+Module::Module(Kernel::KernelSystem& kernel) : kernel(kernel) {}
 
 Module::~Module() = default;
 
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 771bbfb53..22481179e 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -10,15 +10,15 @@
 #include <string>
 #include <vector>
 #include <boost/serialization/array.hpp>
-#include <boost/serialization/vector.hpp>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/cia_container.h"
 #include "core/file_sys/file_backend.h"
+#include "core/global.h"
 #include "core/hle/kernel/mutex.h"
 #include "core/hle/result.h"
 #include "core/hle/service/service.h"
-#include "core/global.h"
 
 namespace Core {
 class System;
@@ -585,11 +585,10 @@ private:
     std::shared_ptr<Kernel::Mutex> system_updater_mutex;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & cia_installing;
-        ar & am_title_list;
-        ar & system_updater_mutex;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& cia_installing;
+        ar& am_title_list;
+        ar& system_updater_mutex;
     }
     friend class boost::serialization::access;
 };
@@ -599,9 +598,8 @@ void InstallInterfaces(Core::System& system);
 } // namespace Service::AM
 
 namespace boost::serialization {
-    template <class Archive>
-    inline void load_construct_data(Archive& ar, Service::AM::Module* t, const unsigned int)
-    {
-        ::new(t)Service::AM::Module(Core::Global<Kernel::KernelSystem>());
-    }
+template <class Archive>
+inline void load_construct_data(Archive& ar, Service::AM::Module* t, const unsigned int) {
+    ::new (t) Service::AM::Module(Core::Global<Kernel::KernelSystem>());
 }
+} // namespace boost::serialization
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index 52d256ca2..788ee090c 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/am/am_app.h"
 #include "common/archives.h"
+#include "core/hle/service/am/am_app.h"
 
 namespace Service::AM {
 
diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h
index fae22d96f..b8e858cb4 100644
--- a/src/core/hle/service/am/am_app.h
+++ b/src/core/hle/service/am/am_app.h
@@ -11,6 +11,7 @@ namespace Service::AM {
 class AM_APP final : public Module::Interface {
 public:
     explicit AM_APP(std::shared_ptr<Module> am);
+
 private:
     SERVICE_SERIALIZATION(AM_APP, am, Module)
 };
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index 44c852c19..cd88965af 100644
--- a/src/core/hle/service/am/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/am/am_net.h"
 #include "common/archives.h"
+#include "core/hle/service/am/am_net.h"
 
 namespace Service::AM {
 
diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h
index 4a50c6c07..b73610df9 100644
--- a/src/core/hle/service/am/am_net.h
+++ b/src/core/hle/service/am/am_net.h
@@ -11,6 +11,7 @@ namespace Service::AM {
 class AM_NET final : public Module::Interface {
 public:
     explicit AM_NET(std::shared_ptr<Module> am);
+
 private:
     SERVICE_SERIALIZATION(AM_NET, am, Module)
 };
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp
index c6817fe87..6c7e99235 100644
--- a/src/core/hle/service/am/am_sys.cpp
+++ b/src/core/hle/service/am/am_sys.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/am/am_sys.h"
 #include "common/archives.h"
+#include "core/hle/service/am/am_sys.h"
 
 namespace Service::AM {
 
diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h
index c67052302..fdee63b13 100644
--- a/src/core/hle/service/am/am_sys.h
+++ b/src/core/hle/service/am/am_sys.h
@@ -11,6 +11,7 @@ namespace Service::AM {
 class AM_SYS final : public Module::Interface {
 public:
     explicit AM_SYS(std::shared_ptr<Module> am);
+
 private:
     SERVICE_SERIALIZATION(AM_SYS, am, Module)
 };
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp
index c9b80bf06..cffb88388 100644
--- a/src/core/hle/service/am/am_u.cpp
+++ b/src/core/hle/service/am/am_u.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/am/am_u.h"
 #include "common/archives.h"
+#include "core/hle/service/am/am_u.h"
 
 namespace Service::AM {
 
diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h
index c09e27c09..d71bf722c 100644
--- a/src/core/hle/service/am/am_u.h
+++ b/src/core/hle/service/am/am_u.h
@@ -11,6 +11,7 @@ namespace Service::AM {
 class AM_U final : public Module::Interface {
 public:
     explicit AM_U(std::shared_ptr<Module> am);
+
 private:
     SERVICE_SERIALIZATION(AM_U, am, Module)
 };
diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h
index 9410b6b54..e799c92d2 100644
--- a/src/core/hle/service/apt/applet_manager.h
+++ b/src/core/hle/service/apt/applet_manager.h
@@ -10,10 +10,10 @@
 #include <vector>
 #include <boost/serialization/array.hpp>
 #include "common/serialization/optional.h"
+#include "core/global.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/result.h"
 #include "core/hle/service/fs/archive.h"
-#include "core/global.h"
 
 namespace Core {
 class System;
@@ -90,13 +90,12 @@ struct MessageParameter {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & sender_id;
-        ar & destination_id;
-        ar & signal;
-        ar & object;
-        ar & buffer;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& sender_id;
+        ar& destination_id;
+        ar& signal;
+        ar& object;
+        ar& buffer;
     }
     friend class boost::serialization::access;
 };
@@ -179,12 +178,11 @@ public:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int)
-        {
-            ar & next_title_id;
-            ar & next_media_type;
-            ar & current_title_id;
-            ar & current_media_type;
+        void serialize(Archive& ar, const unsigned int) {
+            ar& next_title_id;
+            ar& next_media_type;
+            ar& current_title_id;
+            ar& current_media_type;
         }
         friend class boost::serialization::access;
     };
@@ -228,16 +226,15 @@ private:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int)
-        {
-            ar & applet_id;
-            ar & slot;
-            ar & title_id;
-            ar & registered;
-            ar & loaded;
-            ar & attributes.raw;
-            ar & notification_event;
-            ar & parameter_event;
+        void serialize(Archive& ar, const unsigned int) {
+            ar& applet_id;
+            ar& slot;
+            ar& title_id;
+            ar& registered;
+            ar& loaded;
+            ar& attributes.raw;
+            ar& notification_event;
+            ar& parameter_event;
         }
         friend class boost::serialization::access;
     };
@@ -260,12 +257,11 @@ private:
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & next_parameter;
-        ar & app_jump_parameters;
-        ar & applet_slots;
-        ar & library_applet_closing_command;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& next_parameter;
+        ar& app_jump_parameters;
+        ar& applet_slots;
+        ar& library_applet_closing_command;
     }
     friend class boost::serialization::access;
 };
@@ -273,9 +269,8 @@ private:
 } // namespace Service::APT
 
 namespace boost::serialization {
-    template <class Archive>
-    inline void load_construct_data(Archive& ar, Service::APT::AppletManager* t, const unsigned int)
-    {
-        ::new(t)Service::APT::AppletManager(Core::Global<Core::System>());
-    }
+template <class Archive>
+inline void load_construct_data(Archive& ar, Service::APT::AppletManager* t, const unsigned int) {
+    ::new (t) Service::APT::AppletManager(Core::Global<Core::System>());
 }
+} // namespace boost::serialization
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index d5a7fb001..8780f67e0 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -2,10 +2,10 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "common/common_paths.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
-#include "common/archives.h"
 #include "core/core.h"
 #include "core/file_sys/archive_ncch.h"
 #include "core/file_sys/file_backend.h"
@@ -32,17 +32,16 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::Module)
 namespace Service::APT {
 
 template <class Archive>
-void Module::serialize(Archive& ar, const unsigned int)
-{
-    ar & shared_font_mem;
-    ar & shared_font_loaded;
-    ar & shared_font_relocated;
-    ar & lock;
-    ar & cpu_percent;
-    ar & unknown_ns_state_field;
-    ar & screen_capture_buffer;
-    ar & screen_capture_post_permission;
-    ar & applet_manager;
+void Module::serialize(Archive& ar, const unsigned int) {
+    ar& shared_font_mem;
+    ar& shared_font_loaded;
+    ar& shared_font_relocated;
+    ar& lock;
+    ar& cpu_percent;
+    ar& unknown_ns_state_field;
+    ar& screen_capture_buffer;
+    ar& screen_capture_post_permission;
+    ar& applet_manager;
 }
 
 SERIALIZE_IMPL(Module)
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 14c07feb3..aa480331c 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -12,10 +12,9 @@
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/swap.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/service/apt/applet_manager.h"
-#include "core/hle/service/service.h"
 #include "core/global.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
 
 namespace Core {
 class System;
@@ -612,9 +611,8 @@ public:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int)
-        {
-            ar & application_reset_prepared;
+        void serialize(Archive& ar, const unsigned int) {
+            ar& application_reset_prepared;
         }
         friend class boost::serialization::access;
     };
@@ -654,6 +652,6 @@ void InstallInterfaces(Core::System& system);
 } // namespace Service::APT
 
 namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::APT::Module* t, const unsigned int);
+template <class Archive>
+void load_construct_data(Archive& ar, Service::APT::Module* t, const unsigned int);
 }
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index db49c57d8..0d6e64d30 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/apt/apt_a.h"
 #include "common/archives.h"
+#include "core/hle/service/apt/apt_a.h"
 
 namespace Service::APT {
 
diff --git a/src/core/hle/service/apt/apt_a.h b/src/core/hle/service/apt/apt_a.h
index 1b81022df..e17e2f323 100644
--- a/src/core/hle/service/apt/apt_a.h
+++ b/src/core/hle/service/apt/apt_a.h
@@ -11,6 +11,7 @@ namespace Service::APT {
 class APT_A final : public Module::APTInterface {
 public:
     explicit APT_A(std::shared_ptr<Module> apt);
+
 private:
     SERVICE_SERIALIZATION(APT_A, apt, Module)
 };
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index 4d151fb3d..d0e5f5526 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/apt/apt_s.h"
 #include "common/archives.h"
+#include "core/hle/service/apt/apt_s.h"
 
 namespace Service::APT {
 
diff --git a/src/core/hle/service/apt/apt_s.h b/src/core/hle/service/apt/apt_s.h
index ef1c235b0..d1dd27ff1 100644
--- a/src/core/hle/service/apt/apt_s.h
+++ b/src/core/hle/service/apt/apt_s.h
@@ -18,6 +18,7 @@ namespace Service::APT {
 class APT_S final : public Module::APTInterface {
 public:
     explicit APT_S(std::shared_ptr<Module> apt);
+
 private:
     SERVICE_SERIALIZATION(APT_S, apt, Module)
 };
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index 7ebaf86e3..05f531a83 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/apt/apt_u.h"
 #include "common/archives.h"
+#include "core/hle/service/apt/apt_u.h"
 
 namespace Service::APT {
 
diff --git a/src/core/hle/service/apt/apt_u.h b/src/core/hle/service/apt/apt_u.h
index 79d2df651..b8a8fe205 100644
--- a/src/core/hle/service/apt/apt_u.h
+++ b/src/core/hle/service/apt/apt_u.h
@@ -18,6 +18,7 @@ namespace Service::APT {
 class APT_U final : public Module::APTInterface {
 public:
     explicit APT_U(std::shared_ptr<Module> apt);
+
 private:
     SERVICE_SERIALIZATION(APT_U, apt, Module)
 };
diff --git a/src/core/hle/service/apt/ns_s.cpp b/src/core/hle/service/apt/ns_s.cpp
index b556845d3..1f86b9a61 100644
--- a/src/core/hle/service/apt/ns_s.cpp
+++ b/src/core/hle/service/apt/ns_s.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/apt/ns_s.h"
 #include "common/archives.h"
+#include "core/hle/service/apt/ns_s.h"
 
 namespace Service::NS {
 
diff --git a/src/core/hle/service/apt/ns_s.h b/src/core/hle/service/apt/ns_s.h
index 8f023e204..eaa0ad9d3 100644
--- a/src/core/hle/service/apt/ns_s.h
+++ b/src/core/hle/service/apt/ns_s.h
@@ -14,6 +14,7 @@ namespace Service::NS {
 class NS_S final : public Service::APT::Module::NSInterface {
 public:
     explicit NS_S(std::shared_ptr<Service::APT::Module> apt);
+
 private:
     SERVICE_SERIALIZATION(NS_S, apt, Service::APT::Module)
 };
diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h
index 7017ce2b6..4dae148f9 100644
--- a/src/core/hle/service/boss/boss.h
+++ b/src/core/hle/service/boss/boss.h
@@ -6,9 +6,9 @@
 
 #include <memory>
 #include <boost/serialization/shared_ptr.hpp>
+#include "core/global.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/service/service.h"
-#include "core/global.h"
 
 namespace Core {
 class System;
@@ -964,12 +964,11 @@ public:
         u8 output_flag;
 
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int)
-        {
-            ar & new_arrival_flag;
-            ar & ns_data_new_flag;
-            ar & ns_data_new_flag_privileged;
-            ar & output_flag;
+        void serialize(Archive& ar, const unsigned int) {
+            ar& new_arrival_flag;
+            ar& ns_data_new_flag;
+            ar& ns_data_new_flag_privileged;
+            ar& output_flag;
         }
         friend class boost::serialization::access;
     };
@@ -978,9 +977,8 @@ private:
     std::shared_ptr<Kernel::Event> task_finish_event;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & task_finish_event;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& task_finish_event;
     }
     friend class boost::serialization::access;
 };
@@ -990,9 +988,8 @@ void InstallInterfaces(Core::System& system);
 } // namespace Service::BOSS
 
 namespace boost::serialization {
-    template <class Archive>
-    inline void load_construct_data(Archive& ar, Service::BOSS::Module* t, const unsigned int)
-    {
-        ::new(t)Service::BOSS::Module(Core::Global<Core::System>());
-    }
+template <class Archive>
+inline void load_construct_data(Archive& ar, Service::BOSS::Module* t, const unsigned int) {
+    ::new (t) Service::BOSS::Module(Core::Global<Core::System>());
 }
+} // namespace boost::serialization
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp
index 4e48fe8f3..802f2643a 100644
--- a/src/core/hle/service/boss/boss_p.cpp
+++ b/src/core/hle/service/boss/boss_p.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/boss/boss_p.h"
 #include "common/archives.h"
+#include "core/hle/service/boss/boss_p.h"
 
 namespace Service::BOSS {
 
diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp
index f839e9292..68a30510d 100644
--- a/src/core/hle/service/boss/boss_u.cpp
+++ b/src/core/hle/service/boss/boss_u.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/boss/boss_u.h"
 #include "common/archives.h"
+#include "core/hle/service/boss/boss_u.h"
 
 namespace Service::BOSS {
 
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index b7acd307c..6f9a81e75 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -24,11 +24,10 @@
 namespace Service::CAM {
 
 template <class Archive>
-void Module::serialize(Archive& ar, const unsigned int)
-{
-    ar & cameras;
-    ar & ports;
-    ar & is_camera_reload_pending;
+void Module::serialize(Archive& ar, const unsigned int) {
+    ar& cameras;
+    ar& ports;
+    ar& is_camera_reload_pending;
 }
 
 SERIALIZE_IMPL(Module)
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 229c882b5..876e2e185 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -10,9 +10,9 @@
 #include <vector>
 #include "common/common_types.h"
 #include "common/swap.h"
+#include "core/global.h"
 #include "core/hle/result.h"
 #include "core/hle/service/service.h"
-#include "core/global.h"
 
 namespace Core {
 class System;
@@ -183,14 +183,13 @@ struct Resolution {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & width;
-        ar & height;
-        ar & crop_x0;
-        ar & crop_y0;
-        ar & crop_x1;
-        ar & crop_y1;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& width;
+        ar& height;
+        ar& crop_x0;
+        ar& crop_y0;
+        ar& crop_x1;
+        ar& crop_y1;
     }
     friend class boost::serialization::access;
 };
@@ -755,12 +754,11 @@ private:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int)
-        {
-            ar & flip;
-            ar & effect;
-            ar & format;
-            ar & resolution;
+        void serialize(Archive& ar, const unsigned int) {
+            ar& flip;
+            ar& effect;
+            ar& format;
+            ar& resolution;
         }
         friend class boost::serialization::access;
     };
@@ -773,12 +771,11 @@ private:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int)
-        {
-            ar & impl;
-            ar & contexts;
-            ar & current_context;
-            ar & frame_rate;
+        void serialize(Archive& ar, const unsigned int) {
+            ar& impl;
+            ar& contexts;
+            ar& current_context;
+            ar& frame_rate;
         }
         friend class boost::serialization::access;
     };
@@ -818,27 +815,26 @@ private:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int)
-        {
-            ar & camera_id;
-            ar & is_active;
-            ar & is_pending_receiving;
-            ar & is_busy;
-            ar & is_receiving;
-            ar & is_trimming;
-            ar & x0;
-            ar & y0;
-            ar & x1;
-            ar & y1;
-            ar & transfer_bytes;
-            ar & completion_event;
-            ar & buffer_error_interrupt_event;
-            ar & vsync_interrupt_event;
+        void serialize(Archive& ar, const unsigned int) {
+            ar& camera_id;
+            ar& is_active;
+            ar& is_pending_receiving;
+            ar& is_busy;
+            ar& is_receiving;
+            ar& is_trimming;
+            ar& x0;
+            ar& y0;
+            ar& x1;
+            ar& y1;
+            ar& transfer_bytes;
+            ar& completion_event;
+            ar& buffer_error_interrupt_event;
+            ar& vsync_interrupt_event;
             // TODO: Check if this is ever needed:
-            //ar & capture_result;
-            ar & dest_process;
-            ar & dest;
-            ar & dest_size;
+            // ar & capture_result;
+            ar& dest_process;
+            ar& dest;
+            ar& dest_size;
         }
         friend class boost::serialization::access;
     };
@@ -864,9 +860,8 @@ void InstallInterfaces(Core::System& system);
 } // namespace Service::CAM
 
 namespace boost::serialization {
-    template <class Archive>
-    inline void load_construct_data(Archive& ar, Service::CAM::Module* t, const unsigned int)
-    {
-        ::new(t)Service::CAM::Module(Core::Global<Core::System>());
-    }
+template <class Archive>
+inline void load_construct_data(Archive& ar, Service::CAM::Module* t, const unsigned int) {
+    ::new (t) Service::CAM::Module(Core::Global<Core::System>());
 }
+} // namespace boost::serialization
diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp
index a29e9db3e..e86d33115 100644
--- a/src/core/hle/service/cam/cam_c.cpp
+++ b/src/core/hle/service/cam/cam_c.cpp
@@ -2,9 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cam/cam.h"
 #include "core/hle/service/cam/cam_c.h"
-#include "common/archives.h"
 
 namespace Service::CAM {
 
diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp
index ac477bf04..6f0c04598 100644
--- a/src/core/hle/service/cam/cam_q.cpp
+++ b/src/core/hle/service/cam/cam_q.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/cam/cam_q.h"
 #include "common/archives.h"
+#include "core/hle/service/cam/cam_q.h"
 
 namespace Service::CAM {
 
diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h
index 33943ca21..ab901cf85 100644
--- a/src/core/hle/service/cam/cam_q.h
+++ b/src/core/hle/service/cam/cam_q.h
@@ -11,11 +11,11 @@ namespace Service::CAM {
 class CAM_Q : public ServiceFramework<CAM_Q> {
 public:
     CAM_Q();
+
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp
index 0797ed4e1..8cfd3c1d7 100644
--- a/src/core/hle/service/cam/cam_s.cpp
+++ b/src/core/hle/service/cam/cam_s.cpp
@@ -2,9 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cam/cam.h"
 #include "core/hle/service/cam/cam_s.h"
-#include "common/archives.h"
 
 namespace Service::CAM {
 
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp
index 16c652a26..72a62c04e 100644
--- a/src/core/hle/service/cam/cam_u.cpp
+++ b/src/core/hle/service/cam/cam_u.cpp
@@ -2,9 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cam/cam.h"
 #include "core/hle/service/cam/cam_u.h"
-#include "common/archives.h"
 
 namespace Service::CAM {
 
diff --git a/src/core/hle/service/csnd/csnd_snd.h b/src/core/hle/service/csnd/csnd_snd.h
index 44e4c030c..6ac5d6876 100644
--- a/src/core/hle/service/csnd/csnd_snd.h
+++ b/src/core/hle/service/csnd/csnd_snd.h
@@ -38,10 +38,9 @@ struct AdpcmState {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & predictor;
-        ar & step_index;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& predictor;
+        ar& step_index;
     }
     friend class boost::serialization::access;
 };
@@ -66,24 +65,23 @@ struct Channel {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & block1_address;
-        ar & block2_address;
-        ar & block1_size;
-        ar & block2_size;
-        ar & block1_adpcm_state;
-        ar & block2_adpcm_state;
-        ar & block2_adpcm_reload;
-        ar & left_channel_volume;
-        ar & right_channel_volume;
-        ar & left_capture_volume;
-        ar & right_capture_volume;
-        ar & sample_rate;
-        ar & linear_interpolation;
-        ar & loop_mode;
-        ar & encoding;
-        ar & psg_duty;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& block1_address;
+        ar& block2_address;
+        ar& block1_size;
+        ar& block2_size;
+        ar& block1_adpcm_state;
+        ar& block2_adpcm_state;
+        ar& block2_adpcm_reload;
+        ar& left_channel_volume;
+        ar& right_channel_volume;
+        ar& left_capture_volume;
+        ar& right_capture_volume;
+        ar& sample_rate;
+        ar& linear_interpolation;
+        ar& loop_mode;
+        ar& encoding;
+        ar& psg_duty;
     }
     friend class boost::serialization::access;
 };
@@ -258,18 +256,17 @@ private:
     u32 acquired_channel_mask = 0;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-        ar & mutex;
-        ar & shared_memory;
-        ar & capture_units;
-        ar & channels;
-        ar & master_state_offset;
-        ar & channel_state_offset;
-        ar & capture_state_offset;
-        ar & type1_command_offset;
-        ar & acquired_channel_mask;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar& mutex;
+        ar& shared_memory;
+        ar& capture_units;
+        ar& channels;
+        ar& master_state_offset;
+        ar& channel_state_offset;
+        ar& capture_state_offset;
+        ar& type1_command_offset;
+        ar& acquired_channel_mask;
     }
     friend class boost::serialization::access;
 };
@@ -282,6 +279,6 @@ void InstallInterfaces(Core::System& system);
 BOOST_CLASS_EXPORT_KEY(Service::CSND::CSND_SND)
 
 namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::CSND::CSND_SND* t, const unsigned int);
+template <class Archive>
+void load_construct_data(Archive& ar, Service::CSND::CSND_SND* t, const unsigned int);
 }
diff --git a/src/core/hle/service/dlp/dlp_clnt.cpp b/src/core/hle/service/dlp/dlp_clnt.cpp
index df5b755e1..f8b315c00 100644
--- a/src/core/hle/service/dlp/dlp_clnt.cpp
+++ b/src/core/hle/service/dlp/dlp_clnt.cpp
@@ -2,9 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/dlp/dlp_clnt.h"
-#include "common/archives.h"
 
 SERIALIZE_EXPORT_IMPL(Service::DLP::DLP_CLNT)
 
diff --git a/src/core/hle/service/dlp/dlp_clnt.h b/src/core/hle/service/dlp/dlp_clnt.h
index 3f9020863..835d01748 100644
--- a/src/core/hle/service/dlp/dlp_clnt.h
+++ b/src/core/hle/service/dlp/dlp_clnt.h
@@ -12,11 +12,11 @@ class DLP_CLNT final : public ServiceFramework<DLP_CLNT> {
 public:
     DLP_CLNT();
     ~DLP_CLNT() = default;
+
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/dlp/dlp_fkcl.cpp b/src/core/hle/service/dlp/dlp_fkcl.cpp
index 607c211d4..948b25b67 100644
--- a/src/core/hle/service/dlp/dlp_fkcl.cpp
+++ b/src/core/hle/service/dlp/dlp_fkcl.cpp
@@ -2,9 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/dlp/dlp_fkcl.h"
-#include "common/archives.h"
 
 SERIALIZE_EXPORT_IMPL(Service::DLP::DLP_FKCL)
 
diff --git a/src/core/hle/service/dlp/dlp_fkcl.h b/src/core/hle/service/dlp/dlp_fkcl.h
index ae26b6220..d778ace8b 100644
--- a/src/core/hle/service/dlp/dlp_fkcl.h
+++ b/src/core/hle/service/dlp/dlp_fkcl.h
@@ -12,11 +12,11 @@ class DLP_FKCL final : public ServiceFramework<DLP_FKCL> {
 public:
     DLP_FKCL();
     ~DLP_FKCL() = default;
+
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp
index 0cff2e2bc..87733b71f 100644
--- a/src/core/hle/service/dlp/dlp_srvr.cpp
+++ b/src/core/hle/service/dlp/dlp_srvr.cpp
@@ -2,12 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/result.h"
 #include "core/hle/service/dlp/dlp_srvr.h"
-#include "common/archives.h"
 
 SERIALIZE_EXPORT_IMPL(Service::DLP::DLP_SRVR)
 
diff --git a/src/core/hle/service/dlp/dlp_srvr.h b/src/core/hle/service/dlp/dlp_srvr.h
index 6af350c8e..1f171f950 100644
--- a/src/core/hle/service/dlp/dlp_srvr.h
+++ b/src/core/hle/service/dlp/dlp_srvr.h
@@ -17,9 +17,8 @@ private:
     void IsChild(Kernel::HLERequestContext& ctx);
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/dsp/dsp_dsp.h b/src/core/hle/service/dsp/dsp_dsp.h
index b4c727091..90dd17f65 100644
--- a/src/core/hle/service/dsp/dsp_dsp.h
+++ b/src/core/hle/service/dsp/dsp_dsp.h
@@ -266,14 +266,13 @@ private:
     std::array<std::shared_ptr<Kernel::Event>, AudioCore::num_dsp_pipe> pipes = {{}};
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-        ar & semaphore_event;
-        ar & preset_semaphore;
-        ar & interrupt_zero;
-        ar & interrupt_one;
-        ar & pipes;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar& semaphore_event;
+        ar& preset_semaphore;
+        ar& interrupt_zero;
+        ar& interrupt_one;
+        ar& pipes;
     }
     friend class boost::serialization::access;
 };
@@ -285,6 +284,6 @@ void InstallInterfaces(Core::System& system);
 BOOST_CLASS_EXPORT_KEY(Service::DSP::DSP_DSP)
 
 namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::DSP::DSP_DSP* t, const unsigned int);
+template <class Archive>
+void load_construct_data(Archive& ar, Service::DSP::DSP_DSP* t, const unsigned int);
 }
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 0efc600e8..f88ffef19 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -20,16 +20,15 @@
 SERIALIZE_EXPORT_IMPL(Service::ERR::ERR_F)
 
 namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int)
-    {
-        ::new(t)Service::ERR::ERR_F(Core::Global<Core::System>());
-    }
-
-    template
-    void load_construct_data<iarchive>(iarchive& ar, Service::ERR::ERR_F* t, const unsigned int);
+template <class Archive>
+void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int) {
+    ::new (t) Service::ERR::ERR_F(Core::Global<Core::System>());
 }
 
+template void load_construct_data<iarchive>(iarchive& ar, Service::ERR::ERR_F* t,
+                                            const unsigned int);
+} // namespace boost::serialization
+
 namespace Service::ERR {
 
 enum class FatalErrType : u32 {
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
index a3d0cf11e..de92fed05 100644
--- a/src/core/hle/service/err_f.h
+++ b/src/core/hle/service/err_f.h
@@ -36,9 +36,8 @@ private:
     Core::System& system;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     }
     friend class boost::serialization::access;
 };
@@ -50,6 +49,6 @@ void InstallInterfaces(Core::System& system);
 BOOST_CLASS_EXPORT_KEY(Service::ERR::ERR_F)
 
 namespace boost::serialization {
-    template <class Archive>
-    void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int);
+template <class Archive>
+void load_construct_data(Archive& ar, Service::ERR::ERR_F* t, const unsigned int);
 }
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h
index 46dc96cad..1f34e61fa 100644
--- a/src/core/hle/service/frd/frd.h
+++ b/src/core/hle/service/frd/frd.h
@@ -21,11 +21,10 @@ struct FriendKey {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & friend_id;
-        ar & unknown;
-        ar & friend_code;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& friend_id;
+        ar& unknown;
+        ar& friend_code;
     }
     friend class boost::serialization::access;
 };
@@ -35,9 +34,8 @@ struct MyPresence {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & unknown;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& unknown;
     }
     friend class boost::serialization::access;
 };
@@ -157,10 +155,9 @@ private:
     MyPresence my_presence = {};
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & my_friend_key;
-        ar & my_presence;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& my_friend_key;
+        ar& my_presence;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp
index 6248891af..23a83a55e 100644
--- a/src/core/hle/service/frd/frd_a.cpp
+++ b/src/core/hle/service/frd/frd_a.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/frd/frd_a.h"
 #include "common/archives.h"
+#include "core/hle/service/frd/frd_a.h"
 
 SERIALIZE_EXPORT_IMPL(Service::FRD::FRD_A)
 
diff --git a/src/core/hle/service/frd/frd_a.h b/src/core/hle/service/frd/frd_a.h
index 133d40dc1..0bdd87525 100644
--- a/src/core/hle/service/frd/frd_a.h
+++ b/src/core/hle/service/frd/frd_a.h
@@ -11,6 +11,7 @@ namespace Service::FRD {
 class FRD_A final : public Module::Interface {
 public:
     explicit FRD_A(std::shared_ptr<Module> frd);
+
 private:
     SERVICE_SERIALIZATION(FRD_A, frd, Module)
 };
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index ba499dd2b..d83c8ac8c 100644
--- a/src/core/hle/service/frd/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include "core/hle/service/frd/frd_u.h"
 #include "common/archives.h"
+#include "core/hle/service/frd/frd_u.h"
 
 SERIALIZE_EXPORT_IMPL(Service::FRD::FRD_U)
 
diff --git a/src/core/hle/service/frd/frd_u.h b/src/core/hle/service/frd/frd_u.h
index 281334f51..e6adc37fb 100644
--- a/src/core/hle/service/frd/frd_u.h
+++ b/src/core/hle/service/frd/frd_u.h
@@ -11,6 +11,7 @@ namespace Service::FRD {
 class FRD_U final : public Module::Interface {
 public:
     explicit FRD_U(std::shared_ptr<Module> frd);
+
 private:
     SERVICE_SERIALIZATION(FRD_U, frd, Module)
 };
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 90dfad62f..767faf167 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -13,6 +13,7 @@
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
+#include "core/core.h"
 #include "core/file_sys/archive_backend.h"
 #include "core/file_sys/archive_extsavedata.h"
 #include "core/file_sys/archive_ncch.h"
@@ -27,7 +28,6 @@
 #include "core/file_sys/file_backend.h"
 #include "core/hle/result.h"
 #include "core/hle/service/fs/archive.h"
-#include "core/core.h"
 
 namespace Service::FS {
 
diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h
index c001be0c5..29b47a99c 100644
--- a/src/core/hle/service/fs/fs_user.h
+++ b/src/core/hle/service/fs/fs_user.h
@@ -25,9 +25,8 @@ struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & program_id;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& program_id;
     }
     friend class boost::serialization::access;
 };
@@ -555,10 +554,9 @@ private:
     ArchiveManager& archives;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-        ar & priority;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar& priority;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index b16a4065f..d39e72aca 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -11,8 +11,8 @@
 #include <string>
 #include <boost/container/flat_map.hpp>
 #include <boost/serialization/assume_abstract.hpp>
-#include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
 #include "common/construct.h"
 #include "core/hle/kernel/hle_ipc.h"
@@ -199,42 +199,37 @@ extern const std::array<ServiceModuleInfo, 40> service_module_map;
 
 } // namespace Service
 
-#define SERVICE_SERIALIZATION(T, MFIELD, TMODULE) \
-    template <class Archive> \
-    void save_construct(Archive& ar, const unsigned int file_version) const \
-    { \
-        ar << MFIELD; \
-    } \
- \
-    template <class Archive> \
-    static void load_construct(Archive& ar, T* t, const unsigned int file_version) \
-    { \
-        std::shared_ptr<TMODULE> MFIELD; \
-        ar >> MFIELD; \
-        ::new(t)T(MFIELD); \
-    } \
- \
-    template <class Archive> \
-    void serialize(Archive& ar, const unsigned int) \
-    { \
-        ar & boost::serialization::base_object<Kernel::SessionRequestHandler>(*this); \
-    } \
-    friend class boost::serialization::access; \
+#define SERVICE_SERIALIZATION(T, MFIELD, TMODULE)                                                  \
+    template <class Archive>                                                                       \
+    void save_construct(Archive& ar, const unsigned int file_version) const {                      \
+        ar << MFIELD;                                                                              \
+    }                                                                                              \
+                                                                                                   \
+    template <class Archive>                                                                       \
+    static void load_construct(Archive& ar, T* t, const unsigned int file_version) {               \
+        std::shared_ptr<TMODULE> MFIELD;                                                           \
+        ar >> MFIELD;                                                                              \
+        ::new (t) T(MFIELD);                                                                       \
+    }                                                                                              \
+                                                                                                   \
+    template <class Archive>                                                                       \
+    void serialize(Archive& ar, const unsigned int) {                                              \
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);               \
+    }                                                                                              \
+    friend class boost::serialization::access;                                                     \
     friend class ::construct_access;
 
-#define SERVICE_CONSTRUCT(T) \
-namespace boost::serialization { \
-    template <class Archive> \
-    void load_construct_data(Archive& ar, T* t, const unsigned int); \
-}
+#define SERVICE_CONSTRUCT(T)                                                                       \
+    namespace boost::serialization {                                                               \
+    template <class Archive>                                                                       \
+    void load_construct_data(Archive& ar, T* t, const unsigned int);                               \
+    }
 
-#define SERVICE_CONSTRUCT_IMPL(T) \
-namespace boost::serialization { \
-    template <class Archive> \
-    void load_construct_data(Archive& ar, T* t, const unsigned int) \
-    { \
-        ::new(t)T(Core::Global<Core::System>()); \
-    } \
-    template \
-    void load_construct_data<iarchive>(iarchive& ar, T* t, const unsigned int); \
-}
+#define SERVICE_CONSTRUCT_IMPL(T)                                                                  \
+    namespace boost::serialization {                                                               \
+    template <class Archive>                                                                       \
+    void load_construct_data(Archive& ar, T* t, const unsigned int) {                              \
+        ::new (t) T(Core::Global<Core::System>());                                                 \
+    }                                                                                              \
+    template void load_construct_data<iarchive>(iarchive & ar, T* t, const unsigned int);          \
+    }
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index d91732da9..659e14afb 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -9,9 +9,9 @@
 #include <type_traits>
 #include <unordered_map>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/split_member.hpp>
 #include <boost/serialization/string.hpp>
 #include <boost/serialization/unordered_map.hpp>
-#include <boost/serialization/split_member.hpp>
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
@@ -86,14 +86,12 @@ private:
     std::unordered_map<u32, std::string> registered_services_inverse;
 
     template <class Archive>
-    void save(Archive& ar, const unsigned int file_version) const
-    {
+    void save(Archive& ar, const unsigned int file_version) const {
         ar << registered_services;
     }
 
     template <class Archive>
-    void load(Archive& ar, const unsigned int file_version)
-    {
+    void load(Archive& ar, const unsigned int file_version) {
         ar >> registered_services;
         registered_services_inverse.clear();
         for (const auto& pair : registered_services) {
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 7264e1ec4..6a41ca957 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -4,9 +4,9 @@
 
 #include <array>
 #include <cstring>
+#include "audio_core/dsp_interface.h"
 #include "boost/serialization/array.hpp"
 #include "boost/serialization/binary_object.hpp"
-#include "audio_core/dsp_interface.h"
 #include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_types.h"
@@ -58,12 +58,11 @@ private:
 
     static_assert(sizeof(bool) == 1);
     friend class boost::serialization::access;
-    template<typename Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & vram;
-        ar & linear_heap;
-        ar & new_linear_heap;
+    template <typename Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& vram;
+        ar& linear_heap;
+        ar& new_linear_heap;
     }
 };
 
@@ -82,19 +81,18 @@ public:
     AudioCore::DspInterface* dsp = nullptr;
 
 private:
-
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
         // TODO: Skip n3ds ram when not used?
         auto s_fcram = boost::serialization::binary_object(fcram.get(), Memory::FCRAM_N3DS_SIZE);
         auto s_vram = boost::serialization::binary_object(vram.get(), Memory::VRAM_SIZE);
-        auto s_extra = boost::serialization::binary_object(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
-        ar & s_fcram;
-        ar & s_vram;
-        ar & s_extra;
-        ar & cache_marker;
+        auto s_extra =
+            boost::serialization::binary_object(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
+        ar& s_fcram;
+        ar& s_vram;
+        ar& s_extra;
+        ar& cache_marker;
         // TODO: How the hell to do page tables..
         // ar & page_table_list;
         // ar & current_page_table;
@@ -104,10 +102,9 @@ private:
 MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
 MemorySystem::~MemorySystem() = default;
 
-template<class Archive>
-void MemorySystem::serialize(Archive & ar, const unsigned int file_version)
-{
-    ar & *impl.get();
+template <class Archive>
+void MemorySystem::serialize(Archive& ar, const unsigned int file_version) {
+    ar&* impl.get();
 }
 
 SERIALIZE_IMPL(MemorySystem)
diff --git a/src/core/memory.h b/src/core/memory.h
index 9c1455a80..aac57af26 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -54,12 +54,11 @@ struct SpecialRegion {
     u32 size;
     MMIORegionPointer handler;
 
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & base;
-        ar & size;
-        ar & handler;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& base;
+        ar& size;
+        ar& handler;
     }
 };
 
@@ -326,8 +325,8 @@ private:
     std::unique_ptr<Impl> impl;
 
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version);
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 
 /// Determines if the given VAddr is valid for the specified process.
diff --git a/src/core/mmio.h b/src/core/mmio.h
index 0a8249c9a..2e6323b49 100644
--- a/src/core/mmio.h
+++ b/src/core/mmio.h
@@ -36,9 +36,7 @@ public:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-    }
+    void serialize(Archive& ar, const unsigned int file_version) {}
 };
 
 using MMIORegionPointer = std::shared_ptr<MMIORegion>;
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index e405f6729..62cad0e35 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -26,7 +26,8 @@ static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) {
 TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
     Core::Timing timing;
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
+    Kernel::KernelSystem kernel(
+        memory, timing, [] {}, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 
@@ -238,7 +239,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
 TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
     Core::Timing timing;
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
+    Kernel::KernelSystem kernel(
+        memory, timing, [] {}, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 3a5b35236..1c633cf5c 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -645,8 +645,7 @@ void ProcessCommandList(PAddr list, u32 size) {
     u32* buffer = (u32*)VideoCore::g_memory->GetPhysicalPointer(list);
 
     if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
-        Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, size,
-                                                        list);
+        Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, size, list);
     }
 
     g_state.cmd_list.addr = list;
diff --git a/src/video_core/geometry_pipeline.cpp b/src/video_core/geometry_pipeline.cpp
index 44a2fd6da..159f1df0b 100644
--- a/src/video_core/geometry_pipeline.cpp
+++ b/src/video_core/geometry_pipeline.cpp
@@ -37,9 +37,7 @@ public:
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-    }
+    void serialize(Archive& ar, const unsigned int file_version) {}
     friend class boost::serialization::access;
 };
 
@@ -92,16 +90,14 @@ private:
     unsigned int vs_output_num;
 
     template <typename Class, class Archive>
-    static void serialize_common(Class* self, Archive& ar, const unsigned int version)
-    {
-        ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
+    static void serialize_common(Class* self, Archive& ar, const unsigned int version) {
+        ar& boost::serialization::base_object<GeometryPipelineBackend>(*self);
         ar & self->attribute_buffer;
         ar & self->vs_output_num;
     }
 
-    template<class Archive>
-    void save(Archive & ar, const unsigned int version) const
-    {
+    template <class Archive>
+    void save(Archive& ar, const unsigned int version) const {
         serialize_common(this, ar, version);
         auto buffer_idx = static_cast<u32>(buffer_cur - attribute_buffer.attr);
         auto buffer_size = static_cast<u32>(buffer_end - attribute_buffer.attr);
@@ -109,9 +105,8 @@ private:
         ar << buffer_size;
     }
 
-    template<class Archive>
-    void load(Archive & ar, const unsigned int version)
-    {
+    template <class Archive>
+    void load(Archive& ar, const unsigned int version) {
         serialize_common(this, ar, version);
         u32 buffer_idx, buffer_size;
         ar >> buffer_idx;
@@ -130,8 +125,7 @@ private:
 // value in the batch. This mode is usually used for subdivision.
 class GeometryPipeline_VariablePrimitive : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_VariablePrimitive()
-        : regs(g_state.regs), setup(g_state.gs) {
+    GeometryPipeline_VariablePrimitive() : regs(g_state.regs), setup(g_state.gs) {
         ASSERT(regs.pipeline.variable_primitive == 1);
         ASSERT(regs.gs.input_to_uniform == 1);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -190,26 +184,23 @@ private:
     unsigned int vs_output_num;
 
     template <typename Class, class Archive>
-    static void serialize_common(Class* self, Archive& ar, const unsigned int version)
-    {
-        ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
+    static void serialize_common(Class* self, Archive& ar, const unsigned int version) {
+        ar& boost::serialization::base_object<GeometryPipelineBackend>(*self);
         ar & self->need_index;
         ar & self->main_vertex_num;
         ar & self->total_vertex_num;
         ar & self->vs_output_num;
     }
 
-    template<class Archive>
-    void save(Archive & ar, const unsigned int version) const
-    {
+    template <class Archive>
+    void save(Archive& ar, const unsigned int version) const {
         serialize_common(this, ar, version);
         auto buffer_idx = static_cast<u32>(buffer_cur - setup.uniforms.f);
         ar << buffer_idx;
     }
 
-    template<class Archive>
-    void load(Archive & ar, const unsigned int version)
-    {
+    template <class Archive>
+    void load(Archive& ar, const unsigned int version) {
         serialize_common(this, ar, version);
         u32 buffer_idx;
         ar >> buffer_idx;
@@ -226,8 +217,7 @@ private:
 // particle system.
 class GeometryPipeline_FixedPrimitive : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_FixedPrimitive()
-        : regs(g_state.regs), setup(g_state.gs) {
+    GeometryPipeline_FixedPrimitive() : regs(g_state.regs), setup(g_state.gs) {
         ASSERT(regs.pipeline.variable_primitive == 0);
         ASSERT(regs.gs.input_to_uniform == 1);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -267,15 +257,13 @@ private:
     unsigned int vs_output_num;
 
     template <typename Class, class Archive>
-    static void serialize_common(Class* self, Archive& ar, const unsigned int version)
-    {
-        ar & boost::serialization::base_object<GeometryPipelineBackend>(*self);
+    static void serialize_common(Class* self, Archive& ar, const unsigned int version) {
+        ar& boost::serialization::base_object<GeometryPipelineBackend>(*self);
         ar & self->vs_output_num;
     }
 
-    template<class Archive>
-    void save(Archive & ar, const unsigned int version) const
-    {
+    template <class Archive>
+    void save(Archive& ar, const unsigned int version) const {
         serialize_common(this, ar, version);
         auto buffer_offset = static_cast<u32>(buffer_begin - setup.uniforms.f);
         auto buffer_idx = static_cast<u32>(buffer_cur - setup.uniforms.f);
@@ -285,9 +273,8 @@ private:
         ar << buffer_size;
     }
 
-    template<class Archive>
-    void load(Archive & ar, const unsigned int version)
-    {
+    template <class Archive>
+    void load(Archive& ar, const unsigned int version) {
         serialize_common(this, ar, version);
         u32 buffer_offset, buffer_idx, buffer_size;
         ar >> buffer_offset;
@@ -385,7 +372,7 @@ void GeometryPipeline::SubmitVertex(const Shader::AttributeBuffer& input) {
 template <class Archive>
 void GeometryPipeline::serialize(Archive& ar, const unsigned int version) {
     // vertex_handler and shader_engine are always set to the same value
-    ar & backend;
+    ar& backend;
 }
 
 } // namespace Pica
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index 0b5aaa682..5e0c2d480 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -3,17 +3,19 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
+#include "core/global.h"
 #include "video_core/geometry_pipeline.h"
 #include "video_core/pica.h"
 #include "video_core/pica_state.h"
 #include "video_core/renderer_base.h"
 #include "video_core/video_core.h"
-#include "core/global.h"
 
 namespace Core {
-    template <>
-    Pica::State& Global() { return Pica::g_state; }
+template <>
+Pica::State& Global() {
+    return Pica::g_state;
 }
+} // namespace Core
 
 namespace Pica {
 
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 30cef3496..4e5a5f16b 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -9,23 +9,21 @@
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "common/vector_math.h"
-#include "video_core/video_core.h"
 #include "video_core/geometry_pipeline.h"
 #include "video_core/primitive_assembly.h"
 #include "video_core/regs.h"
 #include "video_core/shader/shader.h"
+#include "video_core/video_core.h"
 
 // Boost::serialization doesn't like union types for some reason,
 // so we need to mark arrays of union values with a special serialization method
-template<typename Value, size_t Size>
-struct UnionArray : public std::array<Value, Size>
-{
+template <typename Value, size_t Size>
+struct UnionArray : public std::array<Value, Size> {
 private:
-    template<class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
         static_assert(sizeof(Value) == sizeof(u32));
-        ar & *static_cast<u32 (*)[Size]>(static_cast<void *>(this->data()));
+        ar&* static_cast<u32(*)[Size]>(static_cast<void*>(this->data()));
     }
     friend class boost::serialization::access;
 };
@@ -99,14 +97,13 @@ struct State {
 
     private:
         friend class boost::serialization::access;
-        template<class Archive>
-        void serialize(Archive & ar, const unsigned int file_version)
-        {
-            ar & noise_table;
-            ar & color_map_table;
-            ar & alpha_map_table;
-            ar & color_table;
-            ar & color_diff_table;
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int file_version) {
+            ar& noise_table;
+            ar& color_map_table;
+            ar& alpha_map_table;
+            ar& color_table;
+            ar& color_diff_table;
         }
     } proctex;
 
@@ -131,10 +128,9 @@ struct State {
                 return neg_difference ? -diff : diff;
             }
 
-            template<class Archive>
-            void serialize(Archive & ar, const unsigned int file_version)
-            {
-                ar & raw;
+            template <class Archive>
+            void serialize(Archive& ar, const unsigned int file_version) {
+                ar& raw;
             }
         };
 
@@ -180,12 +176,11 @@ struct State {
 
     private:
         friend class boost::serialization::access;
-        template<class Archive>
-        void serialize(Archive & ar, const unsigned int file_version)
-        {
-            ar & input_vertex;
-            ar & current_attribute;
-            ar & reset_geometry_pipeline;
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int file_version) {
+            ar& input_vertex;
+            ar& current_attribute;
+            ar& reset_geometry_pipeline;
         }
 
     } immediate;
@@ -210,42 +205,38 @@ struct State {
     u32 default_attr_write_buffer[3]{};
 
 private:
-
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & regs.reg_array;
-        ar & vs;
-        ar & gs;
-        ar & input_default_attributes;
-        ar & proctex;
-        ar & lighting.luts;
-        ar & fog.lut;
-        ar & cmd_list.addr;
-        ar & cmd_list.length;
-        ar & immediate;
-        ar & gs_unit;
-        ar & geometry_pipeline;
-        ar & primitive_assembler;
-        ar & vs_float_regs_counter;
-        ar & vs_uniform_write_buffer;
-        ar & gs_float_regs_counter;
-        ar & gs_uniform_write_buffer;
-        ar & default_attr_counter;
-        ar & default_attr_write_buffer;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& regs.reg_array;
+        ar& vs;
+        ar& gs;
+        ar& input_default_attributes;
+        ar& proctex;
+        ar& lighting.luts;
+        ar& fog.lut;
+        ar& cmd_list.addr;
+        ar& cmd_list.length;
+        ar& immediate;
+        ar& gs_unit;
+        ar& geometry_pipeline;
+        ar& primitive_assembler;
+        ar& vs_float_regs_counter;
+        ar& vs_uniform_write_buffer;
+        ar& gs_float_regs_counter;
+        ar& gs_uniform_write_buffer;
+        ar& default_attr_counter;
+        ar& default_attr_write_buffer;
         boost::serialization::split_member(ar, *this, file_version);
     }
 
-    template<class Archive>
-    void save(Archive & ar, const unsigned int file_version) const
-    {
+    template <class Archive>
+    void save(Archive& ar, const unsigned int file_version) const {
         ar << static_cast<u32>(cmd_list.current_ptr - cmd_list.head_ptr);
     }
 
-    template<class Archive>
-    void load(Archive & ar, const unsigned int file_version)
-    {
+    template <class Archive>
+    void load(Archive& ar, const unsigned int file_version) {
         u32 offset{};
         ar >> offset;
         cmd_list.head_ptr = (u32*)VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr);
diff --git a/src/video_core/pica_types.h b/src/video_core/pica_types.h
index bef256e13..33012c259 100644
--- a/src/video_core/pica_types.h
+++ b/src/video_core/pica_types.h
@@ -143,10 +143,9 @@ private:
     float value;
 
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & value;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& value;
     }
 };
 
diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h
index 1545a6b4c..d6547dddd 100644
--- a/src/video_core/primitive_assembly.h
+++ b/src/video_core/primitive_assembly.h
@@ -6,7 +6,9 @@
 
 #include <functional>
 #include "video_core/regs_pipeline.h"
-namespace boost::serialization { class access; }
+namespace boost::serialization {
+class access;
+}
 
 namespace Pica {
 
@@ -65,13 +67,12 @@ private:
     bool winding = false;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int version)
-    {
-        ar & topology;
-        ar & buffer_index;
-        ar & buffer;
-        ar & strip_ready;
-        ar & winding;
+    void serialize(Archive& ar, const unsigned int version) {
+        ar& topology;
+        ar& buffer_index;
+        ar& buffer;
+        ar& strip_ready;
+        ar& winding;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index f20e08d98..a6e42b3bf 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -8,15 +8,15 @@
 #include <cstddef>
 #include <functional>
 #include <type_traits>
-#include <nihstro/shader_bytecode.h>
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/base_object.hpp>
+#include <nihstro/shader_bytecode.h>
 #include "common/assert.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/hash.h"
-#include "common/vector_math.h"
 #include "common/pod.h"
+#include "common/vector_math.h"
 #include "video_core/pica_types.h"
 #include "video_core/regs_rasterizer.h"
 #include "video_core/regs_shader.h"
@@ -38,9 +38,8 @@ struct AttributeBuffer {
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & attr;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& attr;
     }
 };
 
@@ -107,13 +106,12 @@ struct GSEmitter {
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & buffer;
-        ar & vertex_id;
-        ar & prim_emit;
-        ar & winding;
-        ar & output_mask;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& buffer;
+        ar& vertex_id;
+        ar& prim_emit;
+        ar& winding;
+        ar& output_mask;
         // Handlers are ignored because they're constant
     }
 };
@@ -137,11 +135,10 @@ struct UnitState {
     private:
         friend class boost::serialization::access;
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int file_version)
-        {
-            ar & input;
-            ar & temporary;
-            ar & output;
+        void serialize(Archive& ar, const unsigned int file_version) {
+            ar& input;
+            ar& temporary;
+            ar& output;
         }
     } registers;
     static_assert(std::is_pod<Registers>::value, "Structure is not POD");
@@ -199,11 +196,10 @@ struct UnitState {
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & registers;
-        ar & conditional_code;
-        ar & address_registers;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& registers;
+        ar& conditional_code;
+        ar& address_registers;
         // emitter_ptr is only set by GSUnitState and is serialized there
     }
 };
@@ -223,10 +219,9 @@ struct GSUnitState : public UnitState {
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version)
-    {
-        ar & boost::serialization::base_object<UnitState>(*this);
-        ar & emitter;
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<UnitState>(*this);
+        ar& emitter;
     }
 };
 
@@ -252,12 +247,11 @@ struct Uniforms {
 
 private:
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & f;
-        ar & b;
-        ar & i;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& f;
+        ar& b;
+        ar& i;
     }
 };
 
@@ -305,16 +299,15 @@ private:
     u64 swizzle_data_hash = 0xDEADC0DE;
 
     friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive & ar, const unsigned int file_version)
-    {
-        ar & uniforms;
-        ar & program_code;
-        ar & swizzle_data;
-        ar & program_code_hash_dirty;
-        ar & swizzle_data_hash_dirty;
-        ar & program_code_hash;
-        ar & swizzle_data_hash;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {
+        ar& uniforms;
+        ar& program_code;
+        ar& swizzle_data;
+        ar& program_code_hash_dirty;
+        ar& swizzle_data_hash_dirty;
+        ar& program_code_hash;
+        ar& swizzle_data_hash;
     }
 };
 
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 5bc1e8702..a89b41e96 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -87,18 +87,15 @@ u16 GetResolutionScaleFactor() {
     }
 }
 
-void Save(std::ostream &stream)
-{
+void Save(std::ostream& stream) {
     oarchive oa{stream};
-    oa & Pica::g_state;
+    oa& Pica::g_state;
 }
 
-void Load(std::istream &stream)
-{
+void Load(std::istream& stream) {
     iarchive ia{stream};
-    ia & Pica::g_state;
+    ia& Pica::g_state;
     // TODO: Flush/reset things
-
 }
 
 } // namespace VideoCore
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 1ec69f802..10b0d39b6 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -4,8 +4,8 @@
 
 #pragma once
 
-#include <iostream>
 #include <atomic>
+#include <iostream>
 #include <memory>
 #include "core/frontend/emu_window.h"
 
@@ -62,7 +62,7 @@ void RequestScreenshot(void* data, std::function<void()> callback,
 
 u16 GetResolutionScaleFactor();
 
-void Save(std::ostream &stream);
-void Load(std::istream &stream);
+void Save(std::ostream& stream);
+void Load(std::istream& stream);
 
 } // namespace VideoCore

From d6862c2fca114c23be7a1f98b800d5b360d731a8 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 27 Dec 2019 22:45:00 +0000
Subject: [PATCH 034/129] Some CI fixes

---
 src/core/core.cpp                     | 4 ++--
 src/tests/core/hle/kernel/hle_ipc.cpp | 6 ++----
 2 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 6812a9474..5b9b4fca0 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -213,8 +213,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(
-        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
+                                                    [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index 62cad0e35..e405f6729 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -26,8 +26,7 @@ static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) {
 TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
     Core::Timing timing;
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(
-        memory, timing, [] {}, 0);
+    Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 
@@ -239,8 +238,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
 TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
     Core::Timing timing;
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(
-        memory, timing, [] {}, 0);
+    Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 

From c7106e232f1d042c6ba0a129b68e7e0e563d63ef Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Dec 2019 13:53:12 +0000
Subject: [PATCH 035/129] Fix a bug on mingw

---
 externals/boost                             |  2 +-
 src/core/hle/service/apt/applet_manager.cpp |  2 ++
 src/core/hle/service/apt/applet_manager.h   | 14 +++++---------
 3 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/externals/boost b/externals/boost
index 55725b779..1c857c041 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 55725b7796c7faa0a4af869e412d0410bd47612d
+Subproject commit 1c857c04195db89c66c347ddfad93a7f3666f2d3
diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp
index 8a24595ff..6612a720e 100644
--- a/src/core/hle/service/apt/applet_manager.cpp
+++ b/src/core/hle/service/apt/applet_manager.cpp
@@ -10,6 +10,8 @@
 #include "core/hle/service/apt/ns.h"
 #include "core/hle/service/cfg/cfg.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager)
+
 namespace Service::APT {
 
 enum class AppletPos { Application = 0, Library = 1, System = 2, SysLibrary = 3, Resident = 4 };
diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h
index e799c92d2..0f28e57c8 100644
--- a/src/core/hle/service/apt/applet_manager.h
+++ b/src/core/hle/service/apt/applet_manager.h
@@ -6,10 +6,10 @@
 
 #include <array>
 #include <memory>
-#include <optional>
 #include <vector>
 #include <boost/serialization/array.hpp>
-#include "common/serialization/optional.h"
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/optional.hpp>
 #include "core/global.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/result.h"
@@ -193,7 +193,8 @@ public:
 
 private:
     /// Parameter data to be returned in the next call to Glance/ReceiveParameter.
-    std::optional<MessageParameter> next_parameter;
+    // NOTE: A bug in gcc prevents serializing std::optional
+    boost::optional<MessageParameter> next_parameter;
 
     static constexpr std::size_t NumAppletSlot = 4;
 
@@ -268,9 +269,4 @@ private:
 
 } // namespace Service::APT
 
-namespace boost::serialization {
-template <class Archive>
-inline void load_construct_data(Archive& ar, Service::APT::AppletManager* t, const unsigned int) {
-    ::new (t) Service::APT::AppletManager(Core::Global<Core::System>());
-}
-} // namespace boost::serialization
+SERVICE_CONSTRUCT(Service::APT::AppletManager)

From d041901a3002b80eafc8a4b2ab955f8f6b23ecda Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Dec 2019 23:13:39 +0000
Subject: [PATCH 036/129] Some more CI fixes

---
 CMakeLists.txt                            |  4 +-
 TODO                                      |  3 +-
 src/CMakeLists.txt                        |  8 ++-
 src/common/CMakeLists.txt                 |  1 -
 src/common/serialization/optional.h       | 76 -----------------------
 src/core/hle/service/apt/applet_manager.h |  2 +-
 6 files changed, 11 insertions(+), 83 deletions(-)
 delete mode 100644 src/common/serialization/optional.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index df8081f05..ac05c91c7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -126,9 +126,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
 
 add_library(boost_libs INTERFACE)
 
-find_package(Boost 1.66.0 QUIET)
+find_package(Boost 1.70.0 QUIET EXACT)
 if (NOT Boost_FOUND)
-    message(STATUS "Boost 1.66.0 or newer not found, falling back to externals")
+    message(STATUS "Boost 1.70.0 not found, falling back to externals")
 
     set(BOOST_ROOT "${PROJECT_SOURCE_DIR}/externals/boost")
     set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
diff --git a/TODO b/TODO
index be118365d..45e6ae3b7 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,8 @@
 ✔ Memory @done(19-08-13 15:41)
     ☐ Page tables
     ☐ Skip N3DS RAM if unused
-☐ DSP
+✔ DSP @done(19-12-28 16:57)
+    Memory only
 ✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
     ✔ Fix or ignore inverse map @done(19-12-23 12:46)
 ☐ App loader
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4a4c39f17..c13337efe 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -33,7 +33,6 @@ if (MSVC)
     # /Zc:throwingNew     - Let codegen assume `operator new` (without std::nothrow) will never return null
     add_compile_options(
         /W3
-        /MP
         /Zi
         /Zo
         /permissive-
@@ -42,8 +41,13 @@ if (MSVC)
         /volatile:iso
         /Zc:externConstexpr
         /Zc:inline
-        /Zc:throwingNew
     )
+    if (CMAKE_C_COMPILER_ID MATCHES "MSVC")
+        add_compile_options(
+            /MP
+            /Zc:throwingNew
+        )
+    endif()
 
     # /GS- - No stack buffer overflow checks
     add_compile_options("$<$<CONFIG:Release>:/GS->")
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index ac745d868..39ddffbcc 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -96,7 +96,6 @@ add_library(common STATIC
     serialization/boost_discrete_interval.hpp
     serialization/boost_flat_set.h
     serialization/boost_vector.hpp
-    serialization/optional.h
     string_util.cpp
     string_util.h
     swap.h
diff --git a/src/common/serialization/optional.h b/src/common/serialization/optional.h
deleted file mode 100644
index 4e794058e..000000000
--- a/src/common/serialization/optional.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#pragma once
-
-#include <boost/config.hpp>
-
-#include <boost/archive/detail/basic_iarchive.hpp>
-
-#include <optional>
-#include <boost/move/utility_core.hpp>
-
-#include <boost/serialization/detail/is_default_constructible.hpp>
-#include <boost/serialization/detail/stack_constructor.hpp>
-#include <boost/serialization/force_include.hpp>
-#include <boost/serialization/item_version_type.hpp>
-#include <boost/serialization/level.hpp>
-#include <boost/serialization/nvp.hpp>
-#include <boost/serialization/split_free.hpp>
-#include <boost/serialization/version.hpp>
-#include <boost/type_traits/is_pointer.hpp>
-
-// function specializations must be defined in the appropriate
-// namespace - boost::serialization
-namespace boost {
-namespace serialization {
-
-template <class Archive, class T>
-void save(Archive& ar, const std::optional<T>& t, const unsigned int /*version*/
-) {
-// It is an inherent limitation to the serialization of optional.hpp
-// that the underlying type must be either a pointer or must have a
-// default constructor.  It's possible that this could change sometime
-// in the future, but for now, one will have to work around it.  This can
-// be done by serialization the optional<T> as optional<T *>
-#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)
-    BOOST_STATIC_ASSERT(boost::serialization::detail::is_default_constructible<T>::value ||
-                        boost::is_pointer<T>::value);
-#endif
-    const bool tflag = t.has_value();
-    ar << boost::serialization::make_nvp("initialized", tflag);
-    if (tflag) {
-        ar << boost::serialization::make_nvp("value", *t);
-    }
-}
-
-template <class Archive, class T>
-void load(Archive& ar, std::optional<T>& t, const unsigned int version) {
-    bool tflag;
-    ar >> boost::serialization::make_nvp("initialized", tflag);
-    if (!tflag) {
-        t.reset();
-        return;
-    }
-
-    if (0 == version) {
-        boost::serialization::item_version_type item_version(0);
-        boost::archive::library_version_type library_version(ar.get_library_version());
-        if (boost::archive::library_version_type(3) < library_version) {
-            ar >> BOOST_SERIALIZATION_NVP(item_version);
-        }
-    }
-    if (!t.has_value())
-        t = T();
-    ar >> boost::serialization::make_nvp("value", *t);
-}
-
-template <class Archive, class T>
-void serialize(Archive& ar, std::optional<T>& t, const unsigned int version) {
-    boost::serialization::split_free(ar, t, version);
-}
-
-template <class T>
-struct version<std::optional<T>> {
-    BOOST_STATIC_CONSTANT(int, value = 1);
-};
-
-} // namespace serialization
-} // namespace boost
diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h
index 0f28e57c8..7260fb2d3 100644
--- a/src/core/hle/service/apt/applet_manager.h
+++ b/src/core/hle/service/apt/applet_manager.h
@@ -8,8 +8,8 @@
 #include <memory>
 #include <vector>
 #include <boost/serialization/array.hpp>
-#include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/optional.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "core/global.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/result.h"

From a0ac302a93aad8a537fb31011c2f7abe1b95f052 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Dec 2019 23:36:12 +0000
Subject: [PATCH 037/129] Definitely disable using system boost if version
 doesn't match

---
 CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac05c91c7..163b8e7c2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -132,7 +132,7 @@ if (NOT Boost_FOUND)
 
     set(BOOST_ROOT "${PROJECT_SOURCE_DIR}/externals/boost")
     set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
-    set(Boost_NO_SYSTEM_PATHS OFF)
+    set(Boost_NO_SYSTEM_PATHS ON)
     add_definitions( -DBOOST_ALL_NO_LIB )
     find_package(Boost QUIET REQUIRED)
 

From 9877bf7d487ab8b7d1ac1110a2653c91a8e234be Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 00:51:06 +0000
Subject: [PATCH 038/129] Change how the boost target works; disable external
 warnings in  MSVC

---
 CMakeLists.txt                | 35 ++++++++++++++++-------------------
 externals/CMakeLists.txt      | 19 +++++++++++++++++++
 src/CMakeLists.txt            |  6 +++++-
 src/core/CMakeLists.txt       |  2 +-
 src/video_core/CMakeLists.txt |  2 +-
 5 files changed, 42 insertions(+), 22 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 163b8e7c2..0d42aba93 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,6 @@
 # CMake 3.8 required for 17 to be a valid value for CXX_STANDARD
 cmake_minimum_required(VERSION 3.8)
+cmake_policy(SET CMP0092 NEW)
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
 include(DownloadExternals)
@@ -35,6 +36,8 @@ CMAKE_DEPENDENT_OPTION(ENABLE_MF "Use Media Foundation decoder (preferred over F
 
 CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ON "MINGW" OFF)
 
+option(USE_SYSTEM_BOOST "Use the system Boost libs (instead of the bundled ones)" OFF)
+
 if(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit)
     message(STATUS "Copying pre-commit hook")
     file(COPY hooks/pre-commit
@@ -124,25 +127,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
 # System imported libraries
 # ======================
 
-add_library(boost_libs INTERFACE)
-
-find_package(Boost 1.70.0 QUIET EXACT)
-if (NOT Boost_FOUND)
-    message(STATUS "Boost 1.70.0 not found, falling back to externals")
-
-    set(BOOST_ROOT "${PROJECT_SOURCE_DIR}/externals/boost")
-    set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
-    set(Boost_NO_SYSTEM_PATHS ON)
-    add_definitions( -DBOOST_ALL_NO_LIB )
-    find_package(Boost QUIET REQUIRED)
-
-    # Boost external libraries
-    file(GLOB boost_serialization_SRC "externals/boost/libs/serialization/src/*.cpp")
-    add_library(boost_serialization STATIC ${boost_serialization_SRC})
-    target_link_libraries(boost_serialization PUBLIC Boost::boost)
-    target_link_libraries(boost_libs INTERFACE boost_serialization)
-endif()
-
 # Prefer the -pthread flag on Linux.
 set(THREADS_PREFER_PTHREAD_FLAG ON)
 find_package(Threads REQUIRED)
@@ -340,8 +324,21 @@ git_describe(GIT_DESC --always --long --dirty)
 git_branch_name(GIT_BRANCH)
 get_timestamp(BUILD_DATE)
 
+if (NOT USE_SYSTEM_BOOST)
+    add_definitions( -DBOOST_ALL_NO_LIB )
+endif()
+
 enable_testing()
 add_subdirectory(externals)
+
+# Boost
+if (USE_SYSTEM_BOOST)
+    find_package(Boost 1.70.0 QUIET REQUIRED)
+else()
+    add_library(Boost::boost ALIAS boost)
+    add_library(Boost::serialization ALIAS boost_serialization)
+endif()
+
 add_subdirectory(src)
 add_subdirectory(dist/installer)
 
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 63159a52b..47a92794c 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -1,9 +1,28 @@
 # Definitions for all external bundled libraries
 
+# Suppress warnings from external libraries
+if (CMAKE_C_COMPILER_ID MATCHES "MSVC")
+    add_compile_options(/W0)
+endif()
+
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
 include(DownloadExternals)
 include(ExternalProject)
 
+# Boost
+set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/boost")
+set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/boost")
+set(Boost_NO_SYSTEM_PATHS ON)
+add_library(boost INTERFACE)
+target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
+
+# Boost::serialization
+file(GLOB boost_serialization_SRC "${CMAKE_SOURCE_DIR}/externals/boost/libs/serialization/src/*.cpp")
+add_library(boost_serialization STATIC ${boost_serialization_SRC})
+target_link_libraries(boost_serialization PUBLIC boost)
+
+# Add additional boost libs here; remember to ALIAS them in the root CMakeLists!
+
 # Catch
 add_library(catch-single-include INTERFACE)
 target_include_directories(catch-single-include INTERFACE catch/single_include)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c13337efe..d46641570 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -37,7 +37,7 @@ if (MSVC)
         /Zo
         /permissive-
         /EHsc
-        /std:c++latest
+        /std:c++17
         /volatile:iso
         /Zc:externConstexpr
         /Zc:inline
@@ -46,6 +46,10 @@ if (MSVC)
         add_compile_options(
             /MP
             /Zc:throwingNew
+            /experimental:external
+            /external:I "${CMAKE_SOURCE_DIR}/externals"
+            /external:anglebrackets
+            /external:W0
         )
     endif()
 
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9ed9a856d..c6908c59a 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -466,7 +466,7 @@ endif()
 create_target_directory_groups(core)
 
 target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
-target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives boost_libs)
+target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives Boost::serialization)
 if (ENABLE_WEB_SERVICE)
     target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
     target_link_libraries(core PRIVATE web_service)
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 8dbf5d8e0..17e344aa4 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -94,7 +94,7 @@ endif()
 create_target_directory_groups(video_core)
 
 target_link_libraries(video_core PUBLIC common core)
-target_link_libraries(video_core PRIVATE glad nihstro-headers boost_libs)
+target_link_libraries(video_core PRIVATE glad nihstro-headers Boost::serialization)
 
 if (ARCHITECTURE_x86_64)
     target_link_libraries(video_core PUBLIC xbyak)

From 754f63af1a1f027fbfd213c190b937f66dadf89f Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 10:23:20 +0000
Subject: [PATCH 039/129] Don't require cmake 3.15

---
 CMakeLists.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0d42aba93..f986a39af 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,8 @@
 # CMake 3.8 required for 17 to be a valid value for CXX_STANDARD
 cmake_minimum_required(VERSION 3.8)
-cmake_policy(SET CMP0092 NEW)
+if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
+    cmake_policy(SET CMP0092 NEW)
+endif ()
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
 include(DownloadExternals)

From 30494c06a4c8f4277a6919869975e78b001092fd Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 12:45:22 +0000
Subject: [PATCH 040/129] Serialize GSP service

---
 TODO                                 |  3 ++-
 src/core/hle/service/gsp/gsp.cpp     |  2 +-
 src/core/hle/service/gsp/gsp_gpu.cpp |  5 +++++
 src/core/hle/service/gsp/gsp_gpu.h   | 24 ++++++++++++++++++++++++
 src/core/hle/service/gsp/gsp_lcd.cpp |  3 +++
 src/core/hle/service/gsp/gsp_lcd.h   |  2 ++
 6 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index 45e6ae3b7..fa627b214 100644
--- a/TODO
+++ b/TODO
@@ -81,7 +81,8 @@
         ✔ ERR @done(19-12-26 18:14)
         ✔ FRD @done(19-12-26 19:09)
         ✔ FS @done(19-12-27 11:46)
-        ☐ GSP
+        ✔ GSP @done(19-12-30 12:45)
+            ☐ Fix the global weak_ptr to gsp
         ☐ HID
         ☐ HTTP
         ☐ IR
diff --git a/src/core/hle/service/gsp/gsp.cpp b/src/core/hle/service/gsp/gsp.cpp
index 4291b9971..3d3f497b2 100644
--- a/src/core/hle/service/gsp/gsp.cpp
+++ b/src/core/hle/service/gsp/gsp.cpp
@@ -10,7 +10,7 @@
 
 namespace Service::GSP {
 
-static std::weak_ptr<GSP_GPU> gsp_gpu;
+static std::weak_ptr<GSP_GPU> gsp_gpu; // TODO: Fix this for the love of god
 
 void SignalInterrupt(InterruptId interrupt_id) {
     auto gpu = gsp_gpu.lock();
diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp
index 33558fe10..78d84499b 100644
--- a/src/core/hle/service/gsp/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp/gsp_gpu.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <vector>
+#include "common/archives.h"
 #include "common/bit_field.h"
 #include "common/microprofile.h"
 #include "common/swap.h"
@@ -21,6 +22,10 @@
 #include "video_core/debug_utils/debug_utils.h"
 #include "video_core/gpu_debugger.h"
 
+SERIALIZE_EXPORT_IMPL(Service::GSP::SessionData)
+SERIALIZE_EXPORT_IMPL(Service::GSP::GSP_GPU)
+SERVICE_CONSTRUCT_IMPL(Service::GSP::GSP_GPU)
+
 // Main graphics debugger object - TODO: Here is probably not the best place for this
 GraphicsDebugger g_debugger;
 
diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h
index 8b43b9cea..d1f2c0742 100644
--- a/src/core/hle/service/gsp/gsp_gpu.h
+++ b/src/core/hle/service/gsp/gsp_gpu.h
@@ -199,6 +199,16 @@ public:
     u32 thread_id;
     /// Whether RegisterInterruptRelayQueue was called for this session
     bool registered = false;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& gsp;
+        ar& interrupt_event;
+        ar& thread_id;
+        ar& registered;
+    }
+    friend class boost::serialization::access;
 };
 
 class GSP_GPU final : public ServiceFramework<GSP_GPU, SessionData> {
@@ -431,8 +441,22 @@ private:
     std::array<bool, MaxGSPThreads> used_thread_ids = {false, false, false, false};
 
     friend class SessionData;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& shared_memory;
+        ar& active_thread_id;
+        ar& first_initialization;
+        ar& used_thread_ids;
+    }
+
+    friend class boost::serialization::access;
 };
 
 ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
 
 } // namespace Service::GSP
+
+BOOST_CLASS_EXPORT_KEY(Service::GSP::SessionData)
+BOOST_CLASS_EXPORT_KEY(Service::GSP::GSP_GPU)
+SERVICE_CONSTRUCT(Service::GSP::GSP_GPU)
diff --git a/src/core/hle/service/gsp/gsp_lcd.cpp b/src/core/hle/service/gsp/gsp_lcd.cpp
index d795b8716..67a2e7628 100644
--- a/src/core/hle/service/gsp/gsp_lcd.cpp
+++ b/src/core/hle/service/gsp/gsp_lcd.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/gsp/gsp_lcd.h"
 
+SERIALIZE_EXPORT_IMPL(Service::GSP::GSP_LCD)
+
 namespace Service::GSP {
 
 GSP_LCD::GSP_LCD() : ServiceFramework("gsp::Lcd") {
diff --git a/src/core/hle/service/gsp/gsp_lcd.h b/src/core/hle/service/gsp/gsp_lcd.h
index 24e57fb42..781d9dba8 100644
--- a/src/core/hle/service/gsp/gsp_lcd.h
+++ b/src/core/hle/service/gsp/gsp_lcd.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::GSP
+
+BOOST_CLASS_EXPORT_KEY(Service::GSP::GSP_LCD)

From 74361fa3fbed7ab4669c59e84619fda501180ece Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 14:46:35 +0000
Subject: [PATCH 041/129] Serialize HID service

---
 TODO                                  |  2 +-
 src/core/hle/service/hid/hid.cpp      | 25 +++++++++++++++++++++++++
 src/core/hle/service/hid/hid.h        |  9 ++++++++-
 src/core/hle/service/hid/hid_spvr.cpp |  3 +++
 src/core/hle/service/hid/hid_spvr.h   |  5 +++++
 src/core/hle/service/hid/hid_user.cpp |  3 +++
 src/core/hle/service/hid/hid_user.h   |  5 +++++
 7 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index fa627b214..51cbc627c 100644
--- a/TODO
+++ b/TODO
@@ -83,7 +83,7 @@
         ✔ FS @done(19-12-27 11:46)
         ✔ GSP @done(19-12-30 12:45)
             ☐ Fix the global weak_ptr to gsp
-        ☐ HID
+        ✔ HID @done(19-12-30 14:46)
         ☐ HTTP
         ☐ IR
         ☐ LDR_RO
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index ded1809b1..f20cebca7 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <cmath>
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/3ds.h"
 #include "core/core.h"
@@ -20,8 +21,32 @@
 #include "core/movie.h"
 #include "video_core/video_core.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::HID::Module)
+SERIALIZE_EXPORT_IMPL(Service::HID::Module)
+
 namespace Service::HID {
 
+template <class Archive>
+void Module::serialize(Archive& ar, const unsigned int) {
+    ar& shared_mem;
+    ar& event_pad_or_touch_1;
+    ar& event_pad_or_touch_2;
+    ar& event_accelerometer;
+    ar& event_gyroscope;
+    ar& event_debug_pad;
+    ar& next_pad_index;
+    ar& next_touch_index;
+    ar& next_accelerometer_index;
+    ar& next_gyroscope_index;
+    ar& enable_accelerometer_count;
+    ar& enable_gyroscope_count;
+    ReloadInputDevices();
+    // Pad state not needed as it's always updated
+    // Update events are set in the constructor
+    // Devices are set from the implementation (and are stateless afaik)
+}
+SERIALIZE_IMPL(Module)
+
 // Updating period for each HID device. These empirical values are measured from a 11.2 3DS.
 constexpr u64 pad_update_ticks = BASE_CLOCK_RATE_ARM11 / 234;
 constexpr u64 accelerometer_update_ticks = BASE_CLOCK_RATE_ARM11 / 104;
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 8d217f835..e34c1186a 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -294,7 +294,7 @@ public:
          */
         void GetGyroscopeLowCalibrateParam(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> hid;
     };
 
@@ -342,9 +342,16 @@ private:
     std::unique_ptr<Input::AnalogDevice> circle_pad;
     std::unique_ptr<Input::MotionDevice> motion_device;
     std::unique_ptr<Input::TouchDevice> touch_device;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 std::shared_ptr<Module> GetModule(Core::System& system);
 
 void InstallInterfaces(Core::System& system);
 } // namespace Service::HID
+
+SERVICE_CONSTRUCT(Service::HID::Module)
+BOOST_CLASS_EXPORT_KEY(Service::HID::Module)
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
index 8371a6169..87791f073 100644
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ b/src/core/hle/service/hid/hid_spvr.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/hid/hid_spvr.h"
 
+SERIALIZE_EXPORT_IMPL(Service::HID::Spvr)
+
 namespace Service::HID {
 
 Spvr::Spvr(std::shared_ptr<Module> hid) : Module::Interface(std::move(hid), "hid:SPVR", 6) {
diff --git a/src/core/hle/service/hid/hid_spvr.h b/src/core/hle/service/hid/hid_spvr.h
index e2346dda5..a49101dc3 100644
--- a/src/core/hle/service/hid/hid_spvr.h
+++ b/src/core/hle/service/hid/hid_spvr.h
@@ -11,6 +11,11 @@ namespace Service::HID {
 class Spvr final : public Module::Interface {
 public:
     explicit Spvr(std::shared_ptr<Module> hid);
+private:
+    SERVICE_SERIALIZATION(Spvr, hid, Module)
 };
 
 } // namespace Service::HID
+
+BOOST_CLASS_EXPORT_KEY(Service::HID::Spvr)
+BOOST_SERIALIZATION_CONSTRUCT(Service::HID::Spvr)
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp
index 129b3fd02..97ce8f111 100644
--- a/src/core/hle/service/hid/hid_user.cpp
+++ b/src/core/hle/service/hid/hid_user.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/hid/hid_user.h"
 
+SERIALIZE_EXPORT_IMPL(Service::HID::User)
+
 namespace Service::HID {
 
 User::User(std::shared_ptr<Module> hid) : Module::Interface(std::move(hid), "hid:USER", 6) {
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
index 813f09504..6fd9803c6 100644
--- a/src/core/hle/service/hid/hid_user.h
+++ b/src/core/hle/service/hid/hid_user.h
@@ -14,6 +14,11 @@ namespace Service::HID {
 class User final : public Module::Interface {
 public:
     explicit User(std::shared_ptr<Module> hid);
+private:
+    SERVICE_SERIALIZATION(User, hid, Module)
 };
 
 } // namespace Service::HID
+
+BOOST_CLASS_EXPORT_KEY(Service::HID::User)
+BOOST_SERIALIZATION_CONSTRUCT(Service::HID::User)

From 8bd3e8cd27363dda33871baad57f204cc348bd43 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 15:20:13 +0000
Subject: [PATCH 042/129] Serialize HTTP service

---
 TODO                            |   2 +-
 externals/boost                 |   2 +-
 src/core/hle/service/http_c.cpp |   4 +
 src/core/hle/service/http_c.h   | 128 +++++++++++++++++++++++++++++++-
 4 files changed, 130 insertions(+), 6 deletions(-)

diff --git a/TODO b/TODO
index 51cbc627c..f72330fd1 100644
--- a/TODO
+++ b/TODO
@@ -84,7 +84,7 @@
         ✔ GSP @done(19-12-30 12:45)
             ☐ Fix the global weak_ptr to gsp
         ✔ HID @done(19-12-30 14:46)
-        ☐ HTTP
+        ✔ HTTP @done(19-12-30 15:18)
         ☐ IR
         ☐ LDR_RO
         ☐ MIC
diff --git a/externals/boost b/externals/boost
index 1c857c041..65dc954e9 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 1c857c04195db89c66c347ddfad93a7f3666f2d3
+Subproject commit 65dc954e93b22870b8423701e225147c75e3b31b
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp
index 221f3cc20..768dd3bd8 100644
--- a/src/core/hle/service/http_c.cpp
+++ b/src/core/hle/service/http_c.cpp
@@ -4,6 +4,7 @@
 
 #include <cryptopp/aes.h>
 #include <cryptopp/modes.h>
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/file_sys/archive_ncch.h"
 #include "core/file_sys/file_backend.h"
@@ -14,6 +15,9 @@
 #include "core/hle/service/http_c.h"
 #include "core/hw/aes/key.h"
 
+SERIALIZE_EXPORT_IMPL(Service::HTTP::HTTP_C)
+SERIALIZE_EXPORT_IMPL(Service::HTTP::SessionData)
+
 namespace Service::HTTP {
 
 namespace ErrCodes {
diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h
index 91a455820..a3aa62ae0 100644
--- a/src/core/hle/service/http_c.h
+++ b/src/core/hle/service/http_c.h
@@ -5,10 +5,16 @@
 #pragma once
 
 #include <memory>
-#include <optional>
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include <boost/optional.hpp>
+#include <boost/serialization/optional.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/unordered_map.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/weak_ptr.hpp>
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/service/service.h"
 
@@ -50,6 +56,17 @@ struct ClientCertContext {
     u8 cert_id;
     std::vector<u8> certificate;
     std::vector<u8> private_key;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& handle;
+        ar& session_id;
+        ar& cert_id;
+        ar& certificate;
+        ar& private_key;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Represents a root certificate chain, it contains a list of DER-encoded certificates for
@@ -61,12 +78,30 @@ struct RootCertChain {
         Handle handle;
         u32 session_id;
         std::vector<u8> certificate;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& handle;
+            ar& session_id;
+            ar& certificate;
+        }
+        friend class boost::serialization::access;
     };
 
     using Handle = u32;
     Handle handle;
     u32 session_id;
     std::vector<RootCACert> certificates;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& handle;
+        ar& session_id;
+        ar& certificates;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Represents an HTTP context.
@@ -86,30 +121,74 @@ public:
         std::string username;
         std::string password;
         u16 port;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& url;
+            ar& username;
+            ar& password;
+            ar& port;
+        }
+        friend class boost::serialization::access;
     };
 
     struct BasicAuth {
         std::string username;
         std::string password;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& username;
+            ar& password;
+        }
+        friend class boost::serialization::access;
     };
 
     struct RequestHeader {
         RequestHeader(std::string name, std::string value) : name(name), value(value){};
         std::string name;
         std::string value;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& name;
+            ar& value;
+        }
+        friend class boost::serialization::access;
     };
 
     struct PostData {
         // TODO(Subv): Support Binary and Raw POST elements.
         PostData(std::string name, std::string value) : name(name), value(value){};
+        PostData() = default;
         std::string name;
         std::string value;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& name;
+            ar& value;
+        }
+        friend class boost::serialization::access;
     };
 
     struct SSLConfig {
         u32 options;
         std::weak_ptr<ClientCertContext> client_cert_ctx;
         std::weak_ptr<RootCertChain> root_ca_chain;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& options;
+            ar& client_cert_ctx;
+            ar& root_ca_chain;
+        }
+        friend class boost::serialization::access;
     };
 
     Handle handle;
@@ -117,18 +196,35 @@ public:
     std::string url;
     RequestMethod method;
     RequestState state = RequestState::NotStarted;
-    std::optional<Proxy> proxy;
-    std::optional<BasicAuth> basic_auth;
+    boost::optional<Proxy> proxy;
+    boost::optional<BasicAuth> basic_auth;
     SSLConfig ssl_config{};
     u32 socket_buffer_size;
     std::vector<RequestHeader> headers;
     std::vector<PostData> post_data;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& handle;
+        ar& session_id;
+        ar& url;
+        ar& method;
+        ar& state;
+        ar& proxy;
+        ar& basic_auth;
+        ar& ssl_config;
+        ar& socket_buffer_size;
+        ar& headers;
+        ar& post_data;
+    }
+    friend class boost::serialization::access;
 };
 
 struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
     /// The HTTP context that is currently bound to this session, this can be empty if no context
     /// has been bound. Certain commands can only be called on a session with a bound context.
-    std::optional<Context::Handle> current_http_context;
+    boost::optional<Context::Handle> current_http_context;
 
     u32 session_id;
 
@@ -140,6 +236,17 @@ struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
     /// Whether this session has been initialized in some way, be it via Initialize or
     /// InitializeConnectionSession.
     bool initialized = false;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& current_http_context;
+        ar& session_id;
+        ar& num_http_contexts;
+        ar& num_client_certs;
+        ar& initialized;
+    }
+    friend class boost::serialization::access;
 };
 
 class HTTP_C final : public ServiceFramework<HTTP_C, SessionData> {
@@ -326,8 +433,21 @@ private:
         std::vector<u8> private_key;
         bool init = false;
     } ClCertA;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar& ClCertA.certificate;
+        ar& ClCertA.private_key;
+        ar& ClCertA.init;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::HTTP
+
+BOOST_CLASS_EXPORT_KEY(Service::HTTP::HTTP_C)
+BOOST_CLASS_EXPORT_KEY(Service::HTTP::SessionData)

From eb67167b7c9b9262b0c6ce7b5c99732d228a3f8d Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 16:07:03 +0000
Subject: [PATCH 043/129] Serialize IR service

---
 TODO                                |  2 +-
 src/core/hle/service/ir/extra_hid.h | 12 +++++++
 src/core/hle/service/ir/ir_user.cpp | 51 ++++++++++++++++++++++++-----
 src/core/hle/service/ir/ir_user.h   |  9 ++++-
 4 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/TODO b/TODO
index f72330fd1..b679a5168 100644
--- a/TODO
+++ b/TODO
@@ -85,7 +85,7 @@
             ☐ Fix the global weak_ptr to gsp
         ✔ HID @done(19-12-30 14:46)
         ✔ HTTP @done(19-12-30 15:18)
-        ☐ IR
+        ✔ IR @done(19-12-30 16:06)
         ☐ LDR_RO
         ☐ MIC
         ☐ MVD
diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h
index d21cb393f..7924a1e12 100644
--- a/src/core/hle/service/ir/extra_hid.h
+++ b/src/core/hle/service/ir/extra_hid.h
@@ -6,6 +6,8 @@
 
 #include <array>
 #include <atomic>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/bit_field.h"
 #include "common/swap.h"
 #include "core/frontend/input.h"
@@ -65,6 +67,16 @@ private:
     std::unique_ptr<Input::ButtonDevice> zr;
     std::unique_ptr<Input::AnalogDevice> c_stick;
     std::atomic<bool> is_device_reload_pending;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& hid_period;
+        ar& calibration_data; // This isn't writeable for now, but might be in future
+        RequestInputDevicesReload(); // zl, zr, c_stick are loaded here
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::IR
+
+BOOST_CLASS_EXPORT_KEY(Service::IR::ExtraHID)
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
index d392c1983..fd6c1b905 100644
--- a/src/core/hle/service/ir/ir_user.cpp
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -15,6 +15,19 @@
 
 namespace Service::IR {
 
+template <class Archive>
+void IR_USER::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    ar& conn_status_event;
+    ar& send_event;
+    ar& receive_event;
+    ar& shared_memory;
+    ar& connected_device;
+    ar& *receive_buffer.get();
+    ar& *extra_hid.get();
+}
+SERIALIZE_IMPL(IR_USER)
+
 // This is a header that will present in the ir:USER shared memory if it is initialized with
 // InitializeIrNopShared service function. Otherwise the shared memory doesn't have this header if
 // it is initialized with InitializeIrNop service function.
@@ -139,6 +152,16 @@ private:
         u32_le end_index;
         u32_le packet_count;
         u32_le unknown;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& begin_index;
+            ar& end_index;
+            ar& packet_count;
+            ar& unknown;
+        }
+        friend class boost::serialization::access;
     };
     static_assert(sizeof(BufferInfo) == 16, "BufferInfo has wrong size!");
 
@@ -179,6 +202,18 @@ private:
     u32 buffer_offset;
     u32 max_packet_count;
     u32 max_data_size;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& info;
+        ar& shared_memory;
+        ar& info_offset;
+        ar& buffer_offset;
+        ar& max_packet_count;
+        ar& max_data_size;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Wraps the payload into packet and puts it to the receive buffer
@@ -270,8 +305,8 @@ void IR_USER::RequireConnection(Kernel::HLERequestContext& ctx) {
         shared_memory_ptr[offsetof(SharedMemoryHeader, connection_role)] = 2;
         shared_memory_ptr[offsetof(SharedMemoryHeader, connected)] = 1;
 
-        connected_device = extra_hid.get();
-        connected_device->OnConnect();
+        connected_device = true;
+        extra_hid->OnConnect();
         conn_status_event->Signal();
     } else {
         LOG_WARNING(Service_IR, "unknown device id {}. Won't connect.", device_id);
@@ -305,8 +340,8 @@ void IR_USER::GetSendEvent(Kernel::HLERequestContext& ctx) {
 
 void IR_USER::Disconnect(Kernel::HLERequestContext& ctx) {
     if (connected_device) {
-        connected_device->OnDisconnect();
-        connected_device = nullptr;
+        extra_hid->OnDisconnect();
+        connected_device = false;
         conn_status_event->Signal();
     }
 
@@ -331,8 +366,8 @@ void IR_USER::GetConnectionStatusEvent(Kernel::HLERequestContext& ctx) {
 
 void IR_USER::FinalizeIrNop(Kernel::HLERequestContext& ctx) {
     if (connected_device) {
-        connected_device->OnDisconnect();
-        connected_device = nullptr;
+        extra_hid->OnDisconnect();
+        connected_device = false;
     }
 
     shared_memory = nullptr;
@@ -352,7 +387,7 @@ void IR_USER::SendIrNop(Kernel::HLERequestContext& ctx) {
 
     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
     if (connected_device) {
-        connected_device->OnReceive(buffer);
+        extra_hid->OnReceive(buffer);
         send_event->Signal();
         rb.Push(RESULT_SUCCESS);
     } else {
@@ -424,7 +459,7 @@ IR_USER::IR_USER(Core::System& system) : ServiceFramework("ir:USER", 1) {
 
 IR_USER::~IR_USER() {
     if (connected_device) {
-        connected_device->OnDisconnect();
+        extra_hid->OnDisconnect();
     }
 }
 
diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h
index 54a4f3e08..75bbeb779 100644
--- a/src/core/hle/service/ir/ir_user.h
+++ b/src/core/hle/service/ir/ir_user.h
@@ -7,6 +7,7 @@
 #include <functional>
 #include <memory>
 #include <vector>
+#include <boost/serialization/shared_ptr.hpp>
 #include "core/hle/service/service.h"
 
 namespace Kernel {
@@ -45,6 +46,7 @@ protected:
     void Send(const std::vector<u8>& data);
 
 private:
+    // NOTE: This value is *not* serialized because it's always passed in the constructor
     const SendFunc send_func;
 };
 
@@ -164,9 +166,14 @@ private:
 
     std::shared_ptr<Kernel::Event> conn_status_event, send_event, receive_event;
     std::shared_ptr<Kernel::SharedMemory> shared_memory;
-    IRDevice* connected_device{nullptr};
+    bool connected_device;
     std::unique_ptr<BufferManager> receive_buffer;
     std::unique_ptr<ExtraHID> extra_hid;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::IR

From e3c0211b7418a78f43722376305593472c27e574 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 16:15:41 +0000
Subject: [PATCH 044/129] Fix clang format

---
 src/core/hle/service/hid/hid_spvr.h | 1 +
 src/core/hle/service/hid/hid_user.h | 1 +
 2 files changed, 2 insertions(+)

diff --git a/src/core/hle/service/hid/hid_spvr.h b/src/core/hle/service/hid/hid_spvr.h
index a49101dc3..749bd36b8 100644
--- a/src/core/hle/service/hid/hid_spvr.h
+++ b/src/core/hle/service/hid/hid_spvr.h
@@ -11,6 +11,7 @@ namespace Service::HID {
 class Spvr final : public Module::Interface {
 public:
     explicit Spvr(std::shared_ptr<Module> hid);
+
 private:
     SERVICE_SERIALIZATION(Spvr, hid, Module)
 };
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
index 6fd9803c6..8a6763ea6 100644
--- a/src/core/hle/service/hid/hid_user.h
+++ b/src/core/hle/service/hid/hid_user.h
@@ -14,6 +14,7 @@ namespace Service::HID {
 class User final : public Module::Interface {
 public:
     explicit User(std::shared_ptr<Module> hid);
+
 private:
     SERVICE_SERIALIZATION(User, hid, Module)
 };

From 01ec2e8a67999afbacacdb00eb5ed507ac9b1b73 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 16:53:57 +0000
Subject: [PATCH 045/129] Serialize MIC service

---
 TODO                                   |  4 +--
 src/core/hle/service/ldr_ro/ldr_ro.cpp |  4 +++
 src/core/hle/service/ldr_ro/ldr_ro.h   | 18 ++++++++++++
 src/core/hle/service/mic_u.cpp         | 40 ++++++++++++++++++++++++++
 src/core/hle/service/mic_u.h           |  7 +++++
 5 files changed, 71 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index b679a5168..2aff6ae68 100644
--- a/TODO
+++ b/TODO
@@ -86,8 +86,8 @@
         ✔ HID @done(19-12-30 14:46)
         ✔ HTTP @done(19-12-30 15:18)
         ✔ IR @done(19-12-30 16:06)
-        ☐ LDR_RO
-        ☐ MIC
+        ✔ LDR_RO @done(19-12-30 16:25)
+        ✔ MIC @done(19-12-30 16:53)
         ☐ MVD
         ☐ NDM
         ☐ NEWS
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp
index caa063593..0a61f4c23 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include "common/alignment.h"
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "core/arm/arm_interface.h"
@@ -12,6 +13,9 @@
 #include "core/hle/service/ldr_ro/cro_helper.h"
 #include "core/hle/service/ldr_ro/ldr_ro.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::LDR::RO)
+SERIALIZE_EXPORT_IMPL(Service::LDR::RO)
+
 namespace Service::LDR {
 
 static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h
index f90005d13..2b6f79f03 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.h
+++ b/src/core/hle/service/ldr_ro/ldr_ro.h
@@ -14,6 +14,13 @@ namespace Service::LDR {
 
 struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
     VAddr loaded_crs = 0; ///< the virtual address of the static module
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& loaded_crs;
+    }
+    friend class boost::serialization::access;
 };
 
 class RO final : public ServiceFramework<RO, ClientSlot> {
@@ -151,8 +158,19 @@ private:
     void Shutdown(Kernel::HLERequestContext& self);
 
     Core::System& system;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::LDR
+
+SERVICE_CONSTRUCT(Service::LDR::RO)
+BOOST_CLASS_EXPORT_KEY(Service::LDR::RO)
+BOOST_CLASS_EXPORT_KEY(Service::LDR::ClientSlot)
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index ba3e97807..34b16094a 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -5,6 +5,7 @@
 #ifdef HAVE_CUBEB
 #include "audio_core/cubeb_input.h"
 #endif
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/frontend/mic.h"
@@ -17,8 +18,17 @@
 #include "core/hle/service/mic_u.h"
 #include "core/settings.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::MIC::MIC_U)
+SERIALIZE_EXPORT_IMPL(Service::MIC::MIC_U)
+
 namespace Service::MIC {
 
+template <class Archive>
+void MIC_U::serialize(Archive& ar, const unsigned int) {
+    ar&* impl.get();
+}
+SERIALIZE_IMPL(MIC_U)
+
 /// Microphone audio encodings.
 enum class Encoding : u8 {
     PCM8 = 0,        ///< Unsigned 8-bit PCM.
@@ -59,6 +69,7 @@ constexpr u64 GetBufferUpdateRate(SampleRate sample_rate) {
 
 // Variables holding the current mic buffer writing state
 struct State {
+    std::shared_ptr<Kernel::SharedMemory> memory_ref = nullptr;
     u8* sharedmem_buffer = nullptr;
     u32 sharedmem_size = 0;
     std::size_t size = 0;
@@ -95,6 +106,20 @@ struct State {
         std::memcpy(sharedmem_buffer + (sharedmem_size - sizeof(u32)), reinterpret_cast<u8*>(&off),
                     sizeof(u32));
     }
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& sharedmem_size;
+        ar& size;
+        ar& offset;
+        ar& initial_offset;
+        ar& looped_buffer;
+        ar& sample_size;
+        ar& sample_rate;
+        sharedmem_buffer = memory_ref ? memory_ref->GetPointer() : nullptr;
+    }
+    friend class boost::serialization::access;
 };
 
 struct MIC_U::Impl {
@@ -363,6 +388,21 @@ struct MIC_U::Impl {
     std::unique_ptr<Frontend::Mic::Interface> mic;
     Core::Timing& timing;
     State state{};
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& change_mic_impl_requested;
+        ar& buffer_full_event;
+        // buffer_write_event set in constructor
+        ar& shared_memory;
+        ar& client_version;
+        ar& allow_shell_closed;
+        ar& clamp;
+        // mic interface set in constructor
+        ar& state;
+    }
+    friend class boost::serialization::access;
 };
 
 void MIC_U::MapSharedMem(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h
index 2e40ed404..2ca95e924 100644
--- a/src/core/hle/service/mic_u.h
+++ b/src/core/hle/service/mic_u.h
@@ -190,6 +190,10 @@ private:
 
     struct Impl;
     std::unique_ptr<Impl> impl;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 void ReloadMic(Core::System& system);
@@ -197,3 +201,6 @@ void ReloadMic(Core::System& system);
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::MIC
+
+SERVICE_CONSTRUCT(Service::MIC::MIC_U)
+BOOST_CLASS_EXPORT_KEY(Service::MIC::MIC_U)

From 3d6e372f96228fca0dfb17dc8b058af9088beefb Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 30 Dec 2019 17:02:44 +0000
Subject: [PATCH 046/129] More clang format fixes. Really need to standardise
 the version of this

---
 src/core/hle/service/ir/extra_hid.h | 2 +-
 src/core/hle/service/ir/ir_user.cpp | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h
index 7924a1e12..1be403167 100644
--- a/src/core/hle/service/ir/extra_hid.h
+++ b/src/core/hle/service/ir/extra_hid.h
@@ -71,7 +71,7 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& hid_period;
-        ar& calibration_data; // This isn't writeable for now, but might be in future
+        ar& calibration_data;        // This isn't writeable for now, but might be in future
         RequestInputDevicesReload(); // zl, zr, c_stick are loaded here
     }
     friend class boost::serialization::access;
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
index fd6c1b905..64a298103 100644
--- a/src/core/hle/service/ir/ir_user.cpp
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -23,8 +23,8 @@ void IR_USER::serialize(Archive& ar, const unsigned int) {
     ar& receive_event;
     ar& shared_memory;
     ar& connected_device;
-    ar& *receive_buffer.get();
-    ar& *extra_hid.get();
+    ar&* receive_buffer.get();
+    ar&* extra_hid.get();
 }
 SERIALIZE_IMPL(IR_USER)
 

From 2409ee39cbafd6631a5ed1f45f8d0f9c2ccd94ee Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 31 Dec 2019 20:39:38 +0000
Subject: [PATCH 047/129] Serialize IR, MVD, NDM, NEWS, NFC

---
 TODO                                 |  8 ++++----
 src/core/hle/service/ir/ir_rst.cpp   | 17 +++++++++++++++++
 src/core/hle/service/ir/ir_rst.h     |  7 +++++++
 src/core/hle/service/ir/ir_u.cpp     |  3 +++
 src/core/hle/service/ir/ir_u.h       |  2 ++
 src/core/hle/service/mvd/mvd_std.cpp |  3 +++
 src/core/hle/service/mvd/mvd_std.h   |  9 +++++++++
 src/core/hle/service/ndm/ndm_u.cpp   |  3 +++
 src/core/hle/service/ndm/ndm_u.h     | 15 +++++++++++++++
 src/core/hle/service/news/news_s.cpp |  3 +++
 src/core/hle/service/news/news_s.h   |  2 ++
 src/core/hle/service/news/news_u.cpp |  3 +++
 src/core/hle/service/news/news_u.h   |  2 ++
 src/core/hle/service/nfc/nfc.cpp     | 13 +++++++++++++
 src/core/hle/service/nfc/nfc.h       |  9 ++++++++-
 src/core/hle/service/nfc/nfc_m.cpp   |  3 +++
 src/core/hle/service/nfc/nfc_m.h     |  6 ++++++
 src/core/hle/service/nfc/nfc_u.cpp   |  3 +++
 src/core/hle/service/nfc/nfc_u.h     |  6 ++++++
 19 files changed, 112 insertions(+), 5 deletions(-)

diff --git a/TODO b/TODO
index 2aff6ae68..f9fffa60d 100644
--- a/TODO
+++ b/TODO
@@ -88,10 +88,10 @@
         ✔ IR @done(19-12-30 16:06)
         ✔ LDR_RO @done(19-12-30 16:25)
         ✔ MIC @done(19-12-30 16:53)
-        ☐ MVD
-        ☐ NDM
-        ☐ NEWS
-        ☐ NFC
+        ✔ MVD @done(19-12-31 18:26)
+        ✔ NDM @done(19-12-31 18:26)
+        ✔ NEWS @done(19-12-31 18:29)
+        ✔ NFC @done(19-12-31 20:35)
         ☐ NIM
         ☐ NS
         ☐ NWM
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
index 71d16a1ce..dc9612e62 100644
--- a/src/core/hle/service/ir/ir_rst.cpp
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/hle/ipc_helpers.h"
@@ -12,8 +13,24 @@
 #include "core/movie.h"
 #include "core/settings.h"
 
+SERIALIZE_EXPORT_IMPL(Service::IR::IR_RST)
+SERVICE_CONSTRUCT_IMPL(Service::IR::IR_RST)
+
 namespace Service::IR {
 
+template <class Archive>
+void IR_RST::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    ar& update_event;
+    ar& shared_memory;
+    ar& next_pad_index;
+    ar& raw_c_stick;
+    ar& update_period;
+    // update_callback_id and input devices are set separately
+    ReloadInputDevices();
+}
+SERIALIZE_IMPL(IR_RST)
+
 struct PadDataEntry {
     PadState current_state;
     PadState delta_additions;
diff --git a/src/core/hle/service/ir/ir_rst.h b/src/core/hle/service/ir/ir_rst.h
index 84ad70dfc..8e17381ad 100644
--- a/src/core/hle/service/ir/ir_rst.h
+++ b/src/core/hle/service/ir/ir_rst.h
@@ -87,6 +87,13 @@ private:
     std::atomic<bool> is_device_reload_pending{false};
     bool raw_c_stick{false};
     int update_period{0};
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::IR
+
+BOOST_CLASS_EXPORT_KEY(Service::IR::IR_RST)
+SERVICE_CONSTRUCT(Service::IR::IR_RST)
diff --git a/src/core/hle/service/ir/ir_u.cpp b/src/core/hle/service/ir/ir_u.cpp
index d76323e91..61618869a 100644
--- a/src/core/hle/service/ir/ir_u.cpp
+++ b/src/core/hle/service/ir/ir_u.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/ir/ir_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::IR::IR_U)
+
 namespace Service::IR {
 
 IR_U::IR_U() : ServiceFramework("ir:u", 1) {
diff --git a/src/core/hle/service/ir/ir_u.h b/src/core/hle/service/ir/ir_u.h
index ea150b082..eaa54c657 100644
--- a/src/core/hle/service/ir/ir_u.h
+++ b/src/core/hle/service/ir/ir_u.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::IR
+
+BOOST_CLASS_EXPORT_KEY(Service::IR::IR_U)
diff --git a/src/core/hle/service/mvd/mvd_std.cpp b/src/core/hle/service/mvd/mvd_std.cpp
index 2c397f2dd..43dbde584 100644
--- a/src/core/hle/service/mvd/mvd_std.cpp
+++ b/src/core/hle/service/mvd/mvd_std.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/mvd/mvd_std.h"
 
+SERIALIZE_EXPORT_IMPL(Service::MVD::MVD_STD)
+
 namespace Service::MVD {
 
 MVD_STD::MVD_STD() : ServiceFramework("mvd:std", 1) {
diff --git a/src/core/hle/service/mvd/mvd_std.h b/src/core/hle/service/mvd/mvd_std.h
index 6764f6ba8..6e8312e59 100644
--- a/src/core/hle/service/mvd/mvd_std.h
+++ b/src/core/hle/service/mvd/mvd_std.h
@@ -12,6 +12,15 @@ class MVD_STD final : public ServiceFramework<MVD_STD> {
 public:
     MVD_STD();
     ~MVD_STD() = default;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::MVD
+
+BOOST_CLASS_EXPORT_KEY(Service::MVD::MVD_STD)
diff --git a/src/core/hle/service/ndm/ndm_u.cpp b/src/core/hle/service/ndm/ndm_u.cpp
index 057e68ede..936d53799 100644
--- a/src/core/hle/service/ndm/ndm_u.cpp
+++ b/src/core/hle/service/ndm/ndm_u.cpp
@@ -2,10 +2,13 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/ndm/ndm_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NDM::NDM_U)
+
 namespace Service::NDM {
 
 void NDM_U::EnterExclusiveState(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/ndm/ndm_u.h b/src/core/hle/service/ndm/ndm_u.h
index 5f48a3182..3339478d1 100644
--- a/src/core/hle/service/ndm/ndm_u.h
+++ b/src/core/hle/service/ndm/ndm_u.h
@@ -270,8 +270,23 @@ private:
     u32 scan_interval = DEFAULT_SCAN_INTERVAL;
     u32 retry_interval = DEFAULT_RETRY_INTERVAL;
     bool daemon_lock_enabled = false;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar& daemon_bit_mask;
+        ar& default_daemon_bit_mask;
+        ar& daemon_status;
+        ar& exclusive_state;
+        ar& scan_interval;
+        ar& retry_interval;
+        ar& daemon_lock_enabled;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::NDM
+
+BOOST_CLASS_EXPORT_KEY(Service::NDM::NDM_U)
diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp
index 17eaa5ea8..94cf68f4c 100644
--- a/src/core/hle/service/news/news_s.cpp
+++ b/src/core/hle/service/news/news_s.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/news/news_s.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NEWS::NEWS_S)
+
 namespace Service::NEWS {
 
 void NEWS_S::GetTotalNotifications(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/news/news_s.h b/src/core/hle/service/news/news_s.h
index e4673d22c..711a0e99b 100644
--- a/src/core/hle/service/news/news_s.h
+++ b/src/core/hle/service/news/news_s.h
@@ -27,3 +27,5 @@ private:
 };
 
 } // namespace Service::NEWS
+
+BOOST_CLASS_EXPORT_KEY(Service::NEWS::NEWS_S)
diff --git a/src/core/hle/service/news/news_u.cpp b/src/core/hle/service/news/news_u.cpp
index 3d6e87f91..d91b594b8 100644
--- a/src/core/hle/service/news/news_u.cpp
+++ b/src/core/hle/service/news/news_u.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/news/news_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NEWS::NEWS_U)
+
 namespace Service::NEWS {
 
 NEWS_U::NEWS_U() : ServiceFramework("news:u", 1) {
diff --git a/src/core/hle/service/news/news_u.h b/src/core/hle/service/news/news_u.h
index cb06bad39..472dd579c 100644
--- a/src/core/hle/service/news/news_u.h
+++ b/src/core/hle/service/news/news_u.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::NEWS
+
+BOOST_CLASS_EXPORT_KEY(Service::NEWS::NEWS_U)
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 86eb6daeb..0bd6121a2 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/kernel/event.h"
@@ -10,8 +11,20 @@
 #include "core/hle/service/nfc/nfc_m.h"
 #include "core/hle/service/nfc/nfc_u.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::NFC::Module)
+SERIALIZE_EXPORT_IMPL(Service::NFC::Module)
+
 namespace Service::NFC {
 
+template <class Archive>
+void Module::serialize(Archive& ar, const unsigned int) {
+    ar& tag_in_range_event;
+    ar& tag_out_of_range_event;
+    ar& nfc_tag_state;
+    ar& nfc_status;
+}
+SERIALIZE_IMPL(Module)
+
 struct TagInfo {
     u16_le id_offset_size;
     u8 unk1;
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
index 64bd239ac..2d6b26d83 100644
--- a/src/core/hle/service/nfc/nfc.h
+++ b/src/core/hle/service/nfc/nfc.h
@@ -226,7 +226,7 @@ public:
          */
         void GetIdentificationBlock(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> nfc;
     };
 
@@ -241,8 +241,15 @@ private:
 
     AmiiboData amiibo_data{};
     bool amiibo_in_range = false;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::NFC
+
+SERVICE_CONSTRUCT(Service::NFC::Module)
+BOOST_CLASS_EXPORT_KEY(Service::NFC::Module)
diff --git a/src/core/hle/service/nfc/nfc_m.cpp b/src/core/hle/service/nfc/nfc_m.cpp
index 310490b8f..cd591b9c1 100644
--- a/src/core/hle/service/nfc/nfc_m.cpp
+++ b/src/core/hle/service/nfc/nfc_m.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nfc/nfc_m.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NFC::NFC_M)
+
 namespace Service::NFC {
 
 NFC_M::NFC_M(std::shared_ptr<Module> nfc) : Module::Interface(std::move(nfc), "nfc:m", 1) {
diff --git a/src/core/hle/service/nfc/nfc_m.h b/src/core/hle/service/nfc/nfc_m.h
index c9fe9b130..48a9e241b 100644
--- a/src/core/hle/service/nfc/nfc_m.h
+++ b/src/core/hle/service/nfc/nfc_m.h
@@ -11,6 +11,12 @@ namespace Service::NFC {
 class NFC_M final : public Module::Interface {
 public:
     explicit NFC_M(std::shared_ptr<Module> nfc);
+
+private:
+    SERVICE_SERIALIZATION(NFC_M, nfc, Module)
 };
 
 } // namespace Service::NFC
+
+BOOST_CLASS_EXPORT_KEY(Service::NFC::NFC_M)
+BOOST_SERIALIZATION_CONSTRUCT(Service::NFC::NFC_M)
diff --git a/src/core/hle/service/nfc/nfc_u.cpp b/src/core/hle/service/nfc/nfc_u.cpp
index a6e99ace2..58d1843e4 100644
--- a/src/core/hle/service/nfc/nfc_u.cpp
+++ b/src/core/hle/service/nfc/nfc_u.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nfc/nfc_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NFC::NFC_U)
+
 namespace Service::NFC {
 
 NFC_U::NFC_U(std::shared_ptr<Module> nfc) : Module::Interface(std::move(nfc), "nfc:u", 1) {
diff --git a/src/core/hle/service/nfc/nfc_u.h b/src/core/hle/service/nfc/nfc_u.h
index aab408269..2ed6030e6 100644
--- a/src/core/hle/service/nfc/nfc_u.h
+++ b/src/core/hle/service/nfc/nfc_u.h
@@ -11,6 +11,12 @@ namespace Service::NFC {
 class NFC_U final : public Module::Interface {
 public:
     explicit NFC_U(std::shared_ptr<Module> nfc);
+
+private:
+    SERVICE_SERIALIZATION(NFC_U, nfc, Module)
 };
 
 } // namespace Service::NFC
+
+BOOST_CLASS_EXPORT_KEY(Service::NFC::NFC_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::NFC::NFC_U)

From 571b1062f0fd2921d2ea8d559d5dbcdb087e9cd0 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 1 Jan 2020 00:58:36 +0000
Subject: [PATCH 048/129] Serialize NIM, PS, PXI, SOC, SSL services

---
 TODO                                 | 15 +++++++--------
 src/core/hle/service/nim/nim_aoc.cpp |  3 +++
 src/core/hle/service/nim/nim_aoc.h   |  2 ++
 src/core/hle/service/nim/nim_s.cpp   |  3 +++
 src/core/hle/service/nim/nim_s.h     |  2 ++
 src/core/hle/service/nim/nim_u.cpp   |  4 ++++
 src/core/hle/service/nim/nim_u.h     | 10 ++++++++++
 src/core/hle/service/ps/ps_ps.cpp    |  3 +++
 src/core/hle/service/ps/ps_ps.h      |  2 ++
 src/core/hle/service/pxi/dev.cpp     |  3 +++
 src/core/hle/service/pxi/dev.h       |  2 ++
 src/core/hle/service/soc_u.cpp       |  3 +++
 src/core/hle/service/soc_u.h         | 18 ++++++++++++++++++
 src/core/hle/service/ssl_c.cpp       |  2 ++
 src/core/hle/service/ssl_c.h         |  2 ++
 15 files changed, 66 insertions(+), 8 deletions(-)

diff --git a/TODO b/TODO
index f9fffa60d..46ba9b260 100644
--- a/TODO
+++ b/TODO
@@ -17,7 +17,7 @@
 ☐ Telemetry session
 ☐ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE
 ☐ Review constructor/initialization code
-☐ Fix CI
+✔ Fix CI @done(19-12-31 21:32)
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
     ✔ LCD regs @done(19-08-13 15:41)
@@ -92,15 +92,14 @@
         ✔ NDM @done(19-12-31 18:26)
         ✔ NEWS @done(19-12-31 18:29)
         ✔ NFC @done(19-12-31 20:35)
-        ☐ NIM
-        ☐ NS
+        ✔ NIM @done(19-12-31 21:08)
+        ✔ NS @done(20-01-01 00:46)
         ☐ NWM
         ☐ PM
-        ☐ PS
+        ✔ PS @done(20-01-01 00:54)
         ☐ PTM
-        ☐ PXI
+        ✔ PXI @done(20-01-01 00:53)
         ☐ QTM
-        ☐ SM
-        ☐ SOC
-        ☐ SSL
+        ✔ SOC @done(20-01-01 00:51)
+        ✔ SSL @done(20-01-01 00:48)
         ☐ Y2R
\ No newline at end of file
diff --git a/src/core/hle/service/nim/nim_aoc.cpp b/src/core/hle/service/nim/nim_aoc.cpp
index ddd8d5e03..f20c96f69 100644
--- a/src/core/hle/service/nim/nim_aoc.cpp
+++ b/src/core/hle/service/nim/nim_aoc.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nim/nim_aoc.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NIM::NIM_AOC)
+
 namespace Service::NIM {
 
 NIM_AOC::NIM_AOC() : ServiceFramework("nim:aoc", 2) {
diff --git a/src/core/hle/service/nim/nim_aoc.h b/src/core/hle/service/nim/nim_aoc.h
index 5a1f518ec..2d06a9d1c 100644
--- a/src/core/hle/service/nim/nim_aoc.h
+++ b/src/core/hle/service/nim/nim_aoc.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::NIM
+
+BOOST_CLASS_EXPORT_KEY(Service::NIM::NIM_AOC)
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp
index d7236249f..27118e406 100644
--- a/src/core/hle/service/nim/nim_s.cpp
+++ b/src/core/hle/service/nim/nim_s.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nim/nim_s.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NIM::NIM_S)
+
 namespace Service::NIM {
 
 NIM_S::NIM_S() : ServiceFramework("nim:s", 1) {
diff --git a/src/core/hle/service/nim/nim_s.h b/src/core/hle/service/nim/nim_s.h
index 6485cde18..6281270f5 100644
--- a/src/core/hle/service/nim/nim_s.h
+++ b/src/core/hle/service/nim/nim_s.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::NIM
+
+BOOST_CLASS_EXPORT_KEY(Service::NIM::NIM_S)
diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp
index dd0e4d31c..b44ef3539 100644
--- a/src/core/hle/service/nim/nim_u.cpp
+++ b/src/core/hle/service/nim/nim_u.cpp
@@ -2,11 +2,15 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/service/nim/nim_u.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::NIM::NIM_U)
+SERIALIZE_EXPORT_IMPL(Service::NIM::NIM_U)
+
 namespace Service::NIM {
 
 NIM_U::NIM_U(Core::System& system) : ServiceFramework("nim:u", 2) {
diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h
index 367ee6ea8..98fec69b2 100644
--- a/src/core/hle/service/nim/nim_u.h
+++ b/src/core/hle/service/nim/nim_u.h
@@ -41,6 +41,16 @@ private:
     void CheckSysUpdateAvailable(Kernel::HLERequestContext& ctx);
 
     std::shared_ptr<Kernel::Event> nim_system_update_event;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar& nim_system_update_event;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::NIM
+
+SERVICE_CONSTRUCT(Service::NIM::NIM_U)
+BOOST_CLASS_EXPORT_KEY(Service::NIM::NIM_U)
diff --git a/src/core/hle/service/ps/ps_ps.cpp b/src/core/hle/service/ps/ps_ps.cpp
index a48903348..1ba4d7f4c 100644
--- a/src/core/hle/service/ps/ps_ps.cpp
+++ b/src/core/hle/service/ps/ps_ps.cpp
@@ -4,6 +4,7 @@
 
 #include <cryptopp/aes.h>
 #include <cryptopp/modes.h>
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/hle/ipc_helpers.h"
@@ -11,6 +12,8 @@
 #include "core/hw/aes/arithmetic128.h"
 #include "core/hw/aes/key.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PS::PS_PS)
+
 namespace Service::PS {
 
 enum class AlgorithmType : u8 {
diff --git a/src/core/hle/service/ps/ps_ps.h b/src/core/hle/service/ps/ps_ps.h
index 6e8b3ad0a..39f6d62b2 100644
--- a/src/core/hle/service/ps/ps_ps.h
+++ b/src/core/hle/service/ps/ps_ps.h
@@ -231,3 +231,5 @@ private:
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::PS
+
+BOOST_CLASS_EXPORT_KEY(Service::PS::PS_PS)
diff --git a/src/core/hle/service/pxi/dev.cpp b/src/core/hle/service/pxi/dev.cpp
index dcea938a6..113551690 100644
--- a/src/core/hle/service/pxi/dev.cpp
+++ b/src/core/hle/service/pxi/dev.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/pxi/dev.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PXI::DEV)
+
 namespace Service::PXI {
 
 DEV::DEV() : ServiceFramework("pxi:dev", 1) {
diff --git a/src/core/hle/service/pxi/dev.h b/src/core/hle/service/pxi/dev.h
index 115dc2308..ed17435b6 100644
--- a/src/core/hle/service/pxi/dev.h
+++ b/src/core/hle/service/pxi/dev.h
@@ -16,3 +16,5 @@ public:
 };
 
 } // namespace Service::PXI
+
+BOOST_CLASS_EXPORT_KEY(Service::PXI::DEV)
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 5ebe55356..56b48cd3a 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <cstring>
 #include <vector>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/bit_field.h"
 #include "common/common_types.h"
@@ -52,6 +53,8 @@
 #define closesocket(x) close(x)
 #endif
 
+SERIALIZE_EXPORT_IMPL(Service::SOC::SOC_U)
+
 namespace Service::SOC {
 
 const s32 SOCKET_ERROR_VALUE = -1;
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index 273aac49c..595a984f2 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <unordered_map>
+#include <boost/serialization/unordered_map.hpp>
 #include "core/hle/service/service.h"
 
 namespace Core {
@@ -17,6 +18,14 @@ namespace Service::SOC {
 struct SocketHolder {
     u32 socket_fd; ///< The socket descriptor
     bool blocking; ///< Whether the socket is blocking or not, it is only read on Windows.
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& socket_fd;
+        ar& blocking;
+    }
+    friend class boost::serialization::access;
 };
 
 class SOC_U final : public ServiceFramework<SOC_U> {
@@ -55,8 +64,17 @@ private:
 
     /// Holds info about the currently open sockets
     std::unordered_map<u32, SocketHolder> open_sockets;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+        ar& open_sockets;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::SOC
+
+BOOST_CLASS_EXPORT_KEY(Service::SOC::SOC_U)
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index b862c41f1..8e74c1b7c 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -2,12 +2,14 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "core/core.h"
 #include "core/hle/ipc.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/ssl_c.h"
 
+SERIALIZE_EXPORT_IMPL(Service::SSL::SSL_C)
 namespace Service::SSL {
 
 void SSL_C::Initialize(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h
index 807f7c725..3984f7ecc 100644
--- a/src/core/hle/service/ssl_c.h
+++ b/src/core/hle/service/ssl_c.h
@@ -28,3 +28,5 @@ private:
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::SSL
+
+BOOST_CLASS_EXPORT_KEY(Service::SSL::SSL_C)

From f5e2f873b003dacaf0b28b92c60beb5d7804e9ee Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 1 Jan 2020 21:31:52 +0000
Subject: [PATCH 049/129] Serialize NWM service

---
 TODO                                 | 18 ++++++++++++------
 externals/boost                      |  2 +-
 src/core/hle/service/nwm/nwm_cec.cpp |  3 +++
 src/core/hle/service/nwm/nwm_cec.h   |  2 ++
 src/core/hle/service/nwm/nwm_ext.cpp |  3 +++
 src/core/hle/service/nwm/nwm_ext.h   |  2 ++
 src/core/hle/service/nwm/nwm_inf.cpp |  3 +++
 src/core/hle/service/nwm/nwm_inf.h   |  2 ++
 src/core/hle/service/nwm/nwm_sap.cpp |  3 +++
 src/core/hle/service/nwm/nwm_sap.h   |  2 ++
 src/core/hle/service/nwm/nwm_soc.cpp |  3 +++
 src/core/hle/service/nwm/nwm_soc.h   |  2 ++
 src/core/hle/service/nwm/nwm_tst.cpp |  3 +++
 src/core/hle/service/nwm/nwm_tst.h   |  2 ++
 src/core/hle/service/nwm/nwm_uds.cpp | 12 ++++++++++++
 src/core/hle/service/nwm/nwm_uds.h   | 14 ++++++++++++++
 src/network/CMakeLists.txt           |  2 +-
 src/network/room_member.h            | 12 ++++++++++++
 18 files changed, 82 insertions(+), 8 deletions(-)

diff --git a/TODO b/TODO
index 46ba9b260..1f29a4693 100644
--- a/TODO
+++ b/TODO
@@ -10,11 +10,16 @@
 ☐ App loader
 ☐ Archive manager
 ☐ Custom texture cache
-☐ MMIO
-☐ Movie
-☐ Perf stats
-☐ Settings
-☐ Telemetry session
+✘ MMIO @cancelled(20-01-01 01:06)
+    Seems that this whole subsystem is only used in tests
+✘ Movie @cancelled(20-01-01 01:07)
+    Doesn't need to be serialized here
+✘ Perf stats @cancelled(20-01-01 01:09)
+    Doesn't need to be serialized here
+✘ Settings @cancelled(20-01-01 01:11)
+    For now, let the settings just be whatever they are
+✘ Telemetry session @cancelled(20-01-01 01:12)
+    Doesn't need to be serialized here
 ☐ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE
 ☐ Review constructor/initialization code
 ✔ Fix CI @done(19-12-31 21:32)
@@ -94,7 +99,8 @@
         ✔ NFC @done(19-12-31 20:35)
         ✔ NIM @done(19-12-31 21:08)
         ✔ NS @done(20-01-01 00:46)
-        ☐ NWM
+        ✔ NWM @done(20-01-01 21:31)
+            ☐ Fix wifi_packet_received?
         ☐ PM
         ✔ PS @done(20-01-01 00:54)
         ☐ PTM
diff --git a/externals/boost b/externals/boost
index 65dc954e9..6d7edc593 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 65dc954e93b22870b8423701e225147c75e3b31b
+Subproject commit 6d7edc593be8e47c8de7bc5f7d6b32971fad0c24
diff --git a/src/core/hle/service/nwm/nwm_cec.cpp b/src/core/hle/service/nwm/nwm_cec.cpp
index 7c47c88c7..ecd4f16e1 100644
--- a/src/core/hle/service/nwm/nwm_cec.cpp
+++ b/src/core/hle/service/nwm/nwm_cec.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nwm/nwm_cec.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_CEC)
+
 namespace Service::NWM {
 
 NWM_CEC::NWM_CEC() : ServiceFramework("nwm::CEC") {
diff --git a/src/core/hle/service/nwm/nwm_cec.h b/src/core/hle/service/nwm/nwm_cec.h
index afdf98477..4f62f32f1 100644
--- a/src/core/hle/service/nwm/nwm_cec.h
+++ b/src/core/hle/service/nwm/nwm_cec.h
@@ -14,3 +14,5 @@ public:
 };
 
 } // namespace Service::NWM
+
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_CEC)
diff --git a/src/core/hle/service/nwm/nwm_ext.cpp b/src/core/hle/service/nwm/nwm_ext.cpp
index 4bbac391f..d69da94ff 100644
--- a/src/core/hle/service/nwm/nwm_ext.cpp
+++ b/src/core/hle/service/nwm/nwm_ext.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nwm/nwm_ext.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_EXT)
+
 namespace Service::NWM {
 
 NWM_EXT::NWM_EXT() : ServiceFramework("nwm::EXT") {
diff --git a/src/core/hle/service/nwm/nwm_ext.h b/src/core/hle/service/nwm/nwm_ext.h
index 1711db65a..a8d43df70 100644
--- a/src/core/hle/service/nwm/nwm_ext.h
+++ b/src/core/hle/service/nwm/nwm_ext.h
@@ -14,3 +14,5 @@ public:
 };
 
 } // namespace Service::NWM
+
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_EXT)
diff --git a/src/core/hle/service/nwm/nwm_inf.cpp b/src/core/hle/service/nwm/nwm_inf.cpp
index 71cf11891..eaabf6667 100644
--- a/src/core/hle/service/nwm/nwm_inf.cpp
+++ b/src/core/hle/service/nwm/nwm_inf.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nwm/nwm_inf.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_INF)
+
 namespace Service::NWM {
 
 NWM_INF::NWM_INF() : ServiceFramework("nwm::INF") {
diff --git a/src/core/hle/service/nwm/nwm_inf.h b/src/core/hle/service/nwm/nwm_inf.h
index 2c69cfb1e..f13fd4158 100644
--- a/src/core/hle/service/nwm/nwm_inf.h
+++ b/src/core/hle/service/nwm/nwm_inf.h
@@ -14,3 +14,5 @@ public:
 };
 
 } // namespace Service::NWM
+
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_INF)
diff --git a/src/core/hle/service/nwm/nwm_sap.cpp b/src/core/hle/service/nwm/nwm_sap.cpp
index 2ef196ab4..2cedf9371 100644
--- a/src/core/hle/service/nwm/nwm_sap.cpp
+++ b/src/core/hle/service/nwm/nwm_sap.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nwm/nwm_sap.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_SAP)
+
 namespace Service::NWM {
 
 NWM_SAP::NWM_SAP() : ServiceFramework("nwm::SAP") {
diff --git a/src/core/hle/service/nwm/nwm_sap.h b/src/core/hle/service/nwm/nwm_sap.h
index b6700b8ed..1a289542c 100644
--- a/src/core/hle/service/nwm/nwm_sap.h
+++ b/src/core/hle/service/nwm/nwm_sap.h
@@ -14,3 +14,5 @@ public:
 };
 
 } // namespace Service::NWM
+
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_SAP)
diff --git a/src/core/hle/service/nwm/nwm_soc.cpp b/src/core/hle/service/nwm/nwm_soc.cpp
index 443baaf39..d6ca365ab 100644
--- a/src/core/hle/service/nwm/nwm_soc.cpp
+++ b/src/core/hle/service/nwm/nwm_soc.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nwm/nwm_soc.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_SOC)
+
 namespace Service::NWM {
 
 NWM_SOC::NWM_SOC() : ServiceFramework("nwm::SOC") {
diff --git a/src/core/hle/service/nwm/nwm_soc.h b/src/core/hle/service/nwm/nwm_soc.h
index 8e1b922bc..883a20854 100644
--- a/src/core/hle/service/nwm/nwm_soc.h
+++ b/src/core/hle/service/nwm/nwm_soc.h
@@ -14,3 +14,5 @@ public:
 };
 
 } // namespace Service::NWM
+
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_SOC)
diff --git a/src/core/hle/service/nwm/nwm_tst.cpp b/src/core/hle/service/nwm/nwm_tst.cpp
index 3be65200b..65ffabfd9 100644
--- a/src/core/hle/service/nwm/nwm_tst.cpp
+++ b/src/core/hle/service/nwm/nwm_tst.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/nwm/nwm_tst.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_TST)
+
 namespace Service::NWM {
 
 NWM_TST::NWM_TST() : ServiceFramework("nwm::TST") {
diff --git a/src/core/hle/service/nwm/nwm_tst.h b/src/core/hle/service/nwm/nwm_tst.h
index 8214e0d1d..e58fa3371 100644
--- a/src/core/hle/service/nwm/nwm_tst.h
+++ b/src/core/hle/service/nwm/nwm_tst.h
@@ -14,3 +14,5 @@ public:
 };
 
 } // namespace Service::NWM
+
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_TST)
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index fe8f7635f..9a3de82fa 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -4,7 +4,10 @@
 
 #include <algorithm>
 #include <cstring>
+#include <boost/serialization/list.hpp>
+#include <boost/serialization/map.hpp>
 #include <cryptopp/osrng.h>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "core/core.h"
@@ -23,6 +26,15 @@
 
 namespace Service::NWM {
 
+template <class Archive>
+void NWM_UDS::serialize(Archive& ar, const unsigned int) {
+    ar& node_map;
+    ar& connection_event;
+    ar& received_beacons;
+    // TODO: Fix wifi_packet_received?
+}
+SERIALIZE_IMPL(NWM_UDS)
+
 namespace ErrCodes {
 enum {
     NotInitialized = 2,
diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h
index 52ca38663..07dd7e9ba 100644
--- a/src/core/hle/service/nwm/nwm_uds.h
+++ b/src/core/hle/service/nwm/nwm_uds.h
@@ -521,6 +521,14 @@ private:
     struct Node {
         bool connected;
         u16 node_id;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& connected;
+            ar& node_id;
+        }
+        friend class boost::serialization::access;
     };
 
     std::map<MacAddress, Node> node_map;
@@ -543,6 +551,12 @@ private:
 
     // List of the last <MaxBeaconFrames> beacons received from the network.
     std::list<Network::WifiPacket> received_beacons;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
 };
 
 } // namespace Service::NWM
+
+SERVICE_CONSTRUCT(Service::NWM::NWM_UDS)
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_UDS)
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index 24f782653..382a69e2f 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -13,4 +13,4 @@ add_library(network STATIC
 
 create_target_directory_groups(network)
 
-target_link_libraries(network PRIVATE common enet)
+target_link_libraries(network PRIVATE common enet Boost::boost)
diff --git a/src/network/room_member.h b/src/network/room_member.h
index ad5d14b44..d582a8552 100644
--- a/src/network/room_member.h
+++ b/src/network/room_member.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 #include <vector>
+#include <boost/serialization/access.hpp>
 #include "common/common_types.h"
 #include "network/room.h"
 
@@ -30,6 +31,17 @@ struct WifiPacket {
     MacAddress transmitter_address; ///< Mac address of the transmitter.
     MacAddress destination_address; ///< Mac address of the receiver.
     u8 channel;                     ///< WiFi channel where this frame was transmitted.
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& type;
+        ar& data;
+        ar& transmitter_address;
+        ar& destination_address;
+        ar& channel;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Represents a chat message.

From 92857efca4f958f00ac5ee6eb69a6d0ba94f8a8b Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 1 Jan 2020 22:36:58 +0000
Subject: [PATCH 050/129] Serialize PTM service

---
 TODO                                  |  4 ++--
 src/core/hle/service/pm/pm_app.cpp    |  3 +++
 src/core/hle/service/pm/pm_app.h      |  2 ++
 src/core/hle/service/pm/pm_dbg.cpp    |  3 +++
 src/core/hle/service/pm/pm_dbg.h      |  2 ++
 src/core/hle/service/ptm/ptm.cpp      |  3 +++
 src/core/hle/service/ptm/ptm.h        | 12 +++++++++++-
 src/core/hle/service/ptm/ptm_gets.cpp |  3 +++
 src/core/hle/service/ptm/ptm_gets.h   |  6 ++++++
 src/core/hle/service/ptm/ptm_play.cpp |  3 +++
 src/core/hle/service/ptm/ptm_play.h   |  6 ++++++
 src/core/hle/service/ptm/ptm_sets.cpp |  3 +++
 src/core/hle/service/ptm/ptm_sets.h   |  6 ++++++
 src/core/hle/service/ptm/ptm_sysm.cpp |  4 ++++
 src/core/hle/service/ptm/ptm_sysm.h   | 11 +++++++++++
 src/core/hle/service/ptm/ptm_u.cpp    |  3 +++
 src/core/hle/service/ptm/ptm_u.h      |  6 ++++++
 17 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index 1f29a4693..0b7d5dd36 100644
--- a/TODO
+++ b/TODO
@@ -101,9 +101,9 @@
         ✔ NS @done(20-01-01 00:46)
         ✔ NWM @done(20-01-01 21:31)
             ☐ Fix wifi_packet_received?
-        ☐ PM
+        ✔ PM @done(20-01-01 22:14)
         ✔ PS @done(20-01-01 00:54)
-        ☐ PTM
+        ✔ PTM @done(20-01-01 22:36)
         ✔ PXI @done(20-01-01 00:53)
         ☐ QTM
         ✔ SOC @done(20-01-01 00:51)
diff --git a/src/core/hle/service/pm/pm_app.cpp b/src/core/hle/service/pm/pm_app.cpp
index 9599dfcfc..fd0858356 100644
--- a/src/core/hle/service/pm/pm_app.cpp
+++ b/src/core/hle/service/pm/pm_app.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/pm/pm_app.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PM::PM_APP)
+
 namespace Service::PM {
 
 PM_APP::PM_APP() : ServiceFramework("pm:app", 3) {
diff --git a/src/core/hle/service/pm/pm_app.h b/src/core/hle/service/pm/pm_app.h
index 8c7e375f0..0fb290aba 100644
--- a/src/core/hle/service/pm/pm_app.h
+++ b/src/core/hle/service/pm/pm_app.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::PM
+
+BOOST_CLASS_EXPORT_KEY(Service::PM::PM_APP)
diff --git a/src/core/hle/service/pm/pm_dbg.cpp b/src/core/hle/service/pm/pm_dbg.cpp
index 63879ff20..33e195a6f 100644
--- a/src/core/hle/service/pm/pm_dbg.cpp
+++ b/src/core/hle/service/pm/pm_dbg.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/pm/pm_dbg.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PM::PM_DBG)
+
 namespace Service::PM {
 
 PM_DBG::PM_DBG() : ServiceFramework("pm:dbg", 3) {
diff --git a/src/core/hle/service/pm/pm_dbg.h b/src/core/hle/service/pm/pm_dbg.h
index 77b644969..1cfdea6fe 100644
--- a/src/core/hle/service/pm/pm_dbg.h
+++ b/src/core/hle/service/pm/pm_dbg.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::PM
+
+BOOST_CLASS_EXPORT_KEY(Service::PM::PM_DBG)
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 7d30fcc5b..69b51480b 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <cinttypes>
+#include "common/archives.h"
 #include "common/common_paths.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
@@ -18,6 +19,8 @@
 #include "core/hle/service/ptm/ptm_u.h"
 #include "core/settings.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PTM::Module)
+
 namespace Service::PTM {
 
 /// Values for the default gamecoin.dat file
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 549e69353..ba23224d7 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -137,7 +137,7 @@ public:
          */
         void CheckNew3DS(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> ptm;
     };
 
@@ -145,8 +145,18 @@ private:
     bool shell_open = true;
     bool battery_is_charging = true;
     bool pedometer_is_counting = false;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& shell_open;
+        ar& battery_is_charging;
+        ar& pedometer_is_counting;
+    }
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::PTM
+
+BOOST_CLASS_EXPORT_KEY(Service::PTM::Module)
diff --git a/src/core/hle/service/ptm/ptm_gets.cpp b/src/core/hle/service/ptm/ptm_gets.cpp
index e083aed6a..6feedbf94 100644
--- a/src/core/hle/service/ptm/ptm_gets.cpp
+++ b/src/core/hle/service/ptm/ptm_gets.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/ptm/ptm_gets.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PTM::PTM_Gets)
+
 namespace Service::PTM {
 
 PTM_Gets::PTM_Gets(std::shared_ptr<Module> ptm)
diff --git a/src/core/hle/service/ptm/ptm_gets.h b/src/core/hle/service/ptm/ptm_gets.h
index a8d71fdc9..57b8e5f55 100644
--- a/src/core/hle/service/ptm/ptm_gets.h
+++ b/src/core/hle/service/ptm/ptm_gets.h
@@ -12,6 +12,12 @@ namespace Service::PTM {
 class PTM_Gets final : public Module::Interface {
 public:
     explicit PTM_Gets(std::shared_ptr<Module> ptm);
+
+private:
+    SERVICE_SERIALIZATION(PTM_Gets, ptm, Module)
 };
 
 } // namespace Service::PTM
+
+BOOST_CLASS_EXPORT_KEY(Service::PTM::PTM_Gets)
+BOOST_SERIALIZATION_CONSTRUCT(Service::PTM::PTM_Gets)
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 6ef45780e..00585ccce 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/ptm/ptm_play.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PTM::PTM_Play)
+
 namespace Service::PTM {
 
 PTM_Play::PTM_Play(std::shared_ptr<Module> ptm)
diff --git a/src/core/hle/service/ptm/ptm_play.h b/src/core/hle/service/ptm/ptm_play.h
index 3a226149d..091e91d30 100644
--- a/src/core/hle/service/ptm/ptm_play.h
+++ b/src/core/hle/service/ptm/ptm_play.h
@@ -12,6 +12,12 @@ namespace Service::PTM {
 class PTM_Play final : public Module::Interface {
 public:
     explicit PTM_Play(std::shared_ptr<Module> ptm);
+
+private:
+    SERVICE_SERIALIZATION(PTM_Play, ptm, Module)
 };
 
 } // namespace Service::PTM
+
+BOOST_CLASS_EXPORT_KEY(Service::PTM::PTM_Play)
+BOOST_SERIALIZATION_CONSTRUCT(Service::PTM::PTM_Play)
diff --git a/src/core/hle/service/ptm/ptm_sets.cpp b/src/core/hle/service/ptm/ptm_sets.cpp
index b925f49c9..e0f436ddc 100644
--- a/src/core/hle/service/ptm/ptm_sets.cpp
+++ b/src/core/hle/service/ptm/ptm_sets.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/ptm/ptm_sets.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PTM::PTM_Sets)
+
 namespace Service::PTM {
 
 PTM_Sets::PTM_Sets(std::shared_ptr<Module> ptm) : Module::Interface(std::move(ptm), "ptm:sets", 1) {
diff --git a/src/core/hle/service/ptm/ptm_sets.h b/src/core/hle/service/ptm/ptm_sets.h
index 317781faf..573b20dbd 100644
--- a/src/core/hle/service/ptm/ptm_sets.h
+++ b/src/core/hle/service/ptm/ptm_sets.h
@@ -12,6 +12,12 @@ namespace Service::PTM {
 class PTM_Sets final : public Module::Interface {
 public:
     explicit PTM_Sets(std::shared_ptr<Module> ptm);
+
+private:
+    SERVICE_SERIALIZATION(PTM_Sets, ptm, Module)
 };
 
 } // namespace Service::PTM
+
+BOOST_CLASS_EXPORT_KEY(Service::PTM::PTM_Sets)
+BOOST_SERIALIZATION_CONSTRUCT(Service::PTM::PTM_Sets)
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp
index 45ee1b6fc..48b44104e 100644
--- a/src/core/hle/service/ptm/ptm_sysm.cpp
+++ b/src/core/hle/service/ptm/ptm_sysm.cpp
@@ -2,8 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/ptm/ptm_sysm.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PTM::PTM_S)
+SERIALIZE_EXPORT_IMPL(Service::PTM::PTM_Sysm)
+
 namespace Service::PTM {
 
 PTM_S_Common::PTM_S_Common(std::shared_ptr<Module> ptm, const char* name)
diff --git a/src/core/hle/service/ptm/ptm_sysm.h b/src/core/hle/service/ptm/ptm_sysm.h
index 8667f2a95..1e01fdb2e 100644
--- a/src/core/hle/service/ptm/ptm_sysm.h
+++ b/src/core/hle/service/ptm/ptm_sysm.h
@@ -17,11 +17,22 @@ public:
 class PTM_S final : public PTM_S_Common {
 public:
     explicit PTM_S(std::shared_ptr<Module> ptm);
+
+private:
+    SERVICE_SERIALIZATION(PTM_S, ptm, Module)
 };
 
 class PTM_Sysm final : public PTM_S_Common {
 public:
     explicit PTM_Sysm(std::shared_ptr<Module> ptm);
+
+private:
+    SERVICE_SERIALIZATION(PTM_Sysm, ptm, Module)
 };
 
 } // namespace Service::PTM
+
+BOOST_CLASS_EXPORT_KEY(Service::PTM::PTM_S)
+BOOST_CLASS_EXPORT_KEY(Service::PTM::PTM_Sysm)
+BOOST_SERIALIZATION_CONSTRUCT(Service::PTM::PTM_S)
+BOOST_SERIALIZATION_CONSTRUCT(Service::PTM::PTM_Sysm)
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp
index 647ef5961..4c1820df4 100644
--- a/src/core/hle/service/ptm/ptm_u.cpp
+++ b/src/core/hle/service/ptm/ptm_u.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/ptm/ptm_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::PTM::PTM_U)
+
 namespace Service::PTM {
 
 PTM_U::PTM_U(std::shared_ptr<Module> ptm) : Module::Interface(std::move(ptm), "ptm:u", 26) {
diff --git a/src/core/hle/service/ptm/ptm_u.h b/src/core/hle/service/ptm/ptm_u.h
index 618401cec..213972242 100644
--- a/src/core/hle/service/ptm/ptm_u.h
+++ b/src/core/hle/service/ptm/ptm_u.h
@@ -12,6 +12,12 @@ namespace Service::PTM {
 class PTM_U final : public Module::Interface {
 public:
     explicit PTM_U(std::shared_ptr<Module> ptm);
+
+private:
+    SERVICE_SERIALIZATION(PTM_U, ptm, Module)
 };
 
 } // namespace Service::PTM
+
+BOOST_CLASS_EXPORT_KEY(Service::PTM::PTM_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::PTM::PTM_U)

From ef2e50328133f6553046219eb54027800d88a148 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 1 Jan 2020 22:57:21 +0000
Subject: [PATCH 051/129] Serialize QTM, Y2R services

---
 TODO                                |  4 +-
 src/core/hle/service/qtm/qtm_c.cpp  |  3 ++
 src/core/hle/service/qtm/qtm_c.h    |  2 +
 src/core/hle/service/qtm/qtm_s.cpp  |  3 ++
 src/core/hle/service/qtm/qtm_s.h    |  2 +
 src/core/hle/service/qtm/qtm_sp.cpp |  3 ++
 src/core/hle/service/qtm/qtm_sp.h   |  2 +
 src/core/hle/service/qtm/qtm_u.cpp  |  3 ++
 src/core/hle/service/qtm/qtm_u.h    |  2 +
 src/core/hle/service/y2r_u.cpp      | 15 ++++++++
 src/core/hle/service/y2r_u.h        | 60 +++++++++++++++++++++++++++++
 11 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/TODO b/TODO
index 0b7d5dd36..30b51a68c 100644
--- a/TODO
+++ b/TODO
@@ -105,7 +105,7 @@
         ✔ PS @done(20-01-01 00:54)
         ✔ PTM @done(20-01-01 22:36)
         ✔ PXI @done(20-01-01 00:53)
-        ☐ QTM
+        ✔ QTM @done(20-01-01 22:41)
         ✔ SOC @done(20-01-01 00:51)
         ✔ SSL @done(20-01-01 00:48)
-        ☐ Y2R
\ No newline at end of file
+        ✔ Y2R @done(20-01-01 22:56)
\ No newline at end of file
diff --git a/src/core/hle/service/qtm/qtm_c.cpp b/src/core/hle/service/qtm/qtm_c.cpp
index 84baaba3a..2adc896df 100644
--- a/src/core/hle/service/qtm/qtm_c.cpp
+++ b/src/core/hle/service/qtm/qtm_c.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/qtm/qtm_c.h"
 
+SERIALIZE_EXPORT_IMPL(Service::QTM::QTM_C)
+
 namespace Service::QTM {
 
 QTM_C::QTM_C() : ServiceFramework("qtm:c", 2) {
diff --git a/src/core/hle/service/qtm/qtm_c.h b/src/core/hle/service/qtm/qtm_c.h
index c9cad0329..8ad05b6e1 100644
--- a/src/core/hle/service/qtm/qtm_c.h
+++ b/src/core/hle/service/qtm/qtm_c.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::QTM
+
+BOOST_CLASS_EXPORT_KEY(Service::QTM::QTM_C)
diff --git a/src/core/hle/service/qtm/qtm_s.cpp b/src/core/hle/service/qtm/qtm_s.cpp
index 2af7ced7b..6163ef4dc 100644
--- a/src/core/hle/service/qtm/qtm_s.cpp
+++ b/src/core/hle/service/qtm/qtm_s.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/qtm/qtm_s.h"
 
+SERIALIZE_EXPORT_IMPL(Service::QTM::QTM_S)
+
 namespace Service::QTM {
 
 QTM_S::QTM_S() : ServiceFramework("qtm:s", 2) {
diff --git a/src/core/hle/service/qtm/qtm_s.h b/src/core/hle/service/qtm/qtm_s.h
index 72b5e058b..51e1a4bc8 100644
--- a/src/core/hle/service/qtm/qtm_s.h
+++ b/src/core/hle/service/qtm/qtm_s.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::QTM
+
+BOOST_CLASS_EXPORT_KEY(Service::QTM::QTM_S)
diff --git a/src/core/hle/service/qtm/qtm_sp.cpp b/src/core/hle/service/qtm/qtm_sp.cpp
index bd5a71605..fdfc80003 100644
--- a/src/core/hle/service/qtm/qtm_sp.cpp
+++ b/src/core/hle/service/qtm/qtm_sp.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/qtm/qtm_sp.h"
 
+SERIALIZE_EXPORT_IMPL(Service::QTM::QTM_SP)
+
 namespace Service::QTM {
 
 QTM_SP::QTM_SP() : ServiceFramework("qtm:sp", 2) {
diff --git a/src/core/hle/service/qtm/qtm_sp.h b/src/core/hle/service/qtm/qtm_sp.h
index c3f1049a1..3c16dea37 100644
--- a/src/core/hle/service/qtm/qtm_sp.h
+++ b/src/core/hle/service/qtm/qtm_sp.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::QTM
+
+BOOST_CLASS_EXPORT_KEY(Service::QTM::QTM_SP)
diff --git a/src/core/hle/service/qtm/qtm_u.cpp b/src/core/hle/service/qtm/qtm_u.cpp
index 471692189..84415dde9 100644
--- a/src/core/hle/service/qtm/qtm_u.cpp
+++ b/src/core/hle/service/qtm/qtm_u.cpp
@@ -2,9 +2,12 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/qtm/qtm_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::QTM::QTM_U)
+
 namespace Service::QTM {
 
 QTM_U::QTM_U() : ServiceFramework("qtm:u", 2) {
diff --git a/src/core/hle/service/qtm/qtm_u.h b/src/core/hle/service/qtm/qtm_u.h
index 01bb1e6e0..f6b54c8af 100644
--- a/src/core/hle/service/qtm/qtm_u.h
+++ b/src/core/hle/service/qtm/qtm_u.h
@@ -15,3 +15,5 @@ public:
 };
 
 } // namespace Service::QTM
+
+BOOST_CLASS_EXPORT_KEY(Service::QTM::QTM_U)
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 356ebd843..0c981b545 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
+#include "common/archives.h"
 #include "common/common_funcs.h"
 #include "common/logging/log.h"
 #include "core/core.h"
@@ -12,8 +13,22 @@
 #include "core/hle/service/y2r_u.h"
 #include "core/hw/y2r.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::Y2R::Y2R_U)
+SERIALIZE_EXPORT_IMPL(Service::Y2R::Y2R_U)
+
 namespace Service::Y2R {
 
+template <class Archive>
+void Y2R_U::serialize(Archive& ar, const unsigned int) {
+    ar& completion_event;
+    ar& conversion;
+    ar& dithering_weight_params;
+    ar& temporal_dithering_enabled;
+    ar& transfer_end_interrupt_enabled;
+    ar& spacial_dithering_enabled;
+}
+SERIALIZE_IMPL(Y2R_U)
+
 static const CoefficientSet standard_coefficients[4] = {
     {{0x100, 0x166, 0xB6, 0x58, 0x1C5, -0x166F, 0x10EE, -0x1C5B}}, // ITU_Rec601
     {{0x100, 0x193, 0x77, 0x2F, 0x1DB, -0x1933, 0xA7C, -0x1D51}},  // ITU_Rec709
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 332d3b240..1ac675f92 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -7,6 +7,7 @@
 #include <array>
 #include <memory>
 #include <string>
+#include <boost/serialization/array.hpp>
 #include "common/common_types.h"
 #include "core/hle/result.h"
 #include "core/hle/service/service.h"
@@ -91,6 +92,16 @@ struct ConversionBuffer {
     u16 transfer_unit;
     /// Amount of bytes to be skipped between copying each `transfer_unit` bytes.
     u16 gap;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& address;
+        ar& image_size;
+        ar& transfer_unit;
+        ar& gap;
+    }
+    friend class boost::serialization::access;
 };
 
 struct ConversionConfiguration {
@@ -112,6 +123,26 @@ struct ConversionConfiguration {
     ResultCode SetInputLineWidth(u16 width);
     ResultCode SetInputLines(u16 lines);
     ResultCode SetStandardCoefficient(StandardCoefficient standard_coefficient);
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& input_format;
+        ar& output_format;
+        ar& rotation;
+        ar& block_alignment;
+        ar& input_line_width;
+        ar& input_lines;
+        ar& coefficients;
+        ar& padding;
+        ar& alpha;
+        ar& src_Y;
+        ar& src_U;
+        ar& src_V;
+        ar& src_YUYV;
+        ar& dst;
+    }
+    friend class boost::serialization::access;
 };
 
 struct DitheringWeightParams {
@@ -131,6 +162,28 @@ struct DitheringWeightParams {
     u16 w3_xOdd_yEven;
     u16 w3_xEven_yOdd;
     u16 w3_xOdd_yOdd;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& w0_xEven_yEven;
+        ar& w0_xOdd_yEven;
+        ar& w0_xEven_yOdd;
+        ar& w0_xOdd_yOdd;
+        ar& w1_xEven_yEven;
+        ar& w1_xOdd_yEven;
+        ar& w1_xEven_yOdd;
+        ar& w1_xOdd_yOdd;
+        ar& w2_xEven_yEven;
+        ar& w2_xOdd_yEven;
+        ar& w2_xEven_yOdd;
+        ar& w2_xOdd_yOdd;
+        ar& w3_xEven_yEven;
+        ar& w3_xOdd_yEven;
+        ar& w3_xEven_yOdd;
+        ar& w3_xOdd_yOdd;
+    }
+    friend class boost::serialization::access;
 };
 
 struct ConversionParameters {
@@ -301,8 +354,15 @@ private:
     bool temporal_dithering_enabled = false;
     bool transfer_end_interrupt_enabled = false;
     bool spacial_dithering_enabled = false;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::Y2R
+
+SERVICE_CONSTRUCT(Service::Y2R::Y2R_U)
+BOOST_CLASS_EXPORT_KEY(Service::Y2R::Y2R_U)

From 2d2c7218ef3a6651606969219a1909c4fa1b4612 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 2 Jan 2020 00:45:58 +0000
Subject: [PATCH 052/129] Serialize CECD, CFG services

---
 TODO                                   | 23 ++++++++++++++++++-----
 src/common/construct.h                 |  1 +
 src/core/file_sys/archive_backend.h    | 11 ++++++++++-
 src/core/hle/kernel/shared_page.h      |  7 -------
 src/core/hle/service/cecd/cecd.cpp     | 15 ++++++++++++++-
 src/core/hle/service/cecd/cecd.h       |  9 ++++++++-
 src/core/hle/service/cecd/cecd_ndm.cpp |  3 +++
 src/core/hle/service/cecd/cecd_ndm.h   |  6 ++++++
 src/core/hle/service/cecd/cecd_s.cpp   |  3 +++
 src/core/hle/service/cecd/cecd_s.h     |  6 ++++++
 src/core/hle/service/cecd/cecd_u.cpp   |  3 +++
 src/core/hle/service/cecd/cecd_u.h     |  6 ++++++
 src/core/hle/service/cfg/cfg.cpp       | 11 +++++++++++
 src/core/hle/service/cfg/cfg.h         |  8 +++++++-
 src/core/hle/service/cfg/cfg_i.cpp     |  3 +++
 src/core/hle/service/cfg/cfg_i.h       |  6 ++++++
 src/core/hle/service/cfg/cfg_nor.cpp   |  3 +++
 src/core/hle/service/cfg/cfg_nor.h     |  2 ++
 src/core/hle/service/cfg/cfg_s.cpp     |  3 +++
 src/core/hle/service/cfg/cfg_s.h       |  6 ++++++
 src/core/hle/service/cfg/cfg_u.cpp     |  3 +++
 src/core/hle/service/cfg/cfg_u.h       |  6 ++++++
 src/core/hle/service/fs/archive.h      |  7 +++++++
 23 files changed, 135 insertions(+), 16 deletions(-)

diff --git a/TODO b/TODO
index 30b51a68c..5ea46f2e8 100644
--- a/TODO
+++ b/TODO
@@ -7,8 +7,22 @@
     Memory only
 ✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
     ✔ Fix or ignore inverse map @done(19-12-23 12:46)
-☐ App loader
-☐ Archive manager
+✘ App loader @cancelled(20-01-01 22:59)
+    No relevant state
+☐ Archive manager @started(20-01-01 23:03)
+    ☐ NCCH
+        ☐ Normal
+        ☐ Self
+    ☐ SaveData
+        ☐ Normal
+        ☐ Ext
+        ☐ Other
+        ☐ Source SD
+        ☐ System
+    ☐ SDMC
+        ☐ Normal
+        ☐ Write-only
+    ☐ File refs
 ☐ Custom texture cache
 ✘ MMIO @cancelled(20-01-01 01:06)
     Seems that this whole subsystem is only used in tests
@@ -76,9 +90,8 @@
         ✔ BOSS @started(19-12-25 21:48) @done(19-12-25 23:18) @lasted(1h30m14s)
         ☐ CAM @started(19-12-26 10:37)
             Need to check capture_result
-        ☐ CECD
-            ☐ Archive backend / file handles
-        ☐ CFG
+        ✔ CECD @done(20-01-01 23:58)
+        ✔ CFG @done(20-01-02 00:44)
             Also needs archive backend..
         ✔ CSND @started(19-12-26 17:51) @done(19-12-26 17:56) @lasted(5m30s)
         ✔ DLP @done(19-12-26 18:02)
diff --git a/src/common/construct.h b/src/common/construct.h
index 6b2b3ceeb..aba4c7e89 100644
--- a/src/common/construct.h
+++ b/src/common/construct.h
@@ -1,3 +1,4 @@
+#pragma once
 #include <boost/serialization/serialization.hpp>
 
 class construct_access {
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 2df4f98c4..05aa877a3 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -168,7 +168,12 @@ public:
     }
 
 protected:
-    std::unique_ptr<DelayGenerator> delay_generator;
+    std::unique_ptr<DelayGenerator> delay_generator; // TODO: Replace with virtual GetOpenDelayNs
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 class ArchiveFactory : NonCopyable {
@@ -205,6 +210,10 @@ public:
      * @return Format information about the archive or error code
      */
     virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const = 0;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index b3e1a48b6..45f9cd348 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -105,13 +105,6 @@ private:
     std::chrono::seconds init_time;
 
     SharedPageDef shared_page;
-
-    friend class boost::serialization::access;
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version) {
-        auto o_shared_page = boost::serialization::binary_object(&shared_page, sizeof(shared_page));
-        ar& o_shared_page;
-    }
 };
 
 } // namespace SharedPage
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 281f48026..42ac76946 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -5,6 +5,7 @@
 #include <cryptopp/base64.h>
 #include <cryptopp/hmac.h>
 #include <cryptopp/sha.h>
+#include "common/archives.h"
 #include "common/common_paths.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
@@ -24,8 +25,19 @@
 #include "core/hle/service/cfg/cfg.h"
 #include "fmt/format.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::CECD::Module)
+SERIALIZE_EXPORT_IMPL(Service::CECD::Module)
+
 namespace Service::CECD {
 
+template <class Archive>
+void Module::serialize(Archive& ar, const unsigned int) {
+    ar& cecd_system_save_data_archive;
+    ar& cecinfo_event;
+    ar& change_state_event;
+}
+SERIALIZE_IMPL(Module)
+
 using CecDataPathType = Module::CecDataPathType;
 using CecOpenMode = Module::CecOpenMode;
 using CecSystemInfoType = Module::CecSystemInfoType;
@@ -1340,7 +1352,8 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
     case CecDataPathType::MboxData:
     case CecDataPathType::MboxIcon:
     case CecDataPathType::MboxTitle:
-    default: {}
+    default: {
+    }
     }
 }
 
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
index 004ef33e7..dd7fff7cb 100644
--- a/src/core/hle/service/cecd/cecd.h
+++ b/src/core/hle/service/cecd/cecd.h
@@ -584,7 +584,7 @@ public:
          */
         void GetCecInfoEventHandleSys(Kernel::HLERequestContext& ctx);
 
-    private:
+    protected:
         std::shared_ptr<Module> cecd;
     };
 
@@ -613,9 +613,16 @@ private:
     std::shared_ptr<Kernel::Event> change_state_event;
 
     Core::System& system;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 /// Initialize CECD service(s)
 void InstallInterfaces(Core::System& system);
 
 } // namespace Service::CECD
+
+SERVICE_CONSTRUCT(Service::CECD::Module)
+BOOST_CLASS_EXPORT_KEY(Service::CECD::Module)
diff --git a/src/core/hle/service/cecd/cecd_ndm.cpp b/src/core/hle/service/cecd/cecd_ndm.cpp
index e4366e9c6..4b571283d 100644
--- a/src/core/hle/service/cecd/cecd_ndm.cpp
+++ b/src/core/hle/service/cecd/cecd_ndm.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cecd/cecd_ndm.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CECD::CECD_NDM)
+
 namespace Service::CECD {
 
 CECD_NDM::CECD_NDM(std::shared_ptr<Module> cecd)
diff --git a/src/core/hle/service/cecd/cecd_ndm.h b/src/core/hle/service/cecd/cecd_ndm.h
index a9fabb1a1..9fd282585 100644
--- a/src/core/hle/service/cecd/cecd_ndm.h
+++ b/src/core/hle/service/cecd/cecd_ndm.h
@@ -11,6 +11,12 @@ namespace Service::CECD {
 class CECD_NDM final : public Module::Interface {
 public:
     explicit CECD_NDM(std::shared_ptr<Module> cecd);
+
+private:
+    SERVICE_SERIALIZATION(CECD_NDM, cecd, Module)
 };
 
 } // namespace Service::CECD
+
+BOOST_CLASS_EXPORT_KEY(Service::CECD::CECD_NDM)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CECD::CECD_NDM)
diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp
index 3395c405d..fa838d2af 100644
--- a/src/core/hle/service/cecd/cecd_s.cpp
+++ b/src/core/hle/service/cecd/cecd_s.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cecd/cecd_s.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CECD::CECD_S)
+
 namespace Service::CECD {
 
 CECD_S::CECD_S(std::shared_ptr<Module> cecd)
diff --git a/src/core/hle/service/cecd/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h
index 6c50b13ba..9c6a7afec 100644
--- a/src/core/hle/service/cecd/cecd_s.h
+++ b/src/core/hle/service/cecd/cecd_s.h
@@ -11,6 +11,12 @@ namespace Service::CECD {
 class CECD_S final : public Module::Interface {
 public:
     explicit CECD_S(std::shared_ptr<Module> cecd);
+
+private:
+    SERVICE_SERIALIZATION(CECD_S, cecd, Module)
 };
 
 } // namespace Service::CECD
+
+BOOST_CLASS_EXPORT_KEY(Service::CECD::CECD_S)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CECD::CECD_S)
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp
index 81fcd1019..e8cd7d1c9 100644
--- a/src/core/hle/service/cecd/cecd_u.cpp
+++ b/src/core/hle/service/cecd/cecd_u.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cecd/cecd_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CECD::CECD_U)
+
 namespace Service::CECD {
 
 CECD_U::CECD_U(std::shared_ptr<Module> cecd)
diff --git a/src/core/hle/service/cecd/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h
index 49ddadb69..31e7a2367 100644
--- a/src/core/hle/service/cecd/cecd_u.h
+++ b/src/core/hle/service/cecd/cecd_u.h
@@ -11,6 +11,12 @@ namespace Service::CECD {
 class CECD_U final : public Module::Interface {
 public:
     explicit CECD_U(std::shared_ptr<Module> cecd);
+
+private:
+    SERVICE_SERIALIZATION(CECD_U, cecd, Module)
 };
 
 } // namespace Service::CECD
+
+BOOST_CLASS_EXPORT_KEY(Service::CECD::CECD_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CECD::CECD_U)
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index df6fd2e76..655405e77 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -6,6 +6,7 @@
 #include <tuple>
 #include <cryptopp/osrng.h>
 #include <cryptopp/sha.h>
+#include "common/archives.h"
 #include "common/common_paths.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
@@ -24,8 +25,18 @@
 #include "core/hle/service/cfg/cfg_u.h"
 #include "core/settings.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CFG::Module)
+
 namespace Service::CFG {
 
+template <class Archive>
+void Module::serialize(Archive& ar, const unsigned int) {
+    ar& cfg_config_file_buffer;
+    ar& cfg_system_save_data_archive;
+    ar& preferred_region_code;
+}
+SERIALIZE_IMPL(Module)
+
 /// The maximum number of block entries that can exist in the config file
 static const u32 CONFIG_FILE_MAX_BLOCK_ENTRIES = 1479;
 
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
index 6886d513b..58e914583 100644
--- a/src/core/hle/service/cfg/cfg.h
+++ b/src/core/hle/service/cfg/cfg.h
@@ -244,7 +244,7 @@ public:
             (this->*function)(ctx, id);
         }
 
-    private:
+    protected:
         std::shared_ptr<Module> cfg;
     };
 
@@ -426,6 +426,10 @@ private:
     std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer;
     std::unique_ptr<FileSys::ArchiveBackend> cfg_system_save_data_archive;
     u32 preferred_region_code = 0;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 std::shared_ptr<Module> GetModule(Core::System& system);
@@ -436,3 +440,5 @@ void InstallInterfaces(Core::System& system);
 std::string GetConsoleIdHash(Core::System& system);
 
 } // namespace Service::CFG
+
+BOOST_CLASS_EXPORT_KEY(Service::CFG::Module)
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp
index 624299076..4d3d298a2 100644
--- a/src/core/hle/service/cfg/cfg_i.cpp
+++ b/src/core/hle/service/cfg/cfg_i.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cfg/cfg_i.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CFG::CFG_I)
+
 namespace Service::CFG {
 
 CFG_I::CFG_I(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:i", 23) {
diff --git a/src/core/hle/service/cfg/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h
index 704eb4a71..ac8ffb990 100644
--- a/src/core/hle/service/cfg/cfg_i.h
+++ b/src/core/hle/service/cfg/cfg_i.h
@@ -11,6 +11,12 @@ namespace Service::CFG {
 class CFG_I final : public Module::Interface {
 public:
     explicit CFG_I(std::shared_ptr<Module> cfg);
+
+private:
+    SERVICE_SERIALIZATION(CFG_I, cfg, Module)
 };
 
 } // namespace Service::CFG
+
+BOOST_CLASS_EXPORT_KEY(Service::CFG::CFG_I)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CFG::CFG_I)
diff --git a/src/core/hle/service/cfg/cfg_nor.cpp b/src/core/hle/service/cfg/cfg_nor.cpp
index 413548313..0dd21076d 100644
--- a/src/core/hle/service/cfg/cfg_nor.cpp
+++ b/src/core/hle/service/cfg/cfg_nor.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cfg/cfg_nor.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CFG::CFG_NOR)
+
 namespace Service::CFG {
 
 CFG_NOR::CFG_NOR() : ServiceFramework("cfg:nor", 23) {
diff --git a/src/core/hle/service/cfg/cfg_nor.h b/src/core/hle/service/cfg/cfg_nor.h
index 3dace92bd..1eca85a05 100644
--- a/src/core/hle/service/cfg/cfg_nor.h
+++ b/src/core/hle/service/cfg/cfg_nor.h
@@ -14,3 +14,5 @@ public:
 };
 
 } // namespace Service::CFG
+
+BOOST_CLASS_EXPORT_KEY(Service::CFG::CFG_NOR)
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index a211dae05..773a412f7 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cfg/cfg_s.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CFG::CFG_S)
+
 namespace Service::CFG {
 
 CFG_S::CFG_S(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:s", 23) {
diff --git a/src/core/hle/service/cfg/cfg_s.h b/src/core/hle/service/cfg/cfg_s.h
index 7f135b357..d0cbc7a18 100644
--- a/src/core/hle/service/cfg/cfg_s.h
+++ b/src/core/hle/service/cfg/cfg_s.h
@@ -11,6 +11,12 @@ namespace Service::CFG {
 class CFG_S final : public Module::Interface {
 public:
     explicit CFG_S(std::shared_ptr<Module> cfg);
+
+private:
+    SERVICE_SERIALIZATION(CFG_S, cfg, Module)
 };
 
 } // namespace Service::CFG
+
+BOOST_CLASS_EXPORT_KEY(Service::CFG::CFG_S)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CFG::CFG_S)
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index 6aa862f82..bcc590bf8 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -2,8 +2,11 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "core/hle/service/cfg/cfg_u.h"
 
+SERIALIZE_EXPORT_IMPL(Service::CFG::CFG_U)
+
 namespace Service::CFG {
 
 CFG_U::CFG_U(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "cfg:u", 23) {
diff --git a/src/core/hle/service/cfg/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h
index 8b48e963e..906377124 100644
--- a/src/core/hle/service/cfg/cfg_u.h
+++ b/src/core/hle/service/cfg/cfg_u.h
@@ -11,6 +11,12 @@ namespace Service::CFG {
 class CFG_U final : public Module::Interface {
 public:
     explicit CFG_U(std::shared_ptr<Module> cfg);
+
+private:
+    SERVICE_SERIALIZATION(CFG_U, cfg, Module)
 };
 
 } // namespace Service::CFG
+
+BOOST_CLASS_EXPORT_KEY(Service::CFG::CFG_U)
+BOOST_SERIALIZATION_CONSTRUCT(Service::CFG::CFG_U)
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 862e74980..29965491b 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -260,6 +260,13 @@ private:
      */
     std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map;
     ArchiveHandle next_handle = 1;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& id_code_map;
+        ar& handle_map;
+        ar& next_handle;
+    }
 };
 
 } // namespace Service::FS

From 2bf5b464609348e786a068074d41e74fb5331a35 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 2 Jan 2020 23:34:26 +0000
Subject: [PATCH 053/129] Basic archive backend serialization

---
 TODO                                          | 23 +++++++------
 src/core/file_sys/archive_extsavedata.cpp     |  3 ++
 src/core/file_sys/archive_extsavedata.h       | 12 +++++++
 src/core/file_sys/archive_ncch.cpp            |  5 +++
 src/core/file_sys/archive_ncch.h              | 34 ++++++++++++++++++-
 src/core/file_sys/archive_other_savedata.cpp  |  4 +++
 src/core/file_sys/archive_other_savedata.h    | 23 +++++++++++--
 src/core/file_sys/archive_savedata.cpp        |  3 ++
 src/core/file_sys/archive_savedata.h          | 12 ++++++-
 src/core/file_sys/archive_sdmc.cpp            |  4 +++
 src/core/file_sys/archive_sdmc.h              | 21 ++++++++++++
 src/core/file_sys/archive_sdmcwriteonly.cpp   |  4 +++
 src/core/file_sys/archive_sdmcwriteonly.h     | 18 ++++++++++
 .../file_sys/archive_source_sd_savedata.cpp   |  3 ++
 .../file_sys/archive_source_sd_savedata.h     | 11 ++++++
 src/core/file_sys/archive_systemsavedata.cpp  |  3 ++
 src/core/file_sys/archive_systemsavedata.h    | 11 ++++++
 src/core/file_sys/file_backend.h              |  7 +++-
 18 files changed, 185 insertions(+), 16 deletions(-)

diff --git a/TODO b/TODO
index 5ea46f2e8..c1f5e49cd 100644
--- a/TODO
+++ b/TODO
@@ -10,19 +10,20 @@
 ✘ App loader @cancelled(20-01-01 22:59)
     No relevant state
 ☐ Archive manager @started(20-01-01 23:03)
-    ☐ NCCH
-        ☐ Normal
+    ☐ NCCH @started(20-01-02 22:50)
+        ✔ Normal @done(20-01-02 22:50)
         ☐ Self
-    ☐ SaveData
-        ☐ Normal
-        ☐ Ext
-        ☐ Other
-        ☐ Source SD
-        ☐ System
-    ☐ SDMC
-        ☐ Normal
-        ☐ Write-only
+    ✔ SaveData @started(20-01-02 23:03) @done(20-01-02 23:27) @lasted(25m)
+        ✔ Normal @done(20-01-02 23:03)
+        ✔ Ext @done(20-01-02 23:26)
+        ✔ Other @done(20-01-02 23:21)
+        ✔ Source SD @done(20-01-02 23:03)
+        ✔ System @done(20-01-02 23:13)
+    ✔ SDMC @done(20-01-02 23:34)
+        ✔ Normal @done(20-01-02 23:34)
+        ✔ Write-only @done(20-01-02 23:34)
     ☐ File refs
+    ☐ Replace delay generator with virtual fns
 ☐ Custom texture cache
 ✘ MMIO @cancelled(20-01-01 01:06)
     Seems that this whole subsystem is only used in tests
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index efcdb2d7f..22084b690 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -6,6 +6,7 @@
 #include <memory>
 #include <vector>
 #include <fmt/format.h>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
@@ -19,6 +20,8 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_ExtSaveData)
+
 namespace FileSys {
 
 /**
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index 7dc345c84..b00e1633d 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -6,6 +6,8 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
@@ -54,6 +56,14 @@ private:
 
     /// Returns a path with the correct SaveIdHigh value for Shared extdata paths.
     Path GetCorrectedPath(const Path& path);
+
+    ArchiveFactory_ExtSaveData() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& shared;
+        ar& mount_point;
+    }
+    friend class boost::serialization::access;
 };
 
 /**
@@ -94,3 +104,5 @@ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared)
 Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low);
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_ExtSaveData)
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp
index 06fe69622..789547f0e 100644
--- a/src/core/file_sys/archive_ncch.cpp
+++ b/src/core/file_sys/archive_ncch.cpp
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 #include "bad_word_list.app.romfs.h"
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
@@ -28,6 +29,10 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::NCCHArchive)
+SERIALIZE_EXPORT_IMPL(FileSys::NCCHFile)
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_NCCH)
+
 namespace FileSys {
 
 struct NCCHArchivePath {
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index 28d9ff044..52ae827c3 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -7,6 +7,9 @@
 #include <array>
 #include <memory>
 #include <string>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/vector.hpp>
 #include "core/file_sys/archive_backend.h"
 #include "core/file_sys/file_backend.h"
 #include "core/hle/result.h"
@@ -63,6 +66,17 @@ public:
 protected:
     u64 title_id;
     Service::FS::MediaType media_type;
+
+private:
+    NCCHArchive() = default; // NOTE: If the public ctor has behaviour, need to replace this with
+                             // *_construct_data
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveBackend>(*this);
+        ar& title_id;
+        ar& media_type;
+    }
+    friend class boost::serialization::access;
 };
 
 // File backend for NCCH files
@@ -81,7 +95,16 @@ public:
     void Flush() const override {}
 
 private:
-    std::vector<u8> file_buffer;
+    NCCHFile() = default; // NOTE: If the public ctor has behaviour, need to replace this with
+                          // *_construct_data
+    std::vector<u8> file_buffer; // TODO: Replace with file ref for serialization
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<FileBackend>(*this);
+        ar& file_buffer;
+    }
+    friend class boost::serialization::access;
 };
 
 /// File system interface to the NCCH archive
@@ -97,6 +120,15 @@ public:
     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
                       u64 program_id) override;
     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::NCCHArchive)
+BOOST_CLASS_EXPORT_KEY(FileSys::NCCHFile)
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_NCCH)
diff --git a/src/core/file_sys/archive_other_savedata.cpp b/src/core/file_sys/archive_other_savedata.cpp
index 1c3b071ba..d4f8debc4 100644
--- a/src/core/file_sys/archive_other_savedata.cpp
+++ b/src/core/file_sys/archive_other_savedata.cpp
@@ -4,6 +4,7 @@
 
 #include <tuple>
 #include <utility>
+#include "common/archives.h"
 #include "core/file_sys/archive_other_savedata.h"
 #include "core/file_sys/errors.h"
 #include "core/hle/kernel/process.h"
@@ -12,6 +13,9 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_OtherSaveDataPermitted)
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_OtherSaveDataGeneral)
+
 namespace FileSys {
 
 // TODO(wwylele): The storage info in exheader should be checked before accessing these archives
diff --git a/src/core/file_sys/archive_other_savedata.h b/src/core/file_sys/archive_other_savedata.h
index e3e8f83c3..a9deae95a 100644
--- a/src/core/file_sys/archive_other_savedata.h
+++ b/src/core/file_sys/archive_other_savedata.h
@@ -4,6 +4,8 @@
 
 #pragma once
 
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "core/file_sys/archive_source_sd_savedata.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -27,8 +29,15 @@ public:
     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
 
 private:
-    std::string mount_point;
+    std::string mount_point; // TODO: Remove, unused?
     std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
+
+    ArchiveFactory_OtherSaveDataPermitted() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& sd_savedata_source;
+    }
+    friend class boost::serialization::access;
 };
 
 /// File system interface to the OtherSaveDataGeneral archive
@@ -47,8 +56,18 @@ public:
     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
 
 private:
-    std::string mount_point;
+    std::string mount_point; // TODO: Remove, unused?
     std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
+
+    ArchiveFactory_OtherSaveDataGeneral() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& sd_savedata_source;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_OtherSaveDataPermitted)
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_OtherSaveDataGeneral)
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index c1046e2f5..fc4bd34fa 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <utility>
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/file_sys/archive_savedata.h"
 #include "core/hle/kernel/process.h"
@@ -10,6 +11,8 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SaveData)
+
 namespace FileSys {
 
 ArchiveFactory_SaveData::ArchiveFactory_SaveData(
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index 591a3b900..3ebe94a63 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <boost/serialization/shared_ptr.hpp>
 #include "core/file_sys/archive_source_sd_savedata.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -27,8 +28,17 @@ public:
     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
 
 private:
-    std::string mount_point;
+    std::string mount_point; // TODO: Remove this? seems unused
     std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
+
+    ArchiveFactory_SaveData() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& sd_savedata_source;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SaveData)
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index d2269fe7c..1c5118320 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <memory>
+#include "common/archives.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
 #include "core/file_sys/archive_sdmc.h"
@@ -15,6 +16,9 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::SDMCArchive)
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SDMC)
+
 namespace FileSys {
 
 class SDMCDelayGenerator : public DelayGenerator {
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 41d7b7c59..2e0abf44b 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -6,6 +6,9 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/string.hpp>
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
 
@@ -42,6 +45,14 @@ public:
 protected:
     ResultVal<std::unique_ptr<FileBackend>> OpenFileBase(const Path& path, const Mode& mode) const;
     std::string mount_point;
+
+    SDMCArchive() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveBackend>(*this);
+        ar& mount_point;
+    }
+    friend class boost::serialization::access;
 };
 
 /// File system interface to the SDMC archive
@@ -66,6 +77,16 @@ public:
 
 private:
     std::string sdmc_directory;
+
+    ArchiveFactory_SDMC() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& sdmc_directory;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::SDMCArchive)
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SDMC)
diff --git a/src/core/file_sys/archive_sdmcwriteonly.cpp b/src/core/file_sys/archive_sdmcwriteonly.cpp
index 74552d751..ea64dc864 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.cpp
+++ b/src/core/file_sys/archive_sdmcwriteonly.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <memory>
+#include "common/archives.h"
 #include "common/file_util.h"
 #include "core/file_sys/archive_sdmcwriteonly.h"
 #include "core/file_sys/directory_backend.h"
@@ -13,6 +14,9 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::SDMCWriteOnlyArchive)
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SDMCWriteOnly)
+
 namespace FileSys {
 
 class SDMCWriteOnlyDelayGenerator : public DelayGenerator {
diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h
index 8191f053f..2ba504aa7 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.h
+++ b/src/core/file_sys/archive_sdmcwriteonly.h
@@ -31,6 +31,14 @@ public:
                                                      const Mode& mode) const override;
 
     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
+
+private:
+    SDMCWriteOnlyArchive() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<SDMCArchive>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 /// File system interface to the SDMC write-only archive
@@ -55,6 +63,16 @@ public:
 
 private:
     std::string sdmc_directory;
+
+    ArchiveFactory_SDMCWriteOnly() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& sdmc_directory;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::SDMCWriteOnlyArchive)
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SDMCWriteOnly)
diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp
index 0b8072b96..9afbfd73c 100644
--- a/src/core/file_sys/archive_source_sd_savedata.cpp
+++ b/src/core/file_sys/archive_source_sd_savedata.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <fmt/format.h>
+#include "common/archives.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
 #include "core/file_sys/archive_source_sd_savedata.h"
@@ -13,6 +14,8 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveSource_SDSaveData)
+
 namespace FileSys {
 
 namespace {
diff --git a/src/core/file_sys/archive_source_sd_savedata.h b/src/core/file_sys/archive_source_sd_savedata.h
index b5fe43cc1..4ac028a3d 100644
--- a/src/core/file_sys/archive_source_sd_savedata.h
+++ b/src/core/file_sys/archive_source_sd_savedata.h
@@ -6,6 +6,8 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/string.hpp>
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
 
@@ -27,6 +29,15 @@ public:
 
 private:
     std::string mount_point;
+
+    ArchiveSource_SDSaveData() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& mount_point;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveSource_SDSaveData)
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index cef42e561..ecfb34219 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -7,6 +7,7 @@
 #include <memory>
 #include <vector>
 #include <fmt/format.h>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "core/file_sys/archive_systemsavedata.h"
@@ -17,6 +18,8 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SystemSaveData)
+
 namespace FileSys {
 
 std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) {
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index e72ecce3a..cf18cab89 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -6,6 +6,8 @@
 
 #include <memory>
 #include <string>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
@@ -31,6 +33,13 @@ public:
 
 private:
     std::string base_path;
+
+    ArchiveFactory_SystemSaveData() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& base_path;
+    }
+    friend class boost::serialization::access;
 };
 
 /**
@@ -60,3 +69,5 @@ std::string GetSystemSaveDataContainerPath(const std::string& mount_point);
 Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low);
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SystemSaveData)
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index c865c98e8..03dff156d 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -89,7 +89,12 @@ public:
     virtual void Flush() const = 0;
 
 protected:
-    std::unique_ptr<DelayGenerator> delay_generator;
+    std::unique_ptr<DelayGenerator> delay_generator; // TODO: replace with virtual Get*DelayNs
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys

From 558e710e170030e1e9bc8f0105f571b44a43bb79 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 3 Jan 2020 14:00:10 +0000
Subject: [PATCH 054/129] Finished archives; remove pod.h

---
 TODO                                   | 17 +++++++++++------
 src/common/pod.h                       | 17 -----------------
 src/core/file_sys/archive_backend.h    |  4 +++-
 src/core/file_sys/archive_ncch.cpp     |  1 -
 src/core/file_sys/archive_ncch.h       |  8 --------
 src/core/file_sys/archive_selfncch.cpp |  3 +++
 src/core/file_sys/archive_selfncch.h   |  6 +++++-
 src/core/file_sys/delay_generator.cpp  |  3 +++
 src/core/file_sys/delay_generator.h    |  8 ++++++++
 src/core/file_sys/file_backend.h       |  7 +------
 src/core/hle/result.h                  |  9 +++++++--
 src/core/hw/gpu.h                      | 10 ++++++++--
 src/core/hw/lcd.h                      | 12 ++++++++++--
 src/video_core/shader/shader.h         | 15 +++++++++++++--
 14 files changed, 72 insertions(+), 48 deletions(-)
 delete mode 100644 src/common/pod.h

diff --git a/TODO b/TODO
index c1f5e49cd..bc4003d44 100644
--- a/TODO
+++ b/TODO
@@ -9,10 +9,11 @@
     ✔ Fix or ignore inverse map @done(19-12-23 12:46)
 ✘ App loader @cancelled(20-01-01 22:59)
     No relevant state
-☐ Archive manager @started(20-01-01 23:03)
-    ☐ NCCH @started(20-01-02 22:50)
+✔ Archive manager @started(20-01-01 23:03) @done(20-01-03 13:23) @lasted(1d14h20m40s)
+    NB that 'FileBackend' classes are not persistent
+    ✔ NCCH @started(20-01-02 22:50) @done(20-01-03 12:35) @lasted(13h45m50s)
         ✔ Normal @done(20-01-02 22:50)
-        ☐ Self
+        ✔ Self @done(20-01-03 12:35)
     ✔ SaveData @started(20-01-02 23:03) @done(20-01-02 23:27) @lasted(25m)
         ✔ Normal @done(20-01-02 23:03)
         ✔ Ext @done(20-01-02 23:26)
@@ -22,8 +23,12 @@
     ✔ SDMC @done(20-01-02 23:34)
         ✔ Normal @done(20-01-02 23:34)
         ✔ Write-only @done(20-01-02 23:34)
-    ☐ File refs
-    ☐ Replace delay generator with virtual fns
+    ✘ IVFC @cancelled(20-01-03 13:22)
+        Seems IVFCArchive is never used.. which is good because it has a file reference!
+    ✘ File refs @cancelled(20-01-03 13:22)
+        Not needed as nothing serializes file buffers
+    ✘ Replace delay generator with virtual fns @cancelled(20-01-03 13:16)
+        While they have no state, the extra refactoring here is unneeded
 ☐ Custom texture cache
 ✘ MMIO @cancelled(20-01-01 01:06)
     Seems that this whole subsystem is only used in tests
@@ -35,7 +40,7 @@
     For now, let the settings just be whatever they are
 ✘ Telemetry session @cancelled(20-01-01 01:12)
     Doesn't need to be serialized here
-☐ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE
+✔ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE @started(20-01-03 13:47) @done(20-01-03 13:58) @lasted(11m22s)
 ☐ Review constructor/initialization code
 ✔ Fix CI @done(19-12-31 21:32)
 ✔ HW @done(19-08-13 15:41)
diff --git a/src/common/pod.h b/src/common/pod.h
deleted file mode 100644
index bb7095417..000000000
--- a/src/common/pod.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "boost/serialization/split_member.hpp"
-
-#define SERIALIZE_AS_POD                                                                           \
-private:                                                                                           \
-    friend class boost::serialization::access;                                                     \
-    template <typename Archive>                                                                    \
-    void save(Archive& ar, const unsigned int file_version) const {                                \
-        ar.save_binary(this, sizeof(*this));                                                       \
-    }                                                                                              \
-    template <typename Archive>                                                                    \
-    void load(Archive& ar, const unsigned int file_version) {                                      \
-        ar.load_binary(this, sizeof(*this));                                                       \
-    }                                                                                              \
-    template <class Archive>                                                                       \
-    void serialize(Archive& ar, const unsigned int file_version) {                                 \
-        boost::serialization::split_member(ar, *this, file_version);                               \
-    }
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 05aa877a3..756613a30 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -172,7 +172,9 @@ protected:
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {}
+    void serialize(Archive& ar, const unsigned int) {
+        ar& delay_generator;
+    }
     friend class boost::serialization::access;
 };
 
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp
index 789547f0e..636bb81ed 100644
--- a/src/core/file_sys/archive_ncch.cpp
+++ b/src/core/file_sys/archive_ncch.cpp
@@ -30,7 +30,6 @@
 // FileSys namespace
 
 SERIALIZE_EXPORT_IMPL(FileSys::NCCHArchive)
-SERIALIZE_EXPORT_IMPL(FileSys::NCCHFile)
 SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_NCCH)
 
 namespace FileSys {
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index 52ae827c3..0a3f95b5c 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -98,13 +98,6 @@ private:
     NCCHFile() = default; // NOTE: If the public ctor has behaviour, need to replace this with
                           // *_construct_data
     std::vector<u8> file_buffer; // TODO: Replace with file ref for serialization
-
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& boost::serialization::base_object<FileBackend>(*this);
-        ar& file_buffer;
-    }
-    friend class boost::serialization::access;
 };
 
 /// File system interface to the NCCH archive
@@ -130,5 +123,4 @@ private:
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::NCCHArchive)
-BOOST_CLASS_EXPORT_KEY(FileSys::NCCHFile)
 BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_NCCH)
diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp
index 0f8dd8065..214ad7c08 100644
--- a/src/core/file_sys/archive_selfncch.cpp
+++ b/src/core/file_sys/archive_selfncch.cpp
@@ -4,6 +4,7 @@
 
 #include <array>
 #include <cinttypes>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "common/swap.h"
@@ -16,6 +17,8 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SelfNCCH)
+
 namespace FileSys {
 
 enum class SelfNCCHFilePathType : u32 {
diff --git a/src/core/file_sys/archive_selfncch.h b/src/core/file_sys/archive_selfncch.h
index 779e7e75a..de7fd75e0 100644
--- a/src/core/file_sys/archive_selfncch.h
+++ b/src/core/file_sys/archive_selfncch.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
@@ -44,7 +45,10 @@ public:
 
 private:
     /// Mapping of ProgramId -> NCCHData
-    std::unordered_map<u64, NCCHData> ncch_data;
+    std::unordered_map<u64, NCCHData>
+        ncch_data; // TODO: Remove this, or actually set the values here
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SelfNCCH)
diff --git a/src/core/file_sys/delay_generator.cpp b/src/core/file_sys/delay_generator.cpp
index 04f877f83..137e63d69 100644
--- a/src/core/file_sys/delay_generator.cpp
+++ b/src/core/file_sys/delay_generator.cpp
@@ -3,8 +3,11 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include "common/archives.h"
 #include "core/file_sys/delay_generator.h"
 
+SERIALIZE_EXPORT_IMPL(FileSys::DefaultDelayGenerator)
+
 namespace FileSys {
 
 DelayGenerator::~DelayGenerator() = default;
diff --git a/src/core/file_sys/delay_generator.h b/src/core/file_sys/delay_generator.h
index d530f2ee2..8fa92ac41 100644
--- a/src/core/file_sys/delay_generator.h
+++ b/src/core/file_sys/delay_generator.h
@@ -5,6 +5,8 @@
 #pragma once
 
 #include <cstddef>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 
 namespace FileSys {
@@ -16,6 +18,10 @@ public:
     virtual u64 GetOpenDelayNs() = 0;
 
     // TODO (B3N30): Add getter for all other file/directory io operations
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 class DefaultDelayGenerator : public DelayGenerator {
@@ -25,3 +31,5 @@ public:
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::DefaultDelayGenerator);
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 03dff156d..c865c98e8 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -89,12 +89,7 @@ public:
     virtual void Flush() const = 0;
 
 protected:
-    std::unique_ptr<DelayGenerator> delay_generator; // TODO: replace with virtual Get*DelayNs
-
-private:
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {}
-    friend class boost::serialization::access;
+    std::unique_ptr<DelayGenerator> delay_generator;
 };
 
 } // namespace FileSys
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 4168ce36c..40a71e369 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -6,11 +6,11 @@
 
 #include <new>
 #include <utility>
+#include <boost/serialization/access.hpp>
 #include "common/assert.h"
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
-#include "common/pod.h"
 
 // All the constants in this file come from http://3dbrew.org/wiki/Error_codes
 
@@ -227,7 +227,12 @@ union ResultCode {
         return is_error.ExtractValue(raw) == 1;
     }
 
-    SERIALIZE_AS_POD
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& raw;
+    }
+    friend class boost::serialization::access;
 };
 
 constexpr bool operator==(const ResultCode& a, const ResultCode& b) {
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 980b48cd7..fcf7a3137 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -6,11 +6,12 @@
 
 #include <cstddef>
 #include <type_traits>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/binary_object.hpp>
 #include "common/assert.h"
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
-#include "common/pod.h"
 
 namespace Memory {
 class MemorySystem;
@@ -298,7 +299,12 @@ private:
         return register_value * 8;
     }
 
-    SERIALIZE_AS_POD
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        auto obj = boost::serialization::binary_object(this, sizeof(Regs));
+        ar& obj;
+    }
+    friend class boost::serialization::access;
 };
 static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
 
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index ecc9ecea4..9667c7c4c 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -6,10 +6,10 @@
 
 #include <cstddef>
 #include <type_traits>
+#include <boost/serialization/access.hpp>
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
-#include "common/pod.h"
 
 #define LCD_REG_INDEX(field_name) (offsetof(LCD::Regs, field_name) / sizeof(u32))
 
@@ -52,7 +52,15 @@ struct Regs {
         return content[index];
     }
 
-    SERIALIZE_AS_POD
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& color_fill_top.raw;
+        ar& backlight_top;
+        ar& color_fill_bottom.raw;
+        ar& backlight_bottom;
+    }
+    friend class boost::serialization::access;
 };
 static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
 
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index a6e42b3bf..6a5a33419 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -8,6 +8,7 @@
 #include <cstddef>
 #include <functional>
 #include <type_traits>
+#include <boost/serialization/access.hpp>
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/base_object.hpp>
 #include <nihstro/shader_bytecode.h>
@@ -15,7 +16,6 @@
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/hash.h"
-#include "common/pod.h"
 #include "common/vector_math.h"
 #include "video_core/pica_types.h"
 #include "video_core/regs_rasterizer.h"
@@ -65,7 +65,18 @@ struct OutputVertex {
     static OutputVertex FromAttributeBuffer(const RasterizerRegs& regs,
                                             const AttributeBuffer& output);
 
-    SERIALIZE_AS_POD
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& pos;
+        ar& quat;
+        ar& tc0;
+        ar& tc1;
+        ar& tc0_w;
+        ar& view;
+        ar& tc2;
+    }
+    friend class boost::serialization::access;
 };
 #define ASSERT_POS(var, pos)                                                                       \
     static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong "       \

From 26e90a99cd25685ee96184a8e21ff010913d8895 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 3 Jan 2020 17:19:59 +0000
Subject: [PATCH 055/129] Added basic UI; misc memory fixes

---
 TODO                             | 13 +++++++++----
 src/citra_qt/main.cpp            | 24 ++++++++++++++++++++++++
 src/citra_qt/main.h              |  2 ++
 src/citra_qt/main.ui             | 18 ++++++++++++++++++
 src/common/CMakeLists.txt        |  1 -
 src/core/hle/kernel/config_mem.h |  3 +--
 src/core/hle/kernel/ipc.cpp      | 12 ++++++------
 src/core/hle/kernel/ipc.h        | 12 +++++-------
 src/core/hle/kernel/process.cpp  |  2 +-
 src/core/hle/kernel/process.h    |  2 +-
 src/core/hw/gpu.h                |  3 +--
 src/core/memory.cpp              | 19 ++++++++-----------
 src/core/memory.h                | 15 ++++++++++++++-
 13 files changed, 90 insertions(+), 36 deletions(-)

diff --git a/TODO b/TODO
index bc4003d44..ad64a0084 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,11 @@
 ☐ Save/load UI
+    ✔ Basic version @done(20-01-03 15:27)
+    ☐ Multiple slots etc.
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
     ☐ Page tables
-    ☐ Skip N3DS RAM if unused
+    ✘ Skip N3DS RAM if unused @cancelled(20-01-03 15:26)
+        Since no n3ds support, leave this for now
 ✔ DSP @done(19-12-28 16:57)
     Memory only
 ✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
@@ -67,14 +70,16 @@
         ✔ Mutex @done(19-08-13 16:43)
         ✔ Object @done(19-08-13 15:41)
         ✔ Process @started(19-08-13 16:43) @done(19-12-22 18:41)
-        ☐ Code set @started(19-12-22 18:41)
+        ✔ Code set @started(19-12-22 18:41) @done(20-01-03 15:15) @lasted(1w4d20h34m2s)
             Needs a way to reference loaded images (so we don't serialize the entire ROM as well)
+            ☐ Serialize codeset with an apploader reference instead
         ✔ Resource limit @done(19-08-13 16:43)
         ✔ Semaphore @done(19-08-13 16:44)
         ✔ Server port @done(19-08-13 16:44)
         ✔ Server session @done(19-08-13 16:44)
-            ☐ Mapped buffer context
-                This may not be needed!
+            ✔ Mapped buffer context @done(20-01-03 15:25)
+                This is needed because IPC can take as long as it takes
+                Changed the unique_ptr<u8[]> to vector<u8>
         ✔ Session @done(19-08-13 16:44)
         ☐ Shared memory @started(19-12-22 21:20)
             Need to figure out backing memory (a u8*)
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index daccbb083..08e3cac02 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <clocale>
+#include <fstream>
 #include <memory>
 #include <thread>
 #include <QDesktopWidget>
@@ -606,6 +607,8 @@ void GMainWindow::ConnectMenuEvents() {
             &GMainWindow::OnMenuReportCompatibility);
     connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
     connect(ui.action_Cheats, &QAction::triggered, this, &GMainWindow::OnCheats);
+    connect(ui.action_Save, &QAction::triggered, this, &GMainWindow::OnSave);
+    connect(ui.action_Load, &QAction::triggered, this, &GMainWindow::OnLoad);
 
     // View
     connect(ui.action_Single_Window_Mode, &QAction::triggered, this,
@@ -1033,6 +1036,8 @@ void GMainWindow::ShutdownGame() {
     ui.action_Stop->setEnabled(false);
     ui.action_Restart->setEnabled(false);
     ui.action_Cheats->setEnabled(false);
+    ui.action_Save->setEnabled(false);
+    ui.action_Load->setEnabled(false);
     ui.action_Load_Amiibo->setEnabled(false);
     ui.action_Remove_Amiibo->setEnabled(false);
     ui.action_Report_Compatibility->setEnabled(false);
@@ -1343,6 +1348,8 @@ void GMainWindow::OnStartGame() {
     ui.action_Stop->setEnabled(true);
     ui.action_Restart->setEnabled(true);
     ui.action_Cheats->setEnabled(true);
+    ui.action_Save->setEnabled(true);
+    ui.action_Load->setEnabled(true);
     ui.action_Load_Amiibo->setEnabled(true);
     ui.action_Report_Compatibility->setEnabled(true);
     ui.action_Enable_Frame_Advancing->setEnabled(true);
@@ -1496,6 +1503,23 @@ void GMainWindow::OnCheats() {
     cheat_dialog.exec();
 }
 
+void GMainWindow::OnSave() {
+    Core::System& system{Core::System::GetInstance()};
+    auto fs = std::ofstream("save0.citrasave");
+    emu_thread->SetRunning(false);
+    Core::System::GetInstance().Save(fs);
+    emu_thread->SetRunning(true);
+}
+
+void GMainWindow::OnLoad() {
+    if (QFileInfo("save0.citrasave").exists()) {
+        auto fs = std::ifstream("save0.citrasave");
+        emu_thread->SetRunning(false);
+        Core::System::GetInstance().Load(fs);
+        emu_thread->SetRunning(true);
+    }
+}
+
 void GMainWindow::OnConfigure() {
     ConfigureDialog configureDialog(this, hotkey_registry,
                                     !multiplayer_state->IsHostingPublicRoom());
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 91d7eed1b..1858d5988 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -163,6 +163,8 @@ private slots:
     void OnStartGame();
     void OnPauseGame();
     void OnStopGame();
+    void OnSave();
+    void OnLoad();
     void OnMenuReportCompatibility();
     /// Called whenever a user selects a game in the game list widget.
     void OnGameListLoadFile(QString game_path);
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index 6011b0e7f..c0c38e4c8 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -88,6 +88,8 @@
     <addaction name="separator"/>
     <addaction name="action_Configure"/>
     <addaction name="action_Cheats"/>
+    <addaction name="action_Save"/>
+    <addaction name="action_Load"/>
    </widget>
    <widget class="QMenu" name="menu_View">
     <property name="title">
@@ -217,6 +219,22 @@
     <string>&amp;Stop</string>
    </property>
   </action>
+  <action name="action_Save">
+    <property name="enabled">
+      <bool>false</bool>
+    </property>
+    <property name="text">
+      <string>Save</string>
+    </property>
+  </action>
+  <action name="action_Load">
+    <property name="enabled">
+      <bool>false</bool>
+    </property>
+    <property name="text">
+      <string>Load</string>
+    </property>
+  </action>
   <action name="action_FAQ">
    <property name="text">
     <string>FAQ</string>
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 39ddffbcc..c6294c464 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -86,7 +86,6 @@ add_library(common STATIC
     misc.cpp
     param_package.cpp
     param_package.h
-    pod.h
     quaternion.h
     ring_buffer.h
     scm_rev.cpp
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index e4e895516..ef1c889a0 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -61,8 +61,7 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
-        auto o_config_mem = boost::serialization::binary_object(&config_mem, sizeof(config_mem));
-        ar& o_config_mem;
+        ar& boost::serialization::make_binary_object(&config_mem, sizeof(config_mem));
     }
 };
 
diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp
index 3dacb9831..e45b87e49 100644
--- a/src/core/hle/kernel/ipc.cpp
+++ b/src/core/hle/kernel/ipc.cpp
@@ -193,19 +193,19 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
             // TODO(Subv): Perform permission checks.
 
             // Reserve a page of memory before the mapped buffer
-            auto reserve_buffer = std::make_unique<u8[]>(Memory::PAGE_SIZE);
+            auto reserve_buffer = std::vector<u8>(Memory::PAGE_SIZE);
             dst_process->vm_manager.MapBackingMemoryToBase(
-                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.get(),
+                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.data(),
                 Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
 
-            auto buffer = std::make_unique<u8[]>(num_pages * Memory::PAGE_SIZE);
-            memory.ReadBlock(*src_process, source_address, buffer.get() + page_offset, size);
+            auto buffer = std::vector<u8>(num_pages * Memory::PAGE_SIZE);
+            memory.ReadBlock(*src_process, source_address, buffer.data() + page_offset, size);
 
             // Map the page(s) into the target process' address space.
             target_address =
                 dst_process->vm_manager
                     .MapBackingMemoryToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE,
-                                            buffer.get(), num_pages * Memory::PAGE_SIZE,
+                                            buffer.data(), num_pages * Memory::PAGE_SIZE,
                                             Kernel::MemoryState::Shared)
                     .Unwrap();
 
@@ -213,7 +213,7 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
 
             // Reserve a page of memory after the mapped buffer
             dst_process->vm_manager.MapBackingMemoryToBase(
-                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.get(),
+                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.data(),
                 Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
 
             mapped_buffer_context.push_back({permissions, size, source_address,
diff --git a/src/core/hle/kernel/ipc.h b/src/core/hle/kernel/ipc.h
index 2c69617d4..f9fd1a00e 100644
--- a/src/core/hle/kernel/ipc.h
+++ b/src/core/hle/kernel/ipc.h
@@ -6,7 +6,7 @@
 
 #include <memory>
 #include <vector>
-#include <boost/serialization/unique_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/thread.h"
@@ -25,8 +25,8 @@ struct MappedBufferContext {
     VAddr source_address;
     VAddr target_address;
 
-    std::unique_ptr<u8[]> buffer;
-    std::unique_ptr<u8[]> reserve_buffer;
+    std::vector<u8> buffer;
+    std::vector<u8> reserve_buffer;
 
 private:
     template <class Archive>
@@ -35,10 +35,8 @@ private:
         ar& size;
         ar& source_address;
         ar& target_address;
-        // TODO: Check whether we need these. If we do, add a field for the size and/or change to a
-        // 'vector'
-        // ar & buffer;
-        // ar & reserve_buffer;
+        ar& buffer;
+        ar& reserve_buffer;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 78b695e97..18de2cd91 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -29,7 +29,7 @@ template <class Archive>
 void Process::serialize(Archive& ar, const unsigned int file_version) {
     ar& boost::serialization::base_object<Object>(*this);
     ar& handle_table;
-    ar& codeset;
+    ar& codeset; // TODO: Replace with apploader reference
     ar& resource_limit;
     ar& svc_access_mask;
     ar& handle_table_size;
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index f9aa76c67..576cf7e15 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -133,7 +133,7 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
         ar& boost::serialization::base_object<Object>(*this);
-        // TODO: memory reference
+        ar& memory;
         ar& segments;
         ar& entrypoint;
         ar& name;
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index fcf7a3137..9169bf9ae 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -301,8 +301,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
-        auto obj = boost::serialization::binary_object(this, sizeof(Regs));
-        ar& obj;
+        ar& boost::serialization::make_binary_object(this, sizeof(Regs));
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 6a41ca957..92bce0b69 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -84,18 +84,15 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
-        // TODO: Skip n3ds ram when not used?
-        auto s_fcram = boost::serialization::binary_object(fcram.get(), Memory::FCRAM_N3DS_SIZE);
-        auto s_vram = boost::serialization::binary_object(vram.get(), Memory::VRAM_SIZE);
-        auto s_extra =
-            boost::serialization::binary_object(n3ds_extra_ram.get(), Memory::N3DS_EXTRA_RAM_SIZE);
-        ar& s_fcram;
-        ar& s_vram;
-        ar& s_extra;
+        ar& boost::serialization::make_binary_object(fcram.get(), Memory::FCRAM_N3DS_SIZE);
+        ar& boost::serialization::make_binary_object(vram.get(), Memory::VRAM_SIZE);
+        // TODO: When n3ds support is added, put this back in
+        // ar& boost::serialization::make_binary_object(n3ds_extra_ram.get(),
+        //                                              Memory::N3DS_EXTRA_RAM_SIZE);
+        ar& current_page_table;
         ar& cache_marker;
-        // TODO: How the hell to do page tables..
-        // ar & page_table_list;
-        // ar & current_page_table;
+        ar& page_table_list;
+        // dsp is set from Core::System at startup
     }
 };
 
diff --git a/src/core/memory.h b/src/core/memory.h
index aac57af26..564191d89 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -9,7 +9,9 @@
 #include <memory>
 #include <string>
 #include <vector>
-#include "boost/serialization/access.hpp"
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/mmio.h"
 
@@ -54,12 +56,14 @@ struct SpecialRegion {
     u32 size;
     MMIORegionPointer handler;
 
+private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
         ar& base;
         ar& size;
         ar& handler;
     }
+    friend class boost::serialization::access;
 };
 
 /**
@@ -86,6 +90,15 @@ struct PageTable {
      * the corresponding entry in `pointers` MUST be set to null.
      */
     std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        // TODO: Pointers; same as VMA backing regions we need to serialize the u8*
+        ar& special_regions;
+        ar& attributes;
+    }
+    friend class boost::serialization::access;
 };
 
 /// Physical memory regions as seen from the ARM11

From cf985631e04bd1363b483f28ac020c2d5b4c8883 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 4 Jan 2020 00:40:32 +0000
Subject: [PATCH 056/129] Minor tidying up

---
 TODO                               |  8 ++++----
 src/core/core.cpp                  |  8 ++++++--
 src/core/hle/service/cam/cam.h     |  3 +--
 src/core/hle/service/gsp/gsp.cpp   |  6 +++++-
 src/core/hle/service/gsp/gsp.h     |  2 ++
 src/core/hle/service/gsp/gsp_gpu.h |  1 +
 src/core/memory.cpp                | 13 ++++++++-----
 7 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/TODO b/TODO
index ad64a0084..d72a79712 100644
--- a/TODO
+++ b/TODO
@@ -4,8 +4,7 @@
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
     ☐ Page tables
-    ✘ Skip N3DS RAM if unused @cancelled(20-01-03 15:26)
-        Since no n3ds support, leave this for now
+    ✔ Skip N3DS RAM if unused @done(20-01-03 23:26)
 ✔ DSP @done(19-12-28 16:57)
     Memory only
 ✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
@@ -99,7 +98,7 @@
         ✔ AM @started(19-12-24 23:17) @done(19-12-24 23:53) @lasted(36m8s)
         ✔ APT @done(19-12-25 21:41)
         ✔ BOSS @started(19-12-25 21:48) @done(19-12-25 23:18) @lasted(1h30m14s)
-        ☐ CAM @started(19-12-26 10:37)
+        ✔ CAM @started(19-12-26 10:37) @done(20-01-03 23:38) @lasted(1w1d13h1m50s)
             Need to check capture_result
         ✔ CECD @done(20-01-01 23:58)
         ✔ CFG @done(20-01-02 00:44)
@@ -111,7 +110,8 @@
         ✔ FRD @done(19-12-26 19:09)
         ✔ FS @done(19-12-27 11:46)
         ✔ GSP @done(19-12-30 12:45)
-            ☐ Fix the global weak_ptr to gsp
+            ✔ Fix the global weak_ptr to gsp @done(20-01-04 00:29)
+                Didn't quite 'fix' it but worked around it
         ✔ HID @done(19-12-30 14:46)
         ✔ HTTP @done(19-12-30 15:18)
         ✔ IR @done(19-12-30 16:06)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 5b9b4fca0..a05e2a636 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -31,6 +31,7 @@
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/service/fs/archive.h"
+#include "core/hle/service/gsp/gsp.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hw/gpu.h"
@@ -213,8 +214,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
-                                                    [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(
+        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -413,6 +414,9 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     ar & dsp_core->GetDspMemory();
     ar&* memory.get();
     ar&* kernel.get();
+
+    // This needs to be set from somewhere - might as well be here!
+    Service::GSP::SetGlobalModule(*this);
 }
 
 void System::Save(std::ostream& stream) const {
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 876e2e185..9c56407a3 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -830,8 +830,7 @@ private:
             ar& completion_event;
             ar& buffer_error_interrupt_event;
             ar& vsync_interrupt_event;
-            // TODO: Check if this is ever needed:
-            // ar & capture_result;
+            // Ignore capture_result. In-progress captures might be affected but this is OK.
             ar& dest_process;
             ar& dest;
             ar& dest_size;
diff --git a/src/core/hle/service/gsp/gsp.cpp b/src/core/hle/service/gsp/gsp.cpp
index 3d3f497b2..c360d895c 100644
--- a/src/core/hle/service/gsp/gsp.cpp
+++ b/src/core/hle/service/gsp/gsp.cpp
@@ -10,7 +10,7 @@
 
 namespace Service::GSP {
 
-static std::weak_ptr<GSP_GPU> gsp_gpu; // TODO: Fix this for the love of god
+static std::weak_ptr<GSP_GPU> gsp_gpu;
 
 void SignalInterrupt(InterruptId interrupt_id) {
     auto gpu = gsp_gpu.lock();
@@ -27,4 +27,8 @@ void InstallInterfaces(Core::System& system) {
     std::make_shared<GSP_LCD>()->InstallAsService(service_manager);
 }
 
+void SetGlobalModule(Core::System& system) {
+    gsp_gpu = system.ServiceManager().GetService<GSP_GPU>("gsp::Gpu");
+}
+
 } // namespace Service::GSP
diff --git a/src/core/hle/service/gsp/gsp.h b/src/core/hle/service/gsp/gsp.h
index 4cde19e93..a4dd84f27 100644
--- a/src/core/hle/service/gsp/gsp.h
+++ b/src/core/hle/service/gsp/gsp.h
@@ -23,4 +23,6 @@ namespace Service::GSP {
 void SignalInterrupt(InterruptId interrupt_id);
 
 void InstallInterfaces(Core::System& system);
+
+void SetGlobalModule(Core::System& system);
 } // namespace Service::GSP
diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h
index d1f2c0742..6194f0446 100644
--- a/src/core/hle/service/gsp/gsp_gpu.h
+++ b/src/core/hle/service/gsp/gsp_gpu.h
@@ -444,6 +444,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
         ar& shared_memory;
         ar& active_thread_id;
         ar& first_initialization;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 92bce0b69..cba5867eb 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -18,6 +18,7 @@
 #include "core/hle/kernel/process.h"
 #include "core/hle/lock.h"
 #include "core/memory.h"
+#include "core/settings.h"
 #include "video_core/renderer_base.h"
 #include "video_core/video_core.h"
 
@@ -84,15 +85,17 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
-        ar& boost::serialization::make_binary_object(fcram.get(), Memory::FCRAM_N3DS_SIZE);
+        bool save_n3ds_ram = Settings::values.is_new_3ds;
+        ar& save_n3ds_ram;
         ar& boost::serialization::make_binary_object(vram.get(), Memory::VRAM_SIZE);
-        // TODO: When n3ds support is added, put this back in
-        // ar& boost::serialization::make_binary_object(n3ds_extra_ram.get(),
-        //                                              Memory::N3DS_EXTRA_RAM_SIZE);
-        ar& current_page_table;
+        ar& boost::serialization::make_binary_object(
+            fcram.get(), save_n3ds_ram ? Memory::FCRAM_N3DS_SIZE : Memory::FCRAM_SIZE);
+        ar& boost::serialization::make_binary_object(
+            n3ds_extra_ram.get(), save_n3ds_ram ? Memory::N3DS_EXTRA_RAM_SIZE : 0);
         ar& cache_marker;
         ar& page_table_list;
         // dsp is set from Core::System at startup
+        // current page table set from current process?
     }
 };
 

From 65d96bf6c158b9e8a864947a9c60608fc097e078 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 4 Jan 2020 22:39:54 +0000
Subject: [PATCH 057/129] Changed u8* to MemoryRef

---
 TODO                                   |  11 ++-
 src/common/CMakeLists.txt              |   4 +-
 src/common/memory_ref.cpp              |   4 +
 src/common/memory_ref.h                | 112 +++++++++++++++++++++++
 src/core/arm/dynarmic/arm_dynarmic.cpp |   2 +-
 src/core/hle/kernel/config_mem.h       |  11 ++-
 src/core/hle/kernel/ipc.cpp            |  18 ++--
 src/core/hle/kernel/ipc.h              |   6 +-
 src/core/hle/kernel/kernel.cpp         |   4 +-
 src/core/hle/kernel/kernel.h           |   4 +-
 src/core/hle/kernel/memory.cpp         |  26 +++---
 src/core/hle/kernel/process.cpp        |   8 +-
 src/core/hle/kernel/shared_memory.cpp  |   4 +-
 src/core/hle/kernel/shared_memory.h    |   5 +-
 src/core/hle/kernel/shared_page.cpp    |  12 +++
 src/core/hle/kernel/shared_page.h      |  24 ++++-
 src/core/hle/kernel/thread.cpp         |   2 +-
 src/core/hle/kernel/vm_manager.cpp     |  22 ++---
 src/core/hle/kernel/vm_manager.h       |  46 +++-------
 src/core/memory.cpp                    | 122 +++++++++++++++++++++----
 src/core/memory.h                      |  79 ++++++++++++++--
 src/tests/core/arm/arm_test_common.cpp |   3 +-
 src/tests/core/hle/kernel/hle_ipc.cpp  |  97 +++++++++++---------
 src/tests/core/memory/vm_manager.cpp   |  37 ++++----
 24 files changed, 486 insertions(+), 177 deletions(-)
 create mode 100644 src/common/memory_ref.cpp
 create mode 100644 src/common/memory_ref.h

diff --git a/TODO b/TODO
index d72a79712..4bb80f8d5 100644
--- a/TODO
+++ b/TODO
@@ -4,6 +4,7 @@
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
     ☐ Page tables
+        Need to change uses to shared_ptr
     ✔ Skip N3DS RAM if unused @done(20-01-03 23:26)
 ✔ DSP @done(19-12-28 16:57)
     Memory only
@@ -44,6 +45,7 @@
     Doesn't need to be serialized here
 ✔ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE @started(20-01-03 13:47) @done(20-01-03 13:58) @lasted(11m22s)
 ☐ Review constructor/initialization code
+☐ Review core timing events
 ✔ Fix CI @done(19-12-31 21:32)
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
@@ -60,7 +62,7 @@
         ✔ Address arbiter @done(19-08-13 16:40)
         ✔ Client port @done(19-08-13 16:40)
         ✔ Client session @done(19-08-13 16:40)
-        ✔ Config mem @done(19-08-13 16:40)
+        ✔ Config mem @done(20-01-04 21:09)
         ✔ Event @done(19-12-22 18:44)
         ✔ Handle table @done(19-08-13 16:42)
         ✔ HLE IPC @done(19-12-23 00:36)
@@ -80,16 +82,15 @@
                 This is needed because IPC can take as long as it takes
                 Changed the unique_ptr<u8[]> to vector<u8>
         ✔ Session @done(19-08-13 16:44)
-        ☐ Shared memory @started(19-12-22 21:20)
+        ✔ Shared memory @started(19-12-22 21:20) @done(20-01-04 21:09) @lasted(1w5d23h49m26s)
             Need to figure out backing memory (a u8*)
-        ✘ Shared page @started(19-08-13 16:44) @cancelled(19-12-22 11:19)
-            Not needed right now as shared_page is read-only and derived from other data
+        ✔ Shared page @done(20-01-04 21:09)
         ✔ SVC @done(19-12-22 21:32)
             Nothing to do - all data is constant
         ☐ Thread @started(19-08-13 16:45)
             This requires refactoring wakeup_callback to be an object ref
         ✔ Timer @done(19-08-13 16:45)
-        ☐ VM Manager @started(19-08-13 16:46)
+        ✔ VM Manager @started(19-08-13 16:46) @done(20-01-04 21:09) @lasted(20w4d5h23m42s)
             Just need to figure out backing_mem (a u8*)
         ✔ Wait object @done(19-08-13 16:46)
     ☐ Service @started(19-12-23 12:49)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index c6294c464..ea117d440 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -80,6 +80,8 @@ add_library(common STATIC
     logging/text_formatter.cpp
     logging/text_formatter.h
     math_util.h
+    memory_ref.h
+    memory_ref.cpp
     microprofile.cpp
     microprofile.h
     microprofileui.h
@@ -127,7 +129,7 @@ endif()
 
 create_target_directory_groups(common)
 
-target_link_libraries(common PUBLIC fmt microprofile)
+target_link_libraries(common PUBLIC fmt microprofile Boost::boost Boost::serialization)
 target_link_libraries(common PRIVATE libzstd_static)
 if (ARCHITECTURE_x86_64)
     target_link_libraries(common PRIVATE xbyak)
diff --git a/src/common/memory_ref.cpp b/src/common/memory_ref.cpp
new file mode 100644
index 000000000..170784ff8
--- /dev/null
+++ b/src/common/memory_ref.cpp
@@ -0,0 +1,4 @@
+#include "common/archives.h"
+#include "common/memory_ref.h"
+
+SERIALIZE_EXPORT_IMPL(BufferMem)
diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
new file mode 100644
index 000000000..5aaaef468
--- /dev/null
+++ b/src/common/memory_ref.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
+#include "common/assert.h"
+#include "common/common_types.h"
+
+/// Abstract host-side memory - for example a static buffer, or local vector
+class BackingMem {
+public:
+    virtual ~BackingMem() = default;
+    virtual u8* GetPtr() = 0;
+    virtual u32 GetSize() const = 0;
+};
+
+/// Backing memory implemented by a local buffer
+class BufferMem : public BackingMem {
+public:
+    BufferMem() = default;
+    BufferMem(u32 size) : data(std::vector<u8>(size)) {}
+
+    virtual u8* GetPtr() {
+        return data.data();
+    }
+
+    virtual u32 GetSize() const {
+        return static_cast<u32>(data.size());
+    }
+
+    std::vector<u8>& Vector() {
+        return data;
+    }
+
+private:
+    std::vector<u8> data;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& data;
+    }
+    friend class boost::serialization::access;
+};
+
+BOOST_CLASS_EXPORT_KEY(BufferMem);
+
+/// A managed reference to host-side memory. Fast enough to be used everywhere instead of u8*
+/// Supports serialization.
+class MemoryRef {
+public:
+    MemoryRef() = default;
+    MemoryRef(std::nullptr_t) {}
+    MemoryRef(std::shared_ptr<BackingMem> backing_mem_)
+        : backing_mem(std::move(backing_mem_)), offset(0) {
+        Init();
+    }
+    MemoryRef(std::shared_ptr<BackingMem> backing_mem_, u32 offset_)
+        : backing_mem(std::move(backing_mem_)), offset(offset_) {
+        ASSERT(offset < backing_mem->GetSize());
+        Init();
+    }
+    inline operator u8*() {
+        return cptr;
+    }
+    inline u8* GetPtr() {
+        return cptr;
+    }
+    inline operator bool() const {
+        return cptr != nullptr;
+    }
+    inline const u8* GetPtr() const {
+        return cptr;
+    }
+    inline u32 GetSize() const {
+        return csize;
+    }
+    inline void operator+=(u32 offset_by) {
+        ASSERT(offset_by < csize);
+        offset += offset_by;
+        Init();
+    }
+    inline MemoryRef operator+(u32 offset_by) const {
+        ASSERT(offset_by < csize);
+        return MemoryRef(backing_mem, offset + offset_by);
+    }
+    inline u8* operator+(std::size_t offset_by) const {
+        ASSERT(offset_by < csize);
+        return cptr + offset_by;
+    }
+
+private:
+    std::shared_ptr<BackingMem> backing_mem;
+    u32 offset;
+    // Cached values for speed
+    u8* cptr;
+    u32 csize;
+
+    void Init() {
+        cptr = backing_mem->GetPtr() + offset;
+        csize = static_cast<u32>(backing_mem->GetSize() - offset);
+    }
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& backing_mem;
+        ar& offset;
+        Init();
+    }
+    friend class boost::serialization::access;
+};
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index a422db6af..eb3295956 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -298,7 +298,7 @@ void ARM_Dynarmic::PageTableChanged() {
 std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
     Dynarmic::A32::UserConfig config;
     config.callbacks = cb.get();
-    config.page_table = &current_page_table->pointers;
+    config.page_table = &current_page_table->GetPointerArray();
     config.coprocessors[15] = std::make_shared<DynarmicCP15>(interpreter_state);
     config.define_unpredictable_behaviour = true;
     return std::make_unique<Dynarmic::A32::Jit>(config);
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index ef1c889a0..0ec67fb5e 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -12,6 +12,7 @@
 #include <boost/serialization/binary_object.hpp>
 #include "common/common_funcs.h"
 #include "common/common_types.h"
+#include "common/memory_ref.h"
 #include "common/swap.h"
 #include "core/memory.h"
 
@@ -50,11 +51,19 @@ struct ConfigMemDef {
 static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE,
               "Config Memory structure size is wrong");
 
-class Handler {
+class Handler : public BackingMem {
 public:
     Handler();
     ConfigMemDef& GetConfigMem();
 
+    virtual u8* GetPtr() {
+        return static_cast<u8*>(static_cast<void*>(&config_mem));
+    }
+
+    virtual u32 GetSize() const {
+        return sizeof(config_mem);
+    }
+
 private:
     ConfigMemDef config_mem;
 
diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp
index e45b87e49..e39732c14 100644
--- a/src/core/hle/kernel/ipc.cpp
+++ b/src/core/hle/kernel/ipc.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include "common/alignment.h"
+#include "common/memory_ref.h"
 #include "core/core.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/handle_table.h"
@@ -193,28 +194,29 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
             // TODO(Subv): Perform permission checks.
 
             // Reserve a page of memory before the mapped buffer
-            auto reserve_buffer = std::vector<u8>(Memory::PAGE_SIZE);
+            std::shared_ptr<BackingMem> reserve_buffer =
+                std::make_shared<BufferMem>(Memory::PAGE_SIZE);
             dst_process->vm_manager.MapBackingMemoryToBase(
-                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.data(),
+                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
                 Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
 
-            auto buffer = std::vector<u8>(num_pages * Memory::PAGE_SIZE);
-            memory.ReadBlock(*src_process, source_address, buffer.data() + page_offset, size);
+            std::shared_ptr<BackingMem> buffer =
+                std::make_shared<BufferMem>(num_pages * Memory::PAGE_SIZE);
+            memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size);
 
             // Map the page(s) into the target process' address space.
             target_address =
                 dst_process->vm_manager
                     .MapBackingMemoryToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE,
-                                            buffer.data(), num_pages * Memory::PAGE_SIZE,
-                                            Kernel::MemoryState::Shared)
+                                            buffer, buffer->GetSize(), Kernel::MemoryState::Shared)
                     .Unwrap();
 
             cmd_buf[i++] = target_address + page_offset;
 
             // Reserve a page of memory after the mapped buffer
             dst_process->vm_manager.MapBackingMemoryToBase(
-                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.data(),
-                Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
+                Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
+                reserve_buffer->GetSize(), Kernel::MemoryState::Reserved);
 
             mapped_buffer_context.push_back({permissions, size, source_address,
                                              target_address + page_offset, std::move(buffer),
diff --git a/src/core/hle/kernel/ipc.h b/src/core/hle/kernel/ipc.h
index f9fd1a00e..2a5fcb4b2 100644
--- a/src/core/hle/kernel/ipc.h
+++ b/src/core/hle/kernel/ipc.h
@@ -6,7 +6,7 @@
 
 #include <memory>
 #include <vector>
-#include <boost/serialization/vector.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/thread.h"
@@ -25,8 +25,8 @@ struct MappedBufferContext {
     VAddr source_address;
     VAddr target_address;
 
-    std::vector<u8> buffer;
-    std::vector<u8> reserve_buffer;
+    std::shared_ptr<BackingMem> buffer;
+    std::shared_ptr<BackingMem> reserve_buffer;
 
 private:
     template <class Archive>
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 7edef2505..6fef2d4de 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -116,8 +116,8 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
     ar& process_list;
     ar& current_process;
     ar&* thread_manager.get();
-    ar&* config_mem_handler.get();
-    // Shared page data is read-only at the moment, so doesn't need serializing
+    ar& config_mem_handler;
+    ar& shared_page_handler;
     // Deliberately don't include debugger info to allow debugging through loads
 }
 
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 6ca3267fb..0a527d8b4 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -282,8 +282,8 @@ private:
 
     std::unique_ptr<ThreadManager> thread_manager;
 
-    std::unique_ptr<ConfigMem::Handler> config_mem_handler;
-    std::unique_ptr<SharedPage::Handler> shared_page_handler;
+    std::shared_ptr<ConfigMem::Handler> config_mem_handler;
+    std::shared_ptr<SharedPage::Handler> shared_page_handler;
 
     std::unique_ptr<IPCDebugger::Recorder> ipc_recorder;
 
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index e4aae5d13..04d09fa46 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -57,7 +57,7 @@ void KernelSystem::MemoryInit(u32 mem_type) {
     // We must've allocated the entire FCRAM by the end
     ASSERT(base == Memory::FCRAM_SIZE);
 
-    config_mem_handler = std::make_unique<ConfigMem::Handler>();
+    config_mem_handler = std::make_shared<ConfigMem::Handler>();
     auto& config_mem = config_mem_handler->GetConfigMem();
     config_mem.app_mem_type = mem_type;
     // app_mem_malloc does not always match the configured size for memory_region[0]: in case the
@@ -66,7 +66,7 @@ void KernelSystem::MemoryInit(u32 mem_type) {
     config_mem.sys_mem_alloc = memory_regions[1].size;
     config_mem.base_mem_alloc = memory_regions[2].size;
 
-    shared_page_handler = std::make_unique<SharedPage::Handler>(timing);
+    shared_page_handler = std::make_shared<SharedPage::Handler>(timing);
 }
 
 MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) {
@@ -127,7 +127,7 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM
         return;
     }
 
-    u8* target_pointer = memory.GetPhysicalPointer(area->paddr_base + offset_into_region);
+    auto target_pointer = memory.GetPhysicalRef(area->paddr_base + offset_into_region);
 
     // TODO(yuriks): This flag seems to have some other effect, but it's unknown what
     MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO;
@@ -140,20 +140,16 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM
 }
 
 void KernelSystem::MapSharedPages(VMManager& address_space) {
-    auto cfg_mem_vma =
-        address_space
-            .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR,
-                              reinterpret_cast<u8*>(&config_mem_handler->GetConfigMem()),
-                              Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared)
-            .Unwrap();
+    auto cfg_mem_vma = address_space
+                           .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, {config_mem_handler},
+                                             Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared)
+                           .Unwrap();
     address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
 
-    auto shared_page_vma =
-        address_space
-            .MapBackingMemory(Memory::SHARED_PAGE_VADDR,
-                              reinterpret_cast<u8*>(&shared_page_handler->GetSharedPage()),
-                              Memory::SHARED_PAGE_SIZE, MemoryState::Shared)
-            .Unwrap();
+    auto shared_page_vma = address_space
+                               .MapBackingMemory(Memory::SHARED_PAGE_VADDR, {shared_page_handler},
+                                                 Memory::SHARED_PAGE_SIZE, MemoryState::Shared)
+                               .Unwrap();
     address_space.Reprotect(shared_page_vma, VMAPermission::Read);
 }
 
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 18de2cd91..c181bd01a 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -223,7 +223,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
         std::fill(kernel.memory.GetFCRAMPointer(interval.lower()),
                   kernel.memory.GetFCRAMPointer(interval.upper()), 0);
         auto vma = vm_manager.MapBackingMemory(interval_target,
-                                               kernel.memory.GetFCRAMPointer(interval.lower()),
+                                               kernel.memory.GetFCRAMRef(interval.lower()),
                                                interval_size, memory_state);
         ASSERT(vma.Succeeded());
         vm_manager.Reprotect(vma.Unwrap(), perms);
@@ -251,7 +251,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
     // Free heaps block by block
     CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
     for (const auto [backing_memory, block_size] : backing_blocks) {
-        memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory), block_size);
+        memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size);
     }
 
     ResultCode result = vm_manager.UnmapRange(target, size);
@@ -295,9 +295,9 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
         }
     }
 
-    u8* backing_memory = kernel.memory.GetFCRAMPointer(physical_offset);
+    auto backing_memory = kernel.memory.GetFCRAMRef(physical_offset);
 
-    std::fill(backing_memory, backing_memory + size, 0);
+    std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + size, 0);
     auto vma = vm_manager.MapBackingMemory(target, backing_memory, size, MemoryState::Continuous);
     ASSERT(vma.Succeeded());
     vm_manager.Reprotect(vma.Unwrap(), perms);
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 55c374dc5..23f67f733 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -48,7 +48,7 @@ ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
         ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!");
 
         std::fill(memory.GetFCRAMPointer(*offset), memory.GetFCRAMPointer(*offset + size), 0);
-        shared_memory->backing_blocks = {{memory.GetFCRAMPointer(*offset), size}};
+        shared_memory->backing_blocks = {{memory.GetFCRAMRef(*offset), size}};
         shared_memory->holding_memory += MemoryRegionInfo::Interval(*offset, *offset + size);
         shared_memory->linear_heap_phys_offset = *offset;
 
@@ -90,7 +90,7 @@ std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
     shared_memory->other_permissions = other_permissions;
     for (const auto& interval : backing_blocks) {
         shared_memory->backing_blocks.push_back(
-            {memory.GetFCRAMPointer(interval.lower()), interval.upper() - interval.lower()});
+            {memory.GetFCRAMRef(interval.lower()), interval.upper() - interval.lower()});
         std::fill(memory.GetFCRAMPointer(interval.lower()),
                   memory.GetFCRAMPointer(interval.upper()), 0);
     }
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index f2fa1a728..aa2be05a6 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -8,6 +8,7 @@
 #include <utility>
 #include <boost/serialization/export.hpp>
 #include "common/common_types.h"
+#include "common/memory_ref.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/result.h"
@@ -87,7 +88,7 @@ private:
     /// during creation.
     PAddr linear_heap_phys_offset = 0;
     /// Backing memory for this shared memory block.
-    std::vector<std::pair<u8*, u32>> backing_blocks;
+    std::vector<std::pair<MemoryRef, u32>> backing_blocks;
     /// Size of the memory block. Page-aligned.
     u32 size = 0;
     /// Permission restrictions applied to the process which created the block.
@@ -109,7 +110,7 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
         ar& linear_heap_phys_offset;
-        // TODO: backing blocks u8* (this is always FCRAM I think)
+        ar& backing_blocks;
         ar& size;
         ar& permissions;
         ar& other_permissions;
diff --git a/src/core/hle/kernel/shared_page.cpp b/src/core/hle/kernel/shared_page.cpp
index 7067aace8..f7b02993f 100644
--- a/src/core/hle/kernel/shared_page.cpp
+++ b/src/core/hle/kernel/shared_page.cpp
@@ -4,6 +4,7 @@
 
 #include <chrono>
 #include <cstring>
+#include "common/archives.h"
 #include "core/core.h"
 #include "core/core_timing.h"
 #include "core/hle/kernel/shared_page.h"
@@ -13,6 +14,17 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
+namespace boost::serialization {
+
+template <class Archive>
+void load_construct_data(Archive& ar, SharedPage::Handler* t, const unsigned int) {
+    ::new (t) SharedPage::Handler(Core::System::GetInstance().CoreTiming());
+}
+template void load_construct_data<iarchive>(iarchive& ar, SharedPage::Handler* t,
+                                            const unsigned int);
+
+} // namespace boost::serialization
+
 namespace SharedPage {
 
 static std::chrono::seconds GetInitTime() {
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index 45f9cd348..7b1f7ed16 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -17,6 +17,7 @@
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
+#include "common/memory_ref.h"
 #include "common/swap.h"
 #include "core/memory.h"
 
@@ -83,7 +84,7 @@ struct SharedPageDef {
 static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE,
               "Shared page structure size is wrong");
 
-class Handler {
+class Handler : public BackingMem {
 public:
     Handler(Core::Timing& timing);
 
@@ -97,6 +98,14 @@ public:
 
     SharedPageDef& GetSharedPage();
 
+    virtual u8* GetPtr() {
+        return static_cast<u8*>(static_cast<void*>(&shared_page));
+    }
+
+    virtual u32 GetSize() const {
+        return sizeof(shared_page);
+    }
+
 private:
     u64 GetSystemTime() const;
     void UpdateTimeCallback(u64 userdata, int cycles_late);
@@ -105,6 +114,19 @@ private:
     std::chrono::seconds init_time;
 
     SharedPageDef shared_page;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::make_binary_object(&shared_page, sizeof(shared_page));
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace SharedPage
+
+namespace boost::serialization {
+
+template <class Archive>
+void load_construct_data(Archive& ar, SharedPage::Handler* t, const unsigned int);
+
+} // namespace boost::serialization
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index c3c5da7d4..1af2d4f4d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -382,7 +382,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
 
         // Map the page to the current process' address space.
         vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
-                                    memory.GetFCRAMPointer(*offset), Memory::PAGE_SIZE,
+                                    memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE,
                                     MemoryState::Locked);
     }
 
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 3280f99e9..1b9875ee2 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -27,7 +27,8 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
         type != next.type) {
         return false;
     }
-    if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
+    if (type == VMAType::BackingMemory &&
+        backing_memory.GetPtr() + size != next.backing_memory.GetPtr()) {
         return false;
     }
     if (type == VMAType::MMIO && paddr + size != next.paddr) {
@@ -50,8 +51,7 @@ void VMManager::Reset() {
     initial_vma.size = MAX_ADDRESS;
     vma_map.emplace(initial_vma.base, initial_vma);
 
-    page_table.pointers.fill(nullptr);
-    page_table.attributes.fill(Memory::PageType::Unmapped);
+    page_table.Clear();
 
     UpdatePageTableForVMA(initial_vma);
 }
@@ -64,7 +64,7 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
     }
 }
 
-ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory,
+ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory,
                                                    u32 size, MemoryState state) {
 
     // Find the first Free VMA.
@@ -93,9 +93,9 @@ ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size,
     return MakeResult<VAddr>(target);
 }
 
-ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size,
-                                                            MemoryState state) {
-    ASSERT(memory != nullptr);
+ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, MemoryRef memory,
+                                                            u32 size, MemoryState state) {
+    ASSERT(memory.GetPtr() != nullptr);
 
     // This is the appropriately sized VMA that will turn into our allocation.
     CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
@@ -359,9 +359,9 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
     }
 }
 
-ResultVal<std::vector<std::pair<u8*, u32>>> VMManager::GetBackingBlocksForRange(VAddr address,
-                                                                                u32 size) {
-    std::vector<std::pair<u8*, u32>> backing_blocks;
+ResultVal<std::vector<std::pair<MemoryRef, u32>>> VMManager::GetBackingBlocksForRange(VAddr address,
+                                                                                      u32 size) {
+    std::vector<std::pair<MemoryRef, u32>> backing_blocks;
     VAddr interval_target = address;
     while (interval_target != address + size) {
         auto vma = FindVMA(interval_target);
@@ -372,7 +372,7 @@ ResultVal<std::vector<std::pair<u8*, u32>>> VMManager::GetBackingBlocksForRange(
 
         VAddr interval_end = std::min(address + size, vma->second.base + vma->second.size);
         u32 interval_size = interval_end - interval_target;
-        u8* backing_memory = vma->second.backing_memory + (interval_target - vma->second.base);
+        auto backing_memory = vma->second.backing_memory + (interval_target - vma->second.base);
         backing_blocks.push_back({backing_memory, interval_size});
 
         interval_target += interval_size;
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 5fd6d8740..880d9ec81 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -11,6 +11,7 @@
 #include <boost/serialization/map.hpp>
 #include <boost/serialization/split_member.hpp>
 #include "common/common_types.h"
+#include "common/memory_ref.h"
 #include "core/hle/result.h"
 #include "core/memory.h"
 #include "core/mmio.h"
@@ -73,7 +74,7 @@ struct VirtualMemoryArea {
 
     // Settings for type = BackingMemory
     /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
-    u8* backing_memory = nullptr;
+    MemoryRef backing_memory{};
 
     // Settings for type = MMIO
     /// Physical address of the register area this VMA maps to.
@@ -92,8 +93,7 @@ private:
         ar& type;
         ar& permissions;
         ar& meminfo_state;
-        // TODO: backing memory ref
-        // backing memory can be: Physical/FCRAM pointer, config mem, shared page
+        ar& backing_memory;
         ar& paddr;
         ar& mmio_handler;
     }
@@ -151,7 +151,7 @@ public:
      * @param state MemoryState tag to attach to the VMA.
      * @returns The address at which the memory was mapped.
      */
-    ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory, u32 size,
+    ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory, u32 size,
                                             MemoryState state);
     /**
      * Maps an unmanaged host memory pointer at a given address.
@@ -161,7 +161,8 @@ public:
      * @param size Size of the mapping.
      * @param state MemoryState tag to attach to the VMA.
      */
-    ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
+    ResultVal<VMAHandle> MapBackingMemory(VAddr target, MemoryRef memory, u32 size,
+                                          MemoryState state);
 
     /**
      * Maps a memory-mapped IO region at a given address.
@@ -203,38 +204,14 @@ public:
     void LogLayout(Log::Level log_level) const;
 
     /// Gets a list of backing memory blocks for the specified range
-    ResultVal<std::vector<std::pair<u8*, u32>>> GetBackingBlocksForRange(VAddr address, u32 size);
+    ResultVal<std::vector<std::pair<MemoryRef, u32>>> GetBackingBlocksForRange(VAddr address,
+                                                                               u32 size);
 
     /// Each VMManager has its own page table, which is set as the main one when the owning process
     /// is scheduled.
     Memory::PageTable page_table;
 
 private:
-    friend class boost::serialization::access;
-    template <class Archive>
-    void save(Archive& ar, const unsigned int file_version) const {
-        ar& vma_map;
-        for (int i = 0; i < page_table.pointers.size(); i++) {
-            ar << memory.GetFCRAMOffset(page_table.pointers[i]);
-        }
-        ar& page_table.special_regions;
-        ar& page_table.attributes;
-    }
-
-    template <class Archive>
-    void load(Archive& ar, const unsigned int file_version) {
-        ar& vma_map;
-        for (int i = 0; i < page_table.pointers.size(); i++) {
-            u32 offset{};
-            ar >> offset;
-            page_table.pointers[i] = memory.GetFCRAMPointer(offset);
-        }
-        ar& page_table.special_regions;
-        ar& page_table.attributes;
-    }
-
-    BOOST_SERIALIZATION_SPLIT_MEMBER()
-
     using VMAIter = decltype(vma_map)::iterator;
 
     /// Converts a VMAHandle to a mutable VMAIter.
@@ -271,5 +248,12 @@ private:
     void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
 
     Memory::MemorySystem& memory;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& vma_map;
+        ar& page_table;
+    }
+    friend class boost::serialization::access;
 };
 } // namespace Kernel
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index cba5867eb..9762619f0 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,6 +14,7 @@
 #include "common/swap.h"
 #include "core/arm/arm_interface.h"
 #include "core/core.h"
+#include "core/global.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/lock.h"
@@ -22,8 +23,19 @@
 #include "video_core/renderer_base.h"
 #include "video_core/video_core.h"
 
+SERIALIZE_EXPORT_IMPL(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>)
+SERIALIZE_EXPORT_IMPL(Memory::MemorySystem::BackingMemImpl<Memory::Region::VRAM>)
+SERIALIZE_EXPORT_IMPL(Memory::MemorySystem::BackingMemImpl<Memory::Region::DSP>)
+SERIALIZE_EXPORT_IMPL(Memory::MemorySystem::BackingMemImpl<Memory::Region::N3DS>)
+
 namespace Memory {
 
+void PageTable::Clear() {
+    pointers.raw.fill(nullptr);
+    pointers.refs.fill(MemoryRef());
+    attributes.fill(PageType::Unmapped);
+}
+
 class RasterizerCacheMarker {
 public:
     void Mark(VAddr addr, bool cached) {
@@ -81,6 +93,43 @@ public:
 
     AudioCore::DspInterface* dsp = nullptr;
 
+    std::shared_ptr<BackingMem> fcram_mem;
+    std::shared_ptr<BackingMem> vram_mem;
+    std::shared_ptr<BackingMem> n3ds_extra_ram_mem;
+    std::shared_ptr<BackingMem> dsp_mem;
+
+    MemorySystem::Impl();
+
+    virtual u8* GetPtr(Region r) {
+        switch (r) {
+        case Region::VRAM:
+            return vram.get();
+        case Region::DSP:
+            return dsp->GetDspMemory().data();
+        case Region::FCRAM:
+            return fcram.get();
+        case Region::N3DS:
+            return n3ds_extra_ram.get();
+        default:
+            UNREACHABLE();
+        }
+    }
+
+    virtual u32 GetSize(Region r) const {
+        switch (r) {
+        case Region::VRAM:
+            return VRAM_SIZE;
+        case Region::DSP:
+            return DSP_RAM_SIZE;
+        case Region::FCRAM:
+            return FCRAM_N3DS_SIZE;
+        case Region::N3DS:
+            return N3DS_EXTRA_RAM_SIZE;
+        default:
+            UNREACHABLE();
+        }
+    }
+
 private:
     friend class boost::serialization::access;
     template <class Archive>
@@ -95,10 +144,41 @@ private:
         ar& cache_marker;
         ar& page_table_list;
         // dsp is set from Core::System at startup
-        // current page table set from current process?
+        // TODO: current_page_table
+        ar& fcram_mem;
+        ar& vram_mem;
+        ar& n3ds_extra_ram_mem;
+        ar& dsp_mem;
     }
 };
 
+// We use this rather than BufferMem because we don't want new objects to be allocated when
+// deserializing. This avoids unnecessary memory thrashing.
+template <Region R>
+class MemorySystem::BackingMemImpl : public BackingMem {
+public:
+    BackingMemImpl() : system(Core::Global<Core::System>().Memory()) {}
+    virtual u8* GetPtr() {
+        return system.impl->GetPtr(R);
+    }
+    virtual u32 GetSize() const {
+        return system.impl->GetSize(R);
+    }
+
+private:
+    MemorySystem& system;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
+};
+
+MemorySystem::Impl::Impl()
+    : fcram_mem(std::make_shared<BackingMemImpl<Region::FCRAM>>()),
+      vram_mem(std::make_shared<BackingMemImpl<Region::VRAM>>()),
+      n3ds_extra_ram_mem(std::make_shared<BackingMemImpl<Region::N3DS>>()),
+      dsp_mem(std::make_shared<BackingMemImpl<Region::DSP>>()) {}
+
 MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
 MemorySystem::~MemorySystem() = default;
 
@@ -117,8 +197,9 @@ PageTable* MemorySystem::GetCurrentPageTable() const {
     return impl->current_page_table;
 }
 
-void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type) {
-    LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory, base * PAGE_SIZE,
+void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory,
+                            PageType type) {
+    LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), base * PAGE_SIZE,
               (base + size) * PAGE_SIZE);
 
     RasterizerFlushVirtualRegion(base << PAGE_BITS, size * PAGE_SIZE,
@@ -143,7 +224,7 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, u8* memor
     }
 }
 
-void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, u8* target) {
+void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) {
     ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:08X}", size);
     ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:08X}", base);
     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory);
@@ -164,15 +245,15 @@ void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) {
     MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
 }
 
-u8* MemorySystem::GetPointerForRasterizerCache(VAddr addr) {
+MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) {
     if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
-        return impl->fcram.get() + (addr - LINEAR_HEAP_VADDR);
+        return {impl->fcram_mem, addr - LINEAR_HEAP_VADDR};
     }
     if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
-        return impl->fcram.get() + (addr - NEW_LINEAR_HEAP_VADDR);
+        return {impl->fcram_mem, addr - NEW_LINEAR_HEAP_VADDR};
     }
     if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
-        return impl->vram.get() + (addr - VRAM_VADDR);
+        return {impl->vram_mem, addr - VRAM_VADDR};
     }
     UNREACHABLE();
 }
@@ -271,7 +352,7 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
 bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
     auto& page_table = process.vm_manager.page_table;
 
-    const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
+    auto page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
     if (page_pointer)
         return true;
 
@@ -323,6 +404,10 @@ std::string MemorySystem::ReadCString(VAddr vaddr, std::size_t max_length) {
 }
 
 u8* MemorySystem::GetPhysicalPointer(PAddr address) {
+    return GetPhysicalRef(address);
+}
+
+MemoryRef MemorySystem::GetPhysicalRef(PAddr address) {
     struct MemoryArea {
         PAddr paddr_base;
         u32 size;
@@ -349,25 +434,25 @@ u8* MemorySystem::GetPhysicalPointer(PAddr address) {
 
     u32 offset_into_region = address - area->paddr_base;
 
-    u8* target_pointer = nullptr;
+    std::shared_ptr<BackingMem> target_mem = nullptr;
     switch (area->paddr_base) {
     case VRAM_PADDR:
-        target_pointer = impl->vram.get() + offset_into_region;
+        target_mem = impl->vram_mem;
         break;
     case DSP_RAM_PADDR:
-        target_pointer = impl->dsp->GetDspMemory().data() + offset_into_region;
+        target_mem = impl->dsp_mem;
         break;
     case FCRAM_PADDR:
-        target_pointer = impl->fcram.get() + offset_into_region;
+        target_mem = impl->fcram_mem;
         break;
     case N3DS_EXTRA_RAM_PADDR:
-        target_pointer = impl->n3ds_extra_ram.get() + offset_into_region;
+        target_mem = impl->n3ds_extra_ram_mem;
         break;
     default:
         UNREACHABLE();
     }
 
-    return target_pointer;
+    return {target_mem, offset_into_region};
 }
 
 /// For a rasterizer-accessible PAddr, gets a list of all possible VAddr
@@ -781,7 +866,7 @@ void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data)
     mmio_handler->Write64(addr, data);
 }
 
-u32 MemorySystem::GetFCRAMOffset(u8* pointer) {
+u32 MemorySystem::GetFCRAMOffset(const u8* pointer) {
     ASSERT(pointer >= impl->fcram.get() && pointer <= impl->fcram.get() + Memory::FCRAM_N3DS_SIZE);
     return pointer - impl->fcram.get();
 }
@@ -791,6 +876,11 @@ u8* MemorySystem::GetFCRAMPointer(u32 offset) {
     return impl->fcram.get() + offset;
 }
 
+MemoryRef MemorySystem::GetFCRAMRef(u32 offset) {
+    ASSERT(offset <= Memory::FCRAM_N3DS_SIZE);
+    return MemoryRef(impl->fcram_mem, offset);
+}
+
 void MemorySystem::SetDSP(AudioCore::DspInterface& dsp) {
     impl->dsp = &dsp;
 }
diff --git a/src/core/memory.h b/src/core/memory.h
index 564191d89..0dc98a428 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -13,6 +13,7 @@
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
+#include "common/memory_ref.h"
 #include "core/mmio.h"
 
 class ARM_Interface;
@@ -77,7 +78,48 @@ struct PageTable {
      * Array of memory pointers backing each page. An entry can only be non-null if the
      * corresponding entry in the `attributes` array is of type `Memory`.
      */
-    std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers;
+
+    // The reason for this rigmarole is to keep the 'raw' and 'refs' arrays in sync.
+    // We need 'raw' for dynarmic and 'refs' for serialization
+    struct Pointers {
+
+        struct Entry {
+            Entry(Pointers& pointers_, VAddr idx_) : pointers(pointers_), idx(idx_) {}
+
+            inline void operator=(MemoryRef value) {
+                pointers.refs[idx] = value;
+                pointers.raw[idx] = value.GetPtr();
+            }
+
+            inline operator u8*() {
+                return pointers.raw[idx];
+            }
+
+        private:
+            Pointers& pointers;
+            VAddr idx;
+        };
+
+        inline Entry operator[](VAddr idx) {
+            return Entry(*this, idx);
+        }
+
+        inline u8* operator[](VAddr idx) const {
+            return raw[idx];
+        }
+
+        inline Entry operator[](std::size_t idx) {
+            return Entry(*this, static_cast<VAddr>(idx));
+        }
+
+    private:
+        std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw;
+
+        std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs;
+
+        friend struct PageTable;
+    };
+    Pointers pointers;
 
     /**
      * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of
@@ -91,12 +133,21 @@ struct PageTable {
      */
     std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
 
+    inline std::array<u8*, PAGE_TABLE_NUM_ENTRIES>& GetPointerArray() {
+        return pointers.raw;
+    }
+
+    void Clear();
+
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
-        // TODO: Pointers; same as VMA backing regions we need to serialize the u8*
+        ar& pointers.refs;
         ar& special_regions;
         ar& attributes;
+        for (auto i = 0; i < PAGE_TABLE_NUM_ENTRIES; i++) {
+            pointers.raw[i] = pointers.refs[i].GetPtr();
+        }
     }
     friend class boost::serialization::access;
 };
@@ -142,6 +193,8 @@ enum : PAddr {
     FCRAM_N3DS_PADDR_END = FCRAM_PADDR + FCRAM_N3DS_SIZE,
 };
 
+enum class Region { FCRAM, VRAM, DSP, N3DS };
+
 /// Virtual user-space memory regions
 enum : VAddr {
     /// Where the application text, data and bss reside.
@@ -249,7 +302,7 @@ public:
      * @param size The amount of bytes to map. Must be page-aligned.
      * @param target Buffer with the memory backing the mapping. Must be of length at least `size`.
      */
-    void MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, u8* target);
+    void MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target);
 
     /**
      * Maps a region of the emulated process address space as a IO region.
@@ -293,16 +346,21 @@ public:
      */
     u8* GetPhysicalPointer(PAddr address);
 
+    MemoryRef GetPhysicalRef(PAddr address);
+
     u8* GetPointer(VAddr vaddr);
 
     bool IsValidPhysicalAddress(PAddr paddr);
 
     /// Gets offset in FCRAM from a pointer inside FCRAM range
-    u32 GetFCRAMOffset(u8* pointer);
+    u32 GetFCRAMOffset(const u8* pointer);
 
     /// Gets pointer in FCRAM with given offset
     u8* GetFCRAMPointer(u32 offset);
 
+    /// Gets a serializable ref to FCRAM with the given offset
+    MemoryRef GetFCRAMRef(u32 offset);
+
     /**
      * Mark each page touching the region as cached.
      */
@@ -329,9 +387,9 @@ private:
      * Since the cache only happens on linear heap or VRAM, we know the exact physical address and
      * pointer of such virtual address
      */
-    u8* GetPointerForRasterizerCache(VAddr addr);
+    MemoryRef GetPointerForRasterizerCache(VAddr addr);
 
-    void MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type);
+    void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type);
 
     class Impl;
 
@@ -340,9 +398,18 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version);
+
+public:
+    template <Region R>
+    class BackingMemImpl;
 };
 
 /// Determines if the given VAddr is valid for the specified process.
 bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
 
 } // namespace Memory
+
+BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::FCRAM>)
+BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::VRAM>)
+BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::DSP>)
+BOOST_CLASS_EXPORT_KEY(Memory::MemorySystem::BackingMemImpl<Memory::Region::N3DS>)
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index dbbc21c8c..3f90482ec 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -22,8 +22,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
     kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
     page_table = &kernel->GetCurrentProcess()->vm_manager.page_table;
 
-    page_table->pointers.fill(nullptr);
-    page_table->attributes.fill(Memory::PageType::Unmapped);
+    page_table->Clear();
 
     memory->MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
     memory->MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index e405f6729..414d64021 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -138,67 +138,70 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
     }
 
     SECTION("translates StaticBuffer descriptors") {
-        auto buffer = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
-        std::fill(buffer->begin(), buffer->end(), 0xAB);
+        auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE);
+        MemoryRef buffer{mem};
+        std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xAB);
 
         VAddr target_address = 0x10000000;
-        auto result = process->vm_manager.MapBackingMemory(target_address, buffer->data(),
-                                                           buffer->size(), MemoryState::Private);
+        auto result = process->vm_manager.MapBackingMemory(target_address, buffer, buffer.GetSize(),
+                                                           MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
         const u32_le input[]{
             IPC::MakeHeader(0, 0, 2),
-            IPC::StaticBufferDesc(buffer->size(), 0),
+            IPC::StaticBufferDesc(buffer.GetSize(), 0),
             target_address,
         };
 
         context.PopulateFromIncomingCommandBuffer(input, *process);
 
-        CHECK(context.GetStaticBuffer(0) == *buffer);
+        CHECK(context.GetStaticBuffer(0) == mem->Vector());
 
-        REQUIRE(process->vm_manager.UnmapRange(target_address, buffer->size()) == RESULT_SUCCESS);
+        REQUIRE(process->vm_manager.UnmapRange(target_address, buffer.GetSize()) == RESULT_SUCCESS);
     }
 
     SECTION("translates MappedBuffer descriptors") {
-        auto buffer = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
-        std::fill(buffer->begin(), buffer->end(), 0xCD);
+        auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE);
+        MemoryRef buffer{mem};
+        std::fill(buffer.GetPtr(), buffer.GetPtr() + buffer.GetSize(), 0xCD);
 
         VAddr target_address = 0x10000000;
-        auto result = process->vm_manager.MapBackingMemory(target_address, buffer->data(),
-                                                           buffer->size(), MemoryState::Private);
+        auto result = process->vm_manager.MapBackingMemory(target_address, buffer, buffer.GetSize(),
+                                                           MemoryState::Private);
 
         const u32_le input[]{
             IPC::MakeHeader(0, 0, 2),
-            IPC::MappedBufferDesc(buffer->size(), IPC::R),
+            IPC::MappedBufferDesc(buffer.GetSize(), IPC::R),
             target_address,
         };
 
         context.PopulateFromIncomingCommandBuffer(input, *process);
 
-        std::vector<u8> other_buffer(buffer->size());
-        context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer->size());
+        std::vector<u8> other_buffer(buffer.GetSize());
+        context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer.GetSize());
 
-        CHECK(other_buffer == *buffer);
+        CHECK(other_buffer == mem->Vector());
 
-        REQUIRE(process->vm_manager.UnmapRange(target_address, buffer->size()) == RESULT_SUCCESS);
+        REQUIRE(process->vm_manager.UnmapRange(target_address, buffer.GetSize()) == RESULT_SUCCESS);
     }
 
     SECTION("translates mixed params") {
-        auto buffer_static = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
-        std::fill(buffer_static->begin(), buffer_static->end(), 0xCE);
+        auto mem_static = std::make_shared<BufferMem>(Memory::PAGE_SIZE);
+        MemoryRef buffer_static{mem_static};
+        std::fill(buffer_static.GetPtr(), buffer_static.GetPtr() + buffer_static.GetSize(), 0xCE);
 
-        auto buffer_mapped = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
-        std::fill(buffer_mapped->begin(), buffer_mapped->end(), 0xDF);
+        auto mem_mapped = std::make_shared<BufferMem>(Memory::PAGE_SIZE);
+        MemoryRef buffer_mapped{mem_mapped};
+        std::fill(buffer_mapped.GetPtr(), buffer_mapped.GetPtr() + buffer_mapped.GetSize(), 0xDF);
 
         VAddr target_address_static = 0x10000000;
-        auto result =
-            process->vm_manager.MapBackingMemory(target_address_static, buffer_static->data(),
-                                                 buffer_static->size(), MemoryState::Private);
+        auto result = process->vm_manager.MapBackingMemory(
+            target_address_static, buffer_static, buffer_static.GetSize(), MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
         VAddr target_address_mapped = 0x20000000;
-        result = process->vm_manager.MapBackingMemory(target_address_mapped, buffer_mapped->data(),
-                                                      buffer_mapped->size(), MemoryState::Private);
+        result = process->vm_manager.MapBackingMemory(
+            target_address_mapped, buffer_mapped, buffer_mapped.GetSize(), MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
         auto a = MakeObject(kernel);
@@ -210,9 +213,9 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             process->handle_table.Create(a).Unwrap(),
             IPC::CallingPidDesc(),
             0,
-            IPC::StaticBufferDesc(buffer_static->size(), 0),
+            IPC::StaticBufferDesc(buffer_static.GetSize(), 0),
             target_address_static,
-            IPC::MappedBufferDesc(buffer_mapped->size(), IPC::R),
+            IPC::MappedBufferDesc(buffer_mapped.GetSize(), IPC::R),
             target_address_mapped,
         };
 
@@ -223,14 +226,14 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
         CHECK(output[2] == 0xABCDEF00);
         CHECK(context.GetIncomingHandle(output[4]) == a);
         CHECK(output[6] == process->process_id);
-        CHECK(context.GetStaticBuffer(0) == *buffer_static);
-        std::vector<u8> other_buffer(buffer_mapped->size());
-        context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer_mapped->size());
-        CHECK(other_buffer == *buffer_mapped);
+        CHECK(context.GetStaticBuffer(0) == mem_static->Vector());
+        std::vector<u8> other_buffer(buffer_mapped.GetSize());
+        context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer_mapped.GetSize());
+        CHECK(other_buffer == mem_mapped->Vector());
 
-        REQUIRE(process->vm_manager.UnmapRange(target_address_static, buffer_static->size()) ==
+        REQUIRE(process->vm_manager.UnmapRange(target_address_static, buffer_static.GetSize()) ==
                 RESULT_SUCCESS);
-        REQUIRE(process->vm_manager.UnmapRange(target_address_mapped, buffer_mapped->size()) ==
+        REQUIRE(process->vm_manager.UnmapRange(target_address_mapped, buffer_mapped.GetSize()) ==
                 RESULT_SUCCESS);
     }
 }
@@ -317,10 +320,12 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
 
         context.AddStaticBuffer(0, input_buffer);
 
-        auto output_buffer = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
+        auto output_mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE);
+        MemoryRef output_buffer{output_mem};
+
         VAddr target_address = 0x10000000;
         auto result = process->vm_manager.MapBackingMemory(
-            target_address, output_buffer->data(), output_buffer->size(), MemoryState::Private);
+            target_address, output_buffer, output_buffer.GetSize(), MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
         input[0] = IPC::MakeHeader(0, 0, 2);
@@ -332,13 +337,13 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
         std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2> output_cmdbuff;
         // Set up the output StaticBuffer
         output_cmdbuff[IPC::COMMAND_BUFFER_LENGTH] =
-            IPC::StaticBufferDesc(output_buffer->size(), 0);
+            IPC::StaticBufferDesc(output_buffer.GetSize(), 0);
         output_cmdbuff[IPC::COMMAND_BUFFER_LENGTH + 1] = target_address;
 
         context.WriteToOutgoingCommandBuffer(output_cmdbuff.data(), *process);
 
-        CHECK(*output_buffer == input_buffer);
-        REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) ==
+        CHECK(output_mem->Vector() == input_buffer);
+        REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer.GetSize()) ==
                 RESULT_SUCCESS);
     }
 
@@ -346,15 +351,17 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
         std::vector<u8> input_buffer(Memory::PAGE_SIZE);
         std::fill(input_buffer.begin(), input_buffer.end(), 0xAB);
 
-        auto output_buffer = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
+        auto output_mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE);
+        MemoryRef output_buffer{output_mem};
+
         VAddr target_address = 0x10000000;
         auto result = process->vm_manager.MapBackingMemory(
-            target_address, output_buffer->data(), output_buffer->size(), MemoryState::Private);
+            target_address, output_buffer, output_buffer.GetSize(), MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
         const u32_le input_cmdbuff[]{
             IPC::MakeHeader(0, 0, 2),
-            IPC::MappedBufferDesc(output_buffer->size(), IPC::W),
+            IPC::MappedBufferDesc(output_buffer.GetSize(), IPC::W),
             target_address,
         };
 
@@ -363,15 +370,15 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
         context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size());
 
         input[0] = IPC::MakeHeader(0, 0, 2);
-        input[1] = IPC::MappedBufferDesc(output_buffer->size(), IPC::W);
+        input[1] = IPC::MappedBufferDesc(output_buffer.GetSize(), IPC::W);
         input[2] = 0;
 
         context.WriteToOutgoingCommandBuffer(output, *process);
 
-        CHECK(output[1] == IPC::MappedBufferDesc(output_buffer->size(), IPC::W));
+        CHECK(output[1] == IPC::MappedBufferDesc(output_buffer.GetSize(), IPC::W));
         CHECK(output[2] == target_address);
-        CHECK(*output_buffer == input_buffer);
-        REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer->size()) ==
+        CHECK(output_mem->Vector() == input_buffer);
+        REQUIRE(process->vm_manager.UnmapRange(target_address, output_buffer.GetSize()) ==
                 RESULT_SUCCESS);
     }
 }
diff --git a/src/tests/core/memory/vm_manager.cpp b/src/tests/core/memory/vm_manager.cpp
index bd510864a..5a8e8b788 100644
--- a/src/tests/core/memory/vm_manager.cpp
+++ b/src/tests/core/memory/vm_manager.cpp
@@ -10,47 +10,48 @@
 #include "core/memory.h"
 
 TEST_CASE("Memory Basics", "[kernel][memory]") {
-    auto block = std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE);
+    auto mem = std::make_shared<BufferMem>(Memory::PAGE_SIZE);
+    MemoryRef block{mem};
     Memory::MemorySystem memory;
     SECTION("mapping memory") {
         // Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
         auto manager = std::make_unique<Kernel::VMManager>(memory);
-        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block->data(), block->size(),
+        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block, block.GetSize(),
                                                 Kernel::MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
         auto vma = manager->FindVMA(Memory::HEAP_VADDR);
         CHECK(vma != manager->vma_map.end());
-        CHECK(vma->second.size == block->size());
+        CHECK(vma->second.size == block.GetSize());
         CHECK(vma->second.type == Kernel::VMAType::BackingMemory);
-        CHECK(vma->second.backing_memory == block->data());
+        CHECK(vma->second.backing_memory.GetPtr() == block.GetPtr());
         CHECK(vma->second.meminfo_state == Kernel::MemoryState::Private);
     }
 
     SECTION("unmapping memory") {
         // Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
         auto manager = std::make_unique<Kernel::VMManager>(memory);
-        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block->data(), block->size(),
+        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block, block.GetSize(),
                                                 Kernel::MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
-        ResultCode code = manager->UnmapRange(Memory::HEAP_VADDR, block->size());
+        ResultCode code = manager->UnmapRange(Memory::HEAP_VADDR, block.GetSize());
         REQUIRE(code == RESULT_SUCCESS);
 
         auto vma = manager->FindVMA(Memory::HEAP_VADDR);
         CHECK(vma != manager->vma_map.end());
         CHECK(vma->second.type == Kernel::VMAType::Free);
-        CHECK(vma->second.backing_memory == nullptr);
+        CHECK(vma->second.backing_memory.GetPtr() == nullptr);
     }
 
     SECTION("changing memory permissions") {
         // Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
         auto manager = std::make_unique<Kernel::VMManager>(memory);
-        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block->data(), block->size(),
+        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block, block.GetSize(),
                                                 Kernel::MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
-        ResultCode code = manager->ReprotectRange(Memory::HEAP_VADDR, block->size(),
+        ResultCode code = manager->ReprotectRange(Memory::HEAP_VADDR, block.GetSize(),
                                                   Kernel::VMAPermission::Execute);
         CHECK(code == RESULT_SUCCESS);
 
@@ -58,24 +59,24 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
         CHECK(vma != manager->vma_map.end());
         CHECK(vma->second.permissions == Kernel::VMAPermission::Execute);
 
-        code = manager->UnmapRange(Memory::HEAP_VADDR, block->size());
+        code = manager->UnmapRange(Memory::HEAP_VADDR, block.GetSize());
         REQUIRE(code == RESULT_SUCCESS);
     }
 
     SECTION("changing memory state") {
         // Because of the PageTable, Kernel::VMManager is too big to be created on the stack.
         auto manager = std::make_unique<Kernel::VMManager>(memory);
-        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block->data(), block->size(),
+        auto result = manager->MapBackingMemory(Memory::HEAP_VADDR, block, block.GetSize(),
                                                 Kernel::MemoryState::Private);
         REQUIRE(result.Code() == RESULT_SUCCESS);
 
-        ResultCode code = manager->ReprotectRange(Memory::HEAP_VADDR, block->size(),
+        ResultCode code = manager->ReprotectRange(Memory::HEAP_VADDR, block.GetSize(),
                                                   Kernel::VMAPermission::ReadWrite);
         REQUIRE(code == RESULT_SUCCESS);
 
         SECTION("with invalid address") {
             ResultCode code = manager->ChangeMemoryState(
-                0xFFFFFFFF, block->size(), Kernel::MemoryState::Locked,
+                0xFFFFFFFF, block.GetSize(), Kernel::MemoryState::Locked,
                 Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Aliased,
                 Kernel::VMAPermission::Execute);
             CHECK(code == Kernel::ERR_INVALID_ADDRESS);
@@ -83,7 +84,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
 
         SECTION("ignoring the original permissions") {
             ResultCode code = manager->ChangeMemoryState(
-                Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Private,
+                Memory::HEAP_VADDR, block.GetSize(), Kernel::MemoryState::Private,
                 Kernel::VMAPermission::None, Kernel::MemoryState::Locked,
                 Kernel::VMAPermission::Write);
             CHECK(code == RESULT_SUCCESS);
@@ -96,7 +97,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
 
         SECTION("enforcing the original permissions with correct expectations") {
             ResultCode code = manager->ChangeMemoryState(
-                Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Private,
+                Memory::HEAP_VADDR, block.GetSize(), Kernel::MemoryState::Private,
                 Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Aliased,
                 Kernel::VMAPermission::Execute);
             CHECK(code == RESULT_SUCCESS);
@@ -109,7 +110,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
 
         SECTION("with incorrect permission expectations") {
             ResultCode code = manager->ChangeMemoryState(
-                Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Private,
+                Memory::HEAP_VADDR, block.GetSize(), Kernel::MemoryState::Private,
                 Kernel::VMAPermission::Execute, Kernel::MemoryState::Aliased,
                 Kernel::VMAPermission::Execute);
             CHECK(code == Kernel::ERR_INVALID_ADDRESS_STATE);
@@ -122,7 +123,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
 
         SECTION("with incorrect state expectations") {
             ResultCode code = manager->ChangeMemoryState(
-                Memory::HEAP_VADDR, block->size(), Kernel::MemoryState::Locked,
+                Memory::HEAP_VADDR, block.GetSize(), Kernel::MemoryState::Locked,
                 Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Aliased,
                 Kernel::VMAPermission::Execute);
             CHECK(code == Kernel::ERR_INVALID_ADDRESS_STATE);
@@ -133,7 +134,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
             CHECK(vma->second.meminfo_state == Kernel::MemoryState::Private);
         }
 
-        code = manager->UnmapRange(Memory::HEAP_VADDR, block->size());
+        code = manager->UnmapRange(Memory::HEAP_VADDR, block.GetSize());
         REQUIRE(code == RESULT_SUCCESS);
     }
 }

From e4afa8e5124a61c17f171406b2011a1ea8b163ea Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 5 Jan 2020 13:26:16 +0000
Subject: [PATCH 058/129] Make the tests pass

---
 src/common/memory_ref.h            | 17 +++++++++++------
 src/core/core.cpp                  |  4 ++--
 src/core/hle/service/cecd/cecd.cpp |  3 +--
 src/core/memory.cpp                | 21 +++++++++++----------
 4 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
index 5aaaef468..05b1c7901 100644
--- a/src/common/memory_ref.h
+++ b/src/common/memory_ref.h
@@ -91,15 +91,20 @@ public:
     }
 
 private:
-    std::shared_ptr<BackingMem> backing_mem;
-    u32 offset;
+    std::shared_ptr<BackingMem> backing_mem = nullptr;
+    u32 offset = 0;
     // Cached values for speed
-    u8* cptr;
-    u32 csize;
+    u8* cptr = nullptr;
+    u32 csize = 0;
 
     void Init() {
-        cptr = backing_mem->GetPtr() + offset;
-        csize = static_cast<u32>(backing_mem->GetSize() - offset);
+        if (backing_mem) {
+            cptr = backing_mem->GetPtr() + offset;
+            csize = static_cast<u32>(backing_mem->GetSize() - offset);
+        } else {
+            cptr = nullptr;
+            csize = 0;
+        }
     }
 
     template <class Archive>
diff --git a/src/core/core.cpp b/src/core/core.cpp
index a05e2a636..bada80b55 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -214,8 +214,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(
-        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
+                                                    [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 42ac76946..f13df6926 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -1352,8 +1352,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
     case CecDataPathType::MboxData:
     case CecDataPathType::MboxIcon:
     case CecDataPathType::MboxTitle:
-    default: {
-    }
+    default: {}
     }
 }
 
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 9762619f0..dd3a07804 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -98,7 +98,7 @@ public:
     std::shared_ptr<BackingMem> n3ds_extra_ram_mem;
     std::shared_ptr<BackingMem> dsp_mem;
 
-    MemorySystem::Impl();
+    Impl();
 
     virtual u8* GetPtr(Region r) {
         switch (r) {
@@ -157,16 +157,17 @@ private:
 template <Region R>
 class MemorySystem::BackingMemImpl : public BackingMem {
 public:
-    BackingMemImpl() : system(Core::Global<Core::System>().Memory()) {}
+    BackingMemImpl() : impl(*Core::Global<Core::System>().Memory().impl) {}
+    BackingMemImpl(MemorySystem::Impl& impl_) : impl(impl_) {}
     virtual u8* GetPtr() {
-        return system.impl->GetPtr(R);
+        return impl.GetPtr(R);
     }
     virtual u32 GetSize() const {
-        return system.impl->GetSize(R);
+        return impl.GetSize(R);
     }
 
 private:
-    MemorySystem& system;
+    MemorySystem::Impl& impl;
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {}
@@ -174,10 +175,10 @@ private:
 };
 
 MemorySystem::Impl::Impl()
-    : fcram_mem(std::make_shared<BackingMemImpl<Region::FCRAM>>()),
-      vram_mem(std::make_shared<BackingMemImpl<Region::VRAM>>()),
-      n3ds_extra_ram_mem(std::make_shared<BackingMemImpl<Region::N3DS>>()),
-      dsp_mem(std::make_shared<BackingMemImpl<Region::DSP>>()) {}
+    : fcram_mem(std::make_shared<BackingMemImpl<Region::FCRAM>>(*this)),
+      vram_mem(std::make_shared<BackingMemImpl<Region::VRAM>>(*this)),
+      n3ds_extra_ram_mem(std::make_shared<BackingMemImpl<Region::N3DS>>(*this)),
+      dsp_mem(std::make_shared<BackingMemImpl<Region::DSP>>(*this)) {}
 
 MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
 MemorySystem::~MemorySystem() = default;
@@ -219,7 +220,7 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef
         }
 
         base += 1;
-        if (memory != nullptr)
+        if (memory != nullptr && memory.GetSize() > PAGE_SIZE)
             memory += PAGE_SIZE;
     }
 }

From 96432589bdeff1ac53ca1e2b7601d9eea1def435 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 5 Jan 2020 16:35:01 +0000
Subject: [PATCH 059/129] Use shared_ptr for PageTable

---
 TODO                                   |  2 +-
 src/core/arm/dynarmic/arm_dynarmic.h   |  4 ++--
 src/core/hle/kernel/kernel.cpp         |  4 ++--
 src/core/hle/kernel/kernel.h           |  2 +-
 src/core/hle/kernel/process.cpp        |  4 ++--
 src/core/hle/kernel/vm_manager.cpp     | 11 ++++++-----
 src/core/hle/kernel/vm_manager.h       |  2 +-
 src/core/memory.cpp                    | 26 +++++++++++++-------------
 src/core/memory.h                      |  8 ++++----
 src/tests/core/arm/arm_test_common.cpp |  4 ++--
 10 files changed, 34 insertions(+), 33 deletions(-)

diff --git a/TODO b/TODO
index 4bb80f8d5..9c77cec5b 100644
--- a/TODO
+++ b/TODO
@@ -3,7 +3,7 @@
     ☐ Multiple slots etc.
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
-    ☐ Page tables
+    ✔ Page tables @done(20-01-05 16:33)
         Need to change uses to shared_ptr
     ✔ Skip N3DS RAM if unused @done(20-01-03 23:26)
 ✔ DSP @done(19-12-28 16:57)
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index ff9a104b5..690c1aa2e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -61,7 +61,7 @@ private:
     std::unique_ptr<Dynarmic::A32::Jit> MakeJit();
 
     Dynarmic::A32::Jit* jit = nullptr;
-    Memory::PageTable* current_page_table = nullptr;
-    std::map<Memory::PageTable*, std::unique_ptr<Dynarmic::A32::Jit>> jits;
+    std::shared_ptr<Memory::PageTable> current_page_table = nullptr;
+    std::map<std::shared_ptr<Memory::PageTable>, std::unique_ptr<Dynarmic::A32::Jit>> jits;
     std::shared_ptr<ARMul_State> interpreter_state;
 };
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 6fef2d4de..968e905ac 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -52,10 +52,10 @@ std::shared_ptr<Process> KernelSystem::GetCurrentProcess() const {
 
 void KernelSystem::SetCurrentProcess(std::shared_ptr<Process> process) {
     current_process = process;
-    SetCurrentMemoryPageTable(&process->vm_manager.page_table);
+    SetCurrentMemoryPageTable(process->vm_manager.page_table);
 }
 
-void KernelSystem::SetCurrentMemoryPageTable(Memory::PageTable* page_table) {
+void KernelSystem::SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table) {
     memory.SetCurrentPageTable(page_table);
     if (current_cpu != nullptr) {
         current_cpu->PageTableChanged(); // notify the CPU the page table in memory has changed
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 0a527d8b4..c07bfdbca 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -214,7 +214,7 @@ public:
     std::shared_ptr<Process> GetCurrentProcess() const;
     void SetCurrentProcess(std::shared_ptr<Process> process);
 
-    void SetCurrentMemoryPageTable(Memory::PageTable* page_table);
+    void SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table);
 
     void SetCPU(std::shared_ptr<ARM_Interface> cpu);
 
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index c181bd01a..ea3449c21 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -435,7 +435,7 @@ ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission pe
 
 Kernel::Process::Process(KernelSystem& kernel)
     : Object(kernel), handle_table(kernel), vm_manager(kernel.memory), kernel(kernel) {
-    kernel.memory.RegisterPageTable(&vm_manager.page_table);
+    kernel.memory.RegisterPageTable(vm_manager.page_table);
 }
 Kernel::Process::~Process() {
     // Release all objects this process owns first so that their potential destructor can do clean
@@ -444,7 +444,7 @@ Kernel::Process::~Process() {
     // memory etc.) even if they are still referenced by other processes.
     handle_table.Clear();
 
-    kernel.memory.UnregisterPageTable(&vm_manager.page_table);
+    kernel.memory.UnregisterPageTable(vm_manager.page_table);
 }
 
 std::shared_ptr<Process> KernelSystem::GetProcessById(u32 process_id) const {
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 1b9875ee2..f1408235b 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -37,7 +37,8 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
     return true;
 }
 
-VMManager::VMManager(Memory::MemorySystem& memory) : memory(memory) {
+VMManager::VMManager(Memory::MemorySystem& memory)
+    : memory(memory), page_table(std::make_shared<Memory::PageTable>()) {
     Reset();
 }
 
@@ -51,7 +52,7 @@ void VMManager::Reset() {
     initial_vma.size = MAX_ADDRESS;
     vma_map.emplace(initial_vma.base, initial_vma);
 
-    page_table.Clear();
+    page_table->Clear();
 
     UpdatePageTableForVMA(initial_vma);
 }
@@ -348,13 +349,13 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
 void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
     switch (vma.type) {
     case VMAType::Free:
-        memory.UnmapRegion(page_table, vma.base, vma.size);
+        memory.UnmapRegion(*page_table, vma.base, vma.size);
         break;
     case VMAType::BackingMemory:
-        memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
+        memory.MapMemoryRegion(*page_table, vma.base, vma.size, vma.backing_memory);
         break;
     case VMAType::MMIO:
-        memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
+        memory.MapIoRegion(*page_table, vma.base, vma.size, vma.mmio_handler);
         break;
     }
 }
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 880d9ec81..3ca46d069 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -209,7 +209,7 @@ public:
 
     /// Each VMManager has its own page table, which is set as the main one when the owning process
     /// is scheduled.
-    Memory::PageTable page_table;
+    std::shared_ptr<Memory::PageTable> page_table;
 
 private:
     using VMAIter = decltype(vma_map)::iterator;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index dd3a07804..ceb6aad4e 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -87,9 +87,9 @@ public:
     std::unique_ptr<u8[]> vram = std::make_unique<u8[]>(Memory::VRAM_SIZE);
     std::unique_ptr<u8[]> n3ds_extra_ram = std::make_unique<u8[]>(Memory::N3DS_EXTRA_RAM_SIZE);
 
-    PageTable* current_page_table = nullptr;
+    std::shared_ptr<PageTable> current_page_table = nullptr;
     RasterizerCacheMarker cache_marker;
-    std::vector<PageTable*> page_table_list;
+    std::vector<std::shared_ptr<PageTable>> page_table_list;
 
     AudioCore::DspInterface* dsp = nullptr;
 
@@ -144,7 +144,7 @@ private:
         ar& cache_marker;
         ar& page_table_list;
         // dsp is set from Core::System at startup
-        // TODO: current_page_table
+        ar& current_page_table;
         ar& fcram_mem;
         ar& vram_mem;
         ar& n3ds_extra_ram_mem;
@@ -190,11 +190,11 @@ void MemorySystem::serialize(Archive& ar, const unsigned int file_version) {
 
 SERIALIZE_IMPL(MemorySystem)
 
-void MemorySystem::SetCurrentPageTable(PageTable* page_table) {
+void MemorySystem::SetCurrentPageTable(std::shared_ptr<PageTable> page_table) {
     impl->current_page_table = page_table;
 }
 
-PageTable* MemorySystem::GetCurrentPageTable() const {
+std::shared_ptr<PageTable> MemorySystem::GetCurrentPageTable() const {
     return impl->current_page_table;
 }
 
@@ -259,11 +259,11 @@ MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) {
     UNREACHABLE();
 }
 
-void MemorySystem::RegisterPageTable(PageTable* page_table) {
+void MemorySystem::RegisterPageTable(std::shared_ptr<PageTable> page_table) {
     impl->page_table_list.push_back(page_table);
 }
 
-void MemorySystem::UnregisterPageTable(PageTable* page_table) {
+void MemorySystem::UnregisterPageTable(std::shared_ptr<PageTable> page_table) {
     impl->page_table_list.erase(
         std::find(impl->page_table_list.begin(), impl->page_table_list.end(), page_table));
 }
@@ -351,7 +351,7 @@ void MemorySystem::Write(const VAddr vaddr, const T data) {
 }
 
 bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
-    auto& page_table = process.vm_manager.page_table;
+    auto& page_table = *process.vm_manager.page_table;
 
     auto page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
     if (page_pointer)
@@ -486,7 +486,7 @@ void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached
     for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
         for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) {
             impl->cache_marker.Mark(vaddr, cached);
-            for (PageTable* page_table : impl->page_table_list) {
+            for (auto page_table : impl->page_table_list) {
                 PageType& page_type = page_table->attributes[vaddr >> PAGE_BITS];
 
                 if (cached) {
@@ -608,7 +608,7 @@ u64 MemorySystem::Read64(const VAddr addr) {
 
 void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr,
                              void* dest_buffer, const std::size_t size) {
-    auto& page_table = process.vm_manager.page_table;
+    auto& page_table = *process.vm_manager.page_table;
 
     std::size_t remaining_size = size;
     std::size_t page_index = src_addr >> PAGE_BITS;
@@ -674,7 +674,7 @@ void MemorySystem::Write64(const VAddr addr, const u64 data) {
 
 void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
                               const void* src_buffer, const std::size_t size) {
-    auto& page_table = process.vm_manager.page_table;
+    auto& page_table = *process.vm_manager.page_table;
     std::size_t remaining_size = size;
     std::size_t page_index = dest_addr >> PAGE_BITS;
     std::size_t page_offset = dest_addr & PAGE_MASK;
@@ -722,7 +722,7 @@ void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_a
 
 void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr,
                              const std::size_t size) {
-    auto& page_table = process.vm_manager.page_table;
+    auto& page_table = *process.vm_manager.page_table;
     std::size_t remaining_size = size;
     std::size_t page_index = dest_addr >> PAGE_BITS;
     std::size_t page_offset = dest_addr & PAGE_MASK;
@@ -777,7 +777,7 @@ void MemorySystem::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VA
 void MemorySystem::CopyBlock(const Kernel::Process& dest_process,
                              const Kernel::Process& src_process, VAddr dest_addr, VAddr src_addr,
                              std::size_t size) {
-    auto& page_table = src_process.vm_manager.page_table;
+    auto& page_table = *src_process.vm_manager.page_table;
     std::size_t remaining_size = size;
     std::size_t page_index = src_addr >> PAGE_BITS;
     std::size_t page_offset = src_addr & PAGE_MASK;
diff --git a/src/core/memory.h b/src/core/memory.h
index 0dc98a428..348fee3c9 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -316,8 +316,8 @@ public:
     void UnmapRegion(PageTable& page_table, VAddr base, u32 size);
 
     /// Currently active page table
-    void SetCurrentPageTable(PageTable* page_table);
-    PageTable* GetCurrentPageTable() const;
+    void SetCurrentPageTable(std::shared_ptr<PageTable> page_table);
+    std::shared_ptr<PageTable> GetCurrentPageTable() const;
 
     u8 Read8(VAddr addr);
     u16 Read16(VAddr addr);
@@ -367,10 +367,10 @@ public:
     void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached);
 
     /// Registers page table for rasterizer cache marking
-    void RegisterPageTable(PageTable* page_table);
+    void RegisterPageTable(std::shared_ptr<PageTable> page_table);
 
     /// Unregisters page table for rasterizer cache marking
-    void UnregisterPageTable(PageTable* page_table);
+    void UnregisterPageTable(std::shared_ptr<PageTable> page_table);
 
     void SetDSP(AudioCore::DspInterface& dsp);
 
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 3f90482ec..cf2ecf0d4 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -10,7 +10,7 @@
 
 namespace ArmTests {
 
-static Memory::PageTable* page_table = nullptr;
+static std::shared_ptr<Memory::PageTable> page_table = nullptr;
 
 TestEnvironment::TestEnvironment(bool mutable_memory_)
     : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
@@ -20,7 +20,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
     kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0);
 
     kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
-    page_table = &kernel->GetCurrentProcess()->vm_manager.page_table;
+    page_table = kernel->GetCurrentProcess()->vm_manager.page_table;
 
     page_table->Clear();
 

From 7019561fd51919ddc21fbc17220d8b2f4bc10461 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 5 Jan 2020 16:42:04 +0000
Subject: [PATCH 060/129] Bind NWM_UDS service in the constructor

---
 TODO                                 |  4 ++--
 src/core/hle/service/nwm/nwm_uds.cpp | 16 ++++++++--------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/TODO b/TODO
index 9c77cec5b..c4f46e312 100644
--- a/TODO
+++ b/TODO
@@ -93,7 +93,7 @@
         ✔ VM Manager @started(19-08-13 16:46) @done(20-01-04 21:09) @lasted(20w4d5h23m42s)
             Just need to figure out backing_mem (a u8*)
         ✔ Wait object @done(19-08-13 16:46)
-    ☐ Service @started(19-12-23 12:49)
+    ✔ Service @started(19-12-23 12:49) @done(20-01-05 16:41) @lasted(1w6d3h52m17s)
         ✔ AC @started(19-12-23 12:48) @done(19-12-24 22:38) @lasted(1d9h50m3s)
         ✔ ACT @done(19-12-24 23:17)
         ✔ AM @started(19-12-24 23:17) @done(19-12-24 23:53) @lasted(36m8s)
@@ -125,7 +125,7 @@
         ✔ NIM @done(19-12-31 21:08)
         ✔ NS @done(20-01-01 00:46)
         ✔ NWM @done(20-01-01 21:31)
-            ☐ Fix wifi_packet_received?
+            ✔ Fix wifi_packet_received @done(20-01-05 16:41)
         ✔ PM @done(20-01-01 22:14)
         ✔ PS @done(20-01-01 00:54)
         ✔ PTM @done(20-01-01 22:36)
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 9a3de82fa..dddf55333 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -31,7 +31,7 @@ void NWM_UDS::serialize(Archive& ar, const unsigned int) {
     ar& node_map;
     ar& connection_event;
     ar& received_beacons;
-    // TODO: Fix wifi_packet_received?
+    // wifi_packet_received set in constructor
 }
 SERIALIZE_IMPL(NWM_UDS)
 
@@ -637,13 +637,6 @@ ResultVal<std::shared_ptr<Kernel::Event>> NWM_UDS::Initialize(
     recv_buffer_memory = std::move(sharedmem);
     ASSERT_MSG(recv_buffer_memory->GetSize() == sharedmem_size, "Invalid shared memory size.");
 
-    if (auto room_member = Network::GetRoomMember().lock()) {
-        wifi_packet_received = room_member->BindOnWifiPacketReceived(
-            [this](const Network::WifiPacket& packet) { OnWifiPacketReceived(packet); });
-    } else {
-        LOG_ERROR(Service_NWM, "Network isn't initalized");
-    }
-
     {
         std::lock_guard lock(connection_status_mutex);
 
@@ -1408,6 +1401,13 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(sy
 
     system.Kernel().GetSharedPageHandler().SetMacAddress(mac);
     system.Kernel().GetSharedPageHandler().SetWifiLinkLevel(SharedPage::WifiLinkLevel::BEST);
+
+    if (auto room_member = Network::GetRoomMember().lock()) {
+        wifi_packet_received = room_member->BindOnWifiPacketReceived(
+            [this](const Network::WifiPacket& packet) { OnWifiPacketReceived(packet); });
+    } else {
+        LOG_ERROR(Service_NWM, "Network isn't initalized");
+    }
 }
 
 NWM_UDS::~NWM_UDS() {

From 116d22d562b294e95f3e924c00ecc40bbcc28117 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 6 Jan 2020 20:03:40 +0000
Subject: [PATCH 061/129] Refactor out the wakeup_callback function pointer

---
 TODO                                          |   3 +-
 src/common/CMakeLists.txt                     |   1 +
 .../serialization/boost_small_vector.hpp      | 144 +++++++++++++++++
 src/common/serialization/boost_vector.hpp     | 148 +++++++-----------
 src/core/hle/kernel/address_arbiter.cpp       |  16 +-
 src/core/hle/kernel/address_arbiter.h         |   6 +-
 src/core/hle/kernel/hle_ipc.cpp               |  95 +++++++----
 src/core/hle/kernel/hle_ipc.h                 |  55 +++++--
 src/core/hle/kernel/ipc.cpp                   |   2 +-
 src/core/hle/kernel/ipc_debugger/recorder.cpp |   4 +-
 src/core/hle/kernel/kernel.h                  |   2 +-
 src/core/hle/kernel/server_session.cpp        |   6 +-
 src/core/hle/kernel/svc.cpp                   | 139 ++++++++--------
 src/core/hle/kernel/svc.h                     |   7 +
 src/core/hle/kernel/thread.cpp                |  29 ++--
 src/core/hle/kernel/thread.h                  |  15 +-
 src/core/hle/kernel/wait_object.cpp           |   2 +-
 src/core/hle/service/fs/file.cpp              |   7 +-
 src/core/hle/service/fs/fs_user.cpp           |  14 +-
 src/core/hle/service/nwm/nwm_uds.cpp          |  36 +++--
 src/core/hle/service/nwm/nwm_uds.h            |   4 +
 src/core/hle/service/sm/srv.cpp               |  66 +++++---
 src/core/hle/service/sm/srv.h                 |   5 +
 src/tests/core/hle/kernel/hle_ipc.cpp         |  22 +--
 24 files changed, 533 insertions(+), 295 deletions(-)
 create mode 100644 src/common/serialization/boost_small_vector.hpp

diff --git a/TODO b/TODO
index c4f46e312..097c310a7 100644
--- a/TODO
+++ b/TODO
@@ -46,6 +46,7 @@
 ✔ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE @started(20-01-03 13:47) @done(20-01-03 13:58) @lasted(11m22s)
 ☐ Review constructor/initialization code
 ☐ Review core timing events
+☐ Review base class serialization everywhere
 ✔ Fix CI @done(19-12-31 21:32)
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
@@ -87,7 +88,7 @@
         ✔ Shared page @done(20-01-04 21:09)
         ✔ SVC @done(19-12-22 21:32)
             Nothing to do - all data is constant
-        ☐ Thread @started(19-08-13 16:45)
+        ✔ Thread @started(19-08-13 16:45) @done(20-01-06 20:01) @lasted(20w6d4h16m22s)
             This requires refactoring wakeup_callback to be an object ref
         ✔ Timer @done(19-08-13 16:45)
         ✔ VM Manager @started(19-08-13 16:46) @done(20-01-04 21:09) @lasted(20w4d5h23m42s)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index ea117d440..7ab54242d 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -96,6 +96,7 @@ add_library(common STATIC
     serialization/atomic.h
     serialization/boost_discrete_interval.hpp
     serialization/boost_flat_set.h
+    serialization/boost_small_vector.hpp
     serialization/boost_vector.hpp
     string_util.cpp
     string_util.h
diff --git a/src/common/serialization/boost_small_vector.hpp b/src/common/serialization/boost_small_vector.hpp
new file mode 100644
index 000000000..b4e07a896
--- /dev/null
+++ b/src/common/serialization/boost_small_vector.hpp
@@ -0,0 +1,144 @@
+#ifndef BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
+#define BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER)
+#pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// boost_vector.hpp: serialization for boost vector templates
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
+// fast array serialization (C) Copyright 2005 Matthias Troyer
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <boost/container/small_vector.hpp>
+
+#include <boost/config.hpp>
+#include <boost/detail/workaround.hpp>
+
+#include <boost/archive/detail/basic_iarchive.hpp>
+#include <boost/serialization/access.hpp>
+#include <boost/serialization/collection_size_type.hpp>
+#include <boost/serialization/item_version_type.hpp>
+#include <boost/serialization/nvp.hpp>
+
+#include <boost/mpl/bool_fwd.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/serialization/array_wrapper.hpp>
+#include <boost/serialization/collections_load_imp.hpp>
+#include <boost/serialization/collections_save_imp.hpp>
+#include <boost/serialization/split_free.hpp>
+
+// default is being compatible with version 1.34.1 files, not 1.35 files
+#ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
+#define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V == 4 || V == 5)
+#endif
+
+namespace boost {
+namespace serialization {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// vector< T >
+
+// the default versions
+
+template <class Archive, class U, std::size_t N>
+inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
+                 const unsigned int /* file_version */, mpl::false_) {
+    boost::serialization::stl::save_collection<Archive, boost::container::small_vector<U, N>>(ar,
+                                                                                              t);
+}
+
+template <class Archive, class U, std::size_t N>
+inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
+                 const unsigned int /* file_version */, mpl::false_) {
+    const boost::archive::library_version_type library_version(ar.get_library_version());
+    // retrieve number of elements
+    item_version_type item_version(0);
+    collection_size_type count;
+    ar >> BOOST_SERIALIZATION_NVP(count);
+    if (boost::archive::library_version_type(3) < library_version) {
+        ar >> BOOST_SERIALIZATION_NVP(item_version);
+    }
+    t.reserve(count);
+    stl::collection_load_impl(ar, t, count, item_version);
+}
+
+// the optimized versions
+
+template <class Archive, class U, std::size_t N>
+inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
+                 const unsigned int /* file_version */, mpl::true_) {
+    const collection_size_type count(t.size());
+    ar << BOOST_SERIALIZATION_NVP(count);
+    if (!t.empty())
+        // explict template arguments to pass intel C++ compiler
+        ar << serialization::make_array<const U, collection_size_type>(static_cast<const U*>(&t[0]),
+                                                                       count);
+}
+
+template <class Archive, class U, std::size_t N>
+inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
+                 const unsigned int /* file_version */, mpl::true_) {
+    collection_size_type count(t.size());
+    ar >> BOOST_SERIALIZATION_NVP(count);
+    t.resize(count);
+    unsigned int item_version = 0;
+    if (BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) {
+        ar >> BOOST_SERIALIZATION_NVP(item_version);
+    }
+    if (!t.empty())
+        // explict template arguments to pass intel C++ compiler
+        ar >> serialization::make_array<U, collection_size_type>(static_cast<U*>(&t[0]), count);
+}
+
+// dispatch to either default or optimized versions
+
+template <class Archive, class U, std::size_t N>
+inline void save(Archive& ar, const boost::container::small_vector<U, N>& t,
+                 const unsigned int file_version) {
+    typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
+        typename remove_const<U>::type>::type use_optimized;
+    save(ar, t, file_version, use_optimized());
+}
+
+template <class Archive, class U, std::size_t N>
+inline void load(Archive& ar, boost::container::small_vector<U, N>& t,
+                 const unsigned int file_version) {
+#ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
+    if (ar.get_library_version() == boost::archive::library_version_type(5)) {
+        load(ar, t, file_version, boost::is_arithmetic<U>());
+        return;
+    }
+#endif
+    typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
+        typename remove_const<U>::type>::type use_optimized;
+    load(ar, t, file_version, use_optimized());
+}
+
+// split non-intrusive serialization function member into separate
+// non intrusive save/load member functions
+template <class Archive, class U, std::size_t N>
+inline void serialize(Archive& ar, boost::container::small_vector<U, N>& t,
+                      const unsigned int file_version) {
+    boost::serialization::split_free(ar, t, file_version);
+}
+
+// split non-intrusive serialization function member into separate
+// non intrusive save/load member functions
+template <class Archive, std::size_t N>
+inline void serialize(Archive& ar, boost::container::small_vector<bool, N>& t,
+                      const unsigned int file_version) {
+    boost::serialization::split_free(ar, t, file_version);
+}
+
+} // namespace serialization
+} // namespace boost
+
+#endif // BOOST_SERIALIZATION_BOOST_SMALL_VECTOR_HPP
diff --git a/src/common/serialization/boost_vector.hpp b/src/common/serialization/boost_vector.hpp
index d97ebd208..55a5b9eae 100644
--- a/src/common/serialization/boost_vector.hpp
+++ b/src/common/serialization/boost_vector.hpp
@@ -1,9 +1,9 @@
-#ifndef  BOOST_SERIALIZATION_BOOST_VECTOR_HPP
+#ifndef BOOST_SERIALIZATION_BOOST_VECTOR_HPP
 #define BOOST_SERIALIZATION_BOOST_VECTOR_HPP
 
 // MS compatible compilers support #pragma once
 #if defined(_MSC_VER)
-# pragma once
+#pragma once
 #endif
 
 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
@@ -24,20 +24,20 @@
 
 #include <boost/archive/detail/basic_iarchive.hpp>
 #include <boost/serialization/access.hpp>
-#include <boost/serialization/nvp.hpp>
 #include <boost/serialization/collection_size_type.hpp>
 #include <boost/serialization/item_version_type.hpp>
+#include <boost/serialization/nvp.hpp>
 
-#include <boost/serialization/collections_save_imp.hpp>
-#include <boost/serialization/collections_load_imp.hpp>
-#include <boost/serialization/split_free.hpp>
-#include <boost/serialization/array_wrapper.hpp>
 #include <boost/mpl/bool_fwd.hpp>
 #include <boost/mpl/if.hpp>
+#include <boost/serialization/array_wrapper.hpp>
+#include <boost/serialization/collections_load_imp.hpp>
+#include <boost/serialization/collections_save_imp.hpp>
+#include <boost/serialization/split_free.hpp>
 
 // default is being compatible with version 1.34.1 files, not 1.35 files
 #ifndef BOOST_SERIALIZATION_VECTOR_VERSIONED
-#define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V==4 || V==5)
+#define BOOST_SERIALIZATION_VECTOR_VERSIONED(V) (V == 4 || V == 5)
 #endif
 
 namespace boost {
@@ -48,33 +48,23 @@ namespace serialization {
 
 // the default versions
 
-template<class Archive, class U, class Allocator>
-inline void save(
-    Archive & ar,
-    const boost::container::vector<U, Allocator> &t,
-    const unsigned int /* file_version */,
-    mpl::false_
-){
-    boost::serialization::stl::save_collection<Archive, boost::container::vector<U, Allocator> >(
-        ar, t
-    );
+template <class Archive, class U, class Allocator, class Options>
+inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
+                 const unsigned int /* file_version */, mpl::false_) {
+    boost::serialization::stl::save_collection<Archive,
+                                               boost::container::vector<U, Allocator, Options>>(ar,
+                                                                                                t);
 }
 
-template<class Archive, class U, class Allocator>
-inline void load(
-    Archive & ar,
-    boost::container::vector<U, Allocator> &t,
-    const unsigned int /* file_version */,
-    mpl::false_
-){
-    const boost::archive::library_version_type library_version(
-        ar.get_library_version()
-    );
+template <class Archive, class U, class Allocator, class Options>
+inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
+                 const unsigned int /* file_version */, mpl::false_) {
+    const boost::archive::library_version_type library_version(ar.get_library_version());
     // retrieve number of elements
     item_version_type item_version(0);
     collection_size_type count;
     ar >> BOOST_SERIALIZATION_NVP(count);
-    if(boost::archive::library_version_type(3) < library_version){
+    if (boost::archive::library_version_type(3) < library_version) {
         ar >> BOOST_SERIALIZATION_NVP(item_version);
     }
     t.reserve(count);
@@ -83,107 +73,77 @@ inline void load(
 
 // the optimized versions
 
-template<class Archive, class U, class Allocator>
-inline void save(
-    Archive & ar,
-    const boost::container::vector<U, Allocator> &t,
-    const unsigned int /* file_version */,
-    mpl::true_
-){
+template <class Archive, class U, class Allocator, class Options>
+inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
+                 const unsigned int /* file_version */, mpl::true_) {
     const collection_size_type count(t.size());
     ar << BOOST_SERIALIZATION_NVP(count);
     if (!t.empty())
         // explict template arguments to pass intel C++ compiler
-        ar << serialization::make_array<const U, collection_size_type>(
-            static_cast<const U *>(&t[0]),
-            count
-        );
+        ar << serialization::make_array<const U, collection_size_type>(static_cast<const U*>(&t[0]),
+                                                                       count);
 }
 
-template<class Archive, class U, class Allocator>
-inline void load(
-    Archive & ar,
-    boost::container::vector<U, Allocator> &t,
-    const unsigned int /* file_version */,
-    mpl::true_
-){
+template <class Archive, class U, class Allocator, class Options>
+inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
+                 const unsigned int /* file_version */, mpl::true_) {
     collection_size_type count(t.size());
     ar >> BOOST_SERIALIZATION_NVP(count);
     t.resize(count);
-    unsigned int item_version=0;
-    if(BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) {
+    unsigned int item_version = 0;
+    if (BOOST_SERIALIZATION_VECTOR_VERSIONED(ar.get_library_version())) {
         ar >> BOOST_SERIALIZATION_NVP(item_version);
     }
     if (!t.empty())
         // explict template arguments to pass intel C++ compiler
-        ar >> serialization::make_array<U, collection_size_type>(
-            static_cast<U *>(&t[0]),
-            count
-        );
-  }
+        ar >> serialization::make_array<U, collection_size_type>(static_cast<U*>(&t[0]), count);
+}
 
 // dispatch to either default or optimized versions
 
-template<class Archive, class U, class Allocator>
-inline void save(
-    Archive & ar,
-    const boost::container::vector<U, Allocator> &t,
-    const unsigned int file_version
-){
-    typedef typename
-    boost::serialization::use_array_optimization<Archive>::template apply<
-        typename remove_const<U>::type
-    >::type use_optimized;
-    save(ar,t,file_version, use_optimized());
+template <class Archive, class U, class Allocator, class Options>
+inline void save(Archive& ar, const boost::container::vector<U, Allocator, Options>& t,
+                 const unsigned int file_version) {
+    typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
+        typename remove_const<U>::type>::type use_optimized;
+    save(ar, t, file_version, use_optimized());
 }
 
-template<class Archive, class U, class Allocator>
-inline void load(
-    Archive & ar,
-    boost::container::vector<U, Allocator> &t,
-    const unsigned int file_version
-){
+template <class Archive, class U, class Allocator, class Options>
+inline void load(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
+                 const unsigned int file_version) {
 #ifdef BOOST_SERIALIZATION_VECTOR_135_HPP
-    if (ar.get_library_version()==boost::archive::library_version_type(5))
-    {
-      load(ar,t,file_version, boost::is_arithmetic<U>());
-      return;
+    if (ar.get_library_version() == boost::archive::library_version_type(5)) {
+        load(ar, t, file_version, boost::is_arithmetic<U>());
+        return;
     }
 #endif
-    typedef typename
-    boost::serialization::use_array_optimization<Archive>::template apply<
-        typename remove_const<U>::type
-    >::type use_optimized;
-    load(ar,t,file_version, use_optimized());
+    typedef typename boost::serialization::use_array_optimization<Archive>::template apply<
+        typename remove_const<U>::type>::type use_optimized;
+    load(ar, t, file_version, use_optimized());
 }
 
 // split non-intrusive serialization function member into separate
 // non intrusive save/load member functions
-template<class Archive, class U, class Allocator>
-inline void serialize(
-    Archive & ar,
-    boost::container::vector<U, Allocator> & t,
-    const unsigned int file_version
-){
+template <class Archive, class U, class Allocator, class Options>
+inline void serialize(Archive& ar, boost::container::vector<U, Allocator, Options>& t,
+                      const unsigned int file_version) {
     boost::serialization::split_free(ar, t, file_version);
 }
 
 // split non-intrusive serialization function member into separate
 // non intrusive save/load member functions
-template<class Archive, class Allocator>
-inline void serialize(
-    Archive & ar,
-    boost::container::vector<bool, Allocator> & t,
-    const unsigned int file_version
-){
+template <class Archive, class Allocator, class Options>
+inline void serialize(Archive& ar, boost::container::vector<bool, Allocator, Options>& t,
+                      const unsigned int file_version) {
     boost::serialization::split_free(ar, t, file_version);
 }
 
-} // serialization
+} // namespace serialization
 } // namespace boost
 
 #include <boost/serialization/collection_traits.hpp>
 
 BOOST_SERIALIZATION_COLLECTION_TRAITS(boost::container::vector)
 
-#endif // BOOST_SERIALIZATION_VECTOR_HPP
+#endif // BOOST_SERIALIZATION_BOOST_VECTOR_HPP
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 7b8329c4d..5074e352f 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -80,16 +80,18 @@ std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string n
     return address_arbiter;
 }
 
+void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+                            std::shared_ptr<WaitObject> object) {
+    ASSERT(reason == ThreadWakeupReason::Timeout);
+    // Remove the newly-awakened thread from the Arbiter's waiting list.
+    waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread),
+                          waiting_threads.end());
+};
+
 ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type,
                                             VAddr address, s32 value, u64 nanoseconds) {
 
-    auto timeout_callback = [this](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
-                                   std::shared_ptr<WaitObject> object) {
-        ASSERT(reason == ThreadWakeupReason::Timeout);
-        // Remove the newly-awakened thread from the Arbiter's waiting list.
-        waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread),
-                              waiting_threads.end());
-    };
+    auto timeout_callback = std::dynamic_pointer_cast<WakeupCallback>(shared_from_this());
 
     switch (type) {
 
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 19b80315f..85a2a065a 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -12,6 +12,7 @@
 #include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
+#include "core/hle/kernel/thread.h"
 #include "core/hle/result.h"
 
 // Address arbiters are an underlying kernel synchronization object that can be created/used via
@@ -34,7 +35,7 @@ enum class ArbitrationType : u32 {
     DecrementAndWaitIfLessThanWithTimeout,
 };
 
-class AddressArbiter final : public Object {
+class AddressArbiter final : public Object, public WakeupCallback {
 public:
     explicit AddressArbiter(KernelSystem& kernel);
     ~AddressArbiter() override;
@@ -56,6 +57,9 @@ public:
     ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address,
                                 s32 value, u64 nanoseconds);
 
+    void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+                std::shared_ptr<WaitObject> object);
+
 private:
     KernelSystem& kernel;
 
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index ab4ecfd05..b1e2f7d8b 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -16,6 +16,46 @@
 
 namespace Kernel {
 
+class HLERequestContext::ThreadCallback : public Kernel::WakeupCallback {
+
+public:
+    ThreadCallback(std::shared_ptr<HLERequestContext> context_,
+                   std::shared_ptr<HLERequestContext::WakeupCallback> callback_)
+        : context(context_), callback(callback_) {}
+    void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+                std::shared_ptr<WaitObject> object) {
+        ASSERT(thread->status == ThreadStatus::WaitHleEvent);
+        if (callback) {
+            callback->WakeUp(thread, *context, reason);
+        }
+
+        auto& process = thread->owner_process;
+        // We must copy the entire command buffer *plus* the entire static buffers area, since
+        // the translation might need to read from it in order to retrieve the StaticBuffer
+        // target addresses.
+        std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
+        Memory::MemorySystem& memory = context->kernel.memory;
+        memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
+                         cmd_buff.size() * sizeof(u32));
+        context->WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
+        // Copy the translated command buffer back into the thread's command buffer area.
+        memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
+                          cmd_buff.size() * sizeof(u32));
+    }
+
+private:
+    ThreadCallback() = default;
+    std::shared_ptr<HLERequestContext::WakeupCallback> callback{};
+    std::shared_ptr<HLERequestContext> context{};
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& callback;
+        ar& context;
+    }
+    friend class boost::serialization::access;
+};
+
 SessionRequestHandler::SessionInfo::SessionInfo(std::shared_ptr<ServerSession> session,
                                                 std::unique_ptr<SessionDataBase> data)
     : session(std::move(session)), data(std::move(data)) {}
@@ -33,34 +73,16 @@ void SessionRequestHandler::ClientDisconnected(std::shared_ptr<ServerSession> se
         connected_sessions.end());
 }
 
-std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& reason,
-                                                            std::chrono::nanoseconds timeout,
-                                                            WakeupCallback&& callback) {
+std::shared_ptr<Event> HLERequestContext::SleepClientThread(
+    const std::string& reason, std::chrono::nanoseconds timeout,
+    std::shared_ptr<WakeupCallback> callback) {
     // Put the client thread to sleep until the wait event is signaled or the timeout expires.
-    thread->wakeup_callback = [context = *this,
-                               callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
-                                         std::shared_ptr<WaitObject> object) mutable {
-        ASSERT(thread->status == ThreadStatus::WaitHleEvent);
-        callback(thread, context, reason);
-
-        auto& process = thread->owner_process;
-        // We must copy the entire command buffer *plus* the entire static buffers area, since
-        // the translation might need to read from it in order to retrieve the StaticBuffer
-        // target addresses.
-        std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
-        Memory::MemorySystem& memory = context.kernel.memory;
-        memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
-                         cmd_buff.size() * sizeof(u32));
-        context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
-        // Copy the translated command buffer back into the thread's command buffer area.
-        memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
-                          cmd_buff.size() * sizeof(u32));
-    };
+    thread->wakeup_callback = std::make_shared<ThreadCallback>(shared_from_this(), callback);
 
     auto event = kernel.CreateEvent(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
     thread->status = ThreadStatus::WaitHleEvent;
     thread->wait_objects = {event};
-    event->AddWaitingThread(SharedFrom(thread));
+    event->AddWaitingThread(thread);
 
     if (timeout.count() > 0)
         thread->WakeAfterDelay(timeout.count());
@@ -68,8 +90,10 @@ std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& r
     return event;
 }
 
+HLERequestContext::HLERequestContext() : kernel(Core::Global<KernelSystem>()) {}
+
 HLERequestContext::HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
-                                     Thread* thread)
+                                     std::shared_ptr<Thread> thread)
     : kernel(kernel), session(std::move(session)), thread(thread) {
     cmd_buf[0] = 0;
 }
@@ -98,8 +122,9 @@ void HLERequestContext::AddStaticBuffer(u8 buffer_id, std::vector<u8> data) {
     static_buffers[buffer_id] = std::move(data);
 }
 
-ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
-                                                                Process& src_process) {
+ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(
+    const u32_le* src_cmdbuf, std::shared_ptr<Process> src_process_) {
+    auto& src_process = *src_process_;
     IPC::Header header{src_cmdbuf[0]};
 
     std::size_t untranslated_size = 1u + header.normal_params_size;
@@ -158,7 +183,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
         }
         case IPC::DescriptorType::MappedBuffer: {
             u32 next_id = static_cast<u32>(request_mapped_buffers.size());
-            request_mapped_buffers.emplace_back(kernel.memory, src_process, descriptor,
+            request_mapped_buffers.emplace_back(kernel.memory, src_process_, descriptor,
                                                 src_cmdbuf[i], next_id);
             cmd_buf[i++] = next_id;
             break;
@@ -170,7 +195,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
 
     if (should_record) {
         std::vector<u32> translated_cmdbuf{cmd_buf.begin(), cmd_buf.begin() + command_size};
-        kernel.GetIPCRecorder().SetRequestInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
+        kernel.GetIPCRecorder().SetRequestInfo(thread, std::move(untranslated_cmdbuf),
                                                std::move(translated_cmdbuf));
     }
 
@@ -248,7 +273,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
 
     if (should_record) {
         std::vector<u32> translated_cmdbuf{dst_cmdbuf, dst_cmdbuf + command_size};
-        kernel.GetIPCRecorder().SetReplyInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
+        kernel.GetIPCRecorder().SetReplyInfo(thread, std::move(untranslated_cmdbuf),
                                              std::move(translated_cmdbuf));
     }
 
@@ -262,13 +287,15 @@ MappedBuffer& HLERequestContext::GetMappedBuffer(u32 id_from_cmdbuf) {
 
 void HLERequestContext::ReportUnimplemented() const {
     if (kernel.GetIPCRecorder().IsEnabled()) {
-        kernel.GetIPCRecorder().SetHLEUnimplemented(SharedFrom(thread));
+        kernel.GetIPCRecorder().SetHLEUnimplemented(thread);
     }
 }
 
-MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
-                           VAddr address, u32 id)
-    : memory(&memory), id(id), address(address), process(&process) {
+MappedBuffer::MappedBuffer() : memory(&Core::Global<Core::System>().Memory()) {}
+
+MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process,
+                           u32 descriptor, VAddr address, u32 id)
+    : memory(&memory), id(id), address(address), process(process) {
     IPC::MappedBufferDescInfo desc{descriptor};
     size = desc.size;
     perms = desc.perms;
@@ -287,3 +314,5 @@ void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t
 }
 
 } // namespace Kernel
+
+SERIALIZE_EXPORT_IMPL(Kernel::HLERequestContext::ThreadCallback)
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 2177b733e..56c6d8ce1 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -16,6 +16,7 @@
 #include <boost/serialization/unique_ptr.hpp>
 #include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
+#include "common/serialization/boost_small_vector.hpp"
 #include "common/swap.h"
 #include "core/hle/ipc.h"
 #include "core/hle/kernel/object.h"
@@ -127,7 +128,7 @@ private:
 
 class MappedBuffer {
 public:
-    MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
+    MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process, u32 descriptor,
                  VAddr address, u32 id);
 
     // interface for service
@@ -151,9 +152,21 @@ private:
     Memory::MemorySystem* memory;
     u32 id;
     VAddr address;
-    const Process* process;
-    std::size_t size;
+    std::shared_ptr<Process> process;
+    u32 size;
     IPC::MappedBufferPermissions perms;
+
+    MappedBuffer();
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& id;
+        ar& address;
+        ar& process;
+        ar& size;
+        ar& perms;
+    }
+    friend class boost::serialization::access;
 };
 
 /**
@@ -185,9 +198,10 @@ private:
  * id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is
  * needed in this case, though.
  */
-class HLERequestContext {
+class HLERequestContext : std::enable_shared_from_this<HLERequestContext> {
 public:
-    HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session, Thread* thread);
+    HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
+                      std::shared_ptr<Thread> thread);
     ~HLERequestContext();
 
     /// Returns a pointer to the IPC command buffer for this request.
@@ -203,8 +217,12 @@ public:
         return session;
     }
 
-    using WakeupCallback = std::function<void(
-        std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
+    class WakeupCallback {
+    public:
+        virtual ~WakeupCallback() = default;
+        virtual void WakeUp(std::shared_ptr<Thread> thread, HLERequestContext& context,
+                            ThreadWakeupReason reason) = 0;
+    };
 
     /**
      * Puts the specified guest thread to sleep until the returned event is signaled or until the
@@ -219,7 +237,7 @@ public:
      */
     std::shared_ptr<Event> SleepClientThread(const std::string& reason,
                                              std::chrono::nanoseconds timeout,
-                                             WakeupCallback&& callback);
+                                             std::shared_ptr<WakeupCallback> callback);
 
     /**
      * Resolves a object id from the request command buffer into a pointer to an object. See the
@@ -259,26 +277,43 @@ public:
     MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
 
     /// Populates this context with data from the requesting process/thread.
-    ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process);
+    ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
+                                                 std::shared_ptr<Process> src_process);
     /// Writes data from this context back to the requesting process/thread.
     ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const;
 
     /// Reports an unimplemented function.
     void ReportUnimplemented() const;
 
+    class ThreadCallback;
+    friend class ThreadCallback;
+
 private:
     KernelSystem& kernel;
     std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
     std::shared_ptr<ServerSession> session;
-    Thread* thread;
+    std::shared_ptr<Thread> thread;
     // TODO(yuriks): Check common usage of this and optimize size accordingly
     boost::container::small_vector<std::shared_ptr<Object>, 8> request_handles;
     // The static buffers will be created when the IPC request is translated.
     std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers;
     // The mapped buffers will be created when the IPC request is translated
     boost::container::small_vector<MappedBuffer, 8> request_mapped_buffers;
+
+    HLERequestContext();
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& cmd_buf;
+        ar& session;
+        ar& thread;
+        ar& request_handles;
+        ar& static_buffers;
+        ar& request_mapped_buffers;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::SessionRequestHandler::SessionDataBase)
+BOOST_CLASS_EXPORT_KEY(Kernel::HLERequestContext::ThreadCallback)
diff --git a/src/core/hle/kernel/ipc.cpp b/src/core/hle/kernel/ipc.cpp
index e39732c14..eb1488840 100644
--- a/src/core/hle/kernel/ipc.cpp
+++ b/src/core/hle/kernel/ipc.cpp
@@ -72,7 +72,7 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
                 if (handle == CurrentThread) {
                     object = src_thread;
                 } else if (handle == CurrentProcess) {
-                    object = SharedFrom(src_process);
+                    object = src_process;
                 } else if (handle != 0) {
                     object = src_process->handle_table.GetGeneric(handle);
                     if (descriptor == IPC::DescriptorType::MoveHandle) {
diff --git a/src/core/hle/kernel/ipc_debugger/recorder.cpp b/src/core/hle/kernel/ipc_debugger/recorder.cpp
index 968815c5b..f1e4a09f1 100644
--- a/src/core/hle/kernel/ipc_debugger/recorder.cpp
+++ b/src/core/hle/kernel/ipc_debugger/recorder.cpp
@@ -52,7 +52,7 @@ void Recorder::RegisterRequest(const std::shared_ptr<Kernel::ClientSession>& cli
 
     RequestRecord record = {/* id */ ++record_count,
                             /* status */ RequestStatus::Sent,
-                            /* client_process */ GetObjectInfo(client_thread->owner_process),
+                            /* client_process */ GetObjectInfo(client_thread->owner_process.get()),
                             /* client_thread */ GetObjectInfo(client_thread.get()),
                             /* client_session */ GetObjectInfo(client_session.get()),
                             /* client_port */ GetObjectInfo(client_session->parent->port.get()),
@@ -82,7 +82,7 @@ void Recorder::SetRequestInfo(const std::shared_ptr<Kernel::Thread>& client_thre
     record.translated_request_cmdbuf = std::move(translated_cmdbuf);
 
     if (server_thread) {
-        record.server_process = GetObjectInfo(server_thread->owner_process);
+        record.server_process = GetObjectInfo(server_thread->owner_process.get());
         record.server_thread = GetObjectInfo(server_thread.get());
     } else {
         record.is_hle = true;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index c07bfdbca..e7b7314d6 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -134,7 +134,7 @@ public:
      */
     ResultVal<std::shared_ptr<Thread>> CreateThread(std::string name, VAddr entry_point,
                                                     u32 priority, u32 arg, s32 processor_id,
-                                                    VAddr stack_top, Process& owner_process);
+                                                    VAddr stack_top, std::shared_ptr<Process> owner_process);
 
     /**
      * Creates a semaphore.
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 4b393b63d..8bb82fc83 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -71,12 +71,12 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
     // If this ServerSession has an associated HLE handler, forward the request to it.
     if (hle_handler != nullptr) {
         std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buf;
-        Kernel::Process* current_process = thread->owner_process;
+        auto current_process = thread->owner_process;
         kernel.memory.ReadBlock(*current_process, thread->GetCommandBufferAddress(), cmd_buf.data(),
                                 cmd_buf.size() * sizeof(u32));
 
-        Kernel::HLERequestContext context(kernel, SharedFrom(this), thread.get());
-        context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), *current_process);
+        Kernel::HLERequestContext context(kernel, SharedFrom(this), thread);
+        context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), current_process);
 
         hle_handler->HandleSyncRequest(context);
 
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index b5ebaf936..7f7cc1272 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -282,7 +282,7 @@ void SVC::ExitProcess() {
     // Stop all the process threads that are currently waiting for objects.
     auto& thread_list = kernel.GetThreadManager().GetThreadList();
     for (auto& thread : thread_list) {
-        if (thread->owner_process != current_process.get())
+        if (thread->owner_process != current_process)
             continue;
 
         if (thread.get() == kernel.GetThreadManager().GetCurrentThread())
@@ -403,6 +403,73 @@ ResultCode SVC::CloseHandle(Handle handle) {
     return kernel.GetCurrentProcess()->handle_table.Close(handle);
 }
 
+static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::MemorySystem& memory,
+                                    std::shared_ptr<ServerSession> server_session,
+                                    std::shared_ptr<Thread> thread);
+
+class SVC_SyncCallback : public Kernel::WakeupCallback {
+public:
+    SVC_SyncCallback(bool do_output_) : do_output(do_output_) {}
+    void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+                std::shared_ptr<WaitObject> object) {
+
+        if (reason == ThreadWakeupReason::Timeout) {
+            thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
+            return;
+        }
+
+        ASSERT(reason == ThreadWakeupReason::Signal);
+
+        thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
+
+        // The wait_all case does not update the output index.
+        if (do_output) {
+            thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
+        }
+    }
+
+private:
+    bool do_output;
+
+    SVC_SyncCallback() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& do_output;
+    }
+    friend class boost::serialization::access;
+};
+
+class SVC_IPCCallback : public Kernel::WakeupCallback {
+public:
+    SVC_IPCCallback(Core::System& system_) : system(system_) {}
+
+    void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+                std::shared_ptr<WaitObject> object) {
+
+        ASSERT(thread->status == ThreadStatus::WaitSynchAny);
+        ASSERT(reason == ThreadWakeupReason::Signal);
+
+        ResultCode result = RESULT_SUCCESS;
+
+        if (object->GetHandleType() == HandleType::ServerSession) {
+            auto server_session = DynamicObjectCast<ServerSession>(object);
+            result = ReceiveIPCRequest(system.Kernel(), system.Memory(), server_session, thread);
+        }
+
+        thread->SetWaitSynchronizationResult(result);
+        thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
+    }
+
+private:
+    Core::System& system;
+
+    SVC_IPCCallback() : system(Core::Global<Core::System>()) {}
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
+};
+
 /// Wait for a handle to synchronize, timeout after the specified nanoseconds
 ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
     auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
@@ -426,21 +493,7 @@ ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
         // Create an event to wake the thread up after the specified nanosecond delay has passed
         thread->WakeAfterDelay(nano_seconds);
 
-        thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
-                                     std::shared_ptr<WaitObject> object) {
-            ASSERT(thread->status == ThreadStatus::WaitSynchAny);
-
-            if (reason == ThreadWakeupReason::Timeout) {
-                thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
-                return;
-            }
-
-            ASSERT(reason == ThreadWakeupReason::Signal);
-            thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
-
-            // WaitSynchronization1 doesn't have an output index like WaitSynchronizationN, so we
-            // don't have to do anything else here.
-        };
+        thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
 
         system.PrepareReschedule();
 
@@ -515,20 +568,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
         // Create an event to wake the thread up after the specified nanosecond delay has passed
         thread->WakeAfterDelay(nano_seconds);
 
-        thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
-                                     std::shared_ptr<WaitObject> object) {
-            ASSERT(thread->status == ThreadStatus::WaitSynchAll);
-
-            if (reason == ThreadWakeupReason::Timeout) {
-                thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
-                return;
-            }
-
-            ASSERT(reason == ThreadWakeupReason::Signal);
-
-            thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
-            // The wait_all case does not update the output index.
-        };
+        thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
 
         system.PrepareReschedule();
 
@@ -575,20 +615,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
         // Create an event to wake the thread up after the specified nanosecond delay has passed
         thread->WakeAfterDelay(nano_seconds);
 
-        thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
-                                     std::shared_ptr<WaitObject> object) {
-            ASSERT(thread->status == ThreadStatus::WaitSynchAny);
-
-            if (reason == ThreadWakeupReason::Timeout) {
-                thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
-                return;
-            }
-
-            ASSERT(reason == ThreadWakeupReason::Signal);
-
-            thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
-            thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
-        };
+        thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(true);
 
         system.PrepareReschedule();
 
@@ -730,22 +757,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
 
     thread->wait_objects = std::move(objects);
 
-    thread->wakeup_callback = [& kernel = this->kernel, &memory = this->memory](
-                                  ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
-                                  std::shared_ptr<WaitObject> object) {
-        ASSERT(thread->status == ThreadStatus::WaitSynchAny);
-        ASSERT(reason == ThreadWakeupReason::Signal);
-
-        ResultCode result = RESULT_SUCCESS;
-
-        if (object->GetHandleType() == HandleType::ServerSession) {
-            auto server_session = DynamicObjectCast<ServerSession>(object);
-            result = ReceiveIPCRequest(kernel, memory, server_session, thread);
-        }
-
-        thread->SetWaitSynchronizationResult(result);
-        thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
-    };
+    thread->wakeup_callback = std::make_shared<SVC_IPCCallback>(system);
 
     system.PrepareReschedule();
 
@@ -911,7 +923,7 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
 
     CASCADE_RESULT(std::shared_ptr<Thread> thread,
                    kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top,
-                                       *current_process));
+                                       current_process));
 
     thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
                               FPSCR_ROUND_TOZERO); // 0x03C00000
@@ -1020,7 +1032,7 @@ ResultCode SVC::GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
     if (thread == nullptr)
         return ERR_INVALID_HANDLE;
 
-    const std::shared_ptr<Process> process = SharedFrom(thread->owner_process);
+    const std::shared_ptr<Process> process = thread->owner_process;
 
     ASSERT_MSG(process != nullptr, "Invalid parent process for thread={:#010X}", thread_handle);
 
@@ -1611,3 +1623,6 @@ void SVCContext::CallSVC(u32 immediate) {
 }
 
 } // namespace Kernel
+
+SERIALIZE_EXPORT_IMPL(Kernel::SVC_SyncCallback)
+SERIALIZE_EXPORT_IMPL(Kernel::SVC_IPCCallback)
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h
index efddff9e8..4cf265400 100644
--- a/src/core/hle/kernel/svc.h
+++ b/src/core/hle/kernel/svc.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 
 namespace Core {
@@ -25,4 +26,10 @@ private:
     std::unique_ptr<SVC> impl;
 };
 
+class SVC_SyncCallback;
+class SVC_IPCCallback;
+
 } // namespace Kernel
+
+BOOST_CLASS_EXPORT_KEY(Kernel::SVC_SyncCallback)
+BOOST_CLASS_EXPORT_KEY(Kernel::SVC_IPCCallback)
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 1af2d4f4d..13a3017a5 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -48,7 +48,7 @@ void Thread::serialize(Archive& ar, const unsigned int file_version) {
     ar& wait_objects;
     ar& wait_address;
     ar& name;
-    // TODO: How the hell to do wakeup_callback
+    ar& wakeup_callback;
 }
 
 SERIALIZE_IMPL(Thread)
@@ -138,8 +138,8 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
         ready_queue.remove(new_thread->current_priority, new_thread);
         new_thread->status = ThreadStatus::Running;
 
-        if (previous_process.get() != current_thread->owner_process) {
-            kernel.SetCurrentProcess(SharedFrom(current_thread->owner_process));
+        if (previous_process != current_thread->owner_process) {
+            kernel.SetCurrentProcess(current_thread->owner_process);
         }
 
         cpu->LoadContext(new_thread->context);
@@ -196,7 +196,7 @@ void ThreadManager::ThreadWakeupCallback(u64 thread_id, s64 cycles_late) {
 
         // Invoke the wakeup callback before clearing the wait objects
         if (thread->wakeup_callback)
-            thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr);
+            thread->wakeup_callback->WakeUp(ThreadWakeupReason::Timeout, thread, nullptr);
 
         // Remove the thread from each of its waiting objects' waitlists
         for (auto& object : thread->wait_objects)
@@ -313,10 +313,9 @@ static void ResetThreadContext(const std::unique_ptr<ARM_Interface::ThreadContex
     context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode
 }
 
-ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name, VAddr entry_point,
-                                                              u32 priority, u32 arg,
-                                                              s32 processor_id, VAddr stack_top,
-                                                              Process& owner_process) {
+ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
+    std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top,
+    std::shared_ptr<Process> owner_process) {
     // Check if priority is in ranged. Lowest priority -> highest priority id.
     if (priority > ThreadPrioLowest) {
         LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
@@ -330,7 +329,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
 
     // TODO(yuriks): Other checks, returning 0xD9001BEA
 
-    if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
+    if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
         LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
         // TODO: Verify error
         return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
@@ -353,10 +352,10 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
     thread->wait_address = 0;
     thread->name = std::move(name);
     thread_manager->wakeup_callback_table[thread->thread_id] = thread.get();
-    thread->owner_process = &owner_process;
+    thread->owner_process = owner_process;
 
     // Find the next available TLS index, and mark it as used
-    auto& tls_slots = owner_process.tls_slots;
+    auto& tls_slots = owner_process->tls_slots;
 
     auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
 
@@ -372,13 +371,13 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
                       "Not enough space in region to allocate a new TLS page for thread");
             return ERR_OUT_OF_MEMORY;
         }
-        owner_process.memory_used += Memory::PAGE_SIZE;
+        owner_process->memory_used += Memory::PAGE_SIZE;
 
         tls_slots.emplace_back(0); // The page is completely available at the start
         available_page = tls_slots.size() - 1;
         available_slot = 0; // Use the first slot in the new page
 
-        auto& vm_manager = owner_process.vm_manager;
+        auto& vm_manager = owner_process->vm_manager;
 
         // Map the page to the current process' address space.
         vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
@@ -391,7 +390,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
     thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
                           available_slot * Memory::TLS_ENTRY_SIZE;
 
-    memory.ZeroBlock(owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
+    memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
 
     // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
     // to initialize the context
@@ -438,7 +437,7 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
     // Initialize new "main" thread
     auto thread_res =
         kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor,
-                            Memory::HEAP_VADDR_END, *owner_process);
+                            Memory::HEAP_VADDR_END, owner_process);
 
     std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
 
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 219db9f2d..9941c76db 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -59,6 +59,15 @@ enum class ThreadWakeupReason {
     Timeout // The thread was woken up due to a wait timeout.
 };
 
+class Thread;
+
+class WakeupCallback {
+public:
+    virtual ~WakeupCallback() = default;
+    virtual void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
+                        std::shared_ptr<WaitObject> object) = 0;
+};
+
 class ThreadManager {
 public:
     explicit ThreadManager(Kernel::KernelSystem& kernel);
@@ -300,7 +309,7 @@ public:
     /// Mutexes that this thread is currently waiting for.
     boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes;
 
-    Process* owner_process; ///< Process that owns this thread
+    std::shared_ptr<Process> owner_process; ///< Process that owns this thread
 
     /// Objects that the thread is waiting on, in the same order as they were
     // passed to WaitSynchronization1/N.
@@ -310,12 +319,10 @@ public:
 
     std::string name;
 
-    using WakeupCallback = void(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
-                                std::shared_ptr<WaitObject> object);
     // Callback that will be invoked when the thread is resumed from a waiting state. If the thread
     // was waiting via WaitSynchronizationN then the object will be the last object that became
     // available. In case of a timeout, the object will be nullptr.
-    std::function<WakeupCallback> wakeup_callback;
+    std::shared_ptr<WakeupCallback> wakeup_callback;
 
 private:
     ThreadManager& thread_manager;
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index 94ae632cd..6fe75b6d8 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -80,7 +80,7 @@ void WaitObject::WakeupAllWaitingThreads() {
 
         // Invoke the wakeup callback before clearing the wait objects
         if (thread->wakeup_callback)
-            thread->wakeup_callback(ThreadWakeupReason::Signal, thread, SharedFrom(this));
+            thread->wakeup_callback->WakeUp(ThreadWakeupReason::Signal, thread, SharedFrom(this));
 
         for (auto& object : thread->wait_objects)
             object->RemoveWaitingThread(thread.get());
diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp
index 946e27211..c8727314b 100644
--- a/src/core/hle/service/fs/file.cpp
+++ b/src/core/hle/service/fs/file.cpp
@@ -71,12 +71,7 @@ void File::Read(Kernel::HLERequestContext& ctx) {
     rb.PushMappedBuffer(buffer);
 
     std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)};
-    ctx.SleepClientThread("file::read", read_timeout_ns,
-                          [](std::shared_ptr<Kernel::Thread> /*thread*/,
-                             Kernel::HLERequestContext& /*ctx*/,
-                             Kernel::ThreadWakeupReason /*reason*/) {
-                              // Nothing to do here
-                          });
+    ctx.SleepClientThread("file::read", read_timeout_ns, nullptr);
 }
 
 void File::Write(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index e027e837f..010600ee2 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -76,12 +76,7 @@ void FS_USER::OpenFile(Kernel::HLERequestContext& ctx) {
         LOG_ERROR(Service_FS, "failed to get a handle for file {}", file_path.DebugStr());
     }
 
-    ctx.SleepClientThread("fs_user::open", open_timeout_ns,
-                          [](std::shared_ptr<Kernel::Thread> /*thread*/,
-                             Kernel::HLERequestContext& /*ctx*/,
-                             Kernel::ThreadWakeupReason /*reason*/) {
-                              // Nothing to do here
-                          });
+    ctx.SleepClientThread("fs_user::open", open_timeout_ns, nullptr);
 }
 
 void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
@@ -134,12 +129,7 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
                   file_path.DebugStr(), mode.hex, attributes);
     }
 
-    ctx.SleepClientThread("fs_user::open_directly", open_timeout_ns,
-                          [](std::shared_ptr<Kernel::Thread> /*thread*/,
-                             Kernel::HLERequestContext& /*ctx*/,
-                             Kernel::ThreadWakeupReason /*reason*/) {
-                              // Nothing to do here
-                          });
+    ctx.SleepClientThread("fs_user::open_directly", open_timeout_ns, nullptr);
 }
 
 void FS_USER::DeleteFile(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index dddf55333..eef8cbd1d 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -1170,6 +1170,29 @@ void NWM_UDS::GetChannel(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_NWM, "called");
 }
 
+class NWM_UDS::ThreadCallback : public Kernel::HLERequestContext::WakeupCallback {
+public:
+    ThreadCallback(u16 command_id_) : command_id(command_id_) {}
+
+    void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
+                Kernel::ThreadWakeupReason reason) {
+        // TODO(B3N30): Add error handling for host full and timeout
+        IPC::RequestBuilder rb(ctx, command_id, 1, 0);
+        rb.Push(RESULT_SUCCESS);
+        LOG_DEBUG(Service_NWM, "connection sequence finished");
+    }
+
+private:
+    ThreadCallback() = default;
+    u16 command_id;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& command_id;
+    }
+    friend class boost::serialization::access;
+};
+
 void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
                                const u8* network_info_buffer, std::size_t network_info_size,
                                u8 connection_type, std::vector<u8> passphrase) {
@@ -1183,15 +1206,8 @@ void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id,
     // Since this timing is handled by core_timing it could differ from the 'real world' time
     static constexpr std::chrono::nanoseconds UDSConnectionTimeout{300000000};
 
-    connection_event = ctx.SleepClientThread(
-        "uds::ConnectToNetwork", UDSConnectionTimeout,
-        [command_id](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
-                     Kernel::ThreadWakeupReason reason) {
-            // TODO(B3N30): Add error handling for host full and timeout
-            IPC::RequestBuilder rb(ctx, command_id, 1, 0);
-            rb.Push(RESULT_SUCCESS);
-            LOG_DEBUG(Service_NWM, "connection sequence finished");
-        });
+    connection_event = ctx.SleepClientThread("uds::ConnectToNetwork", UDSConnectionTimeout,
+                                             std::make_shared<ThreadCallback>(command_id));
 }
 
 void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) {
@@ -1418,3 +1434,5 @@ NWM_UDS::~NWM_UDS() {
 }
 
 } // namespace Service::NWM
+
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_UDS::ThreadCallback)
diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h
index 07dd7e9ba..b2ab1d76a 100644
--- a/src/core/hle/service/nwm/nwm_uds.h
+++ b/src/core/hle/service/nwm/nwm_uds.h
@@ -15,6 +15,7 @@
 #include <unordered_map>
 #include <vector>
 #include <boost/optional.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/hle/service/service.h"
@@ -127,6 +128,8 @@ public:
     explicit NWM_UDS(Core::System& system);
     ~NWM_UDS();
 
+    class ThreadCallback;
+
 private:
     Core::System& system;
 
@@ -560,3 +563,4 @@ private:
 
 SERVICE_CONSTRUCT(Service::NWM::NWM_UDS)
 BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_UDS)
+BOOST_CLASS_EXPORT_KEY(Service::NWM::NWM_UDS::ThreadCallback)
diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp
index 396bd3559..10179f416 100644
--- a/src/core/hle/service/sm/srv.cpp
+++ b/src/core/hle/service/sm/srv.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <tuple>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "core/core.h"
@@ -71,6 +72,46 @@ void SRV::EnableNotification(Kernel::HLERequestContext& ctx) {
     LOG_WARNING(Service_SRV, "(STUBBED) called");
 }
 
+class SRV::ThreadCallback : public Kernel::HLERequestContext::WakeupCallback {
+
+public:
+    ThreadCallback(Core::System& system_, std::string name_) : system(system_), name(name_) {}
+
+    void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
+                Kernel::ThreadWakeupReason reason) {
+        LOG_ERROR(Service_SRV, "called service={} wakeup", name);
+        auto client_port = system.ServiceManager().GetServicePort(name);
+
+        auto session = client_port.Unwrap()->Connect();
+        if (session.Succeeded()) {
+            LOG_DEBUG(Service_SRV, "called service={} -> session={}", name,
+                      (*session)->GetObjectId());
+            IPC::RequestBuilder rb(ctx, 0x5, 1, 2);
+            rb.Push(session.Code());
+            rb.PushMoveObjects(std::move(session).Unwrap());
+        } else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED) {
+            LOG_ERROR(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name);
+            UNREACHABLE();
+        } else {
+            LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, session.Code().raw);
+            IPC::RequestBuilder rb(ctx, 0x5, 1, 0);
+            rb.Push(session.Code());
+        }
+    }
+
+private:
+    Core::System& system;
+    std::string name;
+
+    ThreadCallback() : system(Core::Global<Core::System>()) {}
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& name;
+    }
+    friend class boost::serialization::access;
+};
+
 /**
  * SRV::GetServiceHandle service function
  *  Inputs:
@@ -100,28 +141,7 @@ void SRV::GetServiceHandle(Kernel::HLERequestContext& ctx) {
 
     // TODO(yuriks): Permission checks go here
 
-    auto get_handle = [name, this](std::shared_ptr<Kernel::Thread> thread,
-                                   Kernel::HLERequestContext& ctx,
-                                   Kernel::ThreadWakeupReason reason) {
-        LOG_ERROR(Service_SRV, "called service={} wakeup", name);
-        auto client_port = system.ServiceManager().GetServicePort(name);
-
-        auto session = client_port.Unwrap()->Connect();
-        if (session.Succeeded()) {
-            LOG_DEBUG(Service_SRV, "called service={} -> session={}", name,
-                      (*session)->GetObjectId());
-            IPC::RequestBuilder rb(ctx, 0x5, 1, 2);
-            rb.Push(session.Code());
-            rb.PushMoveObjects(std::move(session).Unwrap());
-        } else if (session.Code() == Kernel::ERR_MAX_CONNECTIONS_REACHED) {
-            LOG_ERROR(Service_SRV, "called service={} -> ERR_MAX_CONNECTIONS_REACHED", name);
-            UNREACHABLE();
-        } else {
-            LOG_ERROR(Service_SRV, "called service={} -> error 0x{:08X}", name, session.Code().raw);
-            IPC::RequestBuilder rb(ctx, 0x5, 1, 0);
-            rb.Push(session.Code());
-        }
-    };
+    auto get_handle = std::make_shared<ThreadCallback>(system, name);
 
     auto client_port = system.ServiceManager().GetServicePort(name);
     if (client_port.Failed()) {
@@ -266,3 +286,5 @@ SRV::SRV(Core::System& system) : ServiceFramework("srv:", 4), system(system) {
 SRV::~SRV() = default;
 
 } // namespace Service::SM
+
+SERIALIZE_EXPORT_IMPL(Service::SM::SRV::ThreadCallback)
diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h
index 2382f4842..7d17f87a5 100644
--- a/src/core/hle/service/sm/srv.h
+++ b/src/core/hle/service/sm/srv.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <unordered_map>
+#include <boost/serialization/export.hpp>
 #include "core/hle/service/service.h"
 
 namespace Core {
@@ -25,6 +26,8 @@ public:
     explicit SRV(Core::System& system);
     ~SRV();
 
+    class ThreadCallback;
+
 private:
     void RegisterClient(Kernel::HLERequestContext& ctx);
     void EnableNotification(Kernel::HLERequestContext& ctx);
@@ -40,3 +43,5 @@ private:
 };
 
 } // namespace Service::SM
+
+BOOST_CLASS_EXPORT_KEY(Service::SM::SRV::ThreadCallback)
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index 414d64021..a4f7c8062 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -37,7 +37,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             IPC::MakeHeader(0x1234, 0, 0),
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         REQUIRE(context.CommandBuffer()[0] == 0x12340000);
     }
@@ -50,7 +50,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             0xAABBCCDD,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         auto* output = context.CommandBuffer();
         REQUIRE(output[1] == 0x12345678);
@@ -67,7 +67,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             a_handle,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         auto* output = context.CommandBuffer();
         REQUIRE(context.GetIncomingHandle(output[2]) == a);
@@ -83,7 +83,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             a_handle,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         auto* output = context.CommandBuffer();
         REQUIRE(context.GetIncomingHandle(output[2]) == a);
@@ -103,7 +103,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             process->handle_table.Create(c).Unwrap(),
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         auto* output = context.CommandBuffer();
         REQUIRE(context.GetIncomingHandle(output[2]) == a);
@@ -118,7 +118,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             0,
         };
 
-        auto result = context.PopulateFromIncomingCommandBuffer(input, *process);
+        auto result = context.PopulateFromIncomingCommandBuffer(input, process);
 
         REQUIRE(result == RESULT_SUCCESS);
         auto* output = context.CommandBuffer();
@@ -132,7 +132,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             0x98989898,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         REQUIRE(context.CommandBuffer()[2] == process->process_id);
     }
@@ -153,7 +153,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             target_address,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         CHECK(context.GetStaticBuffer(0) == mem->Vector());
 
@@ -175,7 +175,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             target_address,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         std::vector<u8> other_buffer(buffer.GetSize());
         context.GetMappedBuffer(0).Read(other_buffer.data(), 0, buffer.GetSize());
@@ -219,7 +219,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
             target_address_mapped,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input, *process);
+        context.PopulateFromIncomingCommandBuffer(input, process);
 
         auto* output = context.CommandBuffer();
         CHECK(output[1] == 0x12345678);
@@ -365,7 +365,7 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
             target_address,
         };
 
-        context.PopulateFromIncomingCommandBuffer(input_cmdbuff, *process);
+        context.PopulateFromIncomingCommandBuffer(input_cmdbuff, process);
 
         context.GetMappedBuffer(0).Write(input_buffer.data(), 0, input_buffer.size());
 

From f2de70c3fbdef9ac16bcbc5c6773c97311bd663b Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 6 Jan 2020 23:20:18 +0000
Subject: [PATCH 062/129] Fix crash bugs

---
 CMakeLists.txt                         |   2 +-
 TODO                                   |  14 +++++++-------
 save0.citrasave                        | Bin 0 -> 776 bytes
 src/common/archives.h                  |   3 +--
 src/core/core.cpp                      |  20 ++++++++++++++------
 src/core/hle/kernel/hle_ipc.h          |   2 +-
 src/core/hle/kernel/server_session.cpp |   9 +++++----
 src/core/memory.cpp                    |   3 +++
 8 files changed, 32 insertions(+), 21 deletions(-)
 create mode 100644 save0.citrasave

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f986a39af..45deee61a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -123,7 +123,7 @@ set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 # set up output paths for executable binaries
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE})
 
 
 # System imported libraries
diff --git a/TODO b/TODO
index 097c310a7..a422fda4d 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,11 @@
 ☐ Save/load UI
     ✔ Basic version @done(20-01-03 15:27)
     ☐ Multiple slots etc.
+☐ Custom texture cache
+☐ Review constructor/initialization code
+☐ Review core timing events
+☐ Review base class serialization everywhere
+☐ Serialize codeset with an apploader reference instead
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
     ✔ Page tables @done(20-01-05 16:33)
@@ -32,7 +37,6 @@
         Not needed as nothing serializes file buffers
     ✘ Replace delay generator with virtual fns @cancelled(20-01-03 13:16)
         While they have no state, the extra refactoring here is unneeded
-☐ Custom texture cache
 ✘ MMIO @cancelled(20-01-01 01:06)
     Seems that this whole subsystem is only used in tests
 ✘ Movie @cancelled(20-01-01 01:07)
@@ -44,9 +48,6 @@
 ✘ Telemetry session @cancelled(20-01-01 01:12)
     Doesn't need to be serialized here
 ✔ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE @started(20-01-03 13:47) @done(20-01-03 13:58) @lasted(11m22s)
-☐ Review constructor/initialization code
-☐ Review core timing events
-☐ Review base class serialization everywhere
 ✔ Fix CI @done(19-12-31 21:32)
 ✔ HW @done(19-08-13 15:41)
     ✔ GPU regs @done(19-08-13 15:41)
@@ -57,8 +58,8 @@
     ✔ PICA state @done(19-08-13 15:41)
     ✔ Primitive assembly @done(19-12-22 16:05)
     ✔ Shader @done(19-08-13 16:03)
-☐ HLE @started(19-08-13 16:43)
-    ☐ Kernel @started(19-08-13 16:43)
+✔ HLE @started(19-08-13 16:43) @done(20-01-06 20:37) @lasted(20w6d4h54m19s)
+    ✔ Kernel @started(19-08-13 16:43) @done(20-01-06 20:37) @lasted(20w6d4h54m17s)
         Most of these require adding Core::Global
         ✔ Address arbiter @done(19-08-13 16:40)
         ✔ Client port @done(19-08-13 16:40)
@@ -74,7 +75,6 @@
         ✔ Process @started(19-08-13 16:43) @done(19-12-22 18:41)
         ✔ Code set @started(19-12-22 18:41) @done(20-01-03 15:15) @lasted(1w4d20h34m2s)
             Needs a way to reference loaded images (so we don't serialize the entire ROM as well)
-            ☐ Serialize codeset with an apploader reference instead
         ✔ Resource limit @done(19-08-13 16:43)
         ✔ Semaphore @done(19-08-13 16:44)
         ✔ Server port @done(19-08-13 16:44)
diff --git a/save0.citrasave b/save0.citrasave
new file mode 100644
index 0000000000000000000000000000000000000000..578174ec6b7489150da4ff634caacf0e34d2ddd8
GIT binary patch
literal 776
zcmWe*fPmuEqRhmc%&Nqa%=|nntHh$@jLfoBK?W8U77j+J8VJP<q}YHMBnrX-WeOZj
zK>9?L0*8h?10RqH1|V?|<IY3{4i2FBml@d%1~ao61Q-|^UU$fY)qu>A17eUl4nX1q
zlntb43brUPIsz>Kd4++2my6*Yh!z9_5UsL-A0!C@U@rjWfQ|zq29QTVfSFN%k%^f}
zfI&eCB+MWP^p>C^gOH$rlAxiY0HY&Nw8DXvfgdC}gusXY|Nn!WyQGVg;ep2k7Zj)K
z{eZ+8iXbT*ADCiTFv9qtbN~VcxmJk<1>lfo1CtP8ILQfOfdU*DXW(!L6CgooJb{=H
X09FNMLyV0NPAw`+ErKZk({Muob(AbM

literal 0
HcmV?d00001

diff --git a/src/common/archives.h b/src/common/archives.h
index 29f23865b..6000bef2c 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -11,5 +11,4 @@ using oarchive = boost::archive::binary_oarchive;
 
 #define SERIALIZE_EXPORT_IMPL(A)                                                                   \
     BOOST_SERIALIZATION_REGISTER_ARCHIVE(iarchive)                                                 \
-    BOOST_SERIALIZATION_REGISTER_ARCHIVE(oarchive)                                                 \
-    BOOST_CLASS_EXPORT_IMPLEMENT(A)
+    BOOST_SERIALIZATION_REGISTER_ARCHIVE(oarchive)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index bada80b55..20a8f32fe 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -44,6 +44,8 @@
 #include "network/network.h"
 #include "video_core/video_core.h"
 
+#include "core/hle/service/pm/pm_app.h"
+
 namespace Core {
 
 /*static*/ System System::s_instance;
@@ -214,8 +216,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
-                                                    [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(
+        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -420,11 +422,17 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
 }
 
 void System::Save(std::ostream& stream) const {
-    {
-        oarchive oa{stream};
-        oa&* this;
+    try {
+
+        {
+            oarchive oa{stream};
+            oa&* this;
+        }
+        VideoCore::Save(stream);
+
+    } catch (const std::exception& e) {
+        LOG_ERROR(Core, "Error saving: {}", e.what());
     }
-    VideoCore::Save(stream);
 }
 
 void System::Load(std::istream& stream) {
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 56c6d8ce1..01fec190b 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -198,7 +198,7 @@ private:
  * id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is
  * needed in this case, though.
  */
-class HLERequestContext : std::enable_shared_from_this<HLERequestContext> {
+class HLERequestContext : public std::enable_shared_from_this<HLERequestContext> {
 public:
     HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
                       std::shared_ptr<Thread> thread);
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 8bb82fc83..3dc20e9a7 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -75,10 +75,11 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
         kernel.memory.ReadBlock(*current_process, thread->GetCommandBufferAddress(), cmd_buf.data(),
                                 cmd_buf.size() * sizeof(u32));
 
-        Kernel::HLERequestContext context(kernel, SharedFrom(this), thread);
-        context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), current_process);
+        auto context =
+            std::make_shared<Kernel::HLERequestContext>(kernel, SharedFrom(this), thread);
+        context->PopulateFromIncomingCommandBuffer(cmd_buf.data(), current_process);
 
-        hle_handler->HandleSyncRequest(context);
+        hle_handler->HandleSyncRequest(*context);
 
         ASSERT(thread->status == Kernel::ThreadStatus::Running ||
                thread->status == Kernel::ThreadStatus::WaitHleEvent);
@@ -86,7 +87,7 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
         // put the thread to sleep then the writing of the command buffer will be deferred to the
         // wakeup callback.
         if (thread->status == Kernel::ThreadStatus::Running) {
-            context.WriteToOutgoingCommandBuffer(cmd_buf.data(), *current_process);
+            context->WriteToOutgoingCommandBuffer(cmd_buf.data(), *current_process);
             kernel.memory.WriteBlock(*current_process, thread->GetCommandBufferAddress(),
                                      cmd_buf.data(), cmd_buf.size() * sizeof(u32));
         }
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index ceb6aad4e..cd3cf8aed 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -452,6 +452,9 @@ MemoryRef MemorySystem::GetPhysicalRef(PAddr address) {
     default:
         UNREACHABLE();
     }
+    if (offset_into_region >= target_mem->GetSize()) {
+        return {nullptr};
+    }
 
     return {target_mem, offset_into_region};
 }

From 996aba39feda48356cddc61af1242cff7b5551e4 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 8 Jan 2020 22:13:56 +0000
Subject: [PATCH 063/129] Correct exports; add some file serialization; fix
 service base object serialization

---
 TODO                                        |  1 +
 src/common/archives.h                       |  1 +
 src/common/file_util.cpp                    |  8 ++++++
 src/common/file_util.h                      | 29 ++++++++++++++++++++-
 src/common/memory_ref.h                     |  6 +++++
 src/core/file_sys/archive_extsavedata.cpp   |  4 +++
 src/core/file_sys/archive_extsavedata.h     |  3 +++
 src/core/file_sys/archive_sdmc.cpp          |  4 +++
 src/core/file_sys/archive_sdmc.h            |  3 +++
 src/core/file_sys/archive_sdmcwriteonly.cpp |  4 +++
 src/core/file_sys/archive_sdmcwriteonly.h   |  3 +++
 src/core/file_sys/delay_generator.h         | 12 ++++++++-
 src/core/file_sys/disk_archive.h            |  9 +++++++
 src/core/file_sys/file_backend.h            |  8 ++++++
 src/core/file_sys/savedata_archive.cpp      |  5 ++++
 src/core/file_sys/savedata_archive.h        |  4 +++
 src/core/hle/service/cam/cam_q.h            |  6 +----
 src/core/hle/service/cfg/cfg_nor.h          |  3 +++
 src/core/hle/service/dlp/dlp_clnt.h         |  6 +----
 src/core/hle/service/dlp/dlp_fkcl.h         |  6 +----
 src/core/hle/service/dlp/dlp_srvr.h         |  6 +----
 src/core/hle/service/err_f.h                |  6 +----
 src/core/hle/service/fs/file.h              | 11 ++++++++
 src/core/hle/service/fs/fs_user.h           |  2 ++
 src/core/hle/service/gsp/gsp_gpu.h          |  2 ++
 src/core/hle/service/http_c.h               |  2 ++
 src/core/hle/service/ldr_ro/ldr_ro.h        |  2 ++
 src/core/hle/service/mic_u.cpp              |  1 +
 src/core/hle/service/mvd/mvd_std.h          |  6 +----
 src/core/hle/service/news/news_s.h          |  2 ++
 src/core/hle/service/news/news_u.h          |  3 +++
 src/core/hle/service/nim/nim_aoc.h          |  3 +++
 src/core/hle/service/nim/nim_s.h            |  3 +++
 src/core/hle/service/nwm/nwm_cec.h          |  3 +++
 src/core/hle/service/nwm/nwm_ext.h          |  3 +++
 src/core/hle/service/nwm/nwm_inf.h          |  3 +++
 src/core/hle/service/nwm/nwm_sap.h          |  3 +++
 src/core/hle/service/nwm/nwm_soc.h          |  3 +++
 src/core/hle/service/nwm/nwm_tst.h          |  3 +++
 src/core/hle/service/nwm/nwm_uds.cpp        |  1 +
 src/core/hle/service/pm/pm_app.h            |  3 +++
 src/core/hle/service/pm/pm_dbg.h            |  3 +++
 src/core/hle/service/ps/ps_ps.h             |  2 ++
 src/core/hle/service/pxi/dev.h              |  3 +++
 src/core/hle/service/qtm/qtm_c.h            |  3 +++
 src/core/hle/service/qtm/qtm_s.h            |  3 +++
 src/core/hle/service/qtm/qtm_sp.h           |  3 +++
 src/core/hle/service/qtm/qtm_u.h            |  3 +++
 src/core/hle/service/service.h              |  7 +++++
 src/core/hle/service/ssl_c.h                |  2 ++
 src/core/hle/service/y2r_u.cpp              |  1 +
 src/core/memory.cpp                         |  4 ++-
 52 files changed, 197 insertions(+), 33 deletions(-)

diff --git a/TODO b/TODO
index a422fda4d..def70ac2b 100644
--- a/TODO
+++ b/TODO
@@ -5,6 +5,7 @@
 ☐ Review constructor/initialization code
 ☐ Review core timing events
 ☐ Review base class serialization everywhere
+    Make sure that all base/derived relationships are registered
 ☐ Serialize codeset with an apploader reference instead
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
diff --git a/src/common/archives.h b/src/common/archives.h
index 6000bef2c..eef292634 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -10,5 +10,6 @@ using oarchive = boost::archive::binary_oarchive;
     template void A::serialize<oarchive>(oarchive & ar, const unsigned int file_version);
 
 #define SERIALIZE_EXPORT_IMPL(A)                                                                   \
+    BOOST_CLASS_EXPORT_IMPLEMENT(A)                                                                \
     BOOST_SERIALIZATION_REGISTER_ARCHIVE(iarchive)                                                 \
     BOOST_SERIALIZATION_REGISTER_ARCHIVE(oarchive)
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index d59e34dae..ca86f7bfc 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -901,10 +901,18 @@ IOFile& IOFile::operator=(IOFile&& other) {
 void IOFile::Swap(IOFile& other) {
     std::swap(m_file, other.m_file);
     std::swap(m_good, other.m_good);
+    std::swap(filename, other.filename);
+    std::swap(openmode, other.openmode);
+    std::swap(flags, other.flags);
 }
 
 bool IOFile::Open(const std::string& filename, const char openmode[], int flags) {
     Close();
+
+    this->filename = filename;
+    this->openmode = openmode;
+    this->flags = flags;
+
 #ifdef _WIN32
     if (flags != 0) {
         m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(),
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 09c3cb6f0..c09aa88d6 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -14,6 +14,8 @@
 #include <string_view>
 #include <type_traits>
 #include <vector>
+#include <boost/serialization/split_member.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #ifdef _MSC_VER
 #include "common/string_util.h"
@@ -221,7 +223,6 @@ public:
 
     void Swap(IOFile& other);
 
-    bool Open(const std::string& filename, const char openmode[], int flags = 0);
     bool Close();
 
     template <typename T>
@@ -305,8 +306,34 @@ public:
     }
 
 private:
+    bool Open(const std::string& filename, const char openmode[], int flags = 0);
+
     std::FILE* m_file = nullptr;
     bool m_good = true;
+
+    std::string filename;
+    std::string openmode;
+    u32 flags;
+
+    template <class Archive>
+    void save(Archive& ar, const unsigned int) const {
+        ar << filename;
+        ar << openmode;
+        ar << flags;
+        ar << Tell();
+    }
+
+    template <class Archive>
+    void load(Archive& ar, const unsigned int) {
+        ar >> filename;
+        ar >> openmode;
+        ar >> flags;
+        u64 pos;
+        ar >> pos;
+        Seek(pos, SEEK_SET);
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER()
 };
 
 } // namespace FileUtil
diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
index 05b1c7901..ae30b009c 100644
--- a/src/common/memory_ref.h
+++ b/src/common/memory_ref.h
@@ -14,6 +14,11 @@ public:
     virtual ~BackingMem() = default;
     virtual u8* GetPtr() = 0;
     virtual u32 GetSize() const = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 /// Backing memory implemented by a local buffer
@@ -39,6 +44,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<BackingMem>(*this);
         ar& data;
     }
     friend class boost::serialization::access;
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 22084b690..59973b8c5 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -80,6 +80,8 @@ public:
         static constexpr u64 IPCDelayNanoseconds(3085068);
         return IPCDelayNanoseconds;
     }
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 /**
@@ -300,3 +302,5 @@ void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data
 }
 
 } // namespace FileSys
+
+SERIALIZE_EXPORT_IMPL(FileSys::ExtSaveDataDelayGenerator)
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index b00e1633d..c9b84c984 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -103,6 +103,9 @@ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared)
  */
 Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low);
 
+class ExtSaveDataDelayGenerator;
+
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_ExtSaveData)
+BOOST_CLASS_EXPORT_KEY(FileSys::ExtSaveDataDelayGenerator)
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 1c5118320..4c3ce6d69 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -41,6 +41,8 @@ public:
         static constexpr u64 IPCDelayNanoseconds(269082);
         return IPCDelayNanoseconds;
     }
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFile(const Path& path,
@@ -409,3 +411,5 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path
     return ResultCode(-1);
 }
 } // namespace FileSys
+
+SERIALIZE_EXPORT_IMPL(FileSys::SDMCDelayGenerator)
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 2e0abf44b..6051abef0 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -86,7 +86,10 @@ private:
     friend class boost::serialization::access;
 };
 
+class SDMCDelayGenerator;
+
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::SDMCArchive)
 BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SDMC)
+BOOST_CLASS_EXPORT_KEY(FileSys::SDMCDelayGenerator)
diff --git a/src/core/file_sys/archive_sdmcwriteonly.cpp b/src/core/file_sys/archive_sdmcwriteonly.cpp
index ea64dc864..241e93f0a 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.cpp
+++ b/src/core/file_sys/archive_sdmcwriteonly.cpp
@@ -39,6 +39,8 @@ public:
         static constexpr u64 IPCDelayNanoseconds(269082);
         return IPCDelayNanoseconds;
     }
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 ResultVal<std::unique_ptr<FileBackend>> SDMCWriteOnlyArchive::OpenFile(const Path& path,
@@ -100,3 +102,5 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const P
 }
 
 } // namespace FileSys
+
+SERIALIZE_EXPORT_IMPL(FileSys::SDMCWriteOnlyDelayGenerator)
diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h
index 2ba504aa7..19982a9db 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.h
+++ b/src/core/file_sys/archive_sdmcwriteonly.h
@@ -72,7 +72,10 @@ private:
     friend class boost::serialization::access;
 };
 
+class SDMCWriteOnlyDelayGenerator;
+
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::SDMCWriteOnlyArchive)
 BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SDMCWriteOnly)
+BOOST_CLASS_EXPORT_KEY(FileSys::SDMCWriteOnlyDelayGenerator)
diff --git a/src/core/file_sys/delay_generator.h b/src/core/file_sys/delay_generator.h
index 8fa92ac41..6513a730e 100644
--- a/src/core/file_sys/delay_generator.h
+++ b/src/core/file_sys/delay_generator.h
@@ -5,10 +5,18 @@
 #pragma once
 
 #include <cstddef>
-#include <boost/serialization/access.hpp>
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 
+#define SERIALIZE_DELAY_GENERATOR                                                                  \
+private:                                                                                           \
+    template <class Archive>                                                                       \
+    void serialize(Archive& ar, const unsigned int) {                                              \
+        ar& boost::serialization::base_object<DelayGenerator>(*this);                              \
+    }                                                                                              \
+    friend class boost::serialization::access;
+
 namespace FileSys {
 
 class DelayGenerator {
@@ -28,6 +36,8 @@ class DefaultDelayGenerator : public DelayGenerator {
 public:
     u64 GetReadDelayNs(std::size_t length) override;
     u64 GetOpenDelayNs() override;
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 } // namespace FileSys
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index 481aa470a..9251749ce 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -8,6 +8,8 @@
 #include <memory>
 #include <string>
 #include <vector>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "core/file_sys/archive_backend.h"
@@ -43,6 +45,13 @@ public:
 protected:
     Mode mode;
     std::unique_ptr<FileUtil::IOFile> file;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<FileBackend>(*this);
+        ar& mode;
+        ar& file;
+    }
 };
 
 class DiskDirectory : public DirectoryBackend {
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index c865c98e8..04f03a77d 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -7,6 +7,8 @@
 #include <algorithm>
 #include <cstddef>
 #include <memory>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/common_types.h"
 #include "core/hle/result.h"
 #include "delay_generator.h"
@@ -90,6 +92,12 @@ public:
 
 protected:
     std::unique_ptr<DelayGenerator> delay_generator;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& delay_generator;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp
index 8d7830468..1f22b50ab 100644
--- a/src/core/file_sys/savedata_archive.cpp
+++ b/src/core/file_sys/savedata_archive.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "common/file_util.h"
 #include "core/file_sys/disk_archive.h"
 #include "core/file_sys/errors.h"
@@ -33,6 +34,8 @@ public:
         static constexpr u64 IPCDelayNanoseconds(269082);
         return IPCDelayNanoseconds;
     }
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& path,
@@ -353,3 +356,5 @@ u64 SaveDataArchive::GetFreeBytes() const {
 }
 
 } // namespace FileSys
+
+SERIALIZE_EXPORT_IMPL(FileSys::SaveDataDelayGenerator)
diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h
index 176d35710..47f2f75e0 100644
--- a/src/core/file_sys/savedata_archive.h
+++ b/src/core/file_sys/savedata_archive.h
@@ -40,4 +40,8 @@ protected:
     std::string mount_point;
 };
 
+class SaveDataDelayGenerator;
+
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::SaveDataDelayGenerator)
diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h
index ab901cf85..992b38390 100644
--- a/src/core/hle/service/cam/cam_q.h
+++ b/src/core/hle/service/cam/cam_q.h
@@ -13,11 +13,7 @@ public:
     CAM_Q();
 
 private:
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-    }
-    friend class boost::serialization::access;
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::CAM
diff --git a/src/core/hle/service/cfg/cfg_nor.h b/src/core/hle/service/cfg/cfg_nor.h
index 1eca85a05..7e0a1a2b8 100644
--- a/src/core/hle/service/cfg/cfg_nor.h
+++ b/src/core/hle/service/cfg/cfg_nor.h
@@ -11,6 +11,9 @@ namespace Service::CFG {
 class CFG_NOR final : public ServiceFramework<CFG_NOR> {
 public:
     CFG_NOR();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::CFG
diff --git a/src/core/hle/service/dlp/dlp_clnt.h b/src/core/hle/service/dlp/dlp_clnt.h
index 835d01748..ac6933e7e 100644
--- a/src/core/hle/service/dlp/dlp_clnt.h
+++ b/src/core/hle/service/dlp/dlp_clnt.h
@@ -14,11 +14,7 @@ public:
     ~DLP_CLNT() = default;
 
 private:
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-    }
-    friend class boost::serialization::access;
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::DLP
diff --git a/src/core/hle/service/dlp/dlp_fkcl.h b/src/core/hle/service/dlp/dlp_fkcl.h
index d778ace8b..c05a77b49 100644
--- a/src/core/hle/service/dlp/dlp_fkcl.h
+++ b/src/core/hle/service/dlp/dlp_fkcl.h
@@ -14,11 +14,7 @@ public:
     ~DLP_FKCL() = default;
 
 private:
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-    }
-    friend class boost::serialization::access;
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::DLP
diff --git a/src/core/hle/service/dlp/dlp_srvr.h b/src/core/hle/service/dlp/dlp_srvr.h
index 1f171f950..625740d2f 100644
--- a/src/core/hle/service/dlp/dlp_srvr.h
+++ b/src/core/hle/service/dlp/dlp_srvr.h
@@ -16,11 +16,7 @@ public:
 private:
     void IsChild(Kernel::HLERequestContext& ctx);
 
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-    }
-    friend class boost::serialization::access;
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::DLP
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
index de92fed05..1b9fad452 100644
--- a/src/core/hle/service/err_f.h
+++ b/src/core/hle/service/err_f.h
@@ -35,11 +35,7 @@ private:
 
     Core::System& system;
 
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-    }
-    friend class boost::serialization::access;
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 void InstallInterfaces(Core::System& system);
diff --git a/src/core/hle/service/fs/file.h b/src/core/hle/service/fs/file.h
index ff4a5670a..18317212e 100644
--- a/src/core/hle/service/fs/file.h
+++ b/src/core/hle/service/fs/file.h
@@ -19,6 +19,17 @@ struct FileSessionSlot : public Kernel::SessionRequestHandler::SessionDataBase {
     u64 offset;   ///< Offset that this session will start reading from.
     u64 size;     ///< Max size of the file that this session is allowed to access
     bool subfile; ///< Whether this file was opened via OpenSubFile or not.
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(
+            *this);
+        ar& priority;
+        ar& offset;
+        ar& size;
+        ar& subfile;
+    }
 };
 
 // TODO: File is not a real service, but it can still utilize ServiceFramework::RegisterHandlers.
diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h
index 29b47a99c..83183ecf6 100644
--- a/src/core/hle/service/fs/fs_user.h
+++ b/src/core/hle/service/fs/fs_user.h
@@ -26,6 +26,8 @@ struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(
+            *this);
         ar& program_id;
     }
     friend class boost::serialization::access;
diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h
index 6194f0446..a97aee278 100644
--- a/src/core/hle/service/gsp/gsp_gpu.h
+++ b/src/core/hle/service/gsp/gsp_gpu.h
@@ -203,6 +203,8 @@ public:
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(
+            *this);
         ar& gsp;
         ar& interrupt_event;
         ar& thread_id;
diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h
index a3aa62ae0..641b6b4d1 100644
--- a/src/core/hle/service/http_c.h
+++ b/src/core/hle/service/http_c.h
@@ -240,6 +240,8 @@ struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(
+            *this);
         ar& current_http_context;
         ar& session_id;
         ar& num_http_contexts;
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h
index 2b6f79f03..7581884f6 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.h
+++ b/src/core/hle/service/ldr_ro/ldr_ro.h
@@ -18,6 +18,8 @@ struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(
+            *this);
         ar& loaded_crs;
     }
     friend class boost::serialization::access;
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index 34b16094a..478bf110f 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -25,6 +25,7 @@ namespace Service::MIC {
 
 template <class Archive>
 void MIC_U::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     ar&* impl.get();
 }
 SERIALIZE_IMPL(MIC_U)
diff --git a/src/core/hle/service/mvd/mvd_std.h b/src/core/hle/service/mvd/mvd_std.h
index 6e8312e59..fed41e6f0 100644
--- a/src/core/hle/service/mvd/mvd_std.h
+++ b/src/core/hle/service/mvd/mvd_std.h
@@ -14,11 +14,7 @@ public:
     ~MVD_STD() = default;
 
 private:
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
-    }
-    friend class boost::serialization::access;
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::MVD
diff --git a/src/core/hle/service/news/news_s.h b/src/core/hle/service/news/news_s.h
index 711a0e99b..9d1ce829f 100644
--- a/src/core/hle/service/news/news_s.h
+++ b/src/core/hle/service/news/news_s.h
@@ -24,6 +24,8 @@ private:
      *      2 : Number of notifications
      */
     void GetTotalNotifications(Kernel::HLERequestContext& ctx);
+
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NEWS
diff --git a/src/core/hle/service/news/news_u.h b/src/core/hle/service/news/news_u.h
index 472dd579c..8e672256d 100644
--- a/src/core/hle/service/news/news_u.h
+++ b/src/core/hle/service/news/news_u.h
@@ -12,6 +12,9 @@ namespace Service::NEWS {
 class NEWS_U final : public ServiceFramework<NEWS_U> {
 public:
     NEWS_U();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NEWS
diff --git a/src/core/hle/service/nim/nim_aoc.h b/src/core/hle/service/nim/nim_aoc.h
index 2d06a9d1c..003b3fd85 100644
--- a/src/core/hle/service/nim/nim_aoc.h
+++ b/src/core/hle/service/nim/nim_aoc.h
@@ -12,6 +12,9 @@ class NIM_AOC final : public ServiceFramework<NIM_AOC> {
 public:
     NIM_AOC();
     ~NIM_AOC();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NIM
diff --git a/src/core/hle/service/nim/nim_s.h b/src/core/hle/service/nim/nim_s.h
index 6281270f5..10b041456 100644
--- a/src/core/hle/service/nim/nim_s.h
+++ b/src/core/hle/service/nim/nim_s.h
@@ -12,6 +12,9 @@ class NIM_S final : public ServiceFramework<NIM_S> {
 public:
     NIM_S();
     ~NIM_S();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NIM
diff --git a/src/core/hle/service/nwm/nwm_cec.h b/src/core/hle/service/nwm/nwm_cec.h
index 4f62f32f1..674c98cae 100644
--- a/src/core/hle/service/nwm/nwm_cec.h
+++ b/src/core/hle/service/nwm/nwm_cec.h
@@ -11,6 +11,9 @@ namespace Service::NWM {
 class NWM_CEC final : public ServiceFramework<NWM_CEC> {
 public:
     NWM_CEC();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NWM
diff --git a/src/core/hle/service/nwm/nwm_ext.h b/src/core/hle/service/nwm/nwm_ext.h
index a8d43df70..1e8bcfde3 100644
--- a/src/core/hle/service/nwm/nwm_ext.h
+++ b/src/core/hle/service/nwm/nwm_ext.h
@@ -11,6 +11,9 @@ namespace Service::NWM {
 class NWM_EXT final : public ServiceFramework<NWM_EXT> {
 public:
     NWM_EXT();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NWM
diff --git a/src/core/hle/service/nwm/nwm_inf.h b/src/core/hle/service/nwm/nwm_inf.h
index f13fd4158..9f8c65a2b 100644
--- a/src/core/hle/service/nwm/nwm_inf.h
+++ b/src/core/hle/service/nwm/nwm_inf.h
@@ -11,6 +11,9 @@ namespace Service::NWM {
 class NWM_INF final : public ServiceFramework<NWM_INF> {
 public:
     NWM_INF();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NWM
diff --git a/src/core/hle/service/nwm/nwm_sap.h b/src/core/hle/service/nwm/nwm_sap.h
index 1a289542c..0422dc658 100644
--- a/src/core/hle/service/nwm/nwm_sap.h
+++ b/src/core/hle/service/nwm/nwm_sap.h
@@ -11,6 +11,9 @@ namespace Service::NWM {
 class NWM_SAP final : public ServiceFramework<NWM_SAP> {
 public:
     NWM_SAP();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NWM
diff --git a/src/core/hle/service/nwm/nwm_soc.h b/src/core/hle/service/nwm/nwm_soc.h
index 883a20854..f13490e83 100644
--- a/src/core/hle/service/nwm/nwm_soc.h
+++ b/src/core/hle/service/nwm/nwm_soc.h
@@ -11,6 +11,9 @@ namespace Service::NWM {
 class NWM_SOC final : public ServiceFramework<NWM_SOC> {
 public:
     NWM_SOC();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NWM
diff --git a/src/core/hle/service/nwm/nwm_tst.h b/src/core/hle/service/nwm/nwm_tst.h
index e58fa3371..576d4d124 100644
--- a/src/core/hle/service/nwm/nwm_tst.h
+++ b/src/core/hle/service/nwm/nwm_tst.h
@@ -11,6 +11,9 @@ namespace Service::NWM {
 class NWM_TST final : public ServiceFramework<NWM_TST> {
 public:
     NWM_TST();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::NWM
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index eef8cbd1d..2aa64f7fc 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -28,6 +28,7 @@ namespace Service::NWM {
 
 template <class Archive>
 void NWM_UDS::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     ar& node_map;
     ar& connection_event;
     ar& received_beacons;
diff --git a/src/core/hle/service/pm/pm_app.h b/src/core/hle/service/pm/pm_app.h
index 0fb290aba..9aefb0cee 100644
--- a/src/core/hle/service/pm/pm_app.h
+++ b/src/core/hle/service/pm/pm_app.h
@@ -12,6 +12,9 @@ class PM_APP final : public ServiceFramework<PM_APP> {
 public:
     PM_APP();
     ~PM_APP() = default;
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::PM
diff --git a/src/core/hle/service/pm/pm_dbg.h b/src/core/hle/service/pm/pm_dbg.h
index 1cfdea6fe..3a6e3c5c7 100644
--- a/src/core/hle/service/pm/pm_dbg.h
+++ b/src/core/hle/service/pm/pm_dbg.h
@@ -12,6 +12,9 @@ class PM_DBG final : public ServiceFramework<PM_DBG> {
 public:
     PM_DBG();
     ~PM_DBG() = default;
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::PM
diff --git a/src/core/hle/service/ps/ps_ps.h b/src/core/hle/service/ps/ps_ps.h
index 39f6d62b2..f5005d444 100644
--- a/src/core/hle/service/ps/ps_ps.h
+++ b/src/core/hle/service/ps/ps_ps.h
@@ -18,6 +18,8 @@ public:
     ~PS_PS() = default;
 
 private:
+    SERVICE_SERIALIZATION_SIMPLE
+
     /**
      * PS_PS::SignRsaSha256 service function
      *  Inputs:
diff --git a/src/core/hle/service/pxi/dev.h b/src/core/hle/service/pxi/dev.h
index ed17435b6..f16491077 100644
--- a/src/core/hle/service/pxi/dev.h
+++ b/src/core/hle/service/pxi/dev.h
@@ -13,6 +13,9 @@ class DEV final : public ServiceFramework<DEV> {
 public:
     DEV();
     ~DEV();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::PXI
diff --git a/src/core/hle/service/qtm/qtm_c.h b/src/core/hle/service/qtm/qtm_c.h
index 8ad05b6e1..b601cd9de 100644
--- a/src/core/hle/service/qtm/qtm_c.h
+++ b/src/core/hle/service/qtm/qtm_c.h
@@ -12,6 +12,9 @@ class QTM_C final : public ServiceFramework<QTM_C> {
 public:
     QTM_C();
     ~QTM_C() = default;
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::QTM
diff --git a/src/core/hle/service/qtm/qtm_s.h b/src/core/hle/service/qtm/qtm_s.h
index 51e1a4bc8..b32a497db 100644
--- a/src/core/hle/service/qtm/qtm_s.h
+++ b/src/core/hle/service/qtm/qtm_s.h
@@ -12,6 +12,9 @@ class QTM_S final : public ServiceFramework<QTM_S> {
 public:
     QTM_S();
     ~QTM_S() = default;
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::QTM
diff --git a/src/core/hle/service/qtm/qtm_sp.h b/src/core/hle/service/qtm/qtm_sp.h
index 3c16dea37..2f290f192 100644
--- a/src/core/hle/service/qtm/qtm_sp.h
+++ b/src/core/hle/service/qtm/qtm_sp.h
@@ -12,6 +12,9 @@ class QTM_SP final : public ServiceFramework<QTM_SP> {
 public:
     QTM_SP();
     ~QTM_SP() = default;
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::QTM
diff --git a/src/core/hle/service/qtm/qtm_u.h b/src/core/hle/service/qtm/qtm_u.h
index f6b54c8af..d1aee1e97 100644
--- a/src/core/hle/service/qtm/qtm_u.h
+++ b/src/core/hle/service/qtm/qtm_u.h
@@ -12,6 +12,9 @@ class QTM_U final : public ServiceFramework<QTM_U> {
 public:
     QTM_U();
     ~QTM_U() = default;
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::QTM
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index d39e72aca..0261d061f 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -219,6 +219,13 @@ extern const std::array<ServiceModuleInfo, 40> service_module_map;
     friend class boost::serialization::access;                                                     \
     friend class ::construct_access;
 
+#define SERVICE_SERIALIZATION_SIMPLE                                                               \
+    template <class Archive>                                                                       \
+    void serialize(Archive& ar, const unsigned int) {                                              \
+        ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);               \
+    }                                                                                              \
+    friend class boost::serialization::access;
+
 #define SERVICE_CONSTRUCT(T)                                                                       \
     namespace boost::serialization {                                                               \
     template <class Archive>                                                                       \
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h
index 3984f7ecc..30b87378a 100644
--- a/src/core/hle/service/ssl_c.h
+++ b/src/core/hle/service/ssl_c.h
@@ -23,6 +23,8 @@ private:
 
     // TODO: Implement a proper CSPRNG in the future when actual security is needed
     std::mt19937 rand_gen;
+
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 void InstallInterfaces(Core::System& system);
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 0c981b545..45e7da13d 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -20,6 +20,7 @@ namespace Service::Y2R {
 
 template <class Archive>
 void Y2R_U::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     ar& completion_event;
     ar& conversion;
     ar& dithering_weight_params;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index cd3cf8aed..4c083d8c0 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -170,7 +170,9 @@ private:
     MemorySystem::Impl& impl;
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {}
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<BackingMem>(*this);
+    }
     friend class boost::serialization::access;
 };
 

From 9525d81344151d2116665a42a7e06ba98cb8db5d Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 8 Jan 2020 23:19:49 +0000
Subject: [PATCH 064/129] More base-derived fixes

---
 TODO                                       |  5 +++++
 src/core/file_sys/archive_extsavedata.h    |  1 +
 src/core/file_sys/archive_ncch.h           |  4 +++-
 src/core/file_sys/archive_other_savedata.h |  2 ++
 src/core/file_sys/archive_savedata.h       |  1 +
 src/core/file_sys/archive_sdmc.h           |  1 +
 src/core/file_sys/archive_sdmcwriteonly.h  |  1 +
 src/core/file_sys/archive_selfncch.h       |  6 ++++++
 src/core/file_sys/archive_systemsavedata.h |  1 +
 src/core/file_sys/savedata_archive.cpp     |  1 +
 src/core/file_sys/savedata_archive.h       | 11 +++++++++++
 src/core/hle/kernel/config_mem.h           |  1 +
 src/core/hle/kernel/hle_ipc.cpp            |  1 +
 src/core/hle/kernel/hle_ipc.h              |  5 +++++
 src/core/hle/kernel/server_session.h       |  2 +-
 src/core/hle/kernel/shared_memory.h        |  1 +
 src/core/hle/kernel/shared_page.h          |  1 +
 src/core/hle/kernel/svc.cpp                |  5 ++++-
 src/core/hle/kernel/thread.cpp             |  1 +
 src/core/hle/kernel/thread.h               |  5 +++++
 src/core/hle/service/nwm/nwm_uds.cpp       |  1 +
 src/core/hle/service/sm/srv.cpp            | 15 +++++++++++++++
 src/core/hle/service/sm/srv.h              |  6 ++++++
 23 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index def70ac2b..a8efb78eb 100644
--- a/TODO
+++ b/TODO
@@ -7,6 +7,11 @@
 ☐ Review base class serialization everywhere
     Make sure that all base/derived relationships are registered
 ☐ Serialize codeset with an apploader reference instead
+☐ Additional stuff to serialize
+    ☐ Self-NCCH archive
+    ☐ File backends
+    ☐ Directory backends
+    ☐ File/directory 'services'
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
     ✔ Page tables @done(20-01-05 16:33)
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index c9b84c984..f33dd1a89 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -60,6 +60,7 @@ private:
     ArchiveFactory_ExtSaveData() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
         ar& shared;
         ar& mount_point;
     }
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index 0a3f95b5c..d17fbc3a2 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -116,7 +116,9 @@ public:
 
 private:
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {}
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
+    }
     friend class boost::serialization::access;
 };
 
diff --git a/src/core/file_sys/archive_other_savedata.h b/src/core/file_sys/archive_other_savedata.h
index a9deae95a..c5bf98a68 100644
--- a/src/core/file_sys/archive_other_savedata.h
+++ b/src/core/file_sys/archive_other_savedata.h
@@ -35,6 +35,7 @@ private:
     ArchiveFactory_OtherSaveDataPermitted() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
         ar& sd_savedata_source;
     }
     friend class boost::serialization::access;
@@ -62,6 +63,7 @@ private:
     ArchiveFactory_OtherSaveDataGeneral() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
         ar& sd_savedata_source;
     }
     friend class boost::serialization::access;
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index 3ebe94a63..6bb22f7a8 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -34,6 +34,7 @@ private:
     ArchiveFactory_SaveData() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
         ar& sd_savedata_source;
     }
     friend class boost::serialization::access;
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 6051abef0..265dd7e93 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -81,6 +81,7 @@ private:
     ArchiveFactory_SDMC() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
         ar& sdmc_directory;
     }
     friend class boost::serialization::access;
diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h
index 19982a9db..f4149961c 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.h
+++ b/src/core/file_sys/archive_sdmcwriteonly.h
@@ -67,6 +67,7 @@ private:
     ArchiveFactory_SDMCWriteOnly() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
         ar& sdmc_directory;
     }
     friend class boost::serialization::access;
diff --git a/src/core/file_sys/archive_selfncch.h b/src/core/file_sys/archive_selfncch.h
index de7fd75e0..571789b9f 100644
--- a/src/core/file_sys/archive_selfncch.h
+++ b/src/core/file_sys/archive_selfncch.h
@@ -47,6 +47,12 @@ private:
     /// Mapping of ProgramId -> NCCHData
     std::unordered_map<u64, NCCHData>
         ncch_data; // TODO: Remove this, or actually set the values here
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index cf18cab89..d4f204a66 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -37,6 +37,7 @@ private:
     ArchiveFactory_SystemSaveData() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveFactory>(*this);
         ar& base_path;
     }
     friend class boost::serialization::access;
diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp
index 1f22b50ab..090dc6fb0 100644
--- a/src/core/file_sys/savedata_archive.cpp
+++ b/src/core/file_sys/savedata_archive.cpp
@@ -357,4 +357,5 @@ u64 SaveDataArchive::GetFreeBytes() const {
 
 } // namespace FileSys
 
+SERIALIZE_EXPORT_IMPL(FileSys::SaveDataArchive)
 SERIALIZE_EXPORT_IMPL(FileSys::SaveDataDelayGenerator)
diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h
index 47f2f75e0..c9956e135 100644
--- a/src/core/file_sys/savedata_archive.h
+++ b/src/core/file_sys/savedata_archive.h
@@ -38,10 +38,21 @@ public:
 
 protected:
     std::string mount_point;
+
+private:
+    SaveDataArchive() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveBackend>(*this);
+        ar& mount_point;
+    }
+    friend class boost::serialization::access;
 };
 
 class SaveDataDelayGenerator;
 
 } // namespace FileSys
 
+BOOST_CLASS_EXPORT_KEY(FileSys::SaveDataArchive)
 BOOST_CLASS_EXPORT_KEY(FileSys::SaveDataDelayGenerator)
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index 0ec67fb5e..46595976e 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -70,6 +70,7 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<BackingMem>(*this);
         ar& boost::serialization::make_binary_object(&config_mem, sizeof(config_mem));
     }
 };
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index b1e2f7d8b..23f577490 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -50,6 +50,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
         ar& callback;
         ar& context;
     }
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 01fec190b..046a31e2e 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -222,6 +222,11 @@ public:
         virtual ~WakeupCallback() = default;
         virtual void WakeUp(std::shared_ptr<Thread> thread, HLERequestContext& context,
                             ThreadWakeupReason reason) = 0;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {}
+        friend class boost::serialization::access;
     };
 
     /**
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 331ac8397..74dbef624 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -111,7 +111,7 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
-        ar& boost::serialization::base_object<Object>(*this);
+        ar& boost::serialization::base_object<WaitObject>(*this);
         ar& name;
         ar& parent;
         ar& hle_handler;
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index aa2be05a6..cb2dee685 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -109,6 +109,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<Object>(*this);
         ar& linear_heap_phys_offset;
         ar& backing_blocks;
         ar& size;
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index 7b1f7ed16..c94cc079e 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -117,6 +117,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<BackingMem>(*this);
         ar& boost::serialization::make_binary_object(&shared_page, sizeof(shared_page));
     }
     friend class boost::serialization::access;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 7f7cc1272..371bbdfe3 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -434,6 +434,7 @@ private:
     SVC_SyncCallback() = default;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
         ar& do_output;
     }
     friend class boost::serialization::access;
@@ -466,7 +467,9 @@ private:
     SVC_IPCCallback() : system(Core::Global<Core::System>()) {}
 
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {}
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
+    }
     friend class boost::serialization::access;
 };
 
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 13a3017a5..f7379f50d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -32,6 +32,7 @@ namespace Kernel {
 
 template <class Archive>
 void Thread::serialize(Archive& ar, const unsigned int file_version) {
+    ar& boost::serialization::base_object<Object>(*this);
     ar&* context.get();
     ar& thread_id;
     ar& status;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 9941c76db..c64e24071 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -66,6 +66,11 @@ public:
     virtual ~WakeupCallback() = default;
     virtual void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
                         std::shared_ptr<WaitObject> object) = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 class ThreadManager {
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 2aa64f7fc..01bdd821e 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -1189,6 +1189,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::HLERequestContext::WakeupCallback>(*this);
         ar& command_id;
     }
     friend class boost::serialization::access;
diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp
index 10179f416..91b26b497 100644
--- a/src/core/hle/service/sm/srv.cpp
+++ b/src/core/hle/service/sm/srv.cpp
@@ -3,6 +3,9 @@
 // Refer to the license.txt file included.
 
 #include <tuple>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/unordered_map.hpp>
 #include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
@@ -21,8 +24,19 @@
 #include "core/hle/service/sm/sm.h"
 #include "core/hle/service/sm/srv.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::SM::SRV)
+SERIALIZE_EXPORT_IMPL(Service::SM::SRV)
+
 namespace Service::SM {
 
+template <class Archive>
+void SRV::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    ar& notification_semaphore;
+    ar& get_service_handle_delayed_map;
+}
+SERIALIZE_IMPL(SRV)
+
 constexpr int MAX_PENDING_NOTIFICATIONS = 16;
 
 /**
@@ -107,6 +121,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<Kernel::HLERequestContext::WakeupCallback>(*this);
         ar& name;
     }
     friend class boost::serialization::access;
diff --git a/src/core/hle/service/sm/srv.h b/src/core/hle/service/sm/srv.h
index 7d17f87a5..753218dca 100644
--- a/src/core/hle/service/sm/srv.h
+++ b/src/core/hle/service/sm/srv.h
@@ -40,8 +40,14 @@ private:
     Core::System& system;
     std::shared_ptr<Kernel::Semaphore> notification_semaphore;
     std::unordered_map<std::string, std::shared_ptr<Kernel::Event>> get_service_handle_delayed_map;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::SM
 
+SERVICE_CONSTRUCT(Service::SM::SRV)
+BOOST_CLASS_EXPORT_KEY(Service::SM::SRV)
 BOOST_CLASS_EXPORT_KEY(Service::SM::SRV::ThreadCallback)

From ca971ff31f49456e01d5e7f9747327f2ce18133a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 10 Jan 2020 23:47:39 +0000
Subject: [PATCH 065/129] Serialize file/directory services

---
 TODO                                  |  4 ++--
 src/core/file_sys/archive_backend.h   | 30 ++++++++++++++++++++++++++-
 src/core/file_sys/directory_backend.h |  5 +++++
 src/core/hle/service/fs/directory.cpp | 12 +++++++++++
 src/core/hle/service/fs/directory.h   |  9 ++++++++
 src/core/hle/service/fs/file.cpp      | 13 ++++++++++++
 src/core/hle/service/fs/file.h        | 11 ++++++++++
 7 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index a8efb78eb..a76890185 100644
--- a/TODO
+++ b/TODO
@@ -4,14 +4,14 @@
 ☐ Custom texture cache
 ☐ Review constructor/initialization code
 ☐ Review core timing events
-☐ Review base class serialization everywhere
+✔ Review base class serialization everywhere @done(20-01-10 23:47)
     Make sure that all base/derived relationships are registered
 ☐ Serialize codeset with an apploader reference instead
 ☐ Additional stuff to serialize
     ☐ Self-NCCH archive
     ☐ File backends
     ☐ Directory backends
-    ☐ File/directory 'services'
+    ✔ File/directory 'services' @done(20-01-10 23:46)
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
     ✔ Page tables @done(20-01-05 16:33)
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 756613a30..6468c0630 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -8,6 +8,8 @@
 #include <string>
 #include <utility>
 #include <vector>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "common/swap.h"
@@ -63,7 +65,33 @@ private:
     LowPathType type;
     std::vector<u8> binary;
     std::string string;
-    std::u16string u16str;
+    std::u16string u16str{};
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& type;
+        switch (type) {
+        case LowPathType::Binary:
+            ar& binary;
+            break;
+        case LowPathType::Char:
+            ar& string;
+            break;
+        case LowPathType::Wchar:
+            static_assert(sizeof(wchar_t) == sizeof(char16_t));
+            {
+                std::wstring wstring(reinterpret_cast<wchar_t*>(u16str.data()));
+                ar& wstring;
+                if (!Archive::is_saving::value) {
+                    u16str = std::u16string(reinterpret_cast<char16_t*>(wstring.data()));
+                }
+            }
+            break;
+        default:
+            break;
+        }
+    }
+    friend class boost::serialization::access;
 };
 
 /// Parameters of the archive, as specified in the Create or Format call.
diff --git a/src/core/file_sys/directory_backend.h b/src/core/file_sys/directory_backend.h
index e9f124b02..4c9dbb4df 100644
--- a/src/core/file_sys/directory_backend.h
+++ b/src/core/file_sys/directory_backend.h
@@ -53,6 +53,11 @@ public:
      * @return true if the directory closed correctly
      */
     virtual bool Close() const = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
diff --git a/src/core/hle/service/fs/directory.cpp b/src/core/hle/service/fs/directory.cpp
index a72a9307a..16b12905c 100644
--- a/src/core/hle/service/fs/directory.cpp
+++ b/src/core/hle/service/fs/directory.cpp
@@ -2,13 +2,25 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/file_sys/directory_backend.h"
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/service/fs/directory.h"
 
+SERIALIZE_EXPORT_IMPL(Service::FS::Directory)
+
 namespace Service::FS {
 
+template <class Archive>
+void Directory::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    ar& path;
+    ar& backend;
+}
+
+Directory::Directory() : ServiceFramework("", 1) {}
+
 Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
                      const FileSys::Path& path)
     : ServiceFramework("", 1), path(path), backend(std::move(backend)) {
diff --git a/src/core/hle/service/fs/directory.h b/src/core/hle/service/fs/directory.h
index 890b26648..77956b166 100644
--- a/src/core/hle/service/fs/directory.h
+++ b/src/core/hle/service/fs/directory.h
@@ -25,6 +25,15 @@ public:
 protected:
     void Read(Kernel::HLERequestContext& ctx);
     void Close(Kernel::HLERequestContext& ctx);
+
+private:
+    Directory();
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::FS
+
+BOOST_CLASS_EXPORT_KEY(Service::FS::Directory)
diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp
index c8727314b..b878197d7 100644
--- a/src/core/hle/service/fs/file.cpp
+++ b/src/core/hle/service/fs/file.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/file_sys/errors.h"
@@ -13,8 +14,20 @@
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/service/fs/file.h"
 
+SERIALIZE_EXPORT_IMPL(Service::FS::File)
+SERIALIZE_EXPORT_IMPL(Service::FS::FileSessionSlot)
+
 namespace Service::FS {
 
+template <class Archive>
+void File::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
+    ar& path;
+    ar& backend;
+}
+
+File::File() : ServiceFramework("", 1), kernel(Core::Global<Kernel::KernelSystem>()) {}
+
 File::File(Kernel::KernelSystem& kernel, std::unique_ptr<FileSys::FileBackend>&& backend,
            const FileSys::Path& path)
     : ServiceFramework("", 1), path(path), backend(std::move(backend)), kernel(kernel) {
diff --git a/src/core/hle/service/fs/file.h b/src/core/hle/service/fs/file.h
index 18317212e..98d448755 100644
--- a/src/core/hle/service/fs/file.h
+++ b/src/core/hle/service/fs/file.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include "core/file_sys/archive_backend.h"
+#include "core/global.h"
 #include "core/hle/service/service.h"
 
 namespace Core {
@@ -30,6 +31,7 @@ private:
         ar& size;
         ar& subfile;
     }
+    friend class boost::serialization::access;
 };
 
 // TODO: File is not a real service, but it can still utilize ServiceFramework::RegisterHandlers.
@@ -71,6 +73,15 @@ private:
     void OpenSubFile(Kernel::HLERequestContext& ctx);
 
     Kernel::KernelSystem& kernel;
+
+    File();
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::FS
+
+BOOST_CLASS_EXPORT_KEY(Service::FS::FileSessionSlot)
+BOOST_CLASS_EXPORT_KEY(Service::FS::File)

From e4f05884c3be6249a8ab03e8b2c6bb8cb9caa7ac Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Jan 2020 16:33:48 +0000
Subject: [PATCH 066/129] Fixed serialization runtime exceptions

---
 TODO                                   | 19 +++++++++----------
 src/common/file_util.h                 |  1 +
 src/core/file_sys/archive_ncch.cpp     |  1 +
 src/core/file_sys/archive_ncch.h       | 14 +++++++++++---
 src/core/file_sys/archive_selfncch.cpp | 21 +++++++++++++++++++++
 src/core/file_sys/archive_selfncch.h   | 18 ++++++++++++++++++
 src/core/file_sys/ivfc_archive.cpp     |  6 ++++++
 src/core/file_sys/ivfc_archive.h       | 22 ++++++++++++++++++++++
 src/core/file_sys/romfs_reader.h       | 21 ++++++++++++++++++---
 src/core/hle/kernel/config_mem.cpp     |  3 +++
 src/core/hle/kernel/config_mem.h       |  3 +++
 src/core/hle/kernel/shared_page.cpp    |  2 ++
 src/core/hle/kernel/shared_page.h      |  3 +++
 src/core/hle/service/gsp/gsp_lcd.h     |  3 +++
 src/core/hle/service/ir/ir_rst.cpp     |  1 -
 src/core/hle/service/ir/ir_u.h         |  3 +++
 src/core/hle/service/ir/ir_user.cpp    | 11 +++++++++--
 src/core/hle/service/ir/ir_user.h      |  4 +++-
 src/core/hle/service/mic_u.cpp         |  1 -
 src/core/hle/service/nwm/nwm_uds.cpp   |  4 +++-
 src/core/hle/service/nwm/nwm_uds.h     |  1 +
 src/core/hle/service/sm/srv.cpp        |  1 -
 src/core/hle/service/y2r_u.cpp         |  1 -
 23 files changed, 140 insertions(+), 24 deletions(-)

diff --git a/TODO b/TODO
index a76890185..83603d1c6 100644
--- a/TODO
+++ b/TODO
@@ -3,14 +3,15 @@
     ☐ Multiple slots etc.
 ☐ Custom texture cache
 ☐ Review constructor/initialization code
-☐ Review core timing events
+☐ Core timing events
+☐ Serialize codeset with an apploader reference instead
 ✔ Review base class serialization everywhere @done(20-01-10 23:47)
     Make sure that all base/derived relationships are registered
-☐ Serialize codeset with an apploader reference instead
-☐ Additional stuff to serialize
-    ☐ Self-NCCH archive
-    ☐ File backends
-    ☐ Directory backends
+✔ Additional stuff to serialize @done(20-01-11 16:32)
+    ✔ Self-NCCH archive @done(20-01-11 16:32)
+    ✔ File backends @done(20-01-11 16:32)
+    ✘ Directory backends @cancelled(20-01-11 16:32)
+        Not needed for now
     ✔ File/directory 'services' @done(20-01-10 23:46)
 ✔ CPU @done(19-08-13 15:41)
 ✔ Memory @done(19-08-13 15:41)
@@ -37,10 +38,8 @@
     ✔ SDMC @done(20-01-02 23:34)
         ✔ Normal @done(20-01-02 23:34)
         ✔ Write-only @done(20-01-02 23:34)
-    ✘ IVFC @cancelled(20-01-03 13:22)
-        Seems IVFCArchive is never used.. which is good because it has a file reference!
-    ✘ File refs @cancelled(20-01-03 13:22)
-        Not needed as nothing serializes file buffers
+    ✔ IVFC @done(20-01-11 16:33)
+    ✔ File refs @done(20-01-11 16:33)
     ✘ Replace delay generator with virtual fns @cancelled(20-01-03 13:16)
         While they have no state, the extra refactoring here is unneeded
 ✘ MMIO @cancelled(20-01-01 01:06)
diff --git a/src/common/file_util.h b/src/common/file_util.h
index c09aa88d6..71f943ed3 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -334,6 +334,7 @@ private:
     }
 
     BOOST_SERIALIZATION_SPLIT_MEMBER()
+    friend class boost::serialization::access;
 };
 
 } // namespace FileUtil
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp
index 636bb81ed..789547f0e 100644
--- a/src/core/file_sys/archive_ncch.cpp
+++ b/src/core/file_sys/archive_ncch.cpp
@@ -30,6 +30,7 @@
 // FileSys namespace
 
 SERIALIZE_EXPORT_IMPL(FileSys::NCCHArchive)
+SERIALIZE_EXPORT_IMPL(FileSys::NCCHFile)
 SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_NCCH)
 
 namespace FileSys {
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index d17fbc3a2..2d38f9a2e 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -95,9 +95,16 @@ public:
     void Flush() const override {}
 
 private:
-    NCCHFile() = default; // NOTE: If the public ctor has behaviour, need to replace this with
-                          // *_construct_data
-    std::vector<u8> file_buffer; // TODO: Replace with file ref for serialization
+    std::vector<u8> file_buffer;
+
+    NCCHFile() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<FileBackend>(*this);
+        ar& file_buffer; // TODO: See about a more efficient way to do this
+    }
+    friend class boost::serialization::access;
 };
 
 /// File system interface to the NCCH archive
@@ -125,4 +132,5 @@ private:
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::NCCHArchive)
+BOOST_CLASS_EXPORT_KEY(FileSys::NCCHFile)
 BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_NCCH)
diff --git a/src/core/file_sys/archive_selfncch.cpp b/src/core/file_sys/archive_selfncch.cpp
index 214ad7c08..e866e9bc0 100644
--- a/src/core/file_sys/archive_selfncch.cpp
+++ b/src/core/file_sys/archive_selfncch.cpp
@@ -77,6 +77,15 @@ public:
 
 private:
     std::shared_ptr<std::vector<u8>> data;
+
+    ExeFSSectionFile() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<FileBackend>(*this);
+        ar& data;
+    }
+    friend class boost::serialization::access;
 };
 
 // SelfNCCHArchive represents the running application itself. From this archive the application can
@@ -234,6 +243,15 @@ private:
     }
 
     NCCHData ncch_data;
+
+    SelfNCCHArchive() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<ArchiveBackend>(*this);
+        ar& ncch_data;
+    }
+    friend class boost::serialization::access;
 };
 
 void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) {
@@ -300,3 +318,6 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&,
 }
 
 } // namespace FileSys
+
+SERIALIZE_EXPORT_IMPL(FileSys::ExeFSSectionFile)
+SERIALIZE_EXPORT_IMPL(FileSys::SelfNCCHArchive)
diff --git a/src/core/file_sys/archive_selfncch.h b/src/core/file_sys/archive_selfncch.h
index 571789b9f..d7b1cf301 100644
--- a/src/core/file_sys/archive_selfncch.h
+++ b/src/core/file_sys/archive_selfncch.h
@@ -9,6 +9,8 @@
 #include <unordered_map>
 #include <vector>
 #include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
@@ -25,6 +27,17 @@ struct NCCHData {
     std::shared_ptr<std::vector<u8>> banner;
     std::shared_ptr<RomFSReader> romfs_file;
     std::shared_ptr<RomFSReader> update_romfs_file;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& icon;
+        ar& logo;
+        ar& banner;
+        ar& romfs_file;
+        ar& update_romfs_file;
+    }
+    friend class boost::serialization::access;
 };
 
 /// File system interface to the SelfNCCH archive
@@ -55,6 +68,11 @@ private:
     friend class boost::serialization::access;
 };
 
+class ExeFSSectionFile;
+class SelfNCCHArchive;
+
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SelfNCCH)
+BOOST_CLASS_EXPORT_KEY(FileSys::ExeFSSectionFile)
+BOOST_CLASS_EXPORT_KEY(FileSys::SelfNCCHArchive)
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index ba16f8cd8..3dbef7049 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -5,6 +5,7 @@
 #include <cstring>
 #include <memory>
 #include <utility>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "core/file_sys/ivfc_archive.h"
@@ -12,6 +13,11 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::IVFCFile)
+SERIALIZE_EXPORT_IMPL(FileSys::IVFCDelayGenerator)
+SERIALIZE_EXPORT_IMPL(FileSys::RomFSDelayGenerator)
+SERIALIZE_EXPORT_IMPL(FileSys::ExeFSDelayGenerator)
+
 namespace FileSys {
 
 IVFCArchive::IVFCArchive(std::shared_ptr<RomFSReader> file,
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h
index 8168e04f4..3926f5229 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -8,6 +8,8 @@
 #include <memory>
 #include <string>
 #include <vector>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "core/file_sys/archive_backend.h"
@@ -38,6 +40,8 @@ class IVFCDelayGenerator : public DelayGenerator {
         static constexpr u64 IPCDelayNanoseconds(9438006);
         return IPCDelayNanoseconds;
     }
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 class RomFSDelayGenerator : public DelayGenerator {
@@ -60,6 +64,8 @@ public:
         static constexpr u64 IPCDelayNanoseconds(9438006);
         return IPCDelayNanoseconds;
     }
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 class ExeFSDelayGenerator : public DelayGenerator {
@@ -82,6 +88,8 @@ public:
         static constexpr u64 IPCDelayNanoseconds(9438006);
         return IPCDelayNanoseconds;
     }
+
+    SERIALIZE_DELAY_GENERATOR
 };
 
 /**
@@ -128,6 +136,15 @@ public:
 
 private:
     std::shared_ptr<RomFSReader> romfs_file;
+
+    IVFCFile() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<FileBackend>(*this);
+        ar& romfs_file;
+    }
+    friend class boost::serialization::access;
 };
 
 class IVFCDirectory : public DirectoryBackend {
@@ -162,3 +179,8 @@ private:
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::IVFCFile)
+BOOST_CLASS_EXPORT_KEY(FileSys::IVFCDelayGenerator)
+BOOST_CLASS_EXPORT_KEY(FileSys::RomFSDelayGenerator)
+BOOST_CLASS_EXPORT_KEY(FileSys::ExeFSDelayGenerator)
diff --git a/src/core/file_sys/romfs_reader.h b/src/core/file_sys/romfs_reader.h
index 72a02cde3..ab1986fe6 100644
--- a/src/core/file_sys/romfs_reader.h
+++ b/src/core/file_sys/romfs_reader.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <array>
+#include <boost/serialization/array.hpp>
 #include "common/common_types.h"
 #include "common/file_util.h"
 
@@ -29,9 +30,23 @@ private:
     FileUtil::IOFile file;
     std::array<u8, 16> key;
     std::array<u8, 16> ctr;
-    std::size_t file_offset;
-    std::size_t crypto_offset;
-    std::size_t data_size;
+    u64 file_offset;
+    u64 crypto_offset;
+    u64 data_size;
+
+    RomFSReader() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& is_encrypted;
+        ar& file;
+        ar& key;
+        ar& ctr;
+        ar& file_offset;
+        ar& crypto_offset;
+        ar& data_size;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
diff --git a/src/core/hle/kernel/config_mem.cpp b/src/core/hle/kernel/config_mem.cpp
index 58bef4110..4b262b501 100644
--- a/src/core/hle/kernel/config_mem.cpp
+++ b/src/core/hle/kernel/config_mem.cpp
@@ -3,10 +3,13 @@
 // Refer to the license.txt file included.
 
 #include <cstring>
+#include "common/archives.h"
 #include "core/hle/kernel/config_mem.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
+SERIALIZE_EXPORT_IMPL(ConfigMem::Handler)
+
 namespace ConfigMem {
 
 Handler::Handler() {
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index 46595976e..74d934345 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -10,6 +10,7 @@
 // putting this as a subset of HLE for now.
 
 #include <boost/serialization/binary_object.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/memory_ref.h"
@@ -76,3 +77,5 @@ private:
 };
 
 } // namespace ConfigMem
+
+BOOST_CLASS_EXPORT_KEY(ConfigMem::Handler)
diff --git a/src/core/hle/kernel/shared_page.cpp b/src/core/hle/kernel/shared_page.cpp
index f7b02993f..5456a48e0 100644
--- a/src/core/hle/kernel/shared_page.cpp
+++ b/src/core/hle/kernel/shared_page.cpp
@@ -14,6 +14,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
+SERIALIZE_EXPORT_IMPL(SharedPage::Handler)
+
 namespace boost::serialization {
 
 template <class Archive>
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index c94cc079e..b74470b4a 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -14,6 +14,7 @@
 #include <ctime>
 #include <memory>
 #include <boost/serialization/binary_object.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
@@ -131,3 +132,5 @@ template <class Archive>
 void load_construct_data(Archive& ar, SharedPage::Handler* t, const unsigned int);
 
 } // namespace boost::serialization
+
+BOOST_CLASS_EXPORT_KEY(SharedPage::Handler)
diff --git a/src/core/hle/service/gsp/gsp_lcd.h b/src/core/hle/service/gsp/gsp_lcd.h
index 781d9dba8..31d17f540 100644
--- a/src/core/hle/service/gsp/gsp_lcd.h
+++ b/src/core/hle/service/gsp/gsp_lcd.h
@@ -12,6 +12,9 @@ class GSP_LCD final : public ServiceFramework<GSP_LCD> {
 public:
     GSP_LCD();
     ~GSP_LCD() = default;
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::GSP
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
index dc9612e62..751460a04 100644
--- a/src/core/hle/service/ir/ir_rst.cpp
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -29,7 +29,6 @@ void IR_RST::serialize(Archive& ar, const unsigned int) {
     // update_callback_id and input devices are set separately
     ReloadInputDevices();
 }
-SERIALIZE_IMPL(IR_RST)
 
 struct PadDataEntry {
     PadState current_state;
diff --git a/src/core/hle/service/ir/ir_u.h b/src/core/hle/service/ir/ir_u.h
index eaa54c657..ecaf1be28 100644
--- a/src/core/hle/service/ir/ir_u.h
+++ b/src/core/hle/service/ir/ir_u.h
@@ -12,6 +12,9 @@ namespace Service::IR {
 class IR_U final : public ServiceFramework<IR_U> {
 public:
     IR_U();
+
+private:
+    SERVICE_SERIALIZATION_SIMPLE
 };
 
 } // namespace Service::IR
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
index 64a298103..4bf6e7499 100644
--- a/src/core/hle/service/ir/ir_user.cpp
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -4,6 +4,8 @@
 
 #include <memory>
 #include <boost/crc.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/string_util.h"
 #include "common/swap.h"
 #include "core/core.h"
@@ -13,6 +15,9 @@
 #include "core/hle/service/ir/extra_hid.h"
 #include "core/hle/service/ir/ir_user.h"
 
+SERIALIZE_EXPORT_IMPL(Service::IR::IR_USER)
+SERVICE_CONSTRUCT_IMPL(Service::IR::IR_USER)
+
 namespace Service::IR {
 
 template <class Archive>
@@ -23,10 +28,9 @@ void IR_USER::serialize(Archive& ar, const unsigned int) {
     ar& receive_event;
     ar& shared_memory;
     ar& connected_device;
-    ar&* receive_buffer.get();
+    ar& receive_buffer;
     ar&* extra_hid.get();
 }
-SERIALIZE_IMPL(IR_USER)
 
 // This is a header that will present in the ir:USER shared memory if it is initialized with
 // InitializeIrNopShared service function. Otherwise the shared memory doesn't have this header if
@@ -204,6 +208,8 @@ private:
     u32 max_data_size;
 
 private:
+    BufferManager() = default;
+
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& info;
@@ -449,6 +455,7 @@ IR_USER::IR_USER(Core::System& system) : ServiceFramework("ir:USER", 1) {
 
     using namespace Kernel;
 
+    connected_device = false;
     conn_status_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:ConnectionStatusEvent");
     send_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:SendEvent");
     receive_event = system.Kernel().CreateEvent(ResetType::OneShot, "IR:ReceiveEvent");
diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h
index 75bbeb779..afb9be4f7 100644
--- a/src/core/hle/service/ir/ir_user.h
+++ b/src/core/hle/service/ir/ir_user.h
@@ -7,7 +7,6 @@
 #include <functional>
 #include <memory>
 #include <vector>
-#include <boost/serialization/shared_ptr.hpp>
 #include "core/hle/service/service.h"
 
 namespace Kernel {
@@ -177,3 +176,6 @@ private:
 };
 
 } // namespace Service::IR
+
+BOOST_CLASS_EXPORT_KEY(Service::IR::IR_USER)
+SERVICE_CONSTRUCT(Service::IR::IR_USER)
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index 478bf110f..bd324ada2 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -28,7 +28,6 @@ void MIC_U::serialize(Archive& ar, const unsigned int) {
     ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
     ar&* impl.get();
 }
-SERIALIZE_IMPL(MIC_U)
 
 /// Microphone audio encodings.
 enum class Encoding : u8 {
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 01bdd821e..b2793285f 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -24,6 +24,9 @@
 #include "core/hle/service/nwm/uds_data.h"
 #include "core/memory.h"
 
+SERIALIZE_EXPORT_IMPL(Service::NWM::NWM_UDS)
+SERVICE_CONSTRUCT_IMPL(Service::NWM::NWM_UDS)
+
 namespace Service::NWM {
 
 template <class Archive>
@@ -34,7 +37,6 @@ void NWM_UDS::serialize(Archive& ar, const unsigned int) {
     ar& received_beacons;
     // wifi_packet_received set in constructor
 }
-SERIALIZE_IMPL(NWM_UDS)
 
 namespace ErrCodes {
 enum {
diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h
index b2ab1d76a..7ae471a53 100644
--- a/src/core/hle/service/nwm/nwm_uds.h
+++ b/src/core/hle/service/nwm/nwm_uds.h
@@ -557,6 +557,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::NWM
diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp
index 91b26b497..f9c62e9ad 100644
--- a/src/core/hle/service/sm/srv.cpp
+++ b/src/core/hle/service/sm/srv.cpp
@@ -35,7 +35,6 @@ void SRV::serialize(Archive& ar, const unsigned int) {
     ar& notification_semaphore;
     ar& get_service_handle_delayed_map;
 }
-SERIALIZE_IMPL(SRV)
 
 constexpr int MAX_PENDING_NOTIFICATIONS = 16;
 
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 45e7da13d..89da8058c 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -28,7 +28,6 @@ void Y2R_U::serialize(Archive& ar, const unsigned int) {
     ar& transfer_end_interrupt_enabled;
     ar& spacial_dithering_enabled;
 }
-SERIALIZE_IMPL(Y2R_U)
 
 static const CoefficientSet standard_coefficients[4] = {
     {{0x100, 0x166, 0xB6, 0x58, 0x1C5, -0x166F, 0x10EE, -0x1C5B}}, // ITU_Rec601

From 8abc5525be98854abecee14046d8e175a8b68b79 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 12 Jan 2020 00:24:44 +0000
Subject: [PATCH 067/129] Added Signals; more runtime fixes

---
 src/citra_qt/main.cpp                  | 11 ++----
 src/common/thread_queue_list.h         | 30 ++++++++++++----
 src/core/arm/arm_interface.h           |  2 +-
 src/core/core.cpp                      | 50 +++++++++++++++++++++-----
 src/core/core.h                        | 11 +++---
 src/core/core_timing.cpp               | 12 +++----
 src/core/file_sys/ivfc_archive.cpp     |  1 +
 src/core/file_sys/ivfc_archive.h       | 12 +++++++
 src/core/hle/kernel/kernel.cpp         |  5 ++-
 src/core/hle/kernel/kernel.h           |  7 ++--
 src/core/hle/kernel/memory.cpp         | 16 ++++-----
 src/core/hle/kernel/process.h          |  2 +-
 src/core/hle/kernel/shared_memory.cpp  |  4 +--
 src/core/hle/kernel/thread.cpp         |  4 +--
 src/core/hle/service/gsp/gsp_gpu.cpp   |  4 ---
 src/core/hle/service/gsp/gsp_gpu.h     |  2 +-
 src/core/hle/service/ldr_ro/ldr_ro.cpp |  1 +
 17 files changed, 118 insertions(+), 56 deletions(-)

diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 08e3cac02..7fe4936f5 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -1504,19 +1504,12 @@ void GMainWindow::OnCheats() {
 }
 
 void GMainWindow::OnSave() {
-    Core::System& system{Core::System::GetInstance()};
-    auto fs = std::ofstream("save0.citrasave");
-    emu_thread->SetRunning(false);
-    Core::System::GetInstance().Save(fs);
-    emu_thread->SetRunning(true);
+    Core::System::GetInstance().SendSignal(Core::System::Signal::Save);
 }
 
 void GMainWindow::OnLoad() {
     if (QFileInfo("save0.citrasave").exists()) {
-        auto fs = std::ifstream("save0.citrasave");
-        emu_thread->SetRunning(false);
-        Core::System::GetInstance().Load(fs);
-        emu_thread->SetRunning(true);
+        Core::System::GetInstance().SendSignal(Core::System::Signal::Load);
     }
 }
 
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 093d86781..f5db59f05 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -160,15 +160,33 @@ private:
     // The priority level queues of thread ids.
     std::array<Queue, NUM_QUEUES> queues;
 
+    s32 ToIndex(Queue* q) const {
+        if (q == nullptr) {
+            return -2;
+        } else if (q == UnlinkedTag()) {
+            return -1;
+        } else {
+            return static_cast<s32>(q - &queues[0]);
+        }
+    }
+
+    Queue* ToPointer(s32 idx) {
+        if (idx == -1) {
+            return UnlinkedTag();
+        } else if (idx < 0) {
+            return nullptr;
+        } else {
+            return &queues[idx];
+        }
+    }
+
     friend class boost::serialization::access;
     template <class Archive>
     void save(Archive& ar, const unsigned int file_version) const {
-        s32 idx = first == UnlinkedTag() ? -1 : static_cast<s32>(first - &queues[0]);
+        s32 idx = ToIndex(first);
         ar << idx;
         for (auto i = 0; i < NUM_QUEUES; i++) {
-            s32 idx1 = first == UnlinkedTag()
-                           ? -1
-                           : static_cast<s32>(queues[i].next_nonempty - &queues[0]);
+            s32 idx1 = ToIndex(queues[i].next_nonempty);
             ar << idx1;
             ar << queues[i].data;
         }
@@ -178,10 +196,10 @@ private:
     void load(Archive& ar, const unsigned int file_version) {
         s32 idx;
         ar >> idx;
-        first = idx < 0 ? UnlinkedTag() : &queues[idx];
+        first = ToPointer(idx);
         for (auto i = 0; i < NUM_QUEUES; i++) {
             ar >> idx;
-            queues[i].next_nonempty = idx < 0 ? UnlinkedTag() : &queues[idx];
+            queues[i].next_nonempty = ToPointer(idx);
             ar >> queues[i].data;
         }
     }
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index be30499d1..e416a5f4c 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -264,7 +264,7 @@ private:
             ar >> r;
             SetCP15Register(static_cast<CP15Register>(i), r);
         }
-        // TODO: Clear caches etc?
+        ClearInstructionCache();
     }
 
     BOOST_SERIALIZATION_SPLIT_MEMBER()
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 20a8f32fe..fcd1268da 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <fstream>
 #include <memory>
 #include <utility>
 #include <boost/serialization/array.hpp>
@@ -103,15 +104,38 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
     HW::Update();
     Reschedule();
 
-    if (reset_requested.exchange(false)) {
+    auto signal = current_signal.exchange(Signal::None);
+    switch (signal) {
+    case Signal::Reset:
         Reset();
-    } else if (shutdown_requested.exchange(false)) {
+        break;
+    case Signal::Shutdown:
         return ResultStatus::ShutdownRequested;
+        break;
+    case Signal::Load: {
+        auto stream = std::ifstream("save0.citrasave", std::fstream::binary);
+        System::Load(stream);
+    } break;
+    case Signal::Save: {
+        auto stream = std::ofstream("save0.citrasave", std::fstream::binary);
+        System::Save(stream);
+    } break;
+    default:
+        break;
     }
 
     return status;
 }
 
+bool System::SendSignal(System::Signal signal) {
+    auto prev = System::Signal::None;
+    if (!current_signal.compare_exchange_strong(prev, signal)) {
+        LOG_ERROR(Core, "Unable to {} as {} is ongoing", signal, prev);
+        return false;
+    }
+    return true;
+}
+
 System::ResultStatus System::SingleStep() {
     return RunLoop(false);
 }
@@ -216,8 +240,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(
-        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
+                                                    [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -409,6 +433,7 @@ void System::Reset() {
 
 template <class Archive>
 void System::serialize(Archive& ar, const unsigned int file_version) {
+    Memory::RasterizerFlushAndInvalidateRegion(0, 0xFFFFFFFF);
     ar&* cpu_core.get();
     ar&* service_manager.get();
     ar& GPU::g_regs;
@@ -436,11 +461,20 @@ void System::Save(std::ostream& stream) const {
 }
 
 void System::Load(std::istream& stream) {
-    {
-        iarchive ia{stream};
-        ia&* this;
+    try {
+
+        {
+            iarchive ia{stream};
+            ia&* this;
+        }
+        VideoCore::Load(stream);
+
+        // Flush state through:
+        Kernel().SetCurrentProcess(Kernel().GetCurrentProcess());
+
+    } catch (const std::exception& e) {
+        LOG_ERROR(Core, "Error loading: {}", e.what());
     }
-    VideoCore::Load(stream);
 }
 
 } // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index 75e0e1a54..a3b2f5cdd 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -116,14 +116,18 @@ public:
     /// Shutdown and then load again
     void Reset();
 
+    enum class Signal : u32 { None, Shutdown, Reset, Save, Load };
+
+    bool SendSignal(Signal signal);
+
     /// Request reset of the system
     void RequestReset() {
-        reset_requested = true;
+        SendSignal(Signal::Reset);
     }
 
     /// Request shutdown of the system
     void RequestShutdown() {
-        shutdown_requested = true;
+        SendSignal(Signal::Shutdown);
     }
 
     /**
@@ -341,8 +345,7 @@ private:
     Frontend::EmuWindow* m_emu_window;
     std::string m_filepath;
 
-    std::atomic<bool> reset_requested;
-    std::atomic<bool> shutdown_requested;
+    std::atomic<Signal> current_signal;
 
     friend class boost::serialization::access;
     template <typename Archive>
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index df355ab27..976a6f3ba 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -23,14 +23,10 @@ bool Timing::Event::operator<(const Event& right) const {
 TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) {
     // check for existing type with same name.
     // we want event type names to remain unique so that we can use them for serialization.
-    ASSERT_MSG(event_types.find(name) == event_types.end(),
-               "CoreTiming Event \"{}\" is already registered. Events should only be registered "
-               "during Init to avoid breaking save states.",
-               name);
-
-    auto info = event_types.emplace(name, TimingEventType{callback, nullptr});
+    auto info = event_types.emplace(name, TimingEventType{});
     TimingEventType* event_type = &info.first->second;
     event_type->name = &info.first->first;
+    event_type->callback = callback;
     return event_type;
 }
 
@@ -129,6 +125,10 @@ void Timing::Advance() {
         Event evt = std::move(event_queue.front());
         std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
         event_queue.pop_back();
+        if (event_types.find(*evt.type->name) == event_types.end()) {
+            LOG_ERROR(Core, "Unknown queued event");
+            continue;
+        }
         evt.type->callback(evt.userdata, global_timer - evt.time);
     }
 
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index 3dbef7049..10d085164 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -14,6 +14,7 @@
 // FileSys namespace
 
 SERIALIZE_EXPORT_IMPL(FileSys::IVFCFile)
+SERIALIZE_EXPORT_IMPL(FileSys::IVFCFileInMemory)
 SERIALIZE_EXPORT_IMPL(FileSys::IVFCDelayGenerator)
 SERIALIZE_EXPORT_IMPL(FileSys::RomFSDelayGenerator)
 SERIALIZE_EXPORT_IMPL(FileSys::ExeFSDelayGenerator)
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h
index 3926f5229..145fabb98 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -176,11 +176,23 @@ private:
     std::vector<u8> romfs_file;
     u64 data_offset;
     u64 data_size;
+
+    IVFCFileInMemory() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<FileBackend>(*this);
+        ar& romfs_file;
+        ar& data_offset;
+        ar& data_size;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::IVFCFile)
+BOOST_CLASS_EXPORT_KEY(FileSys::IVFCFileInMemory)
 BOOST_CLASS_EXPORT_KEY(FileSys::IVFCDelayGenerator)
 BOOST_CLASS_EXPORT_KEY(FileSys::RomFSDelayGenerator)
 BOOST_CLASS_EXPORT_KEY(FileSys::ExeFSDelayGenerator)
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 968e905ac..3c3dfc6c6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -23,6 +23,9 @@ KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
                            std::function<void()> prepare_reschedule_callback, u32 system_mode)
     : memory(memory), timing(timing),
       prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
+    for (auto i = 0; i < memory_regions.size(); i++) {
+        memory_regions[i] = std::make_shared<MemoryRegionInfo>();
+    }
     MemoryInit(system_mode);
 
     resource_limits = std::make_unique<ResourceLimitList>(*this);
@@ -107,7 +110,7 @@ template <class Archive>
 void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
     ar& memory_regions;
     ar& named_ports;
-    ar&* current_cpu.get();
+    // current_cpu set externally
     // NB: subsystem references and prepare_reschedule_callback are constant
     ar&* resource_limits.get();
     ar& next_object_id;
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index e7b7314d6..41ef5272b 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -134,7 +134,8 @@ public:
      */
     ResultVal<std::shared_ptr<Thread>> CreateThread(std::string name, VAddr entry_point,
                                                     u32 priority, u32 arg, s32 processor_id,
-                                                    VAddr stack_top, std::shared_ptr<Process> owner_process);
+                                                    VAddr stack_top,
+                                                    std::shared_ptr<Process> owner_process);
 
     /**
      * Creates a semaphore.
@@ -232,11 +233,11 @@ public:
     IPCDebugger::Recorder& GetIPCRecorder();
     const IPCDebugger::Recorder& GetIPCRecorder() const;
 
-    MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
+    std::shared_ptr<MemoryRegionInfo> GetMemoryRegion(MemoryRegion region);
 
     void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
 
-    std::array<MemoryRegionInfo, 3> memory_regions;
+    std::array<std::shared_ptr<MemoryRegionInfo>, 3> memory_regions{};
 
     /// Adds a port to the named port table
     void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
index 04d09fa46..f8db3c31e 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -49,9 +49,9 @@ void KernelSystem::MemoryInit(u32 mem_type) {
     // the sizes specified in the memory_region_sizes table.
     VAddr base = 0;
     for (int i = 0; i < 3; ++i) {
-        memory_regions[i].Reset(base, memory_region_sizes[mem_type][i]);
+        memory_regions[i]->Reset(base, memory_region_sizes[mem_type][i]);
 
-        base += memory_regions[i].size;
+        base += memory_regions[i]->size;
     }
 
     // We must've allocated the entire FCRAM by the end
@@ -63,20 +63,20 @@ void KernelSystem::MemoryInit(u32 mem_type) {
     // app_mem_malloc does not always match the configured size for memory_region[0]: in case the
     // n3DS type override is in effect it reports the size the game expects, not the real one.
     config_mem.app_mem_alloc = memory_region_sizes[mem_type][0];
-    config_mem.sys_mem_alloc = memory_regions[1].size;
-    config_mem.base_mem_alloc = memory_regions[2].size;
+    config_mem.sys_mem_alloc = memory_regions[1]->size;
+    config_mem.base_mem_alloc = memory_regions[2]->size;
 
     shared_page_handler = std::make_shared<SharedPage::Handler>(timing);
 }
 
-MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) {
+std::shared_ptr<MemoryRegionInfo> KernelSystem::GetMemoryRegion(MemoryRegion region) {
     switch (region) {
     case MemoryRegion::APPLICATION:
-        return &memory_regions[0];
+        return memory_regions[0];
     case MemoryRegion::SYSTEM:
-        return &memory_regions[1];
+        return memory_regions[1];
     case MemoryRegion::BASE:
-        return &memory_regions[2];
+        return memory_regions[2];
     default:
         UNREACHABLE();
     }
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 576cf7e15..6eb79d227 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -200,7 +200,7 @@ public:
 
     u32 memory_used = 0;
 
-    MemoryRegionInfo* memory_region = nullptr;
+    std::shared_ptr<MemoryRegionInfo> memory_region = nullptr;
 
     /// The Thread Local Storage area is allocated as processes create threads,
     /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 23f67f733..47c966fec 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -42,7 +42,7 @@ ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
     if (address == 0) {
         // We need to allocate a block from the Linear Heap ourselves.
         // We'll manually allocate some memory from the linear heap in the specified region.
-        MemoryRegionInfo* memory_region = GetMemoryRegion(region);
+        auto memory_region = GetMemoryRegion(region);
         auto offset = memory_region->LinearAllocate(size);
 
         ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!");
@@ -79,7 +79,7 @@ std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
     auto shared_memory{std::make_shared<SharedMemory>(*this)};
 
     // Allocate memory in heap
-    MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
+    auto memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
     auto backing_blocks = memory_region->HeapAllocate(size);
     ASSERT_MSG(!backing_blocks.empty(), "Not enough space in region to allocate shared memory!");
     shared_memory->holding_memory = backing_blocks;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index f7379f50d..5382f9ec8 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -32,7 +32,7 @@ namespace Kernel {
 
 template <class Archive>
 void Thread::serialize(Archive& ar, const unsigned int file_version) {
-    ar& boost::serialization::base_object<Object>(*this);
+    ar& boost::serialization::base_object<WaitObject>(*this);
     ar&* context.get();
     ar& thread_id;
     ar& status;
@@ -363,7 +363,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
     if (needs_allocation) {
         // There are no already-allocated pages with free slots, lets allocate a new one.
         // TLS pages are allocated from the BASE region in the linear heap.
-        MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE);
+        auto memory_region = GetMemoryRegion(MemoryRegion::BASE);
 
         // Allocate some memory from the end of the linear heap for this region.
         auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE);
diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp
index 78d84499b..5a41f5ca0 100644
--- a/src/core/hle/service/gsp/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp/gsp_gpu.cpp
@@ -824,10 +824,6 @@ std::unique_ptr<Kernel::SessionRequestHandler::SessionDataBase> GSP_GPU::MakeSes
     return std::make_unique<SessionData>(this);
 }
 
-SessionData::SessionData() {
-    UNREACHABLE();
-}
-
 SessionData::SessionData(GSP_GPU* gsp) : gsp(gsp) {
     // Assign a new thread id to this session when it connects. Note: In the real GSP service this
     // is done through a real thread (svcCreateThread) but we have to simulate it since our HLE
diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h
index a97aee278..82ecf2480 100644
--- a/src/core/hle/service/gsp/gsp_gpu.h
+++ b/src/core/hle/service/gsp/gsp_gpu.h
@@ -187,7 +187,7 @@ class GSP_GPU;
 
 class SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
 public:
-    SessionData();
+    SessionData() = default;
     SessionData(GSP_GPU* gsp);
     ~SessionData();
 
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp
index 0a61f4c23..8ac6f1068 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp
@@ -15,6 +15,7 @@
 
 SERVICE_CONSTRUCT_IMPL(Service::LDR::RO)
 SERIALIZE_EXPORT_IMPL(Service::LDR::RO)
+SERIALIZE_EXPORT_IMPL(Service::LDR::ClientSlot)
 
 namespace Service::LDR {
 

From c24ea0f0eea2d263cf3cd9bb616332fed3085c5f Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 12 Jan 2020 20:01:29 +0000
Subject: [PATCH 068/129] Serialize core timing

---
 TODO                         |  3 ++-
 src/core/core.cpp            |  1 +
 src/core/core_timing.cpp     | 10 +++++++--
 src/core/core_timing.h       | 42 ++++++++++++++++++++++++++++++++++++
 src/core/hle/kernel/thread.h |  1 +
 5 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index 83603d1c6..9cc333d46 100644
--- a/TODO
+++ b/TODO
@@ -1,9 +1,10 @@
 ☐ Save/load UI
     ✔ Basic version @done(20-01-03 15:27)
     ☐ Multiple slots etc.
+☐ Add 'force flush all' to Rasterizer interface + impls
 ☐ Custom texture cache
 ☐ Review constructor/initialization code
-☐ Core timing events
+✔ Core timing events @done(20-01-12 15:14)
 ☐ Serialize codeset with an apploader reference instead
 ✔ Review base class serialization everywhere @done(20-01-10 23:47)
     Make sure that all base/derived relationships are registered
diff --git a/src/core/core.cpp b/src/core/core.cpp
index fcd1268da..fa60035dc 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -434,6 +434,7 @@ void System::Reset() {
 template <class Archive>
 void System::serialize(Archive& ar, const unsigned int file_version) {
     Memory::RasterizerFlushAndInvalidateRegion(0, 0xFFFFFFFF);
+    ar&* timing.get();
     ar&* cpu_core.get();
     ar&* service_manager.get();
     ar& GPU::g_regs;
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 976a6f3ba..4b2729a76 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -11,6 +11,8 @@
 
 namespace Core {
 
+Timing* Timing::deserializing = nullptr;
+
 // Sort by time, unless the times are the same, in which case sort by the order added to the queue
 bool Timing::Event::operator>(const Event& right) const {
     return std::tie(time, fifo_order) > std::tie(right.time, right.fifo_order);
@@ -26,7 +28,9 @@ TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback ca
     auto info = event_types.emplace(name, TimingEventType{});
     TimingEventType* event_type = &info.first->second;
     event_type->name = &info.first->first;
-    event_type->callback = callback;
+    if (callback != nullptr) {
+        event_type->callback = callback;
+    }
     return event_type;
 }
 
@@ -129,7 +133,9 @@ void Timing::Advance() {
             LOG_ERROR(Core, "Unknown queued event");
             continue;
         }
-        evt.type->callback(evt.userdata, global_timer - evt.time);
+        if (evt.type->callback != nullptr) {
+            evt.type->callback(evt.userdata, global_timer - evt.time);
+        }
     }
 
     is_global_timer_sane = false;
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 229fc37f4..1e6a3b021 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -23,6 +23,8 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include <boost/serialization/split_member.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "common/threadsafe_queue.h"
@@ -190,6 +192,8 @@ public:
     s64 GetDowncount() const;
 
 private:
+    static Timing* deserializing;
+
     struct Event {
         s64 time;
         u64 fifo_order;
@@ -198,6 +202,29 @@ private:
 
         bool operator>(const Event& right) const;
         bool operator<(const Event& right) const;
+
+    private:
+        template <class Archive>
+        void save(Archive& ar, const unsigned int) const {
+            ar& time;
+            ar& fifo_order;
+            ar& userdata;
+            std::string name = *(type->name);
+            ar << name;
+        }
+
+        template <class Archive>
+        void load(Archive& ar, const unsigned int) {
+            ar& time;
+            ar& fifo_order;
+            ar& userdata;
+            std::string name;
+            ar >> name;
+            type = Timing::deserializing->RegisterEvent(name, nullptr);
+        }
+        friend class boost::serialization::access;
+
+        BOOST_SERIALIZATION_SPLIT_MEMBER()
     };
 
     static constexpr int MAX_SLICE_LENGTH = 20000;
@@ -229,6 +256,21 @@ private:
     // executing the first cycle of each slice to prepare the slice length and downcount for
     // that slice.
     bool is_global_timer_sane = true;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        // event_types set during initialization of other things
+        deserializing = this;
+        MoveEvents();
+        ar& global_timer;
+        ar& slice_length;
+        ar& downcount;
+        ar& event_queue;
+        ar& event_fifo_id;
+        ar& idled_cycles;
+        deserializing = nullptr;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace Core
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index c64e24071..0286e210d 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -172,6 +172,7 @@ private:
         ar& ready_queue;
         ar& wakeup_callback_table;
         ar& thread_list;
+        SwitchContext(current_thread.get());
     }
 };
 

From 2217b3558d98dfcc8a40d901a643c2fb72a9c476 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 16 Jan 2020 00:53:20 +0000
Subject: [PATCH 069/129] Fixed file services serialization

---
 src/common/file_util.cpp              | 13 +++++--------
 src/common/file_util.h                |  3 ++-
 src/core/core.cpp                     |  4 ++++
 src/core/hle/service/fs/directory.cpp |  9 ++++++---
 src/core/hle/service/fs/file.cpp      | 10 ++++++++--
 src/core/hle/service/fs/file.h        |  1 +
 6 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index ca86f7bfc..c5da82973 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -881,8 +881,9 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
 
 IOFile::IOFile() {}
 
-IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
-    Open(filename, openmode, flags);
+IOFile::IOFile(const std::string& filename, const char openmode[], int flags)
+    : filename(filename), openmode(openmode), flags(flags) {
+    Open();
 }
 
 IOFile::~IOFile() {
@@ -906,13 +907,9 @@ void IOFile::Swap(IOFile& other) {
     std::swap(flags, other.flags);
 }
 
-bool IOFile::Open(const std::string& filename, const char openmode[], int flags) {
+bool IOFile::Open() {
     Close();
 
-    this->filename = filename;
-    this->openmode = openmode;
-    this->flags = flags;
-
 #ifdef _WIN32
     if (flags != 0) {
         m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(),
@@ -922,7 +919,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[], int flags)
                   Common::UTF8ToUTF16W(openmode).c_str());
     }
 #else
-    m_file = fopen(filename.c_str(), openmode);
+    m_file = fopen(filename.c_str(), openmode.c_str());
 #endif
 
     m_good = IsOpen();
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 71f943ed3..0368d3665 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -306,7 +306,7 @@ public:
     }
 
 private:
-    bool Open(const std::string& filename, const char openmode[], int flags = 0);
+    bool Open();
 
     std::FILE* m_file = nullptr;
     bool m_good = true;
@@ -330,6 +330,7 @@ private:
         ar >> flags;
         u64 pos;
         ar >> pos;
+        Open();
         Seek(pos, SEEK_SET);
     }
 
diff --git a/src/core/core.cpp b/src/core/core.cpp
index fa60035dc..985d37291 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -113,12 +113,16 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
         return ResultStatus::ShutdownRequested;
         break;
     case Signal::Load: {
+        LOG_INFO(Core, "Begin load");
         auto stream = std::ifstream("save0.citrasave", std::fstream::binary);
         System::Load(stream);
+        LOG_INFO(Core, "Load completed");
     } break;
     case Signal::Save: {
+        LOG_INFO(Core, "Begin save");
         auto stream = std::ofstream("save0.citrasave", std::fstream::binary);
         System::Save(stream);
+        LOG_INFO(Core, "Save completed");
     } break;
     default:
         break;
diff --git a/src/core/hle/service/fs/directory.cpp b/src/core/hle/service/fs/directory.cpp
index 16b12905c..c7fb085ea 100644
--- a/src/core/hle/service/fs/directory.cpp
+++ b/src/core/hle/service/fs/directory.cpp
@@ -19,11 +19,14 @@ void Directory::serialize(Archive& ar, const unsigned int) {
     ar& backend;
 }
 
-Directory::Directory() : ServiceFramework("", 1) {}
-
 Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
                      const FileSys::Path& path)
-    : ServiceFramework("", 1), path(path), backend(std::move(backend)) {
+    : Directory() {
+    this->backend = std::move(backend);
+    this->path = path;
+}
+
+Directory::Directory() : ServiceFramework("", 1), path(""), backend(nullptr) {
     static const FunctionInfo functions[] = {
         // clang-format off
         {0x08010042, &Directory::Read, "Read"},
diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp
index b878197d7..e86d93723 100644
--- a/src/core/hle/service/fs/file.cpp
+++ b/src/core/hle/service/fs/file.cpp
@@ -26,11 +26,17 @@ void File::serialize(Archive& ar, const unsigned int) {
     ar& backend;
 }
 
-File::File() : ServiceFramework("", 1), kernel(Core::Global<Kernel::KernelSystem>()) {}
+File::File() : File(Core::Global<Kernel::KernelSystem>()) {}
 
 File::File(Kernel::KernelSystem& kernel, std::unique_ptr<FileSys::FileBackend>&& backend,
            const FileSys::Path& path)
-    : ServiceFramework("", 1), path(path), backend(std::move(backend)), kernel(kernel) {
+    : File(kernel) {
+    this->backend = std::move(backend);
+    this->path = path;
+}
+
+File::File(Kernel::KernelSystem& kernel)
+    : ServiceFramework("", 1), path(""), backend(nullptr), kernel(kernel) {
     static const FunctionInfo functions[] = {
         {0x08010100, &File::OpenSubFile, "OpenSubFile"},
         {0x080200C2, &File::Read, "Read"},
diff --git a/src/core/hle/service/fs/file.h b/src/core/hle/service/fs/file.h
index 98d448755..6aa301a7b 100644
--- a/src/core/hle/service/fs/file.h
+++ b/src/core/hle/service/fs/file.h
@@ -74,6 +74,7 @@ private:
 
     Kernel::KernelSystem& kernel;
 
+    File(Kernel::KernelSystem& kernel);
     File();
 
     template <class Archive>

From b2370ea35317040ca1159e46ec5c2653898a36ad Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 17 Jan 2020 01:01:18 +0000
Subject: [PATCH 070/129] Fixed setting the right DSP service on
 deserialization

---
 src/core/core.cpp                  | 5 ++++-
 src/core/core_timing.cpp           | 5 +++--
 src/video_core/geometry_pipeline.h | 8 ++++++++
 3 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 985d37291..d199b16e2 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -448,7 +448,10 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     ar&* kernel.get();
 
     // This needs to be set from somewhere - might as well be here!
-    Service::GSP::SetGlobalModule(*this);
+    if (Archive::is_loading::value) {
+        Service::GSP::SetGlobalModule(*this);
+        DSP().SetServiceToInterrupt(ServiceManager().GetService<Service::DSP::DSP_DSP>("dsp::DSP"));
+    }
 }
 
 void System::Save(std::ostream& stream) const {
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 4b2729a76..116ba3a40 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -130,8 +130,9 @@ void Timing::Advance() {
         std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
         event_queue.pop_back();
         if (event_types.find(*evt.type->name) == event_types.end()) {
-            LOG_ERROR(Core, "Unknown queued event");
-            continue;
+            LOG_ERROR(Core, "Unknown queued event {}", *evt.type->name);
+        } else if (evt.type->callback == nullptr) {
+            LOG_ERROR(Core, "Event '{}' has no callback", *evt.type->name);
         }
         if (evt.type->callback != nullptr) {
             evt.type->callback(evt.userdata, global_timer - evt.time);
diff --git a/src/video_core/geometry_pipeline.h b/src/video_core/geometry_pipeline.h
index 1ca2d00c4..1a903b1e0 100644
--- a/src/video_core/geometry_pipeline.h
+++ b/src/video_core/geometry_pipeline.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/export.hpp>
 #include "video_core/shader/shader.h"
 
 namespace Pica {
@@ -12,6 +13,9 @@ namespace Pica {
 struct State;
 
 class GeometryPipelineBackend;
+class GeometryPipeline_Point;
+class GeometryPipeline_VariablePrimitive;
+class GeometryPipeline_FixedPrimitive;
 
 /// A pipeline receiving from vertex shader and sending to geometry shader and primitive assembler
 class GeometryPipeline {
@@ -52,3 +56,7 @@ private:
     friend class boost::serialization::access;
 };
 } // namespace Pica
+
+BOOST_CLASS_EXPORT_KEY(Pica::GeometryPipeline_Point)
+BOOST_CLASS_EXPORT_KEY(Pica::GeometryPipeline_VariablePrimitive)
+BOOST_CLASS_EXPORT_KEY(Pica::GeometryPipeline_FixedPrimitive)

From 35c3ca995cd68f6c827599146c42c7aebfac1567 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 17 Jan 2020 01:34:03 +0000
Subject: [PATCH 071/129] Fixed a bug (??) in arm_dynarmic where
 PageTableChanged could reset the CPU context

---
 src/core/arm/dynarmic/arm_dynarmic.cpp | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index eb3295956..b6494d40e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -283,15 +283,21 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
 
 void ARM_Dynarmic::PageTableChanged() {
     current_page_table = memory.GetCurrentPageTable();
+    Dynarmic::A32::Context ctx{};
+    if (jit) {
+        jit->SaveContext(ctx);
+    }
 
     auto iter = jits.find(current_page_table);
     if (iter != jits.end()) {
         jit = iter->second.get();
+        jit->LoadContext(ctx);
         return;
     }
 
     auto new_jit = MakeJit();
     jit = new_jit.get();
+    jit->LoadContext(ctx);
     jits.emplace(current_page_table, std::move(new_jit));
 }
 

From 0effb229cd754640def04b7d9f9dd3187137aa43 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 17 Jan 2020 07:58:40 +0000
Subject: [PATCH 072/129] Fix geometry pipeline; attempt to fix motion controls

---
 src/core/hle/service/hid/hid.cpp     |  4 +++-
 src/video_core/geometry_pipeline.cpp | 20 ++++++++++++++------
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index f20cebca7..012a37e6b 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -40,7 +40,9 @@ void Module::serialize(Archive& ar, const unsigned int) {
     ar& next_gyroscope_index;
     ar& enable_accelerometer_count;
     ar& enable_gyroscope_count;
-    ReloadInputDevices();
+    if (Archive::is_loading::value) {
+        LoadInputDevices();
+    }
     // Pad state not needed as it's always updated
     // Update events are set in the constructor
     // Devices are set from the implementation (and are stateless afaik)
diff --git a/src/video_core/geometry_pipeline.cpp b/src/video_core/geometry_pipeline.cpp
index 159f1df0b..7e002d55d 100644
--- a/src/video_core/geometry_pipeline.cpp
+++ b/src/video_core/geometry_pipeline.cpp
@@ -49,7 +49,7 @@ private:
 // TODO: what happens when the input size is not divisible by the output size?
 class GeometryPipeline_Point : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_Point() : regs(g_state.regs), unit(g_state.gs_unit) {
+    GeometryPipeline_Point(const Regs& regs, Shader::GSUnitState& unit) : regs(regs), unit(unit) {
         ASSERT(regs.pipeline.variable_primitive == 0);
         ASSERT(regs.gs.input_to_uniform == 0);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -89,6 +89,8 @@ private:
     Common::Vec4<float24>* buffer_end;
     unsigned int vs_output_num;
 
+    GeometryPipeline_Point() : regs(g_state.regs), unit(g_state.gs_unit) {}
+
     template <typename Class, class Archive>
     static void serialize_common(Class* self, Archive& ar, const unsigned int version) {
         ar& boost::serialization::base_object<GeometryPipelineBackend>(*self);
@@ -125,7 +127,8 @@ private:
 // value in the batch. This mode is usually used for subdivision.
 class GeometryPipeline_VariablePrimitive : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_VariablePrimitive() : regs(g_state.regs), setup(g_state.gs) {
+    GeometryPipeline_VariablePrimitive(const Regs& regs, Shader::ShaderSetup& setup)
+        : regs(regs), setup(setup) {
         ASSERT(regs.pipeline.variable_primitive == 1);
         ASSERT(regs.gs.input_to_uniform == 1);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -183,6 +186,8 @@ private:
     Common::Vec4<float24>* buffer_cur;
     unsigned int vs_output_num;
 
+    GeometryPipeline_VariablePrimitive() : regs(g_state.regs), setup(g_state.gs) {}
+
     template <typename Class, class Archive>
     static void serialize_common(Class* self, Archive& ar, const unsigned int version) {
         ar& boost::serialization::base_object<GeometryPipelineBackend>(*self);
@@ -217,7 +222,8 @@ private:
 // particle system.
 class GeometryPipeline_FixedPrimitive : public GeometryPipelineBackend {
 public:
-    GeometryPipeline_FixedPrimitive() : regs(g_state.regs), setup(g_state.gs) {
+    GeometryPipeline_FixedPrimitive(const Regs& regs, Shader::ShaderSetup& setup)
+        : regs(regs), setup(setup) {
         ASSERT(regs.pipeline.variable_primitive == 0);
         ASSERT(regs.gs.input_to_uniform == 1);
         vs_output_num = regs.pipeline.vs_outmap_total_minus_1_a + 1;
@@ -256,6 +262,8 @@ private:
     Common::Vec4<float24>* buffer_end;
     unsigned int vs_output_num;
 
+    GeometryPipeline_FixedPrimitive() : regs(g_state.regs), setup(g_state.gs) {}
+
     template <typename Class, class Archive>
     static void serialize_common(Class* self, Archive& ar, const unsigned int version) {
         ar& boost::serialization::base_object<GeometryPipelineBackend>(*self);
@@ -329,13 +337,13 @@ void GeometryPipeline::Reconfigure() {
 
     switch (state.regs.pipeline.gs_config.mode) {
     case PipelineRegs::GSMode::Point:
-        backend = std::make_unique<GeometryPipeline_Point>();
+        backend = std::make_unique<GeometryPipeline_Point>(state.regs, state.gs_unit);
         break;
     case PipelineRegs::GSMode::VariablePrimitive:
-        backend = std::make_unique<GeometryPipeline_VariablePrimitive>();
+        backend = std::make_unique<GeometryPipeline_VariablePrimitive>(state.regs, state.gs);
         break;
     case PipelineRegs::GSMode::FixedPrimitive:
-        backend = std::make_unique<GeometryPipeline_FixedPrimitive>();
+        backend = std::make_unique<GeometryPipeline_FixedPrimitive>(state.regs, state.gs);
         break;
     default:
         UNREACHABLE();

From 3e34ad6890a08bc2572da52a6b4fc2f967b4681d Mon Sep 17 00:00:00 2001
From: James Rowe <jroweboy@gmail.com>
Date: Thu, 16 Jan 2020 23:17:07 -0700
Subject: [PATCH 073/129] Hack: Workaround crash when loading state and gyro is
 used

---
 src/core/hle/service/hid/hid.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 012a37e6b..6898c1024 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -207,6 +207,10 @@ void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) {
     next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
 
     Common::Vec3<float> accel;
+    if (!motion_device) {
+        is_device_reload_pending.exchange(true);
+        return;
+    }
     std::tie(accel, std::ignore) = motion_device->GetStatus();
     accel *= accelerometer_coef;
     // TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback
@@ -254,6 +258,10 @@ void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) {
     GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
 
     Common::Vec3<float> gyro;
+    if (!motion_device) {
+        is_device_reload_pending.exchange(true);
+        return;
+    }
     std::tie(std::ignore, gyro) = motion_device->GetStatus();
     double stretch = system.perf_stats->GetLastFrameTimeScale();
     gyro *= gyroscope_coef * static_cast<float>(stretch);

From 55c75b5e3e3be6e4baa34aaab4520d3c49d9645c Mon Sep 17 00:00:00 2001
From: James Rowe <jroweboy@gmail.com>
Date: Thu, 16 Jan 2020 23:17:55 -0700
Subject: [PATCH 074/129] Add ClearAll to rasterizer cache for fully wiping the
 cache on save/load

---
 src/core/core.cpp                             |  4 ++-
 src/core/memory.cpp                           | 10 +++++++
 src/core/memory.h                             |  6 ++++
 src/video_core/rasterizer_interface.h         |  3 ++
 .../renderer_opengl/gl_rasterizer.cpp         |  4 +++
 .../renderer_opengl/gl_rasterizer.h           |  1 +
 .../renderer_opengl/gl_rasterizer_cache.cpp   | 29 +++++++++++++++++--
 .../renderer_opengl/gl_rasterizer_cache.h     |  3 ++
 src/video_core/swrasterizer/swrasterizer.h    |  1 +
 9 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index d199b16e2..aeab0d2b5 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -437,7 +437,9 @@ void System::Reset() {
 
 template <class Archive>
 void System::serialize(Archive& ar, const unsigned int file_version) {
-    Memory::RasterizerFlushAndInvalidateRegion(0, 0xFFFFFFFF);
+    // flush on save, don't flush on load
+    bool should_flush = !Archive::is_loading::value;
+    Memory::RasterizerClearAll(should_flush);
     ar&* timing.get();
     ar&* cpu_core.get();
     ar&* service_manager.get();
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 4c083d8c0..a0fa2a738 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -556,6 +556,16 @@ void RasterizerFlushAndInvalidateRegion(PAddr start, u32 size) {
     VideoCore::g_renderer->Rasterizer()->FlushAndInvalidateRegion(start, size);
 }
 
+void RasterizerClearAll(bool flush) {
+    // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
+    // null here
+    if (VideoCore::g_renderer == nullptr) {
+        return;
+    }
+
+    VideoCore::g_renderer->Rasterizer()->ClearAll(flush);
+}
+
 void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) {
     // Since pages are unmapped on shutdown after video core is shutdown, the renderer may be
     // null here
diff --git a/src/core/memory.h b/src/core/memory.h
index 348fee3c9..eb5b6d69c 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -283,6 +283,12 @@ enum class FlushMode {
     FlushAndInvalidate,
 };
 
+/**
+ * Flushes and invalidates all memory in the rasterizer cache and removes any leftover state
+ * If flush is true, the rasterizer should flush any cached resources to RAM before clearing
+ */
+void RasterizerClearAll(bool flush);
+
 /**
  * Flushes and invalidates any externally cached rasterizer resources touching the given virtual
  * address region.
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index 468d84084..a2510292e 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -55,6 +55,9 @@ public:
     /// and invalidated
     virtual void FlushAndInvalidateRegion(PAddr addr, u32 size) = 0;
 
+    /// Removes as much state as possible from the rasterizer in preparation for a save/load state
+    virtual void ClearAll(bool flush) = 0;
+
     /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0
     virtual bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) {
         return false;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 862dcac00..34bac4f87 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1367,6 +1367,10 @@ void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
     res_cache.InvalidateRegion(addr, size, nullptr);
 }
 
+void RasterizerOpenGL::ClearAll(bool flush) {
+    res_cache.ClearAll(flush);
+}
+
 bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) {
     MICROPROFILE_SCOPE(OpenGL_Blits);
 
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index b3356a69b..92cca2e4e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -53,6 +53,7 @@ public:
     void FlushRegion(PAddr addr, u32 size) override;
     void InvalidateRegion(PAddr addr, u32 size) override;
     void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
+    void ClearAll(bool flush) override;
     bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
     bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override;
     bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index af2a918a6..4dcc64832 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -1276,9 +1276,7 @@ void main() {
 }
 
 RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
-    FlushAll();
-    while (!surface_cache.empty())
-        UnregisterSurface(*surface_cache.begin()->second.begin());
+    ClearAll(false);
 }
 
 MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
@@ -1927,6 +1925,31 @@ void RasterizerCacheOpenGL::ValidateSurface(const Surface& surface, PAddr addr,
     }
 }
 
+void RasterizerCacheOpenGL::ClearAll(bool flush) {
+    const SurfaceInterval flush_interval(0x0, 0xFFFFFFFF);
+    // Force flush all surfaces from the cache
+    if (flush) {
+        FlushRegion(0x0, 0xFFFFFFFF);
+    }
+    // Unmark all of the marked pages
+    for (auto& pair : RangeFromInterval(cached_pages, flush_interval)) {
+        const auto interval = pair.first & flush_interval;
+        const int count = pair.second;
+
+        const PAddr interval_start_addr = boost::icl::first(interval) << Memory::PAGE_BITS;
+        const PAddr interval_end_addr = boost::icl::last_next(interval) << Memory::PAGE_BITS;
+        const u32 interval_size = interval_end_addr - interval_start_addr;
+
+        VideoCore::g_memory->RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
+    }
+
+    // Remove the whole cache without really looking at it.
+    cached_pages -= flush_interval;
+    dirty_regions -= flush_interval;
+    surface_cache -= flush_interval;
+    remove_surfaces.clear();
+}
+
 void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, Surface flush_surface) {
     if (size == 0)
         return;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index cd601ef29..69322f713 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -482,6 +482,9 @@ public:
     /// Flush all cached resources tracked by this cache manager
     void FlushAll();
 
+    /// Clear all cached resources tracked by this cache manager
+    void ClearAll(bool flush);
+
 private:
     void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
 
diff --git a/src/video_core/swrasterizer/swrasterizer.h b/src/video_core/swrasterizer/swrasterizer.h
index e2292f4a4..9e7a140f1 100644
--- a/src/video_core/swrasterizer/swrasterizer.h
+++ b/src/video_core/swrasterizer/swrasterizer.h
@@ -22,6 +22,7 @@ class SWRasterizer : public RasterizerInterface {
     void FlushRegion(PAddr addr, u32 size) override {}
     void InvalidateRegion(PAddr addr, u32 size) override {}
     void FlushAndInvalidateRegion(PAddr addr, u32 size) override {}
+    void ClearAll(bool flush) override {}
 };
 
 } // namespace VideoCore

From c983528862987d248c6dcf0db83ed08f3c8dae76 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 19 Jan 2020 22:49:22 +0000
Subject: [PATCH 075/129] Reworked DSP serialization

---
 externals/boost                    |  2 +-
 src/audio_core/dsp_interface.h     |  5 +++
 src/audio_core/hle/hle.cpp         | 37 +++++++++++++++++---
 src/audio_core/hle/hle.h           |  9 +++++
 src/audio_core/hle/mixers.h        | 12 +++++++
 src/audio_core/hle/shared_memory.h |  7 ++++
 src/audio_core/hle/source.h        | 54 ++++++++++++++++++++++++++++--
 src/core/core.cpp                  | 15 ++++++---
 8 files changed, 128 insertions(+), 13 deletions(-)

diff --git a/externals/boost b/externals/boost
index 6d7edc593..eb10fac1e 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 6d7edc593be8e47c8de7bc5f7d6b32971fad0c24
+Subproject commit eb10fac1e1dfa4881c273d87e23d41509017223a
diff --git a/src/audio_core/dsp_interface.h b/src/audio_core/dsp_interface.h
index fc3d7cab2..00adfa3ea 100644
--- a/src/audio_core/dsp_interface.h
+++ b/src/audio_core/dsp_interface.h
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include <vector>
+#include <boost/serialization/access.hpp>
 #include "audio_core/audio_types.h"
 #include "audio_core/time_stretch.h"
 #include "common/common_types.h"
@@ -113,6 +114,10 @@ private:
     Common::RingBuffer<s16, 0x2000, 2> fifo;
     std::array<s16, 2> last_frame{};
     TimeStretcher time_stretcher;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {}
+    friend class boost::serialization::access;
 };
 
 } // namespace AudioCore
diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp
index 873d6a72e..f96e2b642 100644
--- a/src/audio_core/hle/hle.cpp
+++ b/src/audio_core/hle/hle.cpp
@@ -1,7 +1,13 @@
+#pragma optimize("", off)
 // Copyright 2017 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/weak_ptr.hpp>
 #include "audio_core/audio_types.h"
 #ifdef HAVE_MF
 #include "audio_core/hle/wmf_decoder.h"
@@ -22,11 +28,21 @@
 #include "core/core.h"
 #include "core/core_timing.h"
 
+SERIALIZE_EXPORT_IMPL(AudioCore::DspHle)
+
 using InterruptType = Service::DSP::DSP_DSP::InterruptType;
 using Service::DSP::DSP_DSP;
 
 namespace AudioCore {
 
+DspHle::DspHle() : DspHle(Core::System::GetInstance().Memory()) {}
+
+template <class Archive>
+void DspHle::serialize(Archive& ar, const unsigned int) {
+    ar& boost::serialization::base_object<DspInterface>(*this);
+    ar&* impl.get();
+}
+
 static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
 
 struct DspHle::Impl final {
@@ -60,7 +76,7 @@ private:
     void AudioTickCallback(s64 cycles_late);
 
     DspState dsp_state = DspState::Off;
-    std::array<std::vector<u8>, num_dsp_pipe> pipe_data;
+    std::array<std::vector<u8>, num_dsp_pipe> pipe_data{};
 
     HLE::DspMemory dsp_memory;
     std::array<HLE::Source, HLE::num_sources> sources{{
@@ -70,14 +86,25 @@ private:
         HLE::Source(15), HLE::Source(16), HLE::Source(17), HLE::Source(18), HLE::Source(19),
         HLE::Source(20), HLE::Source(21), HLE::Source(22), HLE::Source(23),
     }};
-    HLE::Mixers mixers;
+    HLE::Mixers mixers{};
 
     DspHle& parent;
-    Core::TimingEventType* tick_event;
+    Core::TimingEventType* tick_event{};
 
-    std::unique_ptr<HLE::DecoderBase> decoder;
+    std::unique_ptr<HLE::DecoderBase> decoder{};
 
-    std::weak_ptr<DSP_DSP> dsp_dsp;
+    std::weak_ptr<DSP_DSP> dsp_dsp{};
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& dsp_state;
+        ar& pipe_data;
+        ar& dsp_memory.raw_memory;
+        ar& sources;
+        ar& mixers;
+        ar& dsp_dsp;
+    }
+    friend class boost::serialization::access;
 };
 
 DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(parent_) {
diff --git a/src/audio_core/hle/hle.h b/src/audio_core/hle/hle.h
index 4ab468331..11ec2820a 100644
--- a/src/audio_core/hle/hle.h
+++ b/src/audio_core/hle/hle.h
@@ -7,6 +7,7 @@
 #include <array>
 #include <memory>
 #include <vector>
+#include <boost/serialization/export.hpp>
 #include "audio_core/audio_types.h"
 #include "audio_core/dsp_interface.h"
 #include "common/common_types.h"
@@ -42,6 +43,14 @@ private:
     struct Impl;
     friend struct Impl;
     std::unique_ptr<Impl> impl;
+
+    DspHle();
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int);
+    friend class boost::serialization::access;
 };
 
 } // namespace AudioCore
+
+BOOST_CLASS_EXPORT_KEY(AudioCore::DspHle)
diff --git a/src/audio_core/hle/mixers.h b/src/audio_core/hle/mixers.h
index c5bfd512f..5043be38c 100644
--- a/src/audio_core/hle/mixers.h
+++ b/src/audio_core/hle/mixers.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <array>
+#include <boost/serialization/array.hpp>
 #include "audio_core/audio_types.h"
 #include "audio_core/hle/shared_memory.h"
 
@@ -54,6 +55,17 @@ private:
     void DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& samples);
     /// INTERNAL: Generate DspStatus based on internal state.
     DspStatus GetCurrentStatus() const;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& current_frame;
+        ar& state.intermediate_mixer_volume;
+        ar& state.mixer1_enabled;
+        ar& state.mixer2_enabled;
+        ar& state.intermediate_mix_buffer;
+        ar& state.output_format;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace AudioCore::HLE
diff --git a/src/audio_core/hle/shared_memory.h b/src/audio_core/hle/shared_memory.h
index 8ab9aa88e..43bf1df69 100644
--- a/src/audio_core/hle/shared_memory.h
+++ b/src/audio_core/hle/shared_memory.h
@@ -8,6 +8,7 @@
 #include <cstddef>
 #include <memory>
 #include <type_traits>
+#include <boost/serialization/access.hpp>
 #include "audio_core/audio_types.h"
 #include "audio_core/hle/common.h"
 #include "common/bit_field.h"
@@ -56,6 +57,12 @@ private:
         return (value << 16) | (value >> 16);
     }
     u32_le storage;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& storage;
+    }
+    friend class boost::serialization::access;
 };
 static_assert(std::is_trivially_copyable<u32_dsp>::value, "u32_dsp isn't trivially copyable");
 
diff --git a/src/audio_core/hle/source.h b/src/audio_core/hle/source.h
index b0db4a5d3..17c31672b 100644
--- a/src/audio_core/hle/source.h
+++ b/src/audio_core/hle/source.h
@@ -6,6 +6,10 @@
 
 #include <array>
 #include <vector>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/deque.hpp>
+#include <boost/serialization/priority_queue.hpp>
+#include <boost/serialization/vector.hpp>
 #include <queue>
 #include "audio_core/audio_types.h"
 #include "audio_core/codec.h"
@@ -85,6 +89,24 @@ private:
         bool from_queue;
         u32_dsp play_position; // = 0;
         bool has_played;       // = false;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& physical_address;
+            ar& length;
+            ar& adpcm_ps;
+            ar& adpcm_yn;
+            ar& adpcm_dirty;
+            ar& is_looping;
+            ar& buffer_id;
+            ar& mono_or_stereo;
+            ar& format;
+            ar& from_queue;
+            ar& play_position;
+            ar& has_played;
+        }
+        friend class boost::serialization::access;
     };
 
     struct BufferOrder {
@@ -107,7 +129,7 @@ private:
 
         // Buffer queue
 
-        std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder> input_queue;
+        std::priority_queue<Buffer, std::vector<Buffer>, BufferOrder> input_queue = {};
         MonoOrStereo mono_or_stereo = MonoOrStereo::Mono;
         Format format = Format::ADPCM;
 
@@ -115,7 +137,7 @@ private:
 
         u32 current_sample_number = 0;
         u32 next_sample_number = 0;
-        AudioInterp::StereoBuffer16 current_buffer;
+        AudioInterp::StereoBuffer16 current_buffer = {};
 
         // buffer_id state
 
@@ -135,7 +157,27 @@ private:
 
         // Filter state
 
-        SourceFilters filters;
+        SourceFilters filters = {};
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& enabled;
+            ar& sync;
+            ar& gain;
+            ar& input_queue;
+            ar& mono_or_stereo;
+            ar& format;
+            ar& current_sample_number;
+            ar& next_sample_number;
+            ar& current_buffer;
+            ar& buffer_update;
+            ar& current_buffer_id;
+            ar& adpcm_coeffs;
+            ar& rate_multiplier;
+            ar& interpolation_mode;
+        }
+        friend class boost::serialization::access;
 
     } state;
 
@@ -150,6 +192,12 @@ private:
     bool DequeueBuffer();
     /// INTERNAL: Generates a SourceStatus::Status based on our internal state.
     SourceStatus::Status GetCurrentStatus();
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& state;
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace AudioCore::HLE
diff --git a/src/core/core.cpp b/src/core/core.cpp
index aeab0d2b5..03b64b04e 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -1,3 +1,4 @@
+#pragma optimize("", off)
 // Copyright 2014 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
@@ -244,8 +245,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
-                                                    [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(
+        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -445,14 +446,20 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     ar&* service_manager.get();
     ar& GPU::g_regs;
     ar& LCD::g_regs;
-    ar & dsp_core->GetDspMemory();
+    if (Archive::is_loading::value) {
+        dsp_core.reset();
+    }
+    ar& dsp_core;
     ar&* memory.get();
     ar&* kernel.get();
 
     // This needs to be set from somewhere - might as well be here!
     if (Archive::is_loading::value) {
         Service::GSP::SetGlobalModule(*this);
-        DSP().SetServiceToInterrupt(ServiceManager().GetService<Service::DSP::DSP_DSP>("dsp::DSP"));
+
+        memory->SetDSP(*dsp_core);
+        dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id);
+        dsp_core->EnableStretching(Settings::values.enable_audio_stretching);
     }
 }
 

From 246ae84a521fa286b21beca30638f2150f52f5d9 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 20 Jan 2020 21:32:38 +0000
Subject: [PATCH 076/129] Pretty sure ARM/Thread serialization works now

---
 src/core/arm/arm_interface.h           | 17 +++++++++++++++--
 src/core/arm/dynarmic/arm_dynarmic.cpp | 14 +++++++++++---
 src/core/arm/dynarmic/arm_dynarmic.h   |  4 +++-
 src/core/arm/dyncom/arm_dyncom.cpp     |  8 +++++++-
 src/core/arm/dyncom/arm_dyncom.h       |  4 +++-
 src/core/core.cpp                      |  3 ---
 src/core/hle/kernel/kernel.cpp         |  2 +-
 src/core/hle/kernel/thread.h           |  1 -
 8 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index e416a5f4c..8ef51519b 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -11,6 +11,10 @@
 #include "core/arm/skyeye_common/arm_regformat.h"
 #include "core/arm/skyeye_common/vfp/asm_vfp.h"
 
+namespace Memory {
+struct PageTable;
+}
+
 /// Generic ARM11 CPU interface
 class ARM_Interface : NonCopyable {
 public:
@@ -111,7 +115,9 @@ public:
     virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
 
     /// Notify CPU emulation that page tables have changed
-    virtual void PageTableChanged() = 0;
+    virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
+
+    virtual std::shared_ptr<Memory::PageTable> GetPageTable() const = 0;
 
     /**
      * Set the Program Counter to an address
@@ -214,11 +220,15 @@ public:
     /// Prepare core for thread reschedule (if needed to correctly handle state)
     virtual void PrepareReschedule() = 0;
 
+    virtual void PurgeState() = 0;
+
 private:
     friend class boost::serialization::access;
 
     template <class Archive>
     void save(Archive& ar, const unsigned int file_version) const {
+        auto page_table = GetPageTable();
+        ar << page_table;
         for (auto i = 0; i < 15; i++) {
             auto r = GetReg(i);
             ar << r;
@@ -243,6 +253,10 @@ private:
 
     template <class Archive>
     void load(Archive& ar, const unsigned int file_version) {
+        PurgeState();
+        std::shared_ptr<Memory::PageTable> page_table = nullptr;
+        ar >> page_table;
+        SetPageTable(page_table);
         u32 r;
         for (auto i = 0; i < 15; i++) {
             ar >> r;
@@ -264,7 +278,6 @@ private:
             ar >> r;
             SetCP15Register(static_cast<CP15Register>(i), r);
         }
-        ClearInstructionCache();
     }
 
     BOOST_SERIALIZATION_SPLIT_MEMBER()
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index b6494d40e..33bc03a4f 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -167,7 +167,7 @@ ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory,
                            PrivilegeMode initial_mode)
     : system(*system), memory(memory), cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
     interpreter_state = std::make_shared<ARMul_State>(system, memory, initial_mode);
-    PageTableChanged();
+    SetPageTable(memory.GetCurrentPageTable());
 }
 
 ARM_Dynarmic::~ARM_Dynarmic() = default;
@@ -281,8 +281,12 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
     jit->InvalidateCacheRange(start_address, length);
 }
 
-void ARM_Dynarmic::PageTableChanged() {
-    current_page_table = memory.GetCurrentPageTable();
+std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
+    return current_page_table;
+}
+
+void ARM_Dynarmic::SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) {
+    current_page_table = page_table;
     Dynarmic::A32::Context ctx{};
     if (jit) {
         jit->SaveContext(ctx);
@@ -309,3 +313,7 @@ std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
     config.define_unpredictable_behaviour = true;
     return std::make_unique<Dynarmic::A32::Jit>(config);
 }
+
+void ARM_Dynarmic::PurgeState() {
+    ClearInstructionCache();
+}
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 690c1aa2e..c4d01835d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -51,7 +51,9 @@ public:
 
     void ClearInstructionCache() override;
     void InvalidateCacheRange(u32 start_address, std::size_t length) override;
-    void PageTableChanged() override;
+    void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
+    std::shared_ptr<Memory::PageTable> GetPageTable() const override;
+    void PurgeState() override;
 
 private:
     friend class DynarmicUserCallbacks;
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 6b67644e7..c069b428e 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -94,10 +94,16 @@ void ARM_DynCom::InvalidateCacheRange(u32, std::size_t) {
     ClearInstructionCache();
 }
 
-void ARM_DynCom::PageTableChanged() {
+void ARM_DynCom::SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) {
     ClearInstructionCache();
 }
 
+std::shared_ptr<Memory::PageTable> ARM_DynCom::GetPageTable() const {
+    return nullptr;
+}
+
+void ARM_DynCom::PurgeState() {}
+
 void ARM_DynCom::SetPC(u32 pc) {
     state->Reg[15] = pc;
 }
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 7497b765f..39d55a62a 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -29,7 +29,6 @@ public:
 
     void ClearInstructionCache() override;
     void InvalidateCacheRange(u32 start_address, std::size_t length) override;
-    void PageTableChanged() override;
 
     void SetPC(u32 pc) override;
     u32 GetPC() const override;
@@ -48,7 +47,10 @@ public:
     void SaveContext(const std::unique_ptr<ThreadContext>& arg) override;
     void LoadContext(const std::unique_ptr<ThreadContext>& arg) override;
 
+    void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
+    std::shared_ptr<Memory::PageTable> GetPageTable() const override;
     void PrepareReschedule() override;
+    void PurgeState() override;
 
 private:
     void ExecuteInstructions(u64 num_instructions);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 03b64b04e..18c2e77e1 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -486,9 +486,6 @@ void System::Load(std::istream& stream) {
         }
         VideoCore::Load(stream);
 
-        // Flush state through:
-        Kernel().SetCurrentProcess(Kernel().GetCurrentProcess());
-
     } catch (const std::exception& e) {
         LOG_ERROR(Core, "Error loading: {}", e.what());
     }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 3c3dfc6c6..ea3da508e 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -61,7 +61,7 @@ void KernelSystem::SetCurrentProcess(std::shared_ptr<Process> process) {
 void KernelSystem::SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table) {
     memory.SetCurrentPageTable(page_table);
     if (current_cpu != nullptr) {
-        current_cpu->PageTableChanged(); // notify the CPU the page table in memory has changed
+        current_cpu->SetPageTable(page_table);
     }
 }
 
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 0286e210d..c64e24071 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -172,7 +172,6 @@ private:
         ar& ready_queue;
         ar& wakeup_callback_table;
         ar& thread_list;
-        SwitchContext(current_thread.get());
     }
 };
 

From 5aa5cd60641401878158644a40007f9040732bae Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupf321@gmail.com>
Date: Thu, 13 Feb 2020 17:26:21 +0800
Subject: [PATCH 077/129] Fix externals/boost spec

---
 externals/boost | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/externals/boost b/externals/boost
index eb10fac1e..6d7edc593 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit eb10fac1e1dfa4881c273d87e23d41509017223a
+Subproject commit 6d7edc593be8e47c8de7bc5f7d6b32971fad0c24

From 7e8041df28252b0c974741ffecc87dcf87a7c406 Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupf321@gmail.com>
Date: Fri, 14 Feb 2020 17:13:53 +0800
Subject: [PATCH 078/129] kernel/timer: Add missing base object

---
 src/core/hle/kernel/timer.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index d2c513024..b591c1b03 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -115,6 +115,7 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
+        ar& boost::serialization::base_object<WaitObject>(*this);
         ar& reset_type;
         ar& initial_delay;
         ar& interval_delay;

From 57efc419734aa8b9f187de2c610548061acef74b Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupf321@gmail.com>
Date: Fri, 14 Feb 2020 17:15:08 +0800
Subject: [PATCH 079/129] service/cecd: Add missing SessionData serialization

---
 src/core/hle/service/cecd/cecd.cpp |  1 +
 src/core/hle/service/cecd/cecd.h   | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index f13df6926..36263f622 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -27,6 +27,7 @@
 
 SERVICE_CONSTRUCT_IMPL(Service::CECD::Module)
 SERIALIZE_EXPORT_IMPL(Service::CECD::Module)
+SERIALIZE_EXPORT_IMPL(Service::CECD::Module::SessionData)
 
 namespace Service::CECD {
 
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
index dd7fff7cb..0870f31bf 100644
--- a/src/core/hle/service/cecd/cecd.h
+++ b/src/core/hle/service/cecd/cecd.h
@@ -248,6 +248,19 @@ public:
         FileSys::Path path;
 
         std::unique_ptr<FileSys::FileBackend> file;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& boost::serialization::base_object<Kernel::SessionRequestHandler::SessionDataBase>(
+                *this);
+            ar& ncch_program_id;
+            ar& data_path_type;
+            ar& open_mode.raw;
+            ar& path;
+            ar& file;
+        }
+        friend class boost::serialization::access;
     };
 
     class Interface : public ServiceFramework<Interface, SessionData> {
@@ -626,3 +639,4 @@ void InstallInterfaces(Core::System& system);
 
 SERVICE_CONSTRUCT(Service::CECD::Module)
 BOOST_CLASS_EXPORT_KEY(Service::CECD::Module)
+BOOST_CLASS_EXPORT_KEY(Service::CECD::Module::SessionData)

From 7d880f94db5485fdda342cf72cedf0e7901a2293 Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupf321@gmail.com>
Date: Sun, 16 Feb 2020 23:25:30 +0800
Subject: [PATCH 080/129] Add simple zstd compression

Just a simple default compression is able to shrink savestate file size from ~160MB to ~20MB.
---
 src/core/core.cpp | 29 +++++++++++++++++++++++------
 src/core/core.h   |  2 +-
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 18c2e77e1..0bbb79aea 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -13,6 +13,7 @@
 #include "common/archives.h"
 #include "common/logging/log.h"
 #include "common/texture.h"
+#include "common/zstd_compression.h"
 #include "core/arm/arm_interface.h"
 #ifdef ARCHITECTURE_x86_64
 #include "core/arm/dynarmic/arm_dynarmic.h"
@@ -116,7 +117,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
     case Signal::Load: {
         LOG_INFO(Core, "Begin load");
         auto stream = std::ifstream("save0.citrasave", std::fstream::binary);
-        System::Load(stream);
+        System::Load(stream, FileUtil::GetSize("save0.citrasave"));
         LOG_INFO(Core, "Load completed");
     } break;
     case Signal::Save: {
@@ -464,27 +465,43 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
 }
 
 void System::Save(std::ostream& stream) const {
+    std::ostringstream sstream{std::ios_base::binary};
     try {
 
         {
-            oarchive oa{stream};
+            oarchive oa{sstream};
             oa&* this;
         }
-        VideoCore::Save(stream);
+        VideoCore::Save(sstream);
 
     } catch (const std::exception& e) {
         LOG_ERROR(Core, "Error saving: {}", e.what());
     }
+    const std::string& str{sstream.str()};
+    auto buffer = Common::Compression::CompressDataZSTDDefault(
+        reinterpret_cast<const u8*>(str.data()), str.size());
+    stream.write(reinterpret_cast<const char*>(buffer.data()), buffer.size());
 }
 
-void System::Load(std::istream& stream) {
+void System::Load(std::istream& stream, std::size_t size) {
+    std::vector<u8> decompressed;
+    {
+        std::vector<u8> buffer(size);
+        stream.read(reinterpret_cast<char*>(buffer.data()), size);
+        decompressed = Common::Compression::DecompressDataZSTD(buffer);
+    }
+    std::istringstream sstream{
+        std::string{reinterpret_cast<char*>(decompressed.data()), decompressed.size()},
+        std::ios_base::binary};
+    decompressed.clear();
+
     try {
 
         {
-            iarchive ia{stream};
+            iarchive ia{sstream};
             ia&* this;
         }
-        VideoCore::Load(stream);
+        VideoCore::Load(sstream);
 
     } catch (const std::exception& e) {
         LOG_ERROR(Core, "Error loading: {}", e.what());
diff --git a/src/core/core.h b/src/core/core.h
index a3b2f5cdd..80c1505b5 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -278,7 +278,7 @@ public:
 
     void Save(std::ostream& stream) const;
 
-    void Load(std::istream& stream);
+    void Load(std::istream& stream, std::size_t size);
 
 private:
     /**

From a487016cb42d0d36ed8706909f4423571141fcaf Mon Sep 17 00:00:00 2001
From: zhupengfei <zhupf321@gmail.com>
Date: Tue, 18 Feb 2020 13:19:52 +0800
Subject: [PATCH 081/129] core, citra_qt: Implement a save states file format
 and slot UI

10 slots are offered along with 'Save to Oldest Slot' and 'Load from Newest Slot'.

The savestate format is similar to the movie file format. It is called CST (Citra SavesTate), and is basically a 0x100 byte header (consisting of magic, revision, creation time and title ID) followed by Zstd compressed raw savestate data.

The savestate files are saved to the `states` folder in Citra's user folder. The files are named like `<Title ID>.<Slot ID>.cst`.
---
 src/citra_qt/main.cpp     | 111 +++++++++++++++++++++---
 src/citra_qt/main.h       |  16 +++-
 src/citra_qt/main.ui      |  29 ++++++-
 src/common/common_paths.h |   1 +
 src/common/file_util.cpp  |   1 +
 src/common/file_util.h    |   1 +
 src/core/CMakeLists.txt   |   2 +
 src/core/core.cpp         |  85 ++++++-------------
 src/core/core.h           |  14 ++-
 src/core/savestate.cpp    | 174 ++++++++++++++++++++++++++++++++++++++
 src/core/savestate.h      |  27 ++++++
 11 files changed, 384 insertions(+), 77 deletions(-)
 create mode 100644 src/core/savestate.cpp
 create mode 100644 src/core/savestate.h

diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 7fe4936f5..de66e14ac 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -79,6 +79,7 @@
 #include "core/hle/service/nfc/nfc.h"
 #include "core/loader/loader.h"
 #include "core/movie.h"
+#include "core/savestate.h"
 #include "core/settings.h"
 #include "game_list_p.h"
 #include "video_core/renderer_base.h"
@@ -166,6 +167,7 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
     InitializeWidgets();
     InitializeDebugWidgets();
     InitializeRecentFileMenuActions();
+    InitializeSaveStateMenuActions();
     InitializeHotkeys();
     ShowUpdaterWidgets();
 
@@ -383,6 +385,32 @@ void GMainWindow::InitializeRecentFileMenuActions() {
     UpdateRecentFiles();
 }
 
+void GMainWindow::InitializeSaveStateMenuActions() {
+    for (u32 i = 0; i < Core::SaveStateSlotCount; ++i) {
+        actions_load_state[i] = new QAction(this);
+        actions_load_state[i]->setData(i + 1);
+        connect(actions_load_state[i], &QAction::triggered, this, &GMainWindow::OnLoadState);
+        ui.menu_Load_State->addAction(actions_load_state[i]);
+
+        actions_save_state[i] = new QAction(this);
+        actions_save_state[i]->setData(i + 1);
+        connect(actions_save_state[i], &QAction::triggered, this, &GMainWindow::OnSaveState);
+        ui.menu_Save_State->addAction(actions_save_state[i]);
+    }
+
+    connect(ui.action_Load_from_Newest_Slot, &QAction::triggered,
+            [this] { actions_load_state[newest_slot - 1]->trigger(); });
+    connect(ui.action_Save_to_Oldest_Slot, &QAction::triggered,
+            [this] { actions_save_state[oldest_slot - 1]->trigger(); });
+
+    connect(ui.menu_Load_State->menuAction(), &QAction::hovered, this,
+            &GMainWindow::UpdateSaveStates);
+    connect(ui.menu_Save_State->menuAction(), &QAction::hovered, this,
+            &GMainWindow::UpdateSaveStates);
+
+    UpdateSaveStates();
+}
+
 void GMainWindow::InitializeHotkeys() {
     hotkey_registry.LoadHotkeys();
 
@@ -607,8 +635,6 @@ void GMainWindow::ConnectMenuEvents() {
             &GMainWindow::OnMenuReportCompatibility);
     connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
     connect(ui.action_Cheats, &QAction::triggered, this, &GMainWindow::OnCheats);
-    connect(ui.action_Save, &QAction::triggered, this, &GMainWindow::OnSave);
-    connect(ui.action_Load, &QAction::triggered, this, &GMainWindow::OnLoad);
 
     // View
     connect(ui.action_Single_Window_Mode, &QAction::triggered, this,
@@ -1036,8 +1062,6 @@ void GMainWindow::ShutdownGame() {
     ui.action_Stop->setEnabled(false);
     ui.action_Restart->setEnabled(false);
     ui.action_Cheats->setEnabled(false);
-    ui.action_Save->setEnabled(false);
-    ui.action_Load->setEnabled(false);
     ui.action_Load_Amiibo->setEnabled(false);
     ui.action_Remove_Amiibo->setEnabled(false);
     ui.action_Report_Compatibility->setEnabled(false);
@@ -1061,6 +1085,8 @@ void GMainWindow::ShutdownGame() {
     game_fps_label->setVisible(false);
     emu_frametime_label->setVisible(false);
 
+    UpdateSaveStates();
+
     emulation_running = false;
 
     if (defer_update_prompt) {
@@ -1107,6 +1133,62 @@ void GMainWindow::UpdateRecentFiles() {
     ui.menu_recent_files->setEnabled(num_recent_files != 0);
 }
 
+void GMainWindow::UpdateSaveStates() {
+    if (!Core::System::GetInstance().IsPoweredOn()) {
+        ui.menu_Load_State->setEnabled(false);
+        ui.menu_Save_State->setEnabled(false);
+        return;
+    }
+
+    ui.menu_Load_State->setEnabled(true);
+    ui.menu_Save_State->setEnabled(true);
+    ui.action_Load_from_Newest_Slot->setEnabled(false);
+
+    oldest_slot = newest_slot = 0;
+    oldest_slot_time = std::numeric_limits<u64>::max();
+    newest_slot_time = 0;
+
+    u64 title_id;
+    if (Core::System::GetInstance().GetAppLoader().ReadProgramId(title_id) !=
+        Loader::ResultStatus::Success) {
+        return;
+    }
+    auto savestates = Core::ListSaveStates(title_id);
+    for (u32 i = 0; i < Core::SaveStateSlotCount; ++i) {
+        actions_load_state[i]->setEnabled(false);
+        actions_load_state[i]->setText(tr("Slot %1").arg(i + 1));
+        actions_save_state[i]->setText(tr("Slot %1").arg(i + 1));
+    }
+    for (const auto& savestate : savestates) {
+        const auto text = tr("Slot %1 - %2")
+                              .arg(savestate.slot)
+                              .arg(QDateTime::fromSecsSinceEpoch(savestate.time)
+                                       .toString(QStringLiteral("yyyy-MM-dd hh:mm:ss")));
+        actions_load_state[savestate.slot - 1]->setEnabled(true);
+        actions_load_state[savestate.slot - 1]->setText(text);
+        actions_save_state[savestate.slot - 1]->setText(text);
+
+        ui.action_Load_from_Newest_Slot->setEnabled(true);
+
+        if (savestate.time > newest_slot_time) {
+            newest_slot = savestate.slot;
+            newest_slot_time = savestate.time;
+        }
+        if (savestate.time < oldest_slot_time) {
+            oldest_slot = savestate.slot;
+            oldest_slot_time = savestate.time;
+        }
+    }
+    for (u32 i = 0; i < Core::SaveStateSlotCount; ++i) {
+        if (!actions_load_state[i]->isEnabled()) {
+            // Prefer empty slot
+            oldest_slot = i + 1;
+            oldest_slot_time = 0;
+            break;
+        }
+    }
+}
+
 void GMainWindow::OnGameListLoadFile(QString game_path) {
     BootGame(game_path);
 }
@@ -1348,14 +1430,14 @@ void GMainWindow::OnStartGame() {
     ui.action_Stop->setEnabled(true);
     ui.action_Restart->setEnabled(true);
     ui.action_Cheats->setEnabled(true);
-    ui.action_Save->setEnabled(true);
-    ui.action_Load->setEnabled(true);
     ui.action_Load_Amiibo->setEnabled(true);
     ui.action_Report_Compatibility->setEnabled(true);
     ui.action_Enable_Frame_Advancing->setEnabled(true);
     ui.action_Capture_Screenshot->setEnabled(true);
 
     discord_rpc->Update();
+
+    UpdateSaveStates();
 }
 
 void GMainWindow::OnPauseGame() {
@@ -1503,14 +1585,19 @@ void GMainWindow::OnCheats() {
     cheat_dialog.exec();
 }
 
-void GMainWindow::OnSave() {
-    Core::System::GetInstance().SendSignal(Core::System::Signal::Save);
+void GMainWindow::OnSaveState() {
+    QAction* action = qobject_cast<QAction*>(sender());
+    assert(action);
+
+    Core::System::GetInstance().SendSignal(Core::System::Signal::Save, action->data().toUInt());
+    UpdateSaveStates();
 }
 
-void GMainWindow::OnLoad() {
-    if (QFileInfo("save0.citrasave").exists()) {
-        Core::System::GetInstance().SendSignal(Core::System::Signal::Load);
-    }
+void GMainWindow::OnLoadState() {
+    QAction* action = qobject_cast<QAction*>(sender());
+    assert(action);
+
+    Core::System::GetInstance().SendSignal(Core::System::Signal::Load, action->data().toUInt());
 }
 
 void GMainWindow::OnConfigure() {
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index 1858d5988..ebe1a013a 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <array>
 #include <memory>
 #include <QLabel>
 #include <QMainWindow>
@@ -14,6 +15,7 @@
 #include "common/announce_multiplayer_room.h"
 #include "core/core.h"
 #include "core/hle/service/am/am.h"
+#include "core/savestate.h"
 #include "ui_main.h"
 
 class AboutDialog;
@@ -106,6 +108,7 @@ private:
     void InitializeWidgets();
     void InitializeDebugWidgets();
     void InitializeRecentFileMenuActions();
+    void InitializeSaveStateMenuActions();
 
     void SetDefaultUIGeometry();
     void SyncMenuUISettings();
@@ -149,6 +152,8 @@ private:
      */
     void UpdateRecentFiles();
 
+    void UpdateSaveStates();
+
     /**
      * If the emulation is running,
      * asks the user if he really want to close the emulator
@@ -163,8 +168,8 @@ private slots:
     void OnStartGame();
     void OnPauseGame();
     void OnStopGame();
-    void OnSave();
-    void OnLoad();
+    void OnSaveState();
+    void OnLoadState();
     void OnMenuReportCompatibility();
     /// Called whenever a user selects a game in the game list widget.
     void OnGameListLoadFile(QString game_path);
@@ -276,6 +281,13 @@ private:
     bool defer_update_prompt = false;
 
     QAction* actions_recent_files[max_recent_files_item];
+    std::array<QAction*, Core::SaveStateSlotCount> actions_load_state;
+    std::array<QAction*, Core::SaveStateSlotCount> actions_save_state;
+
+    u32 oldest_slot;
+    u64 oldest_slot_time;
+    u32 newest_slot;
+    u64 newest_slot_time;
 
     QTranslator translator;
 
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index c0c38e4c8..2eff98083 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -79,17 +79,32 @@
     <property name="title">
      <string>&amp;Emulation</string>
     </property>
+    <widget class="QMenu" name="menu_Save_State">
+     <property name="title">
+      <string>Save State</string>
+     </property>
+     <addaction name="action_Save_to_Oldest_Slot"/>
+     <addaction name="separator"/>
+    </widget>
+    <widget class="QMenu" name="menu_Load_State">
+     <property name="title">
+      <string>Load State</string>
+     </property>
+     <addaction name="action_Load_from_Newest_Slot"/>
+     <addaction name="separator"/>
+    </widget>
     <addaction name="action_Start"/>
     <addaction name="action_Pause"/>
     <addaction name="action_Stop"/>
     <addaction name="action_Restart"/>
     <addaction name="separator"/>
+    <addaction name="menu_Load_State"/>
+    <addaction name="menu_Save_State"/>
+    <addaction name="separator"/>
     <addaction name="action_Report_Compatibility"/>
     <addaction name="separator"/>
     <addaction name="action_Configure"/>
     <addaction name="action_Cheats"/>
-    <addaction name="action_Save"/>
-    <addaction name="action_Load"/>
    </widget>
    <widget class="QMenu" name="menu_View">
     <property name="title">
@@ -253,6 +268,16 @@
     <string>Single Window Mode</string>
    </property>
   </action>
+  <action name="action_Save_to_Oldest_Slot">
+   <property name="text">
+    <string>Save to Oldest Slot</string>
+   </property>
+  </action>
+  <action name="action_Load_from_Newest_Slot">
+   <property name="text">
+    <string>Load from Newest Slot</string>
+   </property>
+  </action>
   <action name="action_Configure">
    <property name="text">
     <string>Configure...</string>
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 13e71615e..eec4dde9c 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -47,6 +47,7 @@
 #define DUMP_DIR "dump"
 #define LOAD_DIR "load"
 #define SHADER_DIR "shaders"
+#define STATES_DIR "states"
 
 // Filenames
 // Files in the directory returned by GetUserPath(UserPath::LogDir)
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index c5da82973..cd3f4e102 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -725,6 +725,7 @@ void SetUserPath(const std::string& path) {
     g_paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
     g_paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
     g_paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
+    g_paths.emplace(UserPath::StatesDir, user_path + STATES_DIR DIR_SEP);
 }
 
 const std::string& GetUserPath(UserPath path) {
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 0368d3665..8af5a2a61 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -36,6 +36,7 @@ enum class UserPath {
     RootDir,
     SDMCDir,
     ShaderDir,
+    StatesDir,
     SysDataDir,
     UserDir,
 };
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c6908c59a..2b02ffc41 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -447,6 +447,8 @@ add_library(core STATIC
     rpc/server.h
     rpc/udp_server.cpp
     rpc/udp_server.h
+    savestate.cpp
+    savestate.h
     settings.cpp
     settings.h
     telemetry_session.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 0bbb79aea..f17474a85 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -10,10 +10,8 @@
 #include "audio_core/dsp_interface.h"
 #include "audio_core/hle/hle.h"
 #include "audio_core/lle/lle.h"
-#include "common/archives.h"
 #include "common/logging/log.h"
 #include "common/texture.h"
-#include "common/zstd_compression.h"
 #include "core/arm/arm_interface.h"
 #ifdef ARCHITECTURE_x86_64
 #include "core/arm/dynarmic/arm_dynarmic.h"
@@ -63,6 +61,8 @@ Kernel::KernelSystem& Global() {
     return System::GetInstance().Kernel();
 }
 
+System::~System() = default;
+
 System::ResultStatus System::RunLoop(bool tight_loop) {
     status = ResultStatus::Success;
     if (!cpu_core) {
@@ -106,7 +106,16 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
     HW::Update();
     Reschedule();
 
-    auto signal = current_signal.exchange(Signal::None);
+    Signal signal{Signal::None};
+    u32 param{};
+    {
+        std::lock_guard lock{signal_mutex};
+        if (current_signal != Signal::None) {
+            signal = current_signal;
+            param = signal_param;
+            current_signal = Signal::None;
+        }
+    }
     switch (signal) {
     case Signal::Reset:
         Reset();
@@ -116,14 +125,16 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
         break;
     case Signal::Load: {
         LOG_INFO(Core, "Begin load");
-        auto stream = std::ifstream("save0.citrasave", std::fstream::binary);
-        System::Load(stream, FileUtil::GetSize("save0.citrasave"));
+        System::LoadState(param);
+        // auto stream = std::ifstream("save0.citrasave", std::fstream::binary);
+        // System::Load(stream, FileUtil::GetSize("save0.citrasave"));
         LOG_INFO(Core, "Load completed");
     } break;
     case Signal::Save: {
         LOG_INFO(Core, "Begin save");
-        auto stream = std::ofstream("save0.citrasave", std::fstream::binary);
-        System::Save(stream);
+        System::SaveState(param);
+        // auto stream = std::ofstream("save0.citrasave", std::fstream::binary);
+        // System::Save(stream);
         LOG_INFO(Core, "Save completed");
     } break;
     default:
@@ -133,12 +144,14 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
     return status;
 }
 
-bool System::SendSignal(System::Signal signal) {
-    auto prev = System::Signal::None;
-    if (!current_signal.compare_exchange_strong(prev, signal)) {
-        LOG_ERROR(Core, "Unable to {} as {} is ongoing", signal, prev);
+bool System::SendSignal(System::Signal signal, u32 param) {
+    std::lock_guard lock{signal_mutex};
+    if (current_signal != signal && current_signal != Signal::None) {
+        LOG_ERROR(Core, "Unable to {} as {} is ongoing", signal, current_signal);
         return false;
     }
+    current_signal = signal;
+    signal_param = param;
     return true;
 }
 
@@ -196,7 +209,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
         }
     }
     cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
-    u64 title_id{0};
+    title_id = 0;
     if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
         LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
                   static_cast<u32>(load_result));
@@ -246,8 +259,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     timing = std::make_unique<Timing>();
 
-    kernel = std::make_unique<Kernel::KernelSystem>(
-        *memory, *timing, [this] { PrepareReschedule(); }, system_mode);
+    kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
+                                                    [this] { PrepareReschedule(); }, system_mode);
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
@@ -464,48 +477,6 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     }
 }
 
-void System::Save(std::ostream& stream) const {
-    std::ostringstream sstream{std::ios_base::binary};
-    try {
-
-        {
-            oarchive oa{sstream};
-            oa&* this;
-        }
-        VideoCore::Save(sstream);
-
-    } catch (const std::exception& e) {
-        LOG_ERROR(Core, "Error saving: {}", e.what());
-    }
-    const std::string& str{sstream.str()};
-    auto buffer = Common::Compression::CompressDataZSTDDefault(
-        reinterpret_cast<const u8*>(str.data()), str.size());
-    stream.write(reinterpret_cast<const char*>(buffer.data()), buffer.size());
-}
-
-void System::Load(std::istream& stream, std::size_t size) {
-    std::vector<u8> decompressed;
-    {
-        std::vector<u8> buffer(size);
-        stream.read(reinterpret_cast<char*>(buffer.data()), size);
-        decompressed = Common::Compression::DecompressDataZSTD(buffer);
-    }
-    std::istringstream sstream{
-        std::string{reinterpret_cast<char*>(decompressed.data()), decompressed.size()},
-        std::ios_base::binary};
-    decompressed.clear();
-
-    try {
-
-        {
-            iarchive ia{sstream};
-            ia&* this;
-        }
-        VideoCore::Load(sstream);
-
-    } catch (const std::exception& e) {
-        LOG_ERROR(Core, "Error loading: {}", e.what());
-    }
-}
+SERIALIZE_IMPL(System)
 
 } // namespace Core
diff --git a/src/core/core.h b/src/core/core.h
index 80c1505b5..0ce6924cd 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <mutex>
 #include <string>
 #include "boost/serialization/access.hpp"
 #include "common/common_types.h"
@@ -92,6 +93,8 @@ public:
         ErrorUnknown                        ///< Any other error
     };
 
+    ~System();
+
     /**
      * Run the core CPU loop
      * This function runs the core for the specified number of CPU instructions before trying to
@@ -118,7 +121,7 @@ public:
 
     enum class Signal : u32 { None, Shutdown, Reset, Save, Load };
 
-    bool SendSignal(Signal signal);
+    bool SendSignal(Signal signal, u32 param = 0);
 
     /// Request reset of the system
     void RequestReset() {
@@ -276,9 +279,9 @@ public:
         return registered_image_interface;
     }
 
-    void Save(std::ostream& stream) const;
+    void SaveState(u32 slot) const;
 
-    void Load(std::istream& stream, std::size_t size);
+    void LoadState(u32 slot);
 
 private:
     /**
@@ -344,8 +347,11 @@ private:
     /// Saved variables for reset
     Frontend::EmuWindow* m_emu_window;
     std::string m_filepath;
+    u64 title_id;
 
-    std::atomic<Signal> current_signal;
+    std::mutex signal_mutex;
+    Signal current_signal;
+    u32 signal_param;
 
     friend class boost::serialization::access;
     template <typename Archive>
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
new file mode 100644
index 000000000..d52789b2c
--- /dev/null
+++ b/src/core/savestate.cpp
@@ -0,0 +1,174 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <chrono>
+#include <cryptopp/hex.h>
+#include "common/archives.h"
+#include "common/logging/log.h"
+#include "common/scm_rev.h"
+#include "common/zstd_compression.h"
+#include "core/core.h"
+#include "core/savestate.h"
+#include "video_core/video_core.h"
+
+namespace Core {
+
+#pragma pack(push, 1)
+struct CSTHeader {
+    std::array<u8, 4> filetype;  /// Unique Identifier to check the file type (always "CST"0x1B)
+    u64_le program_id;           /// ID of the ROM being executed. Also called title_id
+    std::array<u8, 20> revision; /// Git hash of the revision this savestate was created with
+    u64_le time;                 /// The time when this save state was created
+
+    std::array<u8, 216> reserved; /// Make heading 256 bytes so it has consistent size
+};
+static_assert(sizeof(CSTHeader) == 256, "CSTHeader should be 256 bytes");
+#pragma pack(pop)
+
+constexpr std::array<u8, 4> header_magic_bytes{{'C', 'S', 'T', 0x1B}};
+
+std::string GetSaveStatePath(u64 program_id, u32 slot) {
+    return fmt::format("{}{:016X}.{:02d}.cst", FileUtil::GetUserPath(FileUtil::UserPath::StatesDir),
+                       program_id, slot);
+}
+
+std::vector<SaveStateInfo> ListSaveStates(u64 program_id) {
+    std::vector<SaveStateInfo> result;
+    for (u32 slot = 1; slot <= SaveStateSlotCount; ++slot) {
+        const auto path = GetSaveStatePath(program_id, slot);
+        if (!FileUtil::Exists(path)) {
+            continue;
+        }
+
+        SaveStateInfo info;
+        info.slot = slot;
+
+        FileUtil::IOFile file(path, "rb");
+        if (!file) {
+            LOG_ERROR(Core, "Could not open file {}", path);
+            continue;
+        }
+        CSTHeader header;
+        if (file.GetSize() < sizeof(header)) {
+            LOG_ERROR(Core, "File too small {}", path);
+            continue;
+        }
+        if (file.ReadBytes(&header, sizeof(header)) != sizeof(header)) {
+            LOG_ERROR(Core, "Could not read from file {}", path);
+            continue;
+        }
+        if (header.filetype != header_magic_bytes) {
+            LOG_WARNING(Core, "Invalid save state file {}", path);
+            continue;
+        }
+        info.time = header.time;
+
+        if (header.program_id != program_id) {
+            LOG_WARNING(Core, "Save state file isn't for the current game {}", path);
+            continue;
+        }
+        std::string revision = fmt::format("{:02x}", fmt::join(header.revision, ""));
+        if (revision == Common::g_scm_rev) {
+            info.status = SaveStateInfo::ValidationStatus::OK;
+        } else {
+            LOG_WARNING(Core, "Save state file created from a different revision {}", path);
+            info.status = SaveStateInfo::ValidationStatus::RevisionDismatch;
+        }
+        result.emplace_back(std::move(info));
+    }
+    return result;
+}
+
+void System::SaveState(u32 slot) const {
+    std::ostringstream sstream{std::ios_base::binary};
+    try {
+
+        {
+            oarchive oa{sstream};
+            oa&* this;
+        }
+        VideoCore::Save(sstream);
+
+    } catch (const std::exception& e) {
+        LOG_ERROR(Core, "Error saving: {}", e.what());
+    }
+    const std::string& str{sstream.str()};
+    auto buffer = Common::Compression::CompressDataZSTDDefault(
+        reinterpret_cast<const u8*>(str.data()), str.size());
+
+    const auto path = GetSaveStatePath(title_id, slot);
+    if (!FileUtil::CreateFullPath(path)) {
+        LOG_ERROR(Core, "Could not create path {}", path);
+        return;
+    }
+
+    FileUtil::IOFile file(path, "wb");
+    if (!file) {
+        LOG_ERROR(Core, "Could not open file {}", path);
+        return;
+    }
+
+    CSTHeader header{};
+    header.filetype = header_magic_bytes;
+    header.program_id = title_id;
+    std::string rev_bytes;
+    CryptoPP::StringSource(Common::g_scm_rev, true,
+                           new CryptoPP::HexDecoder(new CryptoPP::StringSink(rev_bytes)));
+    std::memcpy(header.revision.data(), rev_bytes.data(), sizeof(header.revision));
+    header.time = std::chrono::duration_cast<std::chrono::seconds>(
+                      std::chrono::system_clock::now().time_since_epoch())
+                      .count();
+
+    if (file.WriteBytes(&header, sizeof(header)) != sizeof(header)) {
+        LOG_ERROR(Core, "Could not write to file {}", path);
+        return;
+    }
+    if (file.WriteBytes(buffer.data(), buffer.size()) != buffer.size()) {
+        LOG_ERROR(Core, "Could not write to file {}", path);
+        return;
+    }
+}
+
+void System::LoadState(u32 slot) {
+    const auto path = GetSaveStatePath(title_id, slot);
+    if (!FileUtil::Exists(path)) {
+        LOG_ERROR(Core, "File not exist {}", path);
+        return;
+    }
+
+    std::vector<u8> decompressed;
+    {
+        std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader));
+
+        FileUtil::IOFile file(path, "rb");
+        if (!file) {
+            LOG_ERROR(Core, "Could not open file {}", path);
+            return;
+        }
+        file.Seek(sizeof(CSTHeader), SEEK_SET); // Skip header
+        if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
+            LOG_ERROR(Core, "Could not read from file {}", path);
+            return;
+        }
+        decompressed = Common::Compression::DecompressDataZSTD(buffer);
+    }
+    std::istringstream sstream{
+        std::string{reinterpret_cast<char*>(decompressed.data()), decompressed.size()},
+        std::ios_base::binary};
+    decompressed.clear();
+
+    try {
+
+        {
+            iarchive ia{sstream};
+            ia&* this;
+        }
+        VideoCore::Load(sstream);
+
+    } catch (const std::exception& e) {
+        LOG_ERROR(Core, "Error loading: {}", e.what());
+    }
+}
+
+} // namespace Core
diff --git a/src/core/savestate.h b/src/core/savestate.h
new file mode 100644
index 000000000..f67bee22f
--- /dev/null
+++ b/src/core/savestate.h
@@ -0,0 +1,27 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+
+namespace Core {
+
+struct CSTHeader;
+
+struct SaveStateInfo {
+    u32 slot;
+    u64 time;
+    enum class ValidationStatus {
+        OK,
+        RevisionDismatch,
+    } status;
+};
+
+constexpr u32 SaveStateSlotCount = 10; // Maximum count of savestate slots
+
+std::vector<SaveStateInfo> ListSaveStates(u64 program_id);
+
+} // namespace Core

From 56046136424be85c625cd622506c2aefee38d915 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 27 Mar 2020 21:48:58 +0000
Subject: [PATCH 082/129] More merge fixes

---
 TODO                               |   2 +-
 save0.citrasave                    | Bin 776 -> 0 bytes
 src/core/core.cpp                  |   6 ++++++
 src/core/core_timing.h             |   7 ++++---
 src/core/file_sys/layered_fs.cpp   |  16 +++++++++++----
 src/core/file_sys/layered_fs.h     |  32 +++++++++++++++++++++++++++++
 src/core/file_sys/romfs_reader.cpp |   3 +++
 src/core/file_sys/romfs_reader.h   |  10 +++++++++
 src/core/hle/service/cecd/cecd.h   |   2 +-
 9 files changed, 69 insertions(+), 9 deletions(-)
 delete mode 100644 save0.citrasave

diff --git a/TODO b/TODO
index 9cc333d46..41fa8503a 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,7 @@
 ☐ Save/load UI
     ✔ Basic version @done(20-01-03 15:27)
     ☐ Multiple slots etc.
-☐ Add 'force flush all' to Rasterizer interface + impls
+✔ Add 'force flush all' to Rasterizer interface + impls @done(20-03-07 21:54)
 ☐ Custom texture cache
 ☐ Review constructor/initialization code
 ✔ Core timing events @done(20-01-12 15:14)
diff --git a/save0.citrasave b/save0.citrasave
deleted file mode 100644
index 578174ec6b7489150da4ff634caacf0e34d2ddd8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 776
zcmWe*fPmuEqRhmc%&Nqa%=|nntHh$@jLfoBK?W8U77j+J8VJP<q}YHMBnrX-WeOZj
zK>9?L0*8h?10RqH1|V?|<IY3{4i2FBml@d%1~ao61Q-|^UU$fY)qu>A17eUl4nX1q
zlntb43brUPIsz>Kd4++2my6*Yh!z9_5UsL-A0!C@U@rjWfQ|zq29QTVfSFN%k%^f}
zfI&eCB+MWP^p>C^gOH$rlAxiY0HY&Nw8DXvfgdC}gusXY|Nn!WyQGVg;ep2k7Zj)K
z{eZ+8iXbT*ADCiTFv9qtbN~VcxmJk<1>lfo1CtP8ILQfOfdU*DXW(!L6CgooJb{=H
X09FNMLyV0NPAw`+ErKZk({Muob(AbM

diff --git a/src/core/core.cpp b/src/core/core.cpp
index fea1705ed..ca2299920 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -530,6 +530,9 @@ void System::Reset() {
 template <class Archive>
 void System::serialize(Archive& ar, const unsigned int file_version) {
     u32 num_cores;
+    if (Archive::is_saving::value) {
+        num_cores = this->GetNumCores();
+    }
     ar& num_cores;
     if (num_cores != this->GetNumCores()) {
         throw std::runtime_error("Wrong N3DS mode");
@@ -547,6 +550,9 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     if (Archive::is_loading::value) {
         dsp_core.reset();
     }
+    if (dsp_core) {
+        throw "BLEH";
+    }
     ar& dsp_core;
     ar&* memory.get();
     ar&* kernel.get();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index a56a9097d..4e11b7bd2 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -223,10 +223,12 @@ public:
         template <class Archive>
         void serialize(Archive& ar, const unsigned int) {
             MoveEvents();
-            ar& slice_length;
-            ar& downcount;
+            // NOTE: ts_queue should be empty now
             ar& event_queue;
             ar& event_fifo_id;
+            ar& slice_length;
+            ar& downcount;
+            ar& executed_ticks;
             ar& idled_cycles;
         }
         friend class boost::serialization::access;
@@ -283,7 +285,6 @@ private:
         deserializing = nullptr;
     }
     friend class boost::serialization::access;
-
 };
 
 } // namespace Core
diff --git a/src/core/file_sys/layered_fs.cpp b/src/core/file_sys/layered_fs.cpp
index 9d5fbf7c2..c8af6b5b0 100644
--- a/src/core/file_sys/layered_fs.cpp
+++ b/src/core/file_sys/layered_fs.cpp
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <cstring>
 #include "common/alignment.h"
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_paths.h"
 #include "common/file_util.h"
@@ -13,6 +14,8 @@
 #include "core/file_sys/layered_fs.h"
 #include "core/file_sys/patch.h"
 
+SERIALIZE_EXPORT_IMPL(FileSys::LayeredFS)
+
 namespace FileSys {
 
 struct FileRelocationInfo {
@@ -51,11 +54,16 @@ struct FileMetadata {
 };
 static_assert(sizeof(FileMetadata) == 0x20, "Size of FileMetadata is not correct");
 
-LayeredFS::LayeredFS(std::shared_ptr<RomFSReader> romfs_, std::string patch_path_,
-                     std::string patch_ext_path_, bool load_relocations)
-    : romfs(std::move(romfs_)), patch_path(std::move(patch_path_)),
-      patch_ext_path(std::move(patch_ext_path_)) {
+LayeredFS::LayeredFS() = default;
 
+LayeredFS::LayeredFS(std::shared_ptr<RomFSReader> romfs_, std::string patch_path_,
+                     std::string patch_ext_path_, bool load_relocations_)
+    : romfs(std::move(romfs_)), patch_path(std::move(patch_path_)),
+      patch_ext_path(std::move(patch_ext_path_)), load_relocations(load_relocations_) {
+    Load();
+}
+
+void LayeredFS::Load() {
     romfs->ReadFile(0, sizeof(header), reinterpret_cast<u8*>(&header));
 
     ASSERT_MSG(header.header_length == sizeof(header), "Header size is incorrect");
diff --git a/src/core/file_sys/layered_fs.h b/src/core/file_sys/layered_fs.h
index 956eedcfa..dc71d052f 100644
--- a/src/core/file_sys/layered_fs.h
+++ b/src/core/file_sys/layered_fs.h
@@ -9,6 +9,10 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/file_sys/romfs_reader.h"
@@ -19,6 +23,14 @@ struct RomFSHeader {
     struct Descriptor {
         u32_le offset;
         u32_le length;
+
+    private:
+        template <class Archive>
+        void serialize(Archive& ar, const unsigned int) {
+            ar& offset;
+            ar& length;
+        }
+        friend class boost::serialization::access;
     };
     u32_le header_length;
     Descriptor directory_hash_table;
@@ -92,9 +104,12 @@ private:
 
     void RebuildMetadata();
 
+    void Load();
+
     std::shared_ptr<RomFSReader> romfs;
     std::string patch_path;
     std::string patch_ext_path;
+    bool load_relocations;
 
     RomFSHeader header;
     Directory root;
@@ -118,6 +133,23 @@ private:
     u64 current_file_offset{};           // current file metadata offset
     std::vector<u8> file_metadata_table; // rebuilt file metadata table
     u64 current_data_offset{};           // current assigned data offset
+
+    LayeredFS();
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<RomFSReader>(*this);
+        ar& romfs;
+        ar& patch_path;
+        ar& patch_ext_path;
+        ar& load_relocations;
+        if (Archive::is_loading::value) {
+            Load();
+        }
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::LayeredFS)
diff --git a/src/core/file_sys/romfs_reader.cpp b/src/core/file_sys/romfs_reader.cpp
index 64374684a..a1ff38945 100644
--- a/src/core/file_sys/romfs_reader.cpp
+++ b/src/core/file_sys/romfs_reader.cpp
@@ -1,8 +1,11 @@
 #include <algorithm>
 #include <cryptopp/aes.h>
 #include <cryptopp/modes.h>
+#include "common/archives.h"
 #include "core/file_sys/romfs_reader.h"
 
+SERIALIZE_EXPORT_IMPL(FileSys::DirectRomFSReader)
+
 namespace FileSys {
 
 std::size_t DirectRomFSReader::ReadFile(std::size_t offset, std::size_t length, u8* buffer) {
diff --git a/src/core/file_sys/romfs_reader.h b/src/core/file_sys/romfs_reader.h
index 1cfaa3b4f..26dcb9857 100644
--- a/src/core/file_sys/romfs_reader.h
+++ b/src/core/file_sys/romfs_reader.h
@@ -2,6 +2,8 @@
 
 #include <array>
 #include <boost/serialization/array.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
 #include "common/common_types.h"
 #include "common/file_util.h"
 
@@ -16,6 +18,11 @@ public:
 
     virtual std::size_t GetSize() const = 0;
     virtual std::size_t ReadFile(std::size_t offset, std::size_t length, u8* buffer) = 0;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int file_version) {}
+    friend class boost::serialization::access;
 };
 
 /**
@@ -54,6 +61,7 @@ private:
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<RomFSReader>(*this);
         ar& is_encrypted;
         ar& file;
         ar& key;
@@ -66,3 +74,5 @@ private:
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::DirectRomFSReader)
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
index 0870f31bf..b752701fe 100644
--- a/src/core/hle/service/cecd/cecd.h
+++ b/src/core/hle/service/cecd/cecd.h
@@ -258,7 +258,7 @@ public:
             ar& data_path_type;
             ar& open_mode.raw;
             ar& path;
-            ar& file;
+            // ar& file;
         }
         friend class boost::serialization::access;
     };

From 3d1180ee21603392c32b4d610b6e866a1af0d262 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 27 Mar 2020 22:19:29 +0000
Subject: [PATCH 083/129] DSP now works... committing this!!

---
 src/audio_core/dsp_interface.cpp |  7 ++++++-
 src/audio_core/hle/hle.cpp       | 11 ++++++++++-
 src/core/core.cpp                | 11 ++++-------
 3 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/audio_core/dsp_interface.cpp b/src/audio_core/dsp_interface.cpp
index b6e74b82c..fc2e231f2 100644
--- a/src/audio_core/dsp_interface.cpp
+++ b/src/audio_core/dsp_interface.cpp
@@ -1,3 +1,4 @@
+#pragma optimize("", off)
 // Copyright 2017 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
@@ -14,7 +15,11 @@
 namespace AudioCore {
 
 DspInterface::DspInterface() = default;
-DspInterface::~DspInterface() = default;
+DspInterface::~DspInterface() {
+    LOG_WARNING(Audio_DSP, "c1");
+    sink.reset();
+    LOG_WARNING(Audio_DSP, "c2");
+}
 
 void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) {
     sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp
index 87af17ba7..cac8a7df5 100644
--- a/src/audio_core/hle/hle.cpp
+++ b/src/audio_core/hle/hle.cpp
@@ -16,6 +16,7 @@
 #elif HAVE_FDK
 #include "audio_core/hle/fdk_decoder.h"
 #endif
+#include <iostream>
 #include "audio_core/hle/common.h"
 #include "audio_core/hle/decoder.h"
 #include "audio_core/hle/hle.h"
@@ -148,8 +149,11 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(paren
 }
 
 DspHle::Impl::~Impl() {
+    LOG_WARNING(Audio_DSP, "b1");
     Core::Timing& timing = Core::System::GetInstance().CoreTiming();
+    LOG_WARNING(Audio_DSP, "b2");
     timing.UnscheduleEvent(tick_event, 0);
+    LOG_WARNING(Audio_DSP, "b3");
 }
 
 DspState DspHle::Impl::GetDspState() const {
@@ -448,7 +452,12 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) {
 }
 
 DspHle::DspHle(Memory::MemorySystem& memory) : impl(std::make_unique<Impl>(*this, memory)) {}
-DspHle::~DspHle() = default;
+DspHle::~DspHle() {
+
+    LOG_WARNING(Audio_DSP, "a1");
+    impl.reset();
+    LOG_WARNING(Audio_DSP, "a2");
+}
 
 u16 DspHle::RecvData(u32 register_number) {
     return impl->RecvData(register_number);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ca2299920..1c18af202 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -547,13 +547,10 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     ar&* service_manager.get();
     ar& GPU::g_regs;
     ar& LCD::g_regs;
-    if (Archive::is_loading::value) {
-        dsp_core.reset();
+    if (!dynamic_cast<AudioCore::DspHle*>(dsp_core.get())) {
+        throw std::runtime_error("Only HLE audio supported");
     }
-    if (dsp_core) {
-        throw "BLEH";
-    }
-    ar& dsp_core;
+    ar&* dynamic_cast<AudioCore::DspHle*>(dsp_core.get());
     ar&* memory.get();
     ar&* kernel.get();
 
@@ -562,7 +559,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
         Service::GSP::SetGlobalModule(*this);
 
         memory->SetDSP(*dsp_core);
-        dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id);
+        // dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id);
         dsp_core->EnableStretching(Settings::values.enable_audio_stretching);
     }
 }

From 232b52a27d6d633f8cbed7111310d7aeb82469af Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 09:59:45 +0000
Subject: [PATCH 084/129] Minor cleanup

---
 src/audio_core/dsp_interface.cpp |  7 +------
 src/audio_core/hle/hle.cpp       | 11 +---------
 src/core/core.cpp                | 35 ++++++++++++++++++++------------
 src/core/file_sys/layered_fs.cpp |  8 ++++----
 4 files changed, 28 insertions(+), 33 deletions(-)

diff --git a/src/audio_core/dsp_interface.cpp b/src/audio_core/dsp_interface.cpp
index fc2e231f2..b6e74b82c 100644
--- a/src/audio_core/dsp_interface.cpp
+++ b/src/audio_core/dsp_interface.cpp
@@ -1,4 +1,3 @@
-#pragma optimize("", off)
 // Copyright 2017 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
@@ -15,11 +14,7 @@
 namespace AudioCore {
 
 DspInterface::DspInterface() = default;
-DspInterface::~DspInterface() {
-    LOG_WARNING(Audio_DSP, "c1");
-    sink.reset();
-    LOG_WARNING(Audio_DSP, "c2");
-}
+DspInterface::~DspInterface() = default;
 
 void DspInterface::SetSink(const std::string& sink_id, const std::string& audio_device) {
     sink = CreateSinkFromID(Settings::values.sink_id, Settings::values.audio_device_id);
diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp
index cac8a7df5..6f54b75e6 100644
--- a/src/audio_core/hle/hle.cpp
+++ b/src/audio_core/hle/hle.cpp
@@ -1,4 +1,3 @@
-#pragma optimize("", off)
 // Copyright 2017 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
@@ -149,11 +148,8 @@ DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(paren
 }
 
 DspHle::Impl::~Impl() {
-    LOG_WARNING(Audio_DSP, "b1");
     Core::Timing& timing = Core::System::GetInstance().CoreTiming();
-    LOG_WARNING(Audio_DSP, "b2");
     timing.UnscheduleEvent(tick_event, 0);
-    LOG_WARNING(Audio_DSP, "b3");
 }
 
 DspState DspHle::Impl::GetDspState() const {
@@ -452,12 +448,7 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) {
 }
 
 DspHle::DspHle(Memory::MemorySystem& memory) : impl(std::make_unique<Impl>(*this, memory)) {}
-DspHle::~DspHle() {
-
-    LOG_WARNING(Audio_DSP, "a1");
-    impl.reset();
-    LOG_WARNING(Audio_DSP, "a2");
-}
+DspHle::~DspHle() = default;
 
 u16 DspHle::RecvData(u32 register_number) {
     return impl->RecvData(register_number);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 1c18af202..db9fa83c7 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -1,4 +1,3 @@
-#pragma optimize("", off)
 // Copyright 2014 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
@@ -313,7 +312,7 @@ void System::Reschedule() {
 System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode) {
     LOG_DEBUG(HW_Memory, "initialized OK");
 
-    std::size_t num_cores = 2;
+    u32 num_cores = 2;
     if (Settings::values.is_new_3ds) {
         num_cores = 4;
     }
@@ -327,19 +326,19 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
 
     if (Settings::values.use_cpu_jit) {
 #ifdef ARCHITECTURE_x86_64
-        for (std::size_t i = 0; i < num_cores; ++i) {
+        for (u32 i = 0; i < num_cores; ++i) {
             cpu_cores.push_back(
                 std::make_shared<ARM_Dynarmic>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
         }
 #else
-        for (std::size_t i = 0; i < num_cores; ++i) {
+        for (u32 i = 0; i < num_cores; ++i) {
             cpu_cores.push_back(
                 std::make_shared<ARM_DynCom>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
         }
         LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
 #endif
     } else {
-        for (std::size_t i = 0; i < num_cores; ++i) {
+        for (u32 i = 0; i < num_cores; ++i) {
             cpu_cores.push_back(
                 std::make_shared<ARM_DynCom>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
         }
@@ -541,26 +540,36 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     bool should_flush = !Archive::is_loading::value;
     Memory::RasterizerClearAll(should_flush);
     ar&* timing.get();
-    for (int i = 0; i < num_cores; i++) {
+    for (u32 i = 0; i < num_cores; i++) {
         ar&* cpu_cores[i].get();
     }
     ar&* service_manager.get();
     ar& GPU::g_regs;
     ar& LCD::g_regs;
-    if (!dynamic_cast<AudioCore::DspHle*>(dsp_core.get())) {
-        throw std::runtime_error("Only HLE audio supported");
+
+    // NOTE: DSP doesn't like being destroyed and recreated. So instead we do an inline
+    // serialization; this means that the DSP Settings need to match for loading to work.
+    bool dsp_type = Settings::values.enable_dsp_lle;
+    ar& dsp_type;
+    if (dsp_type != Settings::values.enable_dsp_lle) {
+        throw std::runtime_error(
+            "Incorrect DSP type - please change this in Settings before loading");
     }
-    ar&* dynamic_cast<AudioCore::DspHle*>(dsp_core.get());
+    auto dsp_hle = dynamic_cast<AudioCore::DspHle*>(dsp_core.get());
+    if (dsp_hle) {
+        ar&* dsp_hle;
+    }
+    auto dsp_lle = dynamic_cast<AudioCore::DspLle*>(dsp_core.get());
+    if (dsp_lle) {
+        ar&* dsp_lle;
+    }
+
     ar&* memory.get();
     ar&* kernel.get();
 
     // This needs to be set from somewhere - might as well be here!
     if (Archive::is_loading::value) {
         Service::GSP::SetGlobalModule(*this);
-
-        memory->SetDSP(*dsp_core);
-        // dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id);
-        dsp_core->EnableStretching(Settings::values.enable_audio_stretching);
     }
 }
 
diff --git a/src/core/file_sys/layered_fs.cpp b/src/core/file_sys/layered_fs.cpp
index c8af6b5b0..a4ef57baf 100644
--- a/src/core/file_sys/layered_fs.cpp
+++ b/src/core/file_sys/layered_fs.cpp
@@ -281,7 +281,7 @@ std::size_t GetNameSize(const std::string& name) {
 }
 
 void LayeredFS::PrepareBuildDirectory(Directory& current) {
-    directory_metadata_offset_map.emplace(&current, current_directory_offset);
+    directory_metadata_offset_map.emplace(&current, static_cast<u32>(current_directory_offset));
     directory_list.emplace_back(&current);
     current_directory_offset += sizeof(DirectoryMetadata) + GetNameSize(current.name);
 }
@@ -290,7 +290,7 @@ void LayeredFS::PrepareBuildFile(File& current) {
     if (current.relocation.type == 3) { // Deleted files are not counted
         return;
     }
-    file_metadata_offset_map.emplace(&current, current_file_offset);
+    file_metadata_offset_map.emplace(&current, static_cast<u32>(current_file_offset));
     file_list.emplace_back(&current);
     current_file_offset += sizeof(FileMetadata) + GetNameSize(current.name);
 }
@@ -369,7 +369,7 @@ void LayeredFS::BuildDirectories() {
 
         // Write metadata and name
         std::u16string u16name = Common::UTF8ToUTF16(directory->name);
-        metadata.name_length = u16name.size() * 2;
+        metadata.name_length = static_cast<u32_le>(u16name.size() * 2);
 
         std::memcpy(directory_metadata_table.data() + written, &metadata, sizeof(metadata));
         written += sizeof(metadata);
@@ -418,7 +418,7 @@ void LayeredFS::BuildFiles() {
 
         // Write metadata and name
         std::u16string u16name = Common::UTF8ToUTF16(file->name);
-        metadata.name_length = u16name.size() * 2;
+        metadata.name_length = static_cast<u32_le>(u16name.size() * 2);
 
         std::memcpy(file_metadata_table.data() + written, &metadata, sizeof(metadata));
         written += sizeof(metadata);

From 5a6093843e63fb9a271b8f04ca5be9e95ab92ee3 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 12:04:00 +0000
Subject: [PATCH 085/129] Remove the TODO (since it's all done now!)

---
 TODO | 143 -----------------------------------------------------------
 1 file changed, 143 deletions(-)
 delete mode 100644 TODO

diff --git a/TODO b/TODO
deleted file mode 100644
index 41fa8503a..000000000
--- a/TODO
+++ /dev/null
@@ -1,143 +0,0 @@
-☐ Save/load UI
-    ✔ Basic version @done(20-01-03 15:27)
-    ☐ Multiple slots etc.
-✔ Add 'force flush all' to Rasterizer interface + impls @done(20-03-07 21:54)
-☐ Custom texture cache
-☐ Review constructor/initialization code
-✔ Core timing events @done(20-01-12 15:14)
-☐ Serialize codeset with an apploader reference instead
-✔ Review base class serialization everywhere @done(20-01-10 23:47)
-    Make sure that all base/derived relationships are registered
-✔ Additional stuff to serialize @done(20-01-11 16:32)
-    ✔ Self-NCCH archive @done(20-01-11 16:32)
-    ✔ File backends @done(20-01-11 16:32)
-    ✘ Directory backends @cancelled(20-01-11 16:32)
-        Not needed for now
-    ✔ File/directory 'services' @done(20-01-10 23:46)
-✔ CPU @done(19-08-13 15:41)
-✔ Memory @done(19-08-13 15:41)
-    ✔ Page tables @done(20-01-05 16:33)
-        Need to change uses to shared_ptr
-    ✔ Skip N3DS RAM if unused @done(20-01-03 23:26)
-✔ DSP @done(19-12-28 16:57)
-    Memory only
-✔ Service manager @started(19-12-23 00:36) @done(19-12-23 11:38) @lasted(11h2m3s)
-    ✔ Fix or ignore inverse map @done(19-12-23 12:46)
-✘ App loader @cancelled(20-01-01 22:59)
-    No relevant state
-✔ Archive manager @started(20-01-01 23:03) @done(20-01-03 13:23) @lasted(1d14h20m40s)
-    NB that 'FileBackend' classes are not persistent
-    ✔ NCCH @started(20-01-02 22:50) @done(20-01-03 12:35) @lasted(13h45m50s)
-        ✔ Normal @done(20-01-02 22:50)
-        ✔ Self @done(20-01-03 12:35)
-    ✔ SaveData @started(20-01-02 23:03) @done(20-01-02 23:27) @lasted(25m)
-        ✔ Normal @done(20-01-02 23:03)
-        ✔ Ext @done(20-01-02 23:26)
-        ✔ Other @done(20-01-02 23:21)
-        ✔ Source SD @done(20-01-02 23:03)
-        ✔ System @done(20-01-02 23:13)
-    ✔ SDMC @done(20-01-02 23:34)
-        ✔ Normal @done(20-01-02 23:34)
-        ✔ Write-only @done(20-01-02 23:34)
-    ✔ IVFC @done(20-01-11 16:33)
-    ✔ File refs @done(20-01-11 16:33)
-    ✘ Replace delay generator with virtual fns @cancelled(20-01-03 13:16)
-        While they have no state, the extra refactoring here is unneeded
-✘ MMIO @cancelled(20-01-01 01:06)
-    Seems that this whole subsystem is only used in tests
-✘ Movie @cancelled(20-01-01 01:07)
-    Doesn't need to be serialized here
-✘ Perf stats @cancelled(20-01-01 01:09)
-    Doesn't need to be serialized here
-✘ Settings @cancelled(20-01-01 01:11)
-    For now, let the settings just be whatever they are
-✘ Telemetry session @cancelled(20-01-01 01:12)
-    Doesn't need to be serialized here
-✔ Replace SERIALIZE_AS_POD with BOOST_IS_BITWISE_SERIALIZABLE @started(20-01-03 13:47) @done(20-01-03 13:58) @lasted(11m22s)
-✔ Fix CI @done(19-12-31 21:32)
-✔ HW @done(19-08-13 15:41)
-    ✔ GPU regs @done(19-08-13 15:41)
-    ✔ LCD regs @done(19-08-13 15:41)
-✔ Video core @started(19-08-13 16:43) @done(19-12-22 16:06)
-    ✔ Geometry pipeline @done(19-12-22 15:52)
-        Required more use of g_state
-    ✔ PICA state @done(19-08-13 15:41)
-    ✔ Primitive assembly @done(19-12-22 16:05)
-    ✔ Shader @done(19-08-13 16:03)
-✔ HLE @started(19-08-13 16:43) @done(20-01-06 20:37) @lasted(20w6d4h54m19s)
-    ✔ Kernel @started(19-08-13 16:43) @done(20-01-06 20:37) @lasted(20w6d4h54m17s)
-        Most of these require adding Core::Global
-        ✔ Address arbiter @done(19-08-13 16:40)
-        ✔ Client port @done(19-08-13 16:40)
-        ✔ Client session @done(19-08-13 16:40)
-        ✔ Config mem @done(20-01-04 21:09)
-        ✔ Event @done(19-12-22 18:44)
-        ✔ Handle table @done(19-08-13 16:42)
-        ✔ HLE IPC @done(19-12-23 00:36)
-        ✔ IPC @done(19-12-23 00:36)
-        ✔ Memory @started(19-08-13 16:43) @done(19-12-22 18:34)
-        ✔ Mutex @done(19-08-13 16:43)
-        ✔ Object @done(19-08-13 15:41)
-        ✔ Process @started(19-08-13 16:43) @done(19-12-22 18:41)
-        ✔ Code set @started(19-12-22 18:41) @done(20-01-03 15:15) @lasted(1w4d20h34m2s)
-            Needs a way to reference loaded images (so we don't serialize the entire ROM as well)
-        ✔ Resource limit @done(19-08-13 16:43)
-        ✔ Semaphore @done(19-08-13 16:44)
-        ✔ Server port @done(19-08-13 16:44)
-        ✔ Server session @done(19-08-13 16:44)
-            ✔ Mapped buffer context @done(20-01-03 15:25)
-                This is needed because IPC can take as long as it takes
-                Changed the unique_ptr<u8[]> to vector<u8>
-        ✔ Session @done(19-08-13 16:44)
-        ✔ Shared memory @started(19-12-22 21:20) @done(20-01-04 21:09) @lasted(1w5d23h49m26s)
-            Need to figure out backing memory (a u8*)
-        ✔ Shared page @done(20-01-04 21:09)
-        ✔ SVC @done(19-12-22 21:32)
-            Nothing to do - all data is constant
-        ✔ Thread @started(19-08-13 16:45) @done(20-01-06 20:01) @lasted(20w6d4h16m22s)
-            This requires refactoring wakeup_callback to be an object ref
-        ✔ Timer @done(19-08-13 16:45)
-        ✔ VM Manager @started(19-08-13 16:46) @done(20-01-04 21:09) @lasted(20w4d5h23m42s)
-            Just need to figure out backing_mem (a u8*)
-        ✔ Wait object @done(19-08-13 16:46)
-    ✔ Service @started(19-12-23 12:49) @done(20-01-05 16:41) @lasted(1w6d3h52m17s)
-        ✔ AC @started(19-12-23 12:48) @done(19-12-24 22:38) @lasted(1d9h50m3s)
-        ✔ ACT @done(19-12-24 23:17)
-        ✔ AM @started(19-12-24 23:17) @done(19-12-24 23:53) @lasted(36m8s)
-        ✔ APT @done(19-12-25 21:41)
-        ✔ BOSS @started(19-12-25 21:48) @done(19-12-25 23:18) @lasted(1h30m14s)
-        ✔ CAM @started(19-12-26 10:37) @done(20-01-03 23:38) @lasted(1w1d13h1m50s)
-            Need to check capture_result
-        ✔ CECD @done(20-01-01 23:58)
-        ✔ CFG @done(20-01-02 00:44)
-            Also needs archive backend..
-        ✔ CSND @started(19-12-26 17:51) @done(19-12-26 17:56) @lasted(5m30s)
-        ✔ DLP @done(19-12-26 18:02)
-        ✔ DSP @done(19-12-26 18:10)
-        ✔ ERR @done(19-12-26 18:14)
-        ✔ FRD @done(19-12-26 19:09)
-        ✔ FS @done(19-12-27 11:46)
-        ✔ GSP @done(19-12-30 12:45)
-            ✔ Fix the global weak_ptr to gsp @done(20-01-04 00:29)
-                Didn't quite 'fix' it but worked around it
-        ✔ HID @done(19-12-30 14:46)
-        ✔ HTTP @done(19-12-30 15:18)
-        ✔ IR @done(19-12-30 16:06)
-        ✔ LDR_RO @done(19-12-30 16:25)
-        ✔ MIC @done(19-12-30 16:53)
-        ✔ MVD @done(19-12-31 18:26)
-        ✔ NDM @done(19-12-31 18:26)
-        ✔ NEWS @done(19-12-31 18:29)
-        ✔ NFC @done(19-12-31 20:35)
-        ✔ NIM @done(19-12-31 21:08)
-        ✔ NS @done(20-01-01 00:46)
-        ✔ NWM @done(20-01-01 21:31)
-            ✔ Fix wifi_packet_received @done(20-01-05 16:41)
-        ✔ PM @done(20-01-01 22:14)
-        ✔ PS @done(20-01-01 00:54)
-        ✔ PTM @done(20-01-01 22:36)
-        ✔ PXI @done(20-01-01 00:53)
-        ✔ QTM @done(20-01-01 22:41)
-        ✔ SOC @done(20-01-01 00:51)
-        ✔ SSL @done(20-01-01 00:48)
-        ✔ Y2R @done(20-01-01 22:56)
\ No newline at end of file

From 025960bcdd486f9747dd25cefa89ff014b414b27 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 15:10:35 +0000
Subject: [PATCH 086/129] Attempt to fix flatpak CI

---
 .travis/linux-flatpak/generate-data.sh | 2 +-
 externals/boost                        | 2 +-
 src/audio_core/hle/hle.cpp             | 1 -
 src/core/hle/kernel/process.cpp        | 5 ++---
 4 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/.travis/linux-flatpak/generate-data.sh b/.travis/linux-flatpak/generate-data.sh
index aaecd0500..799f0f1b8 100644
--- a/.travis/linux-flatpak/generate-data.sh
+++ b/.travis/linux-flatpak/generate-data.sh
@@ -43,7 +43,7 @@ cat > /tmp/org.citra.$REPO_NAME.json <<EOF
 {
     "app-id": "org.citra.$REPO_NAME",
     "runtime": "org.kde.Platform",
-    "runtime-version": "5.12",
+    "runtime-version": "5.13",
     "sdk": "org.kde.Sdk",
     "command": "citra-qt",
     "rename-desktop-file": "citra.desktop",
diff --git a/externals/boost b/externals/boost
index 727f616b6..a37867de9 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit 727f616b6e5cafaba072131c077a3b8fea87b8be
+Subproject commit a37867de91767e3289068997bc004f842894ce1f
diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp
index 6ced77481..f4e372f85 100644
--- a/src/audio_core/hle/hle.cpp
+++ b/src/audio_core/hle/hle.cpp
@@ -17,7 +17,6 @@
 #elif HAVE_FDK
 #include "audio_core/hle/fdk_decoder.h"
 #endif
-#include <iostream>
 #include "audio_core/hle/common.h"
 #include "audio_core/hle/decoder.h"
 #include "audio_core/hle/hle.h"
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index ea3449c21..b72081ad5 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -33,9 +33,8 @@ void Process::serialize(Archive& ar, const unsigned int file_version) {
     ar& resource_limit;
     ar& svc_access_mask;
     ar& handle_table_size;
-    ar&(boost::container::vector<
-        AddressMapping, boost::container::dtl::static_storage_allocator<AddressMapping, 8>>&)
-        address_mappings;
+    ar&(boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<
+                                                     AddressMapping, 8, 0, true>>&)address_mappings;
     ar& flags.raw;
     ar& kernel_version;
     ar& ideal_processor;

From 917d651a3c1be4b99a20ad1a2ad193d2ba1251c7 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 15:21:10 +0000
Subject: [PATCH 087/129] Added copyright notices on new files

---
 src/common/archives.h     | 6 ++++++
 src/common/construct.h    | 5 +++++
 src/common/memory_ref.cpp | 4 ++++
 src/common/memory_ref.h   | 4 ++++
 src/core/global.h         | 6 ++++++
 5 files changed, 25 insertions(+)

diff --git a/src/common/archives.h b/src/common/archives.h
index eef292634..993128197 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -1,3 +1,9 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
 #include "boost/archive/binary_iarchive.hpp"
 #include "boost/archive/binary_oarchive.hpp"
 #include "boost/serialization/export.hpp"
diff --git a/src/common/construct.h b/src/common/construct.h
index aba4c7e89..4e48ee60d 100644
--- a/src/common/construct.h
+++ b/src/common/construct.h
@@ -1,4 +1,9 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
 #pragma once
+
 #include <boost/serialization/serialization.hpp>
 
 class construct_access {
diff --git a/src/common/memory_ref.cpp b/src/common/memory_ref.cpp
index 170784ff8..300f87d58 100644
--- a/src/common/memory_ref.cpp
+++ b/src/common/memory_ref.cpp
@@ -1,3 +1,7 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
 #include "common/archives.h"
 #include "common/memory_ref.h"
 
diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
index ae30b009c..c11beb04d 100644
--- a/src/common/memory_ref.h
+++ b/src/common/memory_ref.h
@@ -1,3 +1,7 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
 #pragma once
 
 #include <memory>
diff --git a/src/core/global.h b/src/core/global.h
index d2e1cd97d..83bd4fc80 100644
--- a/src/core/global.h
+++ b/src/core/global.h
@@ -1,3 +1,9 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
 namespace Core {
 
 template <class T>

From 4aab38f133c2a039eb1d619b896c5eaff76cf939 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 15:47:36 +0000
Subject: [PATCH 088/129] Refactored out the horrible static var in CoreTiming

---
 src/core/core.cpp                   | 5 +++++
 src/core/core_timing.cpp            | 2 --
 src/core/core_timing.h              | 7 ++-----
 src/core/file_sys/archive_backend.h | 2 +-
 src/core/file_sys/archive_ncch.h    | 4 ++--
 src/core/global.h                   | 6 +++++-
 6 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 65c73f03b..ff6da91e7 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -61,6 +61,11 @@ Kernel::KernelSystem& Global() {
     return System::GetInstance().Kernel();
 }
 
+template <>
+Core::Timing& Global() {
+    return System::GetInstance().CoreTiming();
+}
+
 System::~System() = default;
 
 System::ResultStatus System::RunLoop(bool tight_loop) {
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 67fab0dae..493bb6344 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -11,8 +11,6 @@
 
 namespace Core {
 
-Timing* Timing::deserializing = nullptr;
-
 // Sort by time, unless the times are the same, in which case sort by the order added to the queue
 bool Timing::Event::operator>(const Timing::Event& right) const {
     return std::tie(time, fifo_order) > std::tie(right.time, right.fifo_order);
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index cbe17b36b..bb34c79b0 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -28,6 +28,7 @@
 #include "common/common_types.h"
 #include "common/logging/log.h"
 #include "common/threadsafe_queue.h"
+#include "core/global.h"
 
 // The timing we get from the assembly is 268,111,855.956 Hz
 // It is possible that this number isn't just an integer because the compiler could have
@@ -135,8 +136,6 @@ struct TimingEventType {
 };
 
 class Timing {
-private:
-    static Timing* deserializing;
 
 public:
     struct Event {
@@ -165,7 +164,7 @@ public:
             ar& userdata;
             std::string name;
             ar >> name;
-            type = Timing::deserializing->RegisterEvent(name, nullptr);
+            type = Global<Timing>().RegisterEvent(name, nullptr);
         }
         friend class boost::serialization::access;
 
@@ -291,11 +290,9 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         // event_types set during initialization of other things
-        deserializing = this;
         ar& global_timer;
         ar& timers;
         ar& current_timer;
-        deserializing = nullptr;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 6468c0630..658e6f20c 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -196,7 +196,7 @@ public:
     }
 
 protected:
-    std::unique_ptr<DelayGenerator> delay_generator; // TODO: Replace with virtual GetOpenDelayNs
+    std::unique_ptr<DelayGenerator> delay_generator;
 
 private:
     template <class Archive>
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index 2d38f9a2e..76b8d4655 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -68,8 +68,8 @@ protected:
     Service::FS::MediaType media_type;
 
 private:
-    NCCHArchive() = default; // NOTE: If the public ctor has behaviour, need to replace this with
-                             // *_construct_data
+    NCCHArchive() = default;
+
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& boost::serialization::base_object<ArchiveBackend>(*this);
diff --git a/src/core/global.h b/src/core/global.h
index 83bd4fc80..794d71f94 100644
--- a/src/core/global.h
+++ b/src/core/global.h
@@ -9,9 +9,13 @@ namespace Core {
 template <class T>
 T& Global();
 
-// Declare explicit specialisation to prevent im
+// Declare explicit specialisation to prevent automatic instantiation
 class System;
 template <>
 System& Global();
 
+class Timing;
+template <>
+Timing& Global();
+
 } // namespace Core

From bbf8e876ab9dfed345968c550ca44cf39237f2c1 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 16:26:24 +0000
Subject: [PATCH 089/129] Apply suggestions from code review

Co-Authored-By: Pengfei Zhu <zhupf321@gmail.com>
---
 src/video_core/pica_state.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 4e5a5f16b..1879528cb 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -5,7 +5,7 @@
 #pragma once
 
 #include <array>
-#include "boost/serialization/split_member.hpp"
+#include <boost/serialization/split_member.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "common/vector_math.h"
@@ -239,7 +239,7 @@ private:
     void load(Archive& ar, const unsigned int file_version) {
         u32 offset{};
         ar >> offset;
-        cmd_list.head_ptr = (u32*)VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr);
+        cmd_list.head_ptr = reinterpret_cast<u32*>(VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr));
         cmd_list.current_ptr = cmd_list.head_ptr + offset;
     }
 };

From 26f936406235c3b215512f4eabf31465f5fe8e9b Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 16:28:07 +0000
Subject: [PATCH 090/129] Apply suggestions from code review

Co-Authored-By: Ben <bene_thomas@web.de>
---
 src/common/memory_ref.h        | 4 ++--
 src/video_core/shader/shader.h | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
index c11beb04d..f1a3286ab 100644
--- a/src/common/memory_ref.h
+++ b/src/common/memory_ref.h
@@ -31,11 +31,11 @@ public:
     BufferMem() = default;
     BufferMem(u32 size) : data(std::vector<u8>(size)) {}
 
-    virtual u8* GetPtr() {
+    u8* GetPtr() override {
         return data.data();
     }
 
-    virtual u32 GetSize() const {
+    u32 GetSize() const override {
         return static_cast<u32>(data.size());
     }
 
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 6a5a33419..05a1e8b80 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -70,6 +70,7 @@ private:
     void serialize(Archive& ar, const unsigned int) {
         ar& pos;
         ar& quat;
+        ar& color;
         ar& tc0;
         ar& tc1;
         ar& tc0_w;

From d92b3e9754f635ed956fa11a769f29dab704a388 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 16:29:15 +0000
Subject: [PATCH 091/129] Code review changes - clarified HTTP serialization

---
 src/core/hle/service/http_c.h       | 27 +++++++++------------------
 src/core/hle/service/mic_u.cpp      |  2 ++
 src/video_core/primitive_assembly.h |  4 +---
 3 files changed, 12 insertions(+), 21 deletions(-)

diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h
index d94b47a45..490e06648 100644
--- a/src/core/hle/service/http_c.h
+++ b/src/core/hle/service/http_c.h
@@ -6,6 +6,7 @@
 
 #include <future>
 #include <memory>
+#include <optional>
 #include <string>
 #include <unordered_map>
 #include <vector>
@@ -215,24 +216,6 @@ public:
 #ifdef ENABLE_WEB_SERVICE
     httplib::Response response;
 #endif
-
-private:
-    template <class Archive>
-    void serialize(Archive& ar, const unsigned int) {
-        ar& handle;
-        ar& session_id;
-        ar& url;
-        ar& method;
-        ar& state;
-        ar& proxy;
-        ar& basic_auth;
-        ar& ssl_config;
-        ar& socket_buffer_size;
-        ar& headers;
-        ar& post_data;
-    }
-    friend class boost::serialization::access;
-
 };
 
 struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
@@ -453,10 +436,18 @@ private:
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        // NOTE: Serialization of the HTTP service is on a 'best effort' basis.
+        // There is a very good chance that saving/loading during a network connection will break,
+        // regardless!
         ar& boost::serialization::base_object<Kernel::SessionRequestHandler>(*this);
         ar& ClCertA.certificate;
         ar& ClCertA.private_key;
         ar& ClCertA.init;
+        ar& context_counter;
+        ar& client_certs_counter;
+        ar& client_certs;
+        // NOTE: `contexts` is not serialized because it contains non-serializable data. (i.e.
+        // handles to ongoing HTTP requests.) Serializing across HTTP contexts will break.
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index bd324ada2..08ef5473f 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -110,6 +110,7 @@ struct State {
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
+        ar& memory_ref;
         ar& sharedmem_size;
         ar& size;
         ar& offset;
@@ -139,6 +140,7 @@ struct MIC_U::Impl {
 
         if (shared_memory) {
             shared_memory->SetName("MIC_U:shared_memory");
+            state.memory_ref = shared_memory;
             state.sharedmem_buffer = shared_memory->GetPointer();
             state.sharedmem_size = size;
         }
diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h
index d6547dddd..404bc5316 100644
--- a/src/video_core/primitive_assembly.h
+++ b/src/video_core/primitive_assembly.h
@@ -5,10 +5,8 @@
 #pragma once
 
 #include <functional>
+#include <boost/serialization/access.hpp>
 #include "video_core/regs_pipeline.h"
-namespace boost::serialization {
-class access;
-}
 
 namespace Pica {
 

From 8f164a16ce9c7b2def438bf998e631c035679f2a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 17:08:27 +0000
Subject: [PATCH 092/129] Review changes

---
 CMakeLists.txt                             | 1 +
 externals/CMakeLists.txt                   | 2 +-
 src/CMakeLists.txt                         | 2 +-
 src/citra_qt/main.cpp                      | 2 +-
 src/core/core.cpp                          | 7 +------
 src/core/file_sys/archive_ncch.h           | 2 +-
 src/core/file_sys/archive_other_savedata.h | 2 --
 src/core/file_sys/archive_savedata.h       | 1 -
 src/core/file_sys/archive_selfncch.h       | 4 ++--
 src/core/hle/kernel/config_mem.h           | 4 ++--
 src/core/hle/kernel/hle_ipc.h              | 2 +-
 src/core/hle/service/err_f.cpp             | 3 ++-
 12 files changed, 13 insertions(+), 19 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index faa41ea54..315bc237d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,7 @@
 # CMake 3.8 required for 17 to be a valid value for CXX_STANDARD
 cmake_minimum_required(VERSION 3.8)
 if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.15)
+    # Don't override the warning flags in MSVC:
     cmake_policy(SET CMP0092 NEW)
 endif ()
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 49cca86a1..7d687a4dc 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -1,7 +1,7 @@
 # Definitions for all external bundled libraries
 
 # Suppress warnings from external libraries
-if (CMAKE_C_COMPILER_ID MATCHES "MSVC")
+if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
     add_compile_options(/W0)
 endif()
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d46641570..38cd0be79 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -42,7 +42,7 @@ if (MSVC)
         /Zc:externConstexpr
         /Zc:inline
     )
-    if (CMAKE_C_COMPILER_ID MATCHES "MSVC")
+    if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
         add_compile_options(
             /MP
             /Zc:throwingNew
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 6ceaea57d..a583e903a 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -1438,7 +1438,7 @@ void GMainWindow::OnCIAInstallFinished() {
 
 void GMainWindow::OnMenuRecentFile() {
     QAction* action = qobject_cast<QAction*>(sender());
-    assert(action);
+    ASSERT(action);
 
     const QString filename = action->data().toString();
     if (QFileInfo::exists(filename)) {
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ff6da91e7..589744367 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -33,6 +33,7 @@
 #include "core/hle/kernel/thread.h"
 #include "core/hle/service/fs/archive.h"
 #include "core/hle/service/gsp/gsp.h"
+#include "core/hle/service/pm/pm_app.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/sm/sm.h"
 #include "core/hw/gpu.h"
@@ -45,8 +46,6 @@
 #include "network/network.h"
 #include "video_core/video_core.h"
 
-#include "core/hle/service/pm/pm_app.h"
-
 namespace Core {
 
 /*static*/ System System::s_instance;
@@ -183,15 +182,11 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
     case Signal::Load: {
         LOG_INFO(Core, "Begin load");
         System::LoadState(param);
-        // auto stream = std::ifstream("save0.citrasave", std::fstream::binary);
-        // System::Load(stream, FileUtil::GetSize("save0.citrasave"));
         LOG_INFO(Core, "Load completed");
     } break;
     case Signal::Save: {
         LOG_INFO(Core, "Begin save");
         System::SaveState(param);
-        // auto stream = std::ofstream("save0.citrasave", std::fstream::binary);
-        // System::Save(stream);
         LOG_INFO(Core, "Save completed");
     } break;
     default:
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index 76b8d4655..95fe889ea 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -102,7 +102,7 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& boost::serialization::base_object<FileBackend>(*this);
-        ar& file_buffer; // TODO: See about a more efficient way to do this
+        ar& file_buffer;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/file_sys/archive_other_savedata.h b/src/core/file_sys/archive_other_savedata.h
index c5bf98a68..cc0cfe404 100644
--- a/src/core/file_sys/archive_other_savedata.h
+++ b/src/core/file_sys/archive_other_savedata.h
@@ -29,7 +29,6 @@ public:
     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
 
 private:
-    std::string mount_point; // TODO: Remove, unused?
     std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
 
     ArchiveFactory_OtherSaveDataPermitted() = default;
@@ -57,7 +56,6 @@ public:
     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
 
 private:
-    std::string mount_point; // TODO: Remove, unused?
     std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
 
     ArchiveFactory_OtherSaveDataGeneral() = default;
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index 6bb22f7a8..3f73adba3 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -28,7 +28,6 @@ public:
     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
 
 private:
-    std::string mount_point; // TODO: Remove this? seems unused
     std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
 
     ArchiveFactory_SaveData() = default;
diff --git a/src/core/file_sys/archive_selfncch.h b/src/core/file_sys/archive_selfncch.h
index d7b1cf301..68b48074f 100644
--- a/src/core/file_sys/archive_selfncch.h
+++ b/src/core/file_sys/archive_selfncch.h
@@ -58,12 +58,12 @@ public:
 
 private:
     /// Mapping of ProgramId -> NCCHData
-    std::unordered_map<u64, NCCHData>
-        ncch_data; // TODO: Remove this, or actually set the values here
+    std::unordered_map<u64, NCCHData> ncch_data;
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& boost::serialization::base_object<ArchiveFactory>(*this);
+        // NOTE: ncch_data is never written to, so we don't serialize it here
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index 74d934345..c466345ec 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -57,11 +57,11 @@ public:
     Handler();
     ConfigMemDef& GetConfigMem();
 
-    virtual u8* GetPtr() {
+    u8* GetPtr() override {
         return static_cast<u8*>(static_cast<void*>(&config_mem));
     }
 
-    virtual u32 GetSize() const {
+    u32 GetSize() const override {
         return sizeof(config_mem);
     }
 
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 046a31e2e..000486825 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -99,12 +99,12 @@ protected:
 
     struct SessionInfo {
         SessionInfo(std::shared_ptr<ServerSession> session, std::unique_ptr<SessionDataBase> data);
-        SessionInfo() = default;
 
         std::shared_ptr<ServerSession> session;
         std::unique_ptr<SessionDataBase> data;
 
     private:
+        SessionInfo() = default;
         template <class Archive>
         void serialize(Archive& ar, const unsigned int file_version) {
             ar& session;
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index f88ffef19..85759f9d2 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -15,7 +15,8 @@
 #include "core/hle/ipc_helpers.h"
 #include "core/hle/result.h"
 #include "core/hle/service/err_f.h"
-#undef exception_info
+#undef exception_info // We use 'exception_info' as a plain identifier, but MSVC defines this in one
+                      // of its many headers.
 
 SERIALIZE_EXPORT_IMPL(Service::ERR::ERR_F)
 

From 570fc45d03173c4ad6217c817fd2e259ab756896 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 17:11:35 +0000
Subject: [PATCH 093/129] Change boost submodule

---
 .gitmodules     | 2 +-
 externals/boost | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index b0bfcaee8..b247ccdbe 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
 [submodule "boost"]
     path = externals/boost
-    url = https://github.com/hamish-milne/ext-boost.git
+    url = https://github.com/citra-emu/ext-boost.git
 [submodule "nihstro"]
     path = externals/nihstro
     url = https://github.com/neobrain/nihstro.git
diff --git a/externals/boost b/externals/boost
index a37867de9..36603a1e6 160000
--- a/externals/boost
+++ b/externals/boost
@@ -1 +1 @@
-Subproject commit a37867de91767e3289068997bc004f842894ce1f
+Subproject commit 36603a1e665e849d29b1735a12c0a51284a10dd0

From 38e9eb379d97f8ba0914949a2e8c10b24c077840 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 17:23:54 +0000
Subject: [PATCH 094/129] Update src/CMakeLists.txt

---
 src/CMakeLists.txt | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 38cd0be79..96c7f35cd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -37,7 +37,6 @@ if (MSVC)
         /Zo
         /permissive-
         /EHsc
-        /std:c++17
         /volatile:iso
         /Zc:externConstexpr
         /Zc:inline

From de9ae140593a67523c71fa3d66bfd02a89d532fb Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 19:29:29 +0000
Subject: [PATCH 095/129] Only serialize wchar paths on windows

---
 src/core/file_sys/archive_backend.h | 2 ++
 src/core/hle/kernel/thread.cpp      | 3 +--
 src/video_core/pica_state.h         | 3 ++-
 3 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 658e6f20c..87a42b028 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -77,6 +77,7 @@ private:
         case LowPathType::Char:
             ar& string;
             break;
+#ifdef _WIN32
         case LowPathType::Wchar:
             static_assert(sizeof(wchar_t) == sizeof(char16_t));
             {
@@ -87,6 +88,7 @@ private:
                 }
             }
             break;
+#endif
         default:
             break;
         }
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 465ba46f5..0567ef325 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -63,8 +63,7 @@ void Thread::Acquire(Thread* thread) {
 }
 
 Thread::Thread(KernelSystem& kernel, u32 core_id)
-    : WaitObject(kernel), context(kernel.GetThreadManager(core_id).NewContext()),
-      core_id(core_id),
+    : WaitObject(kernel), context(kernel.GetThreadManager(core_id).NewContext()), core_id(core_id),
       thread_manager(kernel.GetThreadManager(core_id)) {}
 Thread::~Thread() {}
 
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 1879528cb..3a9ec79c5 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -239,7 +239,8 @@ private:
     void load(Archive& ar, const unsigned int file_version) {
         u32 offset{};
         ar >> offset;
-        cmd_list.head_ptr = reinterpret_cast<u32*>(VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr));
+        cmd_list.head_ptr =
+            reinterpret_cast<u32*>(VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr));
         cmd_list.current_ptr = cmd_list.head_ptr + offset;
     }
 };

From 841255cd16f0a9578cd90a860232e34c209c3c3a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 28 Mar 2020 21:40:18 +0000
Subject: [PATCH 096/129] Attempt to fix the linux builds

---
 src/audio_core/CMakeLists.txt      | 2 +-
 src/core/file_sys/romfs_reader.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 3cb9b538d..63a566596 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -35,7 +35,7 @@ add_library(audio_core STATIC
 
 create_target_directory_groups(audio_core)
 
-target_link_libraries(audio_core PUBLIC common core)
+target_link_libraries(audio_core PUBLIC common)
 target_link_libraries(audio_core PRIVATE SoundTouch teakra)
 
 if(ENABLE_MF)
diff --git a/src/core/file_sys/romfs_reader.cpp b/src/core/file_sys/romfs_reader.cpp
index a1ff38945..4c83515b3 100644
--- a/src/core/file_sys/romfs_reader.cpp
+++ b/src/core/file_sys/romfs_reader.cpp
@@ -12,7 +12,7 @@ std::size_t DirectRomFSReader::ReadFile(std::size_t offset, std::size_t length,
     if (length == 0)
         return 0; // Crypto++ does not like zero size buffer
     file.Seek(file_offset + offset, SEEK_SET);
-    std::size_t read_length = std::min(length, data_size - offset);
+    std::size_t read_length = std::min(length, static_cast<std::size_t>(data_size) - offset);
     read_length = file.ReadBytes(buffer, read_length);
     if (is_encrypted) {
         CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption d(key.data(), key.size(), ctr.data());

From 8f059ae3982c5b6a1ae9d313ea4229563328423c Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 29 Mar 2020 11:39:46 +0100
Subject: [PATCH 097/129] Apply suggestions from code review

Co-Authored-By: Mat M. <mathew1800@gmail.com>
---
 src/common/archives.h                     |  2 +-
 src/common/memory_ref.h                   |  4 ++--
 src/common/serialization/boost_flat_set.h |  2 +-
 src/common/thread_queue_list.h            |  6 +++---
 src/core/arm/arm_interface.h              | 18 +++++++++---------
 src/core/hle/kernel/config_mem.h          |  2 +-
 src/core/hle/kernel/hle_ipc.cpp           |  4 ++--
 src/core/hle/kernel/kernel.cpp            |  3 ++-
 src/core/hle/kernel/svc.cpp               |  4 ++--
 9 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/src/common/archives.h b/src/common/archives.h
index 993128197..4f8b735d3 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -4,7 +4,7 @@
 
 #pragma once
 
-#include "boost/archive/binary_iarchive.hpp"
+#include <boost/archive/binary_iarchive.hpp>
 #include "boost/archive/binary_oarchive.hpp"
 #include "boost/serialization/export.hpp"
 
diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
index f1a3286ab..65946fc58 100644
--- a/src/common/memory_ref.h
+++ b/src/common/memory_ref.h
@@ -29,7 +29,7 @@ private:
 class BufferMem : public BackingMem {
 public:
     BufferMem() = default;
-    BufferMem(u32 size) : data(std::vector<u8>(size)) {}
+    explicit BufferMem(std::size_t size) : data(size) {}
 
     u8* GetPtr() override {
         return data.data();
@@ -77,7 +77,7 @@ public:
     inline u8* GetPtr() {
         return cptr;
     }
-    inline operator bool() const {
+    explicit operator bool() const {
         return cptr != nullptr;
     }
     inline const u8* GetPtr() const {
diff --git a/src/common/serialization/boost_flat_set.h b/src/common/serialization/boost_flat_set.h
index 7fe0fe097..c47e8c1a7 100644
--- a/src/common/serialization/boost_flat_set.h
+++ b/src/common/serialization/boost_flat_set.h
@@ -19,7 +19,7 @@ void load(Archive& ar, boost::container::flat_set<T>& set, const unsigned int fi
     u64 count{};
     ar >> count;
     set.clear();
-    for (auto i = 0; i < count; i++) {
+    for (u64 i = 0; i < count; i++) {
         T value{};
         ar >> value;
         set.insert(value);
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index c25bbe585..abeb465ad 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -167,7 +167,7 @@ private:
         } else if (q == UnlinkedTag()) {
             return -1;
         } else {
-            return static_cast<s32>(q - &queues[0]);
+            return q - queues.data();
         }
     }
 
@@ -186,8 +186,8 @@ private:
     void save(Archive& ar, const unsigned int file_version) const {
         s32 idx = ToIndex(first);
         ar << idx;
-        for (auto i = 0; i < NUM_QUEUES; i++) {
-            s32 idx1 = ToIndex(queues[i].next_nonempty);
+        for (size_t i = 0; i < NUM_QUEUES; i++) {
+            const s32 idx1 = ToIndex(queues[i].next_nonempty);
             ar << idx1;
             ar << queues[i].data;
         }
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index b02e3941f..e39e1b9fa 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -28,12 +28,12 @@ public:
 
         template <class Archive>
         void save(Archive& ar, const unsigned int file_version) const {
-            for (auto i = 0; i < 16; i++) {
-                auto r = GetCpuRegister(i);
+            for (size_t i = 0; i < 16; i++) {
+                const auto r = GetCpuRegister(i);
                 ar << r;
             }
-            for (auto i = 0; i < 16; i++) {
-                auto r = GetFpuRegister(i);
+            for (size_t i = 0; i < 16; i++) {
+                const auto r = GetFpuRegister(i);
                 ar << r;
             }
             auto r1 = GetCpsr();
@@ -47,11 +47,11 @@ public:
         template <class Archive>
         void load(Archive& ar, const unsigned int file_version) {
             u32 r;
-            for (auto i = 0; i < 16; i++) {
+            for (size_t i = 0; i < 16; i++) {
                 ar >> r;
                 SetCpuRegister(i, r);
             }
-            for (auto i = 0; i < 16; i++) {
+            for (size_t i = 0; i < 16; i++) {
                 ar >> r;
                 SetFpuRegister(i, r);
             }
@@ -247,7 +247,7 @@ private:
         ar << id;
         auto page_table = GetPageTable();
         ar << page_table;
-        for (auto i = 0; i < 15; i++) {
+        for (size_t i = 0; i < 15; i++) {
             auto r = GetReg(i);
             ar << r;
         }
@@ -255,7 +255,7 @@ private:
         ar << pc;
         auto cpsr = GetCPSR();
         ar << cpsr;
-        for (auto i = 0; i < 32; i++) {
+        for (size_t i = 0; i < 32; i++) {
             auto r = GetVFPReg(i);
             ar << r;
         }
@@ -278,7 +278,7 @@ private:
         ar >> page_table;
         SetPageTable(page_table);
         u32 r;
-        for (auto i = 0; i < 15; i++) {
+        for (size_t = 0; i < 15; i++) {
             ar >> r;
             SetReg(i, r);
         }
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index c466345ec..a81a5d291 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -58,7 +58,7 @@ public:
     ConfigMemDef& GetConfigMem();
 
     u8* GetPtr() override {
-        return static_cast<u8*>(static_cast<void*>(&config_mem));
+        return reinterpret_cast<u8*>(&config_mem));
     }
 
     u32 GetSize() const override {
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 23f577490..88bd6b71b 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -21,7 +21,7 @@ class HLERequestContext::ThreadCallback : public Kernel::WakeupCallback {
 public:
     ThreadCallback(std::shared_ptr<HLERequestContext> context_,
                    std::shared_ptr<HLERequestContext::WakeupCallback> callback_)
-        : context(context_), callback(callback_) {}
+        : context(std::move(context_)), callback(std::move(callback_)) {}
     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
                 std::shared_ptr<WaitObject> object) {
         ASSERT(thread->status == ThreadStatus::WaitHleEvent);
@@ -296,7 +296,7 @@ MappedBuffer::MappedBuffer() : memory(&Core::Global<Core::System>().Memory()) {}
 
 MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process,
                            u32 descriptor, VAddr address, u32 id)
-    : memory(&memory), id(id), address(address), process(process) {
+    : memory(&memory), id(id), address(address), process(std::move(process)) {
     IPC::MappedBufferDescInfo desc{descriptor};
     size = desc.size;
     perms = desc.perms;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 8afddb499..11ef90771 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -24,7 +24,8 @@ KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
                            u32 num_cores, u8 n3ds_mode)
     : memory(memory), timing(timing),
       prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
-    for (auto i = 0; i < memory_regions.size(); i++) {
+std::generate(memory_regions.begin(), memory_regions.end(),
+              [] { return std::make_shared<MemoryRegionInfo>(); });
         memory_regions[i] = std::make_shared<MemoryRegionInfo>();
     }
     MemoryInit(system_mode, n3ds_mode);
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 9aeeea236..8f1ba5e01 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -409,7 +409,7 @@ static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::Memory
 
 class SVC_SyncCallback : public Kernel::WakeupCallback {
 public:
-    SVC_SyncCallback(bool do_output_) : do_output(do_output_) {}
+    explicit SVC_SyncCallback(bool do_output_) : do_output(do_output_) {}
     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
                 std::shared_ptr<WaitObject> object) {
 
@@ -442,7 +442,7 @@ private:
 
 class SVC_IPCCallback : public Kernel::WakeupCallback {
 public:
-    SVC_IPCCallback(Core::System& system_) : system(system_) {}
+    explicit SVC_IPCCallback(Core::System& system_) : system(system_) {}
 
     void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
                 std::shared_ptr<WaitObject> object) {

From 04aa351c40a19c67382da5470a37b79df477367a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 29 Mar 2020 16:14:36 +0100
Subject: [PATCH 098/129] Code review - general gardening

---
 src/common/construct.h             | 15 ++++-----
 src/common/memory_ref.h            | 49 ++++++++++++++++--------------
 src/common/thread_queue_list.h     | 10 +++---
 src/core/arm/arm_interface.h       | 38 +++++++++++------------
 src/core/hle/kernel/config_mem.h   |  8 +++--
 src/core/hle/kernel/kernel.cpp     |  6 ++--
 src/core/hle/kernel/shared_page.h  | 10 ++++--
 src/core/hle/service/cecd/cecd.cpp | 43 +++++++++++++++-----------
 src/core/hle/service/http_c.cpp    |  4 +--
 src/core/memory.cpp                | 30 ++++++++++++++----
 10 files changed, 125 insertions(+), 88 deletions(-)

diff --git a/src/common/construct.h b/src/common/construct.h
index 4e48ee60d..cb47bb46e 100644
--- a/src/common/construct.h
+++ b/src/common/construct.h
@@ -6,28 +6,29 @@
 
 #include <boost/serialization/serialization.hpp>
 
+/// Allows classes to define `save_construct` and `load_construct` methods for serialization
+/// This is used where we don't call the default constructor during deserialization, as a shortcut
+/// instead of using load_construct_data directly
 class construct_access {
 public:
     template <class Archive, class T>
-    static inline void save_construct(Archive& ar, const T* t, const unsigned int file_version) {
+    static void save_construct(Archive& ar, const T* t, const unsigned int file_version) {
         t->save_construct(ar, file_version);
     }
     template <class Archive, class T>
-    static inline void load_construct(Archive& ar, T* t, const unsigned int file_version) {
+    static void load_construct(Archive& ar, T* t, const unsigned int file_version) {
         T::load_construct(ar, t, file_version);
     }
 };
 
 #define BOOST_SERIALIZATION_CONSTRUCT(T)                                                           \
-    namespace boost {                                                                              \
-    namespace serialization {                                                                      \
+    namespace boost::serialization {                                                               \
     template <class Archive>                                                                       \
-    inline void save_construct_data(Archive& ar, const T* t, const unsigned int file_version) {    \
+    void save_construct_data(Archive& ar, const T* t, const unsigned int file_version) {           \
         construct_access::save_construct(ar, t, file_version);                                     \
     }                                                                                              \
     template <class Archive>                                                                       \
-    inline void load_construct_data(Archive& ar, T* t, const unsigned int file_version) {          \
+    void load_construct_data(Archive& ar, T* t, const unsigned int file_version) {                 \
         construct_access::load_construct(ar, t, file_version);                                     \
     }                                                                                              \
-    }                                                                                              \
     }
diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
index 65946fc58..30eabbaee 100644
--- a/src/common/memory_ref.h
+++ b/src/common/memory_ref.h
@@ -17,7 +17,8 @@ class BackingMem {
 public:
     virtual ~BackingMem() = default;
     virtual u8* GetPtr() = 0;
-    virtual u32 GetSize() const = 0;
+    virtual const u8* GetPtr() const = 0;
+    virtual std::size_t GetSize() const = 0;
 
 private:
     template <class Archive>
@@ -35,7 +36,11 @@ public:
         return data.data();
     }
 
-    u32 GetSize() const override {
+    const u8* GetPtr() const override {
+        return data.data();
+    }
+
+    std::size_t GetSize() const override {
         return static_cast<u32>(data.size());
     }
 
@@ -66,51 +71,51 @@ public:
         : backing_mem(std::move(backing_mem_)), offset(0) {
         Init();
     }
-    MemoryRef(std::shared_ptr<BackingMem> backing_mem_, u32 offset_)
+    MemoryRef(std::shared_ptr<BackingMem> backing_mem_, u64 offset_)
         : backing_mem(std::move(backing_mem_)), offset(offset_) {
         ASSERT(offset < backing_mem->GetSize());
         Init();
     }
-    inline operator u8*() {
-        return cptr;
-    }
-    inline u8* GetPtr() {
-        return cptr;
-    }
     explicit operator bool() const {
         return cptr != nullptr;
     }
-    inline const u8* GetPtr() const {
+    operator u8*() {
         return cptr;
     }
-    inline u32 GetSize() const {
+    u8* GetPtr() {
+        return cptr;
+    }
+    operator const u8*() const {
+        return cptr;
+    }
+    const u8* GetPtr() const {
+        return cptr;
+    }
+    std::size_t GetSize() const {
         return csize;
     }
-    inline void operator+=(u32 offset_by) {
+    MemoryRef& operator+=(u32 offset_by) {
         ASSERT(offset_by < csize);
         offset += offset_by;
         Init();
+        return *this;
     }
-    inline MemoryRef operator+(u32 offset_by) const {
+    MemoryRef operator+(u32 offset_by) const {
         ASSERT(offset_by < csize);
         return MemoryRef(backing_mem, offset + offset_by);
     }
-    inline u8* operator+(std::size_t offset_by) const {
-        ASSERT(offset_by < csize);
-        return cptr + offset_by;
-    }
 
 private:
-    std::shared_ptr<BackingMem> backing_mem = nullptr;
-    u32 offset = 0;
+    std::shared_ptr<BackingMem> backing_mem{};
+    u64 offset{};
     // Cached values for speed
-    u8* cptr = nullptr;
-    u32 csize = 0;
+    u8* cptr{};
+    std::size_t csize{};
 
     void Init() {
         if (backing_mem) {
             cptr = backing_mem->GetPtr() + offset;
-            csize = static_cast<u32>(backing_mem->GetSize() - offset);
+            csize = static_cast<std::size_t>(backing_mem->GetSize() - offset);
         } else {
             cptr = nullptr;
             csize = 0;
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index abeb465ad..1ba68e1e4 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -161,7 +161,7 @@ private:
     // The priority level queues of thread ids.
     std::array<Queue, NUM_QUEUES> queues;
 
-    s32 ToIndex(Queue* q) const {
+    s64 ToIndex(const Queue* q) const {
         if (q == nullptr) {
             return -2;
         } else if (q == UnlinkedTag()) {
@@ -171,7 +171,7 @@ private:
         }
     }
 
-    Queue* ToPointer(s32 idx) {
+    Queue* ToPointer(s64 idx) {
         if (idx == -1) {
             return UnlinkedTag();
         } else if (idx < 0) {
@@ -184,10 +184,10 @@ private:
     friend class boost::serialization::access;
     template <class Archive>
     void save(Archive& ar, const unsigned int file_version) const {
-        s32 idx = ToIndex(first);
+        const s64 idx = ToIndex(first);
         ar << idx;
         for (size_t i = 0; i < NUM_QUEUES; i++) {
-            const s32 idx1 = ToIndex(queues[i].next_nonempty);
+            const s64 idx1 = ToIndex(queues[i].next_nonempty);
             ar << idx1;
             ar << queues[i].data;
         }
@@ -195,7 +195,7 @@ private:
 
     template <class Archive>
     void load(Archive& ar, const unsigned int file_version) {
-        s32 idx;
+        s64 idx;
         ar >> idx;
         first = ToPointer(idx);
         for (auto i = 0; i < NUM_QUEUES; i++) {
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index e39e1b9fa..fca488586 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -36,11 +36,11 @@ public:
                 const auto r = GetFpuRegister(i);
                 ar << r;
             }
-            auto r1 = GetCpsr();
+            const auto r1 = GetCpsr();
             ar << r1;
-            auto r2 = GetFpscr();
+            const auto r2 = GetFpscr();
             ar << r2;
-            auto r3 = GetFpexc();
+            const auto r3 = GetFpexc();
             ar << r3;
         }
 
@@ -245,26 +245,26 @@ private:
     void save(Archive& ar, const unsigned int file_version) const {
         ar << timer;
         ar << id;
-        auto page_table = GetPageTable();
+        const auto page_table = GetPageTable();
         ar << page_table;
-        for (size_t i = 0; i < 15; i++) {
-            auto r = GetReg(i);
+        for (int i = 0; i < 15; i++) {
+            const auto r = GetReg(i);
             ar << r;
         }
-        auto pc = GetPC();
+        const auto pc = GetPC();
         ar << pc;
-        auto cpsr = GetCPSR();
+        const auto cpsr = GetCPSR();
         ar << cpsr;
-        for (size_t i = 0; i < 32; i++) {
-            auto r = GetVFPReg(i);
+        for (int i = 0; i < 32; i++) {
+            const auto r = GetVFPReg(i);
             ar << r;
         }
-        for (auto i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
-            auto r = GetVFPSystemReg(static_cast<VFPSystemRegister>(i));
+        for (size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
+            const auto r = GetVFPSystemReg(static_cast<VFPSystemRegister>(i));
             ar << r;
         }
-        for (auto i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
-            auto r = GetCP15Register(static_cast<CP15Register>(i));
+        for (size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
+            const auto r = GetCP15Register(static_cast<CP15Register>(i));
             ar << r;
         }
     }
@@ -274,11 +274,11 @@ private:
         PurgeState();
         ar >> timer;
         ar >> id;
-        std::shared_ptr<Memory::PageTable> page_table = nullptr;
+        std::shared_ptr<Memory::PageTable> page_table{};
         ar >> page_table;
         SetPageTable(page_table);
         u32 r;
-        for (size_t = 0; i < 15; i++) {
+        for (int i = 0; i < 15; i++) {
             ar >> r;
             SetReg(i, r);
         }
@@ -286,15 +286,15 @@ private:
         SetPC(r);
         ar >> r;
         SetCPSR(r);
-        for (auto i = 0; i < 32; i++) {
+        for (int i = 0; i < 32; i++) {
             ar >> r;
             SetVFPReg(i, r);
         }
-        for (auto i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
+        for (size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
             ar >> r;
             SetVFPSystemReg(static_cast<VFPSystemRegister>(i), r);
         }
-        for (auto i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
+        for (size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
             ar >> r;
             SetCP15Register(static_cast<CP15Register>(i), r);
         }
diff --git a/src/core/hle/kernel/config_mem.h b/src/core/hle/kernel/config_mem.h
index a81a5d291..b592aff7a 100644
--- a/src/core/hle/kernel/config_mem.h
+++ b/src/core/hle/kernel/config_mem.h
@@ -58,10 +58,14 @@ public:
     ConfigMemDef& GetConfigMem();
 
     u8* GetPtr() override {
-        return reinterpret_cast<u8*>(&config_mem));
+        return reinterpret_cast<u8*>(&config_mem);
     }
 
-    u32 GetSize() const override {
+    const u8* GetPtr() const override {
+        return reinterpret_cast<const u8*>(&config_mem);
+    }
+
+    std::size_t GetSize() const override {
         return sizeof(config_mem);
     }
 
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 11ef90771..f0974f88a 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -24,10 +24,8 @@ KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
                            u32 num_cores, u8 n3ds_mode)
     : memory(memory), timing(timing),
       prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
-std::generate(memory_regions.begin(), memory_regions.end(),
-              [] { return std::make_shared<MemoryRegionInfo>(); });
-        memory_regions[i] = std::make_shared<MemoryRegionInfo>();
-    }
+    std::generate(memory_regions.begin(), memory_regions.end(),
+                  [] { return std::make_shared<MemoryRegionInfo>(); });
     MemoryInit(system_mode, n3ds_mode);
 
     resource_limits = std::make_unique<ResourceLimitList>(*this);
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index b74470b4a..c4b174db4 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -99,11 +99,15 @@ public:
 
     SharedPageDef& GetSharedPage();
 
-    virtual u8* GetPtr() {
-        return static_cast<u8*>(static_cast<void*>(&shared_page));
+    u8* GetPtr() override {
+        return reinterpret_cast<u8*>(&shared_page);
     }
 
-    virtual u32 GetSize() const {
+    const u8* GetPtr() const override {
+        return reinterpret_cast<const u8*>(&shared_page);
+    }
+
+    std::size_t GetSize() const override {
         return sizeof(shared_page);
     }
 
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 36263f622..8db49fc82 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -106,7 +106,7 @@ void Module::Interface::Open(Kernel::HLERequestContext& ctx) {
         } else {
             session_data->file = std::move(file_result).Unwrap();
             rb.Push(RESULT_SUCCESS);
-            rb.Push<u32>(session_data->file->GetSize()); // Return file size
+            rb.Push<u32>(static_cast<u32>(session_data->file->GetSize())); // Return file size
         }
 
         if (path_type == CecDataPathType::MboxProgramId) {
@@ -154,8 +154,8 @@ void Module::Interface::Read(Kernel::HLERequestContext& ctx) {
         break;
     default: // If not directory, then it is a file
         std::vector<u8> buffer(write_buffer_size);
-        const u32 bytes_read =
-            session_data->file->Read(0, write_buffer_size, buffer.data()).Unwrap();
+        const u32 bytes_read = static_cast<u32>(
+            session_data->file->Read(0, write_buffer_size, buffer.data()).Unwrap());
 
         write_buffer.Write(buffer.data(), 0, write_buffer_size);
         session_data->file->Close();
@@ -197,7 +197,8 @@ void Module::Interface::ReadMessage(Kernel::HLERequestContext& ctx) {
         auto message = std::move(message_result).Unwrap();
         std::vector<u8> buffer(buffer_size);
 
-        const u32 bytes_read = message->Read(0, buffer_size, buffer.data()).Unwrap();
+        const u32 bytes_read =
+            static_cast<u32>(message->Read(0, buffer_size, buffer.data()).Unwrap());
         write_buffer.Write(buffer.data(), 0, buffer_size);
         message->Close();
 
@@ -266,7 +267,8 @@ void Module::Interface::ReadMessageWithHMAC(Kernel::HLERequestContext& ctx) {
         auto message = std::move(message_result).Unwrap();
         std::vector<u8> buffer(buffer_size);
 
-        const u32 bytes_read = message->Read(0, buffer_size, buffer.data()).Unwrap();
+        const u32 bytes_read =
+            static_cast<u32>(message->Read(0, buffer_size, buffer.data()).Unwrap());
         write_buffer.Write(buffer.data(), 0, buffer_size);
         message->Close();
 
@@ -367,8 +369,8 @@ void Module::Interface::Write(Kernel::HLERequestContext& ctx) {
                                      buffer);
         }
 
-        const u32 bytes_written =
-            session_data->file->Write(0, buffer.size(), true, buffer.data()).Unwrap();
+        const u32 bytes_written = static_cast<u32>(
+            session_data->file->Write(0, buffer.size(), true, buffer.data()).Unwrap());
         session_data->file->Close();
 
         rb.Push(RESULT_SUCCESS);
@@ -429,7 +431,8 @@ void Module::Interface::WriteMessage(Kernel::HLERequestContext& ctx) {
                   msg_header.sender_id, msg_header.sender_id2, msg_header.send_count,
                   msg_header.forward_count, msg_header.user_data);
 
-        const u32 bytes_written = message->Write(0, buffer_size, true, buffer.data()).Unwrap();
+        const u32 bytes_written =
+            static_cast<u32>(message->Write(0, buffer_size, true, buffer.data()).Unwrap());
         message->Close();
 
         rb.Push(RESULT_SUCCESS);
@@ -515,7 +518,8 @@ void Module::Interface::WriteMessageWithHMAC(Kernel::HLERequestContext& ctx) {
         hmac.CalculateDigest(hmac_digest.data(), message_body.data(), msg_header.body_size);
         std::memcpy(buffer.data() + hmac_offset, hmac_digest.data(), hmac_size);
 
-        const u32 bytes_written = message->Write(0, buffer_size, true, buffer.data()).Unwrap();
+        const u32 bytes_written =
+            static_cast<u32>(message->Write(0, buffer_size, true, buffer.data()).Unwrap());
         message->Close();
 
         rb.Push(RESULT_SUCCESS);
@@ -757,7 +761,8 @@ void Module::Interface::OpenAndWrite(Kernel::HLERequestContext& ctx) {
                 cecd->CheckAndUpdateFile(path_type, ncch_program_id, buffer);
             }
 
-            const u32 bytes_written = file->Write(0, buffer.size(), true, buffer.data()).Unwrap();
+            const u32 bytes_written =
+                static_cast<u32>(file->Write(0, buffer.size(), true, buffer.data()).Unwrap());
             file->Close();
 
             rb.Push(RESULT_SUCCESS);
@@ -806,7 +811,8 @@ void Module::Interface::OpenAndRead(Kernel::HLERequestContext& ctx) {
             auto file = std::move(file_result).Unwrap();
             std::vector<u8> buffer(buffer_size);
 
-            const u32 bytes_read = file->Read(0, buffer_size, buffer.data()).Unwrap();
+            const u32 bytes_read =
+                static_cast<u32>(file->Read(0, buffer_size, buffer.data()).Unwrap());
             write_buffer.Write(buffer.data(), 0, buffer_size);
             file->Close();
 
@@ -937,7 +943,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
     constexpr u32 max_num_boxes = 24;
     constexpr u32 name_size = 16;      // fixed size 16 characters long
     constexpr u32 valid_name_size = 8; // 8 characters are valid, the rest are null
-    const u32 file_size = file_buffer.size();
+    const u32 file_size = static_cast<u32>(file_buffer.size());
 
     switch (path_type) {
     case CecDataPathType::MboxList: {
@@ -1021,7 +1027,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
                 std::u16string u16_filename;
 
                 // Loop through entries but don't add mboxlist____ to itself.
-                for (auto i = 0; i < entry_count; i++) {
+                for (u32 i = 0; i < entry_count; i++) {
                     u16_filename = std::u16string(entries[i].filename);
                     file_name = Common::UTF16ToUTF8(u16_filename);
 
@@ -1212,7 +1218,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
         std::string file_name;
         std::u16string u16_filename;
 
-        for (auto i = 0; i < entry_count; i++) {
+        for (u32 i = 0; i < entry_count; i++) {
             u16_filename = std::u16string(entries[i].filename);
             file_name = Common::UTF16ToUTF8(u16_filename);
 
@@ -1230,7 +1236,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
                 auto message_result = cecd_system_save_data_archive->OpenFile(message_path, mode);
 
                 auto message = std::move(message_result).Unwrap();
-                const u32 message_size = message->GetSize();
+                const u32 message_size = static_cast<u32>(message->GetSize());
                 std::vector<u8> buffer(message_size);
 
                 message->Read(0, message_size, buffer.data()).Unwrap();
@@ -1304,7 +1310,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
         std::string file_name;
         std::u16string u16_filename;
 
-        for (auto i = 0; i < entry_count; i++) {
+        for (u32 i = 0; i < entry_count; i++) {
             u16_filename = std::u16string(entries[i].filename);
             file_name = Common::UTF16ToUTF8(u16_filename);
 
@@ -1320,7 +1326,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
                 auto message_result = cecd_system_save_data_archive->OpenFile(message_path, mode);
 
                 auto message = std::move(message_result).Unwrap();
-                const u32 message_size = message->GetSize();
+                const u32 message_size = static_cast<u32>(message->GetSize());
                 std::vector<u8> buffer(message_size);
 
                 message->Read(0, message_size, buffer.data()).Unwrap();
@@ -1353,7 +1359,8 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
     case CecDataPathType::MboxData:
     case CecDataPathType::MboxIcon:
     case CecDataPathType::MboxTitle:
-    default: {}
+    default: {
+    }
     }
 }
 
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp
index af639e493..4879ab371 100644
--- a/src/core/hle/service/http_c.cpp
+++ b/src/core/hle/service/http_c.cpp
@@ -83,10 +83,10 @@ void Context::MakeRequest() {
         client = std::move(ssl_client);
 
         if (auto client_cert = ssl_config.client_cert_ctx.lock()) {
-            SSL_CTX_use_certificate_ASN1(ctx, client_cert->certificate.size(),
+            SSL_CTX_use_certificate_ASN1(ctx, static_cast<int>(client_cert->certificate.size()),
                                          client_cert->certificate.data());
             SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ctx, client_cert->private_key.data(),
-                                        client_cert->private_key.size());
+                                        static_cast<long>(client_cert->private_key.size()));
         }
 
         // TODO(B3N30): Check for SSLOptions-Bits and set the verify method accordingly
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index a0fa2a738..c0c030de1 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -100,7 +100,7 @@ public:
 
     Impl();
 
-    virtual u8* GetPtr(Region r) {
+    const u8* GetPtr(Region r) const {
         switch (r) {
         case Region::VRAM:
             return vram.get();
@@ -115,7 +115,22 @@ public:
         }
     }
 
-    virtual u32 GetSize(Region r) const {
+    u8* GetPtr(Region r) {
+        switch (r) {
+        case Region::VRAM:
+            return vram.get();
+        case Region::DSP:
+            return dsp->GetDspMemory().data();
+        case Region::FCRAM:
+            return fcram.get();
+        case Region::N3DS:
+            return n3ds_extra_ram.get();
+        default:
+            UNREACHABLE();
+        }
+    }
+
+    u32 GetSize(Region r) const {
         switch (r) {
         case Region::VRAM:
             return VRAM_SIZE;
@@ -158,11 +173,14 @@ template <Region R>
 class MemorySystem::BackingMemImpl : public BackingMem {
 public:
     BackingMemImpl() : impl(*Core::Global<Core::System>().Memory().impl) {}
-    BackingMemImpl(MemorySystem::Impl& impl_) : impl(impl_) {}
-    virtual u8* GetPtr() {
+    explicit BackingMemImpl(MemorySystem::Impl& impl_) : impl(impl_) {}
+    u8* GetPtr() override {
         return impl.GetPtr(R);
     }
-    virtual u32 GetSize() const {
+    const u8* GetPtr() const override {
+        return impl.GetPtr(R);
+    }
+    std::size_t GetSize() const override {
         return impl.GetSize(R);
     }
 
@@ -884,7 +902,7 @@ void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data)
 
 u32 MemorySystem::GetFCRAMOffset(const u8* pointer) {
     ASSERT(pointer >= impl->fcram.get() && pointer <= impl->fcram.get() + Memory::FCRAM_N3DS_SIZE);
-    return pointer - impl->fcram.get();
+    return static_cast<u32>(pointer - impl->fcram.get());
 }
 
 u8* MemorySystem::GetFCRAMPointer(u32 offset) {

From 6760ea18b6a63ae9e0afecffcecd081890991b88 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 29 Mar 2020 18:56:25 +0100
Subject: [PATCH 099/129] Serialize ArchiveManager and other code review
 actions

---
 src/core/core.cpp                          |  2 ++
 src/core/file_sys/archive_backend.h        | 22 ++++++++++------------
 src/core/file_sys/archive_extsavedata.cpp  |  9 +++++++++
 src/core/file_sys/archive_other_savedata.h |  1 +
 src/core/file_sys/archive_savedata.h       |  1 +
 src/core/file_sys/archive_selfncch.h       |  3 ++-
 src/core/file_sys/file_backend.h           |  1 -
 src/core/file_sys/layered_fs.h             |  9 +--------
 src/core/file_sys/savedata_archive.h       |  5 +++--
 src/core/hle/kernel/hle_ipc.h              |  3 ---
 src/core/hle/kernel/process.cpp            |  2 +-
 src/core/hle/kernel/process.h              |  1 +
 src/core/hle/service/ac/ac.h               |  2 --
 src/core/hle/service/act/act.h             |  2 +-
 src/core/hle/service/am/am.h               | 21 ++++++++++++++-------
 src/core/hle/service/apt/applet_manager.h  |  1 +
 src/core/hle/service/apt/apt.cpp           |  2 ++
 src/core/hle/service/apt/apt.h             |  7 +------
 src/core/hle/service/boss/boss.h           |  2 +-
 src/core/hle/service/cam/cam.h             |  7 ++++++-
 src/core/hle/service/cecd/cecd.cpp         |  2 ++
 src/core/hle/service/cecd/cecd.h           |  2 +-
 src/core/hle/service/cfg/cfg.cpp           |  2 ++
 src/core/hle/service/csnd/csnd_snd.h       |  6 +-----
 src/core/hle/service/dsp/dsp_dsp.h         |  9 ++++-----
 src/core/hle/service/fs/archive.h          |  6 ++++--
 src/core/hle/service/fs/directory.cpp      |  2 ++
 src/core/hle/service/fs/file.cpp           |  1 +
 src/core/hle/service/fs/file.h             |  1 +
 src/core/hle/service/fs/fs_user.h          |  1 +
 src/core/hle/service/gsp/gsp_gpu.h         |  2 ++
 src/core/hle/service/hid/hid.cpp           |  7 +++++--
 src/core/hle/service/ir/extra_hid.h        |  1 -
 src/core/hle/service/ir/ir_rst.cpp         |  2 ++
 src/core/hle/service/ir/ir_user.cpp        |  1 +
 src/core/hle/service/ndm/ndm_u.h           |  1 +
 src/core/hle/service/nfc/nfc.cpp           |  2 ++
 src/core/hle/service/nfc/nfc.h             |  8 ++++++++
 src/core/hle/service/nwm/nwm_uds.cpp       |  2 +-
 src/core/hle/service/service.h             |  1 -
 src/core/hle/service/sm/srv.cpp            |  3 ++-
 src/network/CMakeLists.txt                 |  2 +-
 src/network/room_member.h                  |  2 +-
 43 files changed, 102 insertions(+), 67 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 589744367..2928d50e7 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -1,3 +1,4 @@
+#pragma optimize("", off)
 // Copyright 2014 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
@@ -544,6 +545,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
         ar&* cpu_cores[i].get();
     }
     ar&* service_manager.get();
+    ar&* archive_manager.get();
     ar& GPU::g_regs;
     ar& LCD::g_regs;
 
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
index 87a42b028..0c5b14dc5 100644
--- a/src/core/file_sys/archive_backend.h
+++ b/src/core/file_sys/archive_backend.h
@@ -65,7 +65,7 @@ private:
     LowPathType type;
     std::vector<u8> binary;
     std::string string;
-    std::u16string u16str{};
+    std::u16string u16str;
 
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
@@ -77,18 +77,16 @@ private:
         case LowPathType::Char:
             ar& string;
             break;
-#ifdef _WIN32
-        case LowPathType::Wchar:
-            static_assert(sizeof(wchar_t) == sizeof(char16_t));
-            {
-                std::wstring wstring(reinterpret_cast<wchar_t*>(u16str.data()));
-                ar& wstring;
-                if (!Archive::is_saving::value) {
-                    u16str = std::u16string(reinterpret_cast<char16_t*>(wstring.data()));
-                }
+        case LowPathType::Wchar: {
+            std::vector<char16_t> data;
+            if (Archive::is_saving::value) {
+                std::copy(u16str.begin(), u16str.end(), std::back_inserter(data));
             }
-            break;
-#endif
+            ar& data;
+            if (Archive::is_loading::value) {
+                u16str = std::u16string(data.data(), data.size());
+            }
+        } break;
         default:
             break;
         }
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 59973b8c5..8326122f5 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -167,6 +167,14 @@ public:
         }
         return SaveDataArchive::CreateFile(path, size);
     }
+
+private:
+    ExtSaveDataArchive() = default;
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<SaveDataArchive>(*this);
+    }
+    friend class boost::serialization::access;
 };
 
 struct ExtSaveDataArchivePath {
@@ -304,3 +312,4 @@ void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data
 } // namespace FileSys
 
 SERIALIZE_EXPORT_IMPL(FileSys::ExtSaveDataDelayGenerator)
+SERIALIZE_EXPORT_IMPL(FileSys::ExtSaveDataArchive)
diff --git a/src/core/file_sys/archive_other_savedata.h b/src/core/file_sys/archive_other_savedata.h
index cc0cfe404..f002fec7f 100644
--- a/src/core/file_sys/archive_other_savedata.h
+++ b/src/core/file_sys/archive_other_savedata.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
 #include <boost/serialization/shared_ptr.hpp>
 #include "core/file_sys/archive_source_sd_savedata.h"
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index 3f73adba3..5bc4b8ecd 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/shared_ptr.hpp>
 #include "core/file_sys/archive_source_sd_savedata.h"
 
diff --git a/src/core/file_sys/archive_selfncch.h b/src/core/file_sys/archive_selfncch.h
index 68b48074f..9f5b353b3 100644
--- a/src/core/file_sys/archive_selfncch.h
+++ b/src/core/file_sys/archive_selfncch.h
@@ -10,6 +10,7 @@
 #include <vector>
 #include <boost/serialization/export.hpp>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unordered_map.hpp>
 #include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/archive_backend.h"
@@ -63,7 +64,7 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& boost::serialization::base_object<ArchiveFactory>(*this);
-        // NOTE: ncch_data is never written to, so we don't serialize it here
+        ar& ncch_data;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 04f03a77d..d56fc4c1c 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <cstddef>
 #include <memory>
-#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/unique_ptr.hpp>
 #include "common/common_types.h"
 #include "core/hle/result.h"
diff --git a/src/core/file_sys/layered_fs.h b/src/core/file_sys/layered_fs.h
index dc71d052f..2a494bd8e 100644
--- a/src/core/file_sys/layered_fs.h
+++ b/src/core/file_sys/layered_fs.h
@@ -23,14 +23,6 @@ struct RomFSHeader {
     struct Descriptor {
         u32_le offset;
         u32_le length;
-
-    private:
-        template <class Archive>
-        void serialize(Archive& ar, const unsigned int) {
-            ar& offset;
-            ar& length;
-        }
-        friend class boost::serialization::access;
     };
     u32_le header_length;
     Descriptor directory_hash_table;
@@ -146,6 +138,7 @@ private:
         if (Archive::is_loading::value) {
             Load();
         }
+        // NOTE: Everything else is essentially cached, updated when we call Load
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h
index c9956e135..38b9653d7 100644
--- a/src/core/file_sys/savedata_archive.h
+++ b/src/core/file_sys/savedata_archive.h
@@ -38,10 +38,9 @@ public:
 
 protected:
     std::string mount_point;
-
-private:
     SaveDataArchive() = default;
 
+private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& boost::serialization::base_object<ArchiveBackend>(*this);
@@ -51,8 +50,10 @@ private:
 };
 
 class SaveDataDelayGenerator;
+class ExtSaveDataArchive;
 
 } // namespace FileSys
 
 BOOST_CLASS_EXPORT_KEY(FileSys::SaveDataArchive)
 BOOST_CLASS_EXPORT_KEY(FileSys::SaveDataDelayGenerator)
+BOOST_CLASS_EXPORT_KEY(FileSys::ExtSaveDataArchive)
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 000486825..47d98af2c 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -22,8 +22,6 @@
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_session.h"
 
-BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::SessionRequestHandler)
-
 namespace Service {
 class ServiceFrameworkBase;
 }
@@ -320,5 +318,4 @@ private:
 
 } // namespace Kernel
 
-BOOST_CLASS_EXPORT_KEY(Kernel::SessionRequestHandler::SessionDataBase)
 BOOST_CLASS_EXPORT_KEY(Kernel::HLERequestContext::ThreadCallback)
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index b72081ad5..9b03f30f9 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -6,12 +6,12 @@
 #include <memory>
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/bitset.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_funcs.h"
 #include "common/logging/log.h"
 #include "common/serialization/boost_vector.hpp"
-#include "core/global.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/process.h"
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 6eb79d227..d9af80cd0 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -13,6 +13,7 @@
 #include <boost/container/static_vector.hpp>
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/vector.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/handle_table.h"
diff --git a/src/core/hle/service/ac/ac.h b/src/core/hle/service/ac/ac.h
index 0f31ca1b4..e4342bde9 100644
--- a/src/core/hle/service/ac/ac.h
+++ b/src/core/hle/service/ac/ac.h
@@ -16,8 +16,6 @@ namespace Kernel {
 class Event;
 }
 
-BOOST_SERIALIZATION_ASSUME_ABSTRACT(Service::AC::Module::Interface)
-
 namespace Service::AC {
 class Module final {
 public:
diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h
index 11812bcfe..e5c2cf7ae 100644
--- a/src/core/hle/service/act/act.h
+++ b/src/core/hle/service/act/act.h
@@ -26,7 +26,7 @@ public:
 
 private:
     template <class Archive>
-    inline void serialize(Archive& ar, const unsigned int file_version) {}
+    void serialize(Archive& ar, const unsigned int file_version) {}
     friend class boost::serialization::access;
 };
 
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 22481179e..deff326b7 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -13,6 +13,7 @@
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
+#include "common/construct.h"
 #include "core/file_sys/cia_container.h"
 #include "core/file_sys/file_backend.h"
 #include "core/global.h"
@@ -154,7 +155,6 @@ std::string GetMediaTitlePath(Service::FS::MediaType media_type);
 class Module final {
 public:
     explicit Module(Core::System& system);
-    explicit Module(Kernel::KernelSystem& kernel);
     Module() = default;
     ~Module();
 
@@ -568,6 +568,8 @@ public:
     };
 
 private:
+    explicit Module(Kernel::KernelSystem& kernel);
+
     /**
      * Scans the for titles in a storage medium for listing.
      * @param media_type the storage medium to scan
@@ -590,6 +592,16 @@ private:
         ar& am_title_list;
         ar& system_updater_mutex;
     }
+
+    template <class Archive>
+    static void load_construct(Archive& ar, Module* t, const unsigned int file_version) {
+        ::new (t) Module(Core::Global<Kernel::KernelSystem>());
+    }
+
+    template <class Archive>
+    void save_construct(Archive& ar, const unsigned int file_version) const {}
+
+    friend class ::construct_access;
     friend class boost::serialization::access;
 };
 
@@ -597,9 +609,4 @@ void InstallInterfaces(Core::System& system);
 
 } // namespace Service::AM
 
-namespace boost::serialization {
-template <class Archive>
-inline void load_construct_data(Archive& ar, Service::AM::Module* t, const unsigned int) {
-    ::new (t) Service::AM::Module(Core::Global<Kernel::KernelSystem>());
-}
-} // namespace boost::serialization
+BOOST_SERIALIZATION_CONSTRUCT(Service::AM::Module);
diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h
index 7260fb2d3..0f1a46a8b 100644
--- a/src/core/hle/service/apt/applet_manager.h
+++ b/src/core/hle/service/apt/applet_manager.h
@@ -10,6 +10,7 @@
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/optional.hpp>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "core/global.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/result.h"
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 8780f67e0..d93b4bcb2 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/archives.h"
 #include "common/common_paths.h"
 #include "common/file_util.h"
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index aa480331c..8b01d3b8e 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -6,8 +6,6 @@
 
 #include <memory>
 #include <vector>
-#include <boost/serialization/shared_ptr.hpp>
-#include <boost/serialization/vector.hpp>
 #include "common/archives.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
@@ -651,7 +649,4 @@ void InstallInterfaces(Core::System& system);
 
 } // namespace Service::APT
 
-namespace boost::serialization {
-template <class Archive>
-void load_construct_data(Archive& ar, Service::APT::Module* t, const unsigned int);
-}
+SERVICE_CONSTRUCT(Service::APT::Module)
diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h
index 4dae148f9..e4000e851 100644
--- a/src/core/hle/service/boss/boss.h
+++ b/src/core/hle/service/boss/boss.h
@@ -989,7 +989,7 @@ void InstallInterfaces(Core::System& system);
 
 namespace boost::serialization {
 template <class Archive>
-inline void load_construct_data(Archive& ar, Service::BOSS::Module* t, const unsigned int) {
+void load_construct_data(Archive& ar, Service::BOSS::Module* t, const unsigned int) {
     ::new (t) Service::BOSS::Module(Core::Global<Core::System>());
 }
 } // namespace boost::serialization
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 85501e8de..375df2b20 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -9,6 +9,10 @@
 #include <future>
 #include <memory>
 #include <vector>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/deque.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/global.h"
@@ -849,6 +853,7 @@ private:
             ar& completion_event;
             ar& buffer_error_interrupt_event;
             ar& vsync_interrupt_event;
+            ar& vsync_timings;
             // Ignore capture_result. In-progress captures might be affected but this is OK.
             ar& dest_process;
             ar& dest;
@@ -879,7 +884,7 @@ void InstallInterfaces(Core::System& system);
 
 namespace boost::serialization {
 template <class Archive>
-inline void load_construct_data(Archive& ar, Service::CAM::Module* t, const unsigned int) {
+void load_construct_data(Archive& ar, Service::CAM::Module* t, const unsigned int) {
     ::new (t) Service::CAM::Module(Core::Global<Core::System>());
 }
 } // namespace boost::serialization
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 8db49fc82..31ecd990b 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/unique_ptr.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include <cryptopp/base64.h>
 #include <cryptopp/hmac.h>
 #include <cryptopp/sha.h>
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
index b752701fe..0870f31bf 100644
--- a/src/core/hle/service/cecd/cecd.h
+++ b/src/core/hle/service/cecd/cecd.h
@@ -258,7 +258,7 @@ public:
             ar& data_path_type;
             ar& open_mode.raw;
             ar& path;
-            // ar& file;
+            ar& file;
         }
         friend class boost::serialization::access;
     };
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 98feea8f7..fc285f662 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -4,6 +4,8 @@
 
 #include <algorithm>
 #include <tuple>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include <cryptopp/osrng.h>
 #include <cryptopp/sha.h>
 #include "common/archives.h"
diff --git a/src/core/hle/service/csnd/csnd_snd.h b/src/core/hle/service/csnd/csnd_snd.h
index 6ac5d6876..0b4cd4331 100644
--- a/src/core/hle/service/csnd/csnd_snd.h
+++ b/src/core/hle/service/csnd/csnd_snd.h
@@ -277,8 +277,4 @@ void InstallInterfaces(Core::System& system);
 } // namespace Service::CSND
 
 BOOST_CLASS_EXPORT_KEY(Service::CSND::CSND_SND)
-
-namespace boost::serialization {
-template <class Archive>
-void load_construct_data(Archive& ar, Service::CSND::CSND_SND* t, const unsigned int);
-}
+SERVICE_CONSTRUCT(Service::CSND::CSND_SND)
diff --git a/src/core/hle/service/dsp/dsp_dsp.h b/src/core/hle/service/dsp/dsp_dsp.h
index 90dd17f65..d580b3d00 100644
--- a/src/core/hle/service/dsp/dsp_dsp.h
+++ b/src/core/hle/service/dsp/dsp_dsp.h
@@ -5,6 +5,9 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "audio_core/dsp_interface.h"
 #include "core/hle/kernel/event.h"
 #include "core/hle/result.h"
@@ -282,8 +285,4 @@ void InstallInterfaces(Core::System& system);
 } // namespace Service::DSP
 
 BOOST_CLASS_EXPORT_KEY(Service::DSP::DSP_DSP)
-
-namespace boost::serialization {
-template <class Archive>
-void load_construct_data(Archive& ar, Service::DSP::DSP_DSP* t, const unsigned int);
-}
+SERVICE_CONSTRUCT(Service::DSP::DSP_DSP)
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 29965491b..aba06ac6f 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -8,7 +8,8 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
-#include <boost/container/flat_map.hpp>
+#include <boost/serialization/unique_ptr.hpp>
+#include <boost/serialization/unordered_map.hpp>
 #include "common/common_types.h"
 #include "core/file_sys/archive_backend.h"
 #include "core/hle/result.h"
@@ -253,7 +254,7 @@ private:
      * Map of registered archives, identified by id code. Once an archive is registered here, it is
      * never removed until UnregisterArchiveTypes is called.
      */
-    boost::container::flat_map<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map;
+    std::unordered_map<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map;
 
     /**
      * Map of active archive handles to archive objects
@@ -267,6 +268,7 @@ private:
         ar& handle_map;
         ar& next_handle;
     }
+    friend class boost::serialization::access;
 };
 
 } // namespace Service::FS
diff --git a/src/core/hle/service/fs/directory.cpp b/src/core/hle/service/fs/directory.cpp
index c7fb085ea..655c5602e 100644
--- a/src/core/hle/service/fs/directory.cpp
+++ b/src/core/hle/service/fs/directory.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/file_sys/directory_backend.h"
diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp
index 3664f238d..3d9eee594 100644
--- a/src/core/hle/service/fs/file.cpp
+++ b/src/core/hle/service/fs/file.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/core.h"
diff --git a/src/core/hle/service/fs/file.h b/src/core/hle/service/fs/file.h
index 6aa301a7b..a6ef69304 100644
--- a/src/core/hle/service/fs/file.h
+++ b/src/core/hle/service/fs/file.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <memory>
+#include <boost/serialization/base_object.hpp>
 #include "core/file_sys/archive_backend.h"
 #include "core/global.h"
 #include "core/hle/service/service.h"
diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h
index 83183ecf6..e972d0dae 100644
--- a/src/core/hle/service/fs/fs_user.h
+++ b/src/core/hle/service/fs/fs_user.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <boost/serialization/base_object.hpp>
 #include "common/common_types.h"
 #include "core/hle/service/service.h"
 
diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h
index 82ecf2480..c8914ef72 100644
--- a/src/core/hle/service/gsp/gsp_gpu.h
+++ b/src/core/hle/service/gsp/gsp_gpu.h
@@ -7,6 +7,8 @@
 #include <cstddef>
 #include <memory>
 #include <string>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/event.h"
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 6898c1024..845319f62 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -4,6 +4,9 @@
 
 #include <algorithm>
 #include <cmath>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include "common/archives.h"
 #include "common/logging/log.h"
 #include "core/3ds.h"
@@ -208,7 +211,7 @@ void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) {
 
     Common::Vec3<float> accel;
     if (!motion_device) {
-        is_device_reload_pending.exchange(true);
+        is_device_reload_pending.store(true);
         return;
     }
     std::tie(accel, std::ignore) = motion_device->GetStatus();
@@ -259,7 +262,7 @@ void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) {
 
     Common::Vec3<float> gyro;
     if (!motion_device) {
-        is_device_reload_pending.exchange(true);
+        is_device_reload_pending.store(true);
         return;
     }
     std::tie(std::ignore, gyro) = motion_device->GetStatus();
diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h
index 1be403167..46c0fdca4 100644
--- a/src/core/hle/service/ir/extra_hid.h
+++ b/src/core/hle/service/ir/extra_hid.h
@@ -7,7 +7,6 @@
 #include <array>
 #include <atomic>
 #include <boost/serialization/array.hpp>
-#include <boost/serialization/export.hpp>
 #include "common/bit_field.h"
 #include "common/swap.h"
 #include "core/frontend/input.h"
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
index 751460a04..bd6c64af3 100644
--- a/src/core/hle/service/ir/ir_rst.cpp
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include "common/archives.h"
 #include "core/core.h"
 #include "core/core_timing.h"
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
index 4bf6e7499..0cc77c928 100644
--- a/src/core/hle/service/ir/ir_user.cpp
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -4,6 +4,7 @@
 
 #include <memory>
 #include <boost/crc.hpp>
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/unique_ptr.hpp>
 #include "common/string_util.h"
diff --git a/src/core/hle/service/ndm/ndm_u.h b/src/core/hle/service/ndm/ndm_u.h
index 3339478d1..aebc6fa8b 100644
--- a/src/core/hle/service/ndm/ndm_u.h
+++ b/src/core/hle/service/ndm/ndm_u.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <array>
+#include <boost/serialization/array.hpp>
 #include "core/hle/service/service.h"
 
 namespace Core {
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 0bd6121a2..7213b79a7 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -22,6 +22,8 @@ void Module::serialize(Archive& ar, const unsigned int) {
     ar& tag_out_of_range_event;
     ar& nfc_tag_state;
     ar& nfc_status;
+    ar& amiibo_data;
+    ar& amiibo_in_range;
 }
 SERIALIZE_IMPL(Module)
 
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
index 2d6b26d83..51fe20b76 100644
--- a/src/core/hle/service/nfc/nfc.h
+++ b/src/core/hle/service/nfc/nfc.h
@@ -6,6 +6,7 @@
 
 #include <atomic>
 #include <memory>
+#include <boost/serialization/binary_object.hpp>
 #include "common/common_types.h"
 #include "core/hle/service/service.h"
 
@@ -35,6 +36,13 @@ struct AmiiboData {
     u16_be model_number;
     u8 series;
     INSERT_PADDING_BYTES(0x1C1);
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::make_binary_object(this, sizeof(AmiiboData));
+    }
+    friend class boost::serialization::access;
 };
 static_assert(sizeof(AmiiboData) == 0x21C, "AmiiboData is an invalid size");
 
diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index b2793285f..1a95d2295 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -1175,7 +1175,7 @@ void NWM_UDS::GetChannel(Kernel::HLERequestContext& ctx) {
 
 class NWM_UDS::ThreadCallback : public Kernel::HLERequestContext::WakeupCallback {
 public:
-    ThreadCallback(u16 command_id_) : command_id(command_id_) {}
+    explicit ThreadCallback(u16 command_id_) : command_id(command_id_) {}
 
     void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
                 Kernel::ThreadWakeupReason reason) {
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 0261d061f..83b0a5fb1 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -10,7 +10,6 @@
 #include <memory>
 #include <string>
 #include <boost/container/flat_map.hpp>
-#include <boost/serialization/assume_abstract.hpp>
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/shared_ptr.hpp>
 #include "common/common_types.h"
diff --git a/src/core/hle/service/sm/srv.cpp b/src/core/hle/service/sm/srv.cpp
index f9c62e9ad..da6d57df7 100644
--- a/src/core/hle/service/sm/srv.cpp
+++ b/src/core/hle/service/sm/srv.cpp
@@ -88,7 +88,8 @@ void SRV::EnableNotification(Kernel::HLERequestContext& ctx) {
 class SRV::ThreadCallback : public Kernel::HLERequestContext::WakeupCallback {
 
 public:
-    ThreadCallback(Core::System& system_, std::string name_) : system(system_), name(name_) {}
+    explicit ThreadCallback(Core::System& system_, std::string name_)
+        : system(system_), name(name_) {}
 
     void WakeUp(std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx,
                 Kernel::ThreadWakeupReason reason) {
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index 382a69e2f..1e0eb4bc9 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -13,4 +13,4 @@ add_library(network STATIC
 
 create_target_directory_groups(network)
 
-target_link_libraries(network PRIVATE common enet Boost::boost)
+target_link_libraries(network PRIVATE common enet Boost::serialization)
diff --git a/src/network/room_member.h b/src/network/room_member.h
index d582a8552..ee1c921d4 100644
--- a/src/network/room_member.h
+++ b/src/network/room_member.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 #include <vector>
-#include <boost/serialization/access.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "network/room.h"
 

From 9bd189a1550a94b30faa72416a8e1a72edfdeae2 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 29 Mar 2020 19:07:56 +0100
Subject: [PATCH 100/129] More cleaning up

---
 src/core/hle/kernel/process.h         | 3 ++-
 src/core/hle/service/am/am.h          | 1 -
 src/core/hle/service/cam/cam.cpp      | 2 ++
 src/core/hle/service/cam/cam.h        | 7 +------
 src/tests/core/hle/kernel/hle_ipc.cpp | 8 ++++----
 5 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index d9af80cd0..4eca568d9 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -11,9 +11,10 @@
 #include <string>
 #include <vector>
 #include <boost/container/static_vector.hpp>
+#include <boost/serialization/array.hpp>
 #include <boost/serialization/base_object.hpp>
-#include <boost/serialization/vector.hpp>
 #include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/handle_table.h"
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index deff326b7..25bd58265 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -155,7 +155,6 @@ std::string GetMediaTitlePath(Service::FS::MediaType media_type);
 class Module final {
 public:
     explicit Module(Core::System& system);
-    Module() = default;
     ~Module();
 
     class Interface : public ServiceFramework<Interface> {
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index bf4bdd9c5..e247d998f 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -21,6 +21,8 @@
 #include "core/memory.h"
 #include "core/settings.h"
 
+SERVICE_CONSTRUCT_IMPL(Service::CAM::Module)
+
 namespace Service::CAM {
 
 template <class Archive>
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 375df2b20..04dc0e2ea 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -882,9 +882,4 @@ void InstallInterfaces(Core::System& system);
 
 } // namespace Service::CAM
 
-namespace boost::serialization {
-template <class Archive>
-void load_construct_data(Archive& ar, Service::CAM::Module* t, const unsigned int) {
-    ::new (t) Service::CAM::Module(Core::Global<Core::System>());
-}
-} // namespace boost::serialization
+SERVICE_CONSTRUCT(Service::CAM::Module)
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index 6c2a493bb..890343cd8 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -15,8 +15,6 @@
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/server_session.h"
 
-SERIALIZE_EXPORT_IMPL(Kernel::SessionRequestHandler::SessionDataBase)
-
 namespace Kernel {
 
 static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) {
@@ -26,7 +24,8 @@ static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) {
 TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
     Core::Timing timing(1, 100);
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0);
+    Kernel::KernelSystem kernel(
+        memory, timing, [] {}, 0, 1, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 
@@ -241,7 +240,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
 TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
     Core::Timing timing(1, 100);
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0);
+    Kernel::KernelSystem kernel(
+        memory, timing, [] {}, 0, 1, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 

From 92640fc29c6fee66b6c110ce7631f8e5b3e74e72 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 31 Mar 2020 17:54:28 +0100
Subject: [PATCH 101/129] Code review actions (plus hopefully fix the linux CI)

---
 src/CMakeLists.txt                            | 17 +++++-------
 src/audio_core/hle/hle.cpp                    |  1 +
 src/common/archives.h                         |  4 +--
 src/common/memory_ref.h                       |  6 ++++-
 src/common/serialization/atomic.h             |  4 +++
 .../serialization/boost_discrete_interval.hpp | 22 ++++++++-------
 src/common/serialization/boost_flat_set.h     |  4 +++
 .../serialization/boost_interval_set.hpp      | 20 ++++++++++++++
 src/common/thread_queue_list.h                |  4 +--
 src/core/arm/arm_interface.h                  | 27 +++++++++----------
 src/core/arm/dynarmic/arm_dynarmic.h          |  4 ++-
 src/core/arm/dyncom/arm_dyncom.h              |  4 ++-
 src/core/core.cpp                             | 19 +++++--------
 src/core/core.h                               |  1 -
 src/core/core_timing.cpp                      |  5 ++--
 src/core/hle/kernel/address_arbiter.h         |  1 +
 src/core/hle/kernel/client_port.h             |  2 ++
 src/core/hle/kernel/client_session.h          |  1 +
 src/core/hle/kernel/event.h                   |  2 ++
 src/core/hle/kernel/kernel.cpp                |  3 +++
 src/core/hle/kernel/kernel.h                  |  3 ---
 src/core/hle/kernel/memory.h                  |  6 ++---
 src/core/hle/kernel/mutex.h                   |  3 +++
 src/core/hle/kernel/object.h                  |  2 +-
 src/core/hle/kernel/resource_limit.h          |  2 ++
 src/core/hle/kernel/semaphore.h               |  2 ++
 src/core/hle/kernel/server_port.cpp           |  4 +++
 src/core/hle/kernel/server_port.h             |  3 ---
 src/core/hle/kernel/server_session.cpp        | 16 ++++++++++-
 src/core/hle/kernel/server_session.h          | 12 +--------
 src/core/hle/kernel/session.cpp               |  1 -
 src/core/hle/kernel/shared_memory.cpp         |  1 -
 src/core/hle/kernel/shared_memory.h           |  4 ++-
 src/core/hle/kernel/shared_page.h             |  1 +
 src/core/hle/kernel/thread.cpp                |  2 +-
 src/core/hle/kernel/timer.cpp                 |  1 -
 src/core/hle/kernel/timer.h                   |  1 +
 src/core/hle/kernel/vm_manager.h              |  1 +
 src/core/hle/kernel/wait_object.cpp           | 10 +++++++
 src/core/hle/kernel/wait_object.h             |  7 +----
 src/core/hle/service/hid/hid.cpp              |  8 ------
 src/core/hle/service/ir/extra_hid.h           |  4 ++-
 src/core/memory.cpp                           |  4 +--
 src/core/memory.h                             | 13 +++++----
 src/video_core/geometry_pipeline.cpp          |  1 -
 src/video_core/pica_state.h                   |  1 +
 46 files changed, 155 insertions(+), 109 deletions(-)
 create mode 100644 src/common/serialization/boost_interval_set.hpp

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 96c7f35cd..1ada1b3eb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -31,8 +31,10 @@ if (MSVC)
     # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates
     # /Zc:inline          - Let codegen omit inline functions in object files
     # /Zc:throwingNew     - Let codegen assume `operator new` (without std::nothrow) will never return null
+    # /external:*         - Suppress warnings from external headers
     add_compile_options(
         /W3
+        /MP
         /Zi
         /Zo
         /permissive-
@@ -40,17 +42,12 @@ if (MSVC)
         /volatile:iso
         /Zc:externConstexpr
         /Zc:inline
+        /Zc:throwingNew
+        /experimental:external
+        /external:I "${CMAKE_SOURCE_DIR}/externals"
+        /external:anglebrackets
+        /external:W0
     )
-    if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
-        add_compile_options(
-            /MP
-            /Zc:throwingNew
-            /experimental:external
-            /external:I "${CMAKE_SOURCE_DIR}/externals"
-            /external:anglebrackets
-            /external:W0
-        )
-    endif()
 
     # /GS- - No stack buffer overflow checks
     add_compile_options("$<$<CONFIG:Release>:/GS->")
diff --git a/src/audio_core/hle/hle.cpp b/src/audio_core/hle/hle.cpp
index f4e372f85..3a761dcfa 100644
--- a/src/audio_core/hle/hle.cpp
+++ b/src/audio_core/hle/hle.cpp
@@ -45,6 +45,7 @@ void DspHle::serialize(Archive& ar, const unsigned int) {
     ar& boost::serialization::base_object<DspInterface>(*this);
     ar&* impl.get();
 }
+SERIALIZE_IMPL(DspHle)
 
 static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
 
diff --git a/src/common/archives.h b/src/common/archives.h
index 4f8b735d3..b9f4330bd 100644
--- a/src/common/archives.h
+++ b/src/common/archives.h
@@ -5,8 +5,8 @@
 #pragma once
 
 #include <boost/archive/binary_iarchive.hpp>
-#include "boost/archive/binary_oarchive.hpp"
-#include "boost/serialization/export.hpp"
+#include <boost/archive/binary_oarchive.hpp>
+#include <boost/serialization/export.hpp>
 
 using iarchive = boost::archive::binary_iarchive;
 using oarchive = boost::archive::binary_oarchive;
diff --git a/src/common/memory_ref.h b/src/common/memory_ref.h
index 30eabbaee..0a50c7be9 100644
--- a/src/common/memory_ref.h
+++ b/src/common/memory_ref.h
@@ -41,13 +41,17 @@ public:
     }
 
     std::size_t GetSize() const override {
-        return static_cast<u32>(data.size());
+        return data.size();
     }
 
     std::vector<u8>& Vector() {
         return data;
     }
 
+    const std::vector<u8>& Vector() const {
+        return data;
+    }
+
 private:
     std::vector<u8> data;
 
diff --git a/src/common/serialization/atomic.h b/src/common/serialization/atomic.h
index dbc4c0dec..0cf0f20bc 100644
--- a/src/common/serialization/atomic.h
+++ b/src/common/serialization/atomic.h
@@ -1,3 +1,7 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
 #pragma once
 
 #include <atomic>
diff --git a/src/common/serialization/boost_discrete_interval.hpp b/src/common/serialization/boost_discrete_interval.hpp
index dc920e439..961a9a7ef 100644
--- a/src/common/serialization/boost_discrete_interval.hpp
+++ b/src/common/serialization/boost_discrete_interval.hpp
@@ -1,33 +1,37 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
 #pragma once
 
-#include "common/common_types.h"
 #include <boost/icl/discrete_interval.hpp>
+#include "common/common_types.h"
 
 namespace boost::serialization {
 
 template <class Archive, class DomainT, ICL_COMPARE Compare>
-void save(Archive& ar, const boost::icl::discrete_interval<DomainT, Compare>& obj, const unsigned int file_version)
-{
+void save(Archive& ar, const boost::icl::discrete_interval<DomainT, Compare>& obj,
+          const unsigned int file_version) {
     ar << obj.lower();
     ar << obj.upper();
     ar << obj.bounds()._bits;
 }
 
 template <class Archive, class DomainT, ICL_COMPARE Compare>
-void load(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj, const unsigned int file_version)
-{
+void load(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj,
+          const unsigned int file_version) {
     DomainT upper, lower;
     boost::icl::bound_type bounds;
-    ar >> upper;
     ar >> lower;
+    ar >> upper;
     ar >> bounds;
     obj = boost::icl::discrete_interval(upper, lower, boost::icl::interval_bounds(bounds));
 }
 
 template <class Archive, class DomainT, ICL_COMPARE Compare>
-void serialize(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj, const unsigned int file_version)
-{
+void serialize(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj,
+               const unsigned int file_version) {
     boost::serialization::split_free(ar, obj, file_version);
 }
 
-}
+} // namespace boost::serialization
diff --git a/src/common/serialization/boost_flat_set.h b/src/common/serialization/boost_flat_set.h
index c47e8c1a7..703bd28b3 100644
--- a/src/common/serialization/boost_flat_set.h
+++ b/src/common/serialization/boost_flat_set.h
@@ -1,3 +1,7 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
 #pragma once
 
 #include <boost/container/flat_set.hpp>
diff --git a/src/common/serialization/boost_interval_set.hpp b/src/common/serialization/boost_interval_set.hpp
new file mode 100644
index 000000000..08e6a14f1
--- /dev/null
+++ b/src/common/serialization/boost_interval_set.hpp
@@ -0,0 +1,20 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <boost/icl/interval_set.hpp>
+#include "common/serialization/boost_discrete_interval.hpp"
+
+namespace boost::serialization {
+
+template <class Archive, class T>
+void serialize(Archive& ar, boost::icl::interval_set<T>& obj, const unsigned int file_version) {
+    using IntervalSet = boost::icl::interval_set<T>;
+    // This works because interval_set has exactly one member of type ImplSetT
+    static_assert(std::is_standard_layout_v<IntervalSet>);
+    ar&*(reinterpret_cast<typename IntervalSet::ImplSetT*>(&obj));
+}
+
+} // namespace boost::serialization
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 1ba68e1e4..af40bf09b 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -186,7 +186,7 @@ private:
     void save(Archive& ar, const unsigned int file_version) const {
         const s64 idx = ToIndex(first);
         ar << idx;
-        for (size_t i = 0; i < NUM_QUEUES; i++) {
+        for (std::size_t i = 0; i < NUM_QUEUES; i++) {
             const s64 idx1 = ToIndex(queues[i].next_nonempty);
             ar << idx1;
             ar << queues[i].data;
@@ -198,7 +198,7 @@ private:
         s64 idx;
         ar >> idx;
         first = ToPointer(idx);
-        for (auto i = 0; i < NUM_QUEUES; i++) {
+        for (std::size_t i = 0; i < NUM_QUEUES; i++) {
             ar >> idx;
             queues[i].next_nonempty = ToPointer(idx);
             ar >> queues[i].data;
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index fca488586..a6b8a279a 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -6,15 +6,13 @@
 
 #include <cstddef>
 #include <memory>
+#include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/split_member.hpp>
 #include "common/common_types.h"
 #include "core/arm/skyeye_common/arm_regformat.h"
 #include "core/arm/skyeye_common/vfp/asm_vfp.h"
 #include "core/core_timing.h"
-
-namespace Memory {
-struct PageTable;
-}
+#include "core/memory.h"
 
 /// Generic ARM11 CPU interface
 class ARM_Interface : NonCopyable {
@@ -28,11 +26,11 @@ public:
 
         template <class Archive>
         void save(Archive& ar, const unsigned int file_version) const {
-            for (size_t i = 0; i < 16; i++) {
+            for (std::size_t i = 0; i < 16; i++) {
                 const auto r = GetCpuRegister(i);
                 ar << r;
             }
-            for (size_t i = 0; i < 16; i++) {
+            for (std::size_t i = 0; i < 16; i++) {
                 const auto r = GetFpuRegister(i);
                 ar << r;
             }
@@ -47,11 +45,11 @@ public:
         template <class Archive>
         void load(Archive& ar, const unsigned int file_version) {
             u32 r;
-            for (size_t i = 0; i < 16; i++) {
+            for (std::size_t i = 0; i < 16; i++) {
                 ar >> r;
                 SetCpuRegister(i, r);
             }
-            for (size_t i = 0; i < 16; i++) {
+            for (std::size_t i = 0; i < 16; i++) {
                 ar >> r;
                 SetFpuRegister(i, r);
             }
@@ -120,8 +118,6 @@ public:
     /// Notify CPU emulation that page tables have changed
     virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
 
-    virtual std::shared_ptr<Memory::PageTable> GetPageTable() const = 0;
-
     /**
      * Set the Program Counter to an address
      * @param addr Address to set PC to
@@ -234,6 +230,9 @@ public:
     }
 
 protected:
+    // This us used for serialization. Returning nullptr is valid if page tables are not used.
+    virtual std::shared_ptr<Memory::PageTable> GetPageTable() const = 0;
+
     std::shared_ptr<Core::Timing::Timer> timer;
 
 private:
@@ -259,11 +258,11 @@ private:
             const auto r = GetVFPReg(i);
             ar << r;
         }
-        for (size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
+        for (std::size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
             const auto r = GetVFPSystemReg(static_cast<VFPSystemRegister>(i));
             ar << r;
         }
-        for (size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
+        for (std::size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
             const auto r = GetCP15Register(static_cast<CP15Register>(i));
             ar << r;
         }
@@ -290,11 +289,11 @@ private:
             ar >> r;
             SetVFPReg(i, r);
         }
-        for (size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
+        for (std::size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
             ar >> r;
             SetVFPSystemReg(static_cast<VFPSystemRegister>(i), r);
         }
-        for (size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
+        for (std::size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
             ar >> r;
             SetCP15Register(static_cast<CP15Register>(i), r);
         }
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index a8f224083..a5b4893a6 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -53,9 +53,11 @@ public:
     void ClearInstructionCache() override;
     void InvalidateCacheRange(u32 start_address, std::size_t length) override;
     void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
-    std::shared_ptr<Memory::PageTable> GetPageTable() const override;
     void PurgeState() override;
 
+protected:
+    std::shared_ptr<Memory::PageTable> GetPageTable() const override;
+
 private:
     friend class DynarmicUserCallbacks;
     Core::System& system;
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 91cbcded0..1452216c2 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -49,10 +49,12 @@ public:
     void LoadContext(const std::unique_ptr<ThreadContext>& arg) override;
 
     void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
-    std::shared_ptr<Memory::PageTable> GetPageTable() const override;
     void PrepareReschedule() override;
     void PurgeState() override;
 
+protected:
+    std::shared_ptr<Memory::PageTable> GetPageTable() const override;
+
 private:
     void ExecuteInstructions(u64 num_instructions);
 
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 2928d50e7..69223a05e 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -1,4 +1,3 @@
-#pragma optimize("", off)
 // Copyright 2014 Citra Emulator Project
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
@@ -184,12 +183,14 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
         LOG_INFO(Core, "Begin load");
         System::LoadState(param);
         LOG_INFO(Core, "Load completed");
-    } break;
+        break;
+    }
     case Signal::Save: {
         LOG_INFO(Core, "Begin save");
         System::SaveState(param);
         LOG_INFO(Core, "Save completed");
-    } break;
+        break;
+    }
     default:
         break;
     }
@@ -551,19 +552,11 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
 
     // NOTE: DSP doesn't like being destroyed and recreated. So instead we do an inline
     // serialization; this means that the DSP Settings need to match for loading to work.
-    bool dsp_type = Settings::values.enable_dsp_lle;
-    ar& dsp_type;
-    if (dsp_type != Settings::values.enable_dsp_lle) {
-        throw std::runtime_error(
-            "Incorrect DSP type - please change this in Settings before loading");
-    }
     auto dsp_hle = dynamic_cast<AudioCore::DspHle*>(dsp_core.get());
     if (dsp_hle) {
         ar&* dsp_hle;
-    }
-    auto dsp_lle = dynamic_cast<AudioCore::DspLle*>(dsp_core.get());
-    if (dsp_lle) {
-        ar&* dsp_lle;
+    } else {
+        throw std::runtime_error("LLE audio not supported for save states");
     }
 
     ar&* memory.get();
diff --git a/src/core/core.h b/src/core/core.h
index 66e880fd1..dfb6aee3e 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -7,7 +7,6 @@
 #include <memory>
 #include <mutex>
 #include <string>
-#include "boost/serialization/access.hpp"
 #include "common/common_types.h"
 #include "core/custom_tex_cache.h"
 #include "core/frontend/applets/mii_selector.h"
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 493bb6344..963926596 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -183,11 +183,10 @@ void Timing::Timer::Advance(s64 max_slice_length) {
         Event evt = std::move(event_queue.front());
         std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
         event_queue.pop_back();
-        if (evt.type->callback == nullptr) {
-            LOG_ERROR(Core, "Event '{}' has no callback", *evt.type->name);
-        }
         if (evt.type->callback != nullptr) {
             evt.type->callback(evt.userdata, executed_ticks - evt.time);
+        } else {
+            LOG_ERROR(Core, "Event '{}' has no callback", *evt.type->name);
         }
     }
 
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 85a2a065a..059ff1400 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -9,6 +9,7 @@
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
 #include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index 1d0f5c024..8d0f50520 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -7,6 +7,8 @@
 #include <memory>
 #include <string>
 #include <boost/serialization/export.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_port.h"
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
index 38f39c299..1943db8e6 100644
--- a/src/core/hle/kernel/client_session.h
+++ b/src/core/hle/kernel/client_session.h
@@ -9,6 +9,7 @@
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/result.h"
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 892718533..02eabd750 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -4,7 +4,9 @@
 
 #pragma once
 
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/wait_object.h"
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f0974f88a..ef9856363 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -2,6 +2,9 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unordered_map.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/archives.h"
 #include "common/serialization/atomic.h"
 #include "core/hle/kernel/client_port.h"
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 828843afc..f0a8368d9 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,9 +11,6 @@
 #include <string>
 #include <unordered_map>
 #include <vector>
-#include <boost/serialization/shared_ptr.hpp>
-#include <boost/serialization/unordered_map.hpp>
-#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/result.h"
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
index f4b0a6d98..0560b0bec 100644
--- a/src/core/hle/kernel/memory.h
+++ b/src/core/hle/kernel/memory.h
@@ -5,10 +5,11 @@
 #pragma once
 
 #include <optional>
+#include <type_traits>
 #include <boost/icl/interval_set.hpp>
 #include <boost/serialization/set.hpp>
 #include "common/common_types.h"
-#include "common/serialization/boost_discrete_interval.hpp"
+#include "common/serialization/boost_interval_set.hpp"
 
 namespace Kernel {
 
@@ -70,8 +71,7 @@ private:
         ar& base;
         ar& size;
         ar& used;
-        // This works because interval_set has exactly one member of type ImplSetT
-        ar&*(reinterpret_cast<IntervalSet::ImplSetT*>(&free_blocks));
+        ar& free_blocks;
     }
 };
 
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 4adf674c3..73ee2a0e6 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -7,6 +7,9 @@
 #include <memory>
 #include <string>
 #include <boost/serialization/export.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/wait_object.h"
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index 57b208dc1..b272366d7 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -104,7 +104,7 @@ BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::Object)
 #define CONSTRUCT_KERNEL_OBJECT(T)                                                                 \
     namespace boost::serialization {                                                               \
     template <class Archive>                                                                       \
-    inline void load_construct_data(Archive& ar, T* t, const unsigned int file_version) {          \
+    void load_construct_data(Archive& ar, T* t, const unsigned int file_version) {                 \
         ::new (t) T(Core::Global<Kernel::KernelSystem>());                                         \
     }                                                                                              \
     }
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 8593a03a3..cb1c8c78e 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -7,7 +7,9 @@
 #include <array>
 #include <memory>
 #include <boost/serialization/array.hpp>
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
index a7ab192a6..b9863a838 100644
--- a/src/core/hle/kernel/semaphore.h
+++ b/src/core/hle/kernel/semaphore.h
@@ -5,7 +5,9 @@
 #pragma once
 
 #include <string>
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
+#include <boost/serialization/string.hpp>
 #include <queue>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 077150222..4d293be34 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -3,6 +3,10 @@
 // Refer to the license.txt file included.
 
 #include <tuple>
+#include <boost/serialization/base_object.hpp>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/archives.h"
 #include "common/assert.h"
 #include "core/hle/kernel/client_port.h"
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index 2f00e586e..00eb10100 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -7,10 +7,7 @@
 #include <memory>
 #include <string>
 #include <tuple>
-#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
-#include <boost/serialization/shared_ptr.hpp>
-#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/server_session.h"
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 3dc20e9a7..61ade5b70 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -3,8 +3,10 @@
 // Refer to the license.txt file included.
 
 #include <tuple>
+#include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/archives.h"
-#include "core/global.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/client_session.h"
 #include "core/hle/kernel/hle_ipc.h"
@@ -16,6 +18,18 @@ SERIALIZE_EXPORT_IMPL(Kernel::ServerSession)
 
 namespace Kernel {
 
+template <class Archive>
+void ServerSession::serialize(Archive& ar, const unsigned int file_version) {
+    ar& boost::serialization::base_object<WaitObject>(*this);
+    ar& name;
+    ar& parent;
+    ar& hle_handler;
+    ar& pending_requesting_threads;
+    ar& currently_handling;
+    ar& mapped_buffer_context;
+}
+SERIALIZE_IMPL(ServerSession)
+
 ServerSession::ServerSession(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
 ServerSession::~ServerSession() {
     // This destructor will be called automatically when the last ServerSession handle is closed by
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
index 74dbef624..b91accce5 100644
--- a/src/core/hle/kernel/server_session.h
+++ b/src/core/hle/kernel/server_session.h
@@ -7,8 +7,6 @@
 #include <memory>
 #include <string>
 #include <boost/serialization/export.hpp>
-#include <boost/serialization/shared_ptr.hpp>
-#include <boost/serialization/vector.hpp>
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "core/hle/kernel/ipc.h"
@@ -110,15 +108,7 @@ private:
 
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version) {
-        ar& boost::serialization::base_object<WaitObject>(*this);
-        ar& name;
-        ar& parent;
-        ar& hle_handler;
-        ar& pending_requesting_threads;
-        ar& currently_handling;
-        ar& mapped_buffer_context;
-    }
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 
 } // namespace Kernel
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp
index 1ec1039dc..8bb846c52 100644
--- a/src/core/hle/kernel/session.cpp
+++ b/src/core/hle/kernel/session.cpp
@@ -6,7 +6,6 @@
 #include "common/archives.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/hle_ipc.h"
 #include "core/hle/kernel/server_session.h"
 #include "core/hle/kernel/session.h"
 
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 47c966fec..e8f792ee8 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -5,7 +5,6 @@
 #include <cstring>
 #include "common/archives.h"
 #include "common/logging/log.h"
-#include "core/global.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/memory.h"
 #include "core/hle/kernel/shared_memory.h"
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index cb2dee685..0e500a1dd 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -6,7 +6,9 @@
 
 #include <string>
 #include <utility>
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/export.hpp>
+#include <boost/serialization/string.hpp>
 #include "common/common_types.h"
 #include "common/memory_ref.h"
 #include "core/hle/kernel/object.h"
@@ -118,7 +120,7 @@ private:
         ar& owner_process;
         ar& base_address;
         ar& name;
-        ar&*(reinterpret_cast<MemoryRegionInfo::IntervalSet::ImplSetT*>(&holding_memory));
+        ar& holding_memory;
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/hle/kernel/shared_page.h b/src/core/hle/kernel/shared_page.h
index c4b174db4..9cd579d52 100644
--- a/src/core/hle/kernel/shared_page.h
+++ b/src/core/hle/kernel/shared_page.h
@@ -13,6 +13,7 @@
 #include <chrono>
 #include <ctime>
 #include <memory>
+#include <boost/serialization/base_object.hpp>
 #include <boost/serialization/binary_object.hpp>
 #include <boost/serialization/export.hpp>
 #include "common/bit_field.h"
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 0567ef325..cdd908b4e 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -6,6 +6,7 @@
 #include <list>
 #include <unordered_map>
 #include <vector>
+#include <boost/serialization/string.hpp>
 #include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_types.h"
@@ -15,7 +16,6 @@
 #include "core/arm/arm_interface.h"
 #include "core/arm/skyeye_common/armstate.h"
 #include "core/core.h"
-#include "core/global.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/kernel.h"
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index d29b25986..d2a12ade1 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -8,7 +8,6 @@
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "core/core.h"
-#include "core/global.h"
 #include "core/hle/kernel/handle_table.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
diff --git a/src/core/hle/kernel/timer.h b/src/core/hle/kernel/timer.h
index b591c1b03..d5af5e654 100644
--- a/src/core/hle/kernel/timer.h
+++ b/src/core/hle/kernel/timer.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <boost/serialization/string.hpp>
 #include <boost/serialization/unordered_map.hpp>
 #include "common/common_types.h"
 #include "core/core_timing.h"
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 3ca46d069..06fbb8672 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -9,6 +9,7 @@
 #include <utility>
 #include <vector>
 #include <boost/serialization/map.hpp>
+#include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/split_member.hpp>
 #include "common/common_types.h"
 #include "common/memory_ref.h"
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp
index 6fe75b6d8..2cd4331c5 100644
--- a/src/core/hle/kernel/wait_object.cpp
+++ b/src/core/hle/kernel/wait_object.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <utility>
+#include "common/archives.h"
 #include "common/assert.h"
 #include "common/logging/log.h"
 #include "core/hle/kernel/errors.h"
@@ -16,6 +17,15 @@
 
 namespace Kernel {
 
+template <class Archive>
+void WaitObject::serialize(Archive& ar, const unsigned int file_version) {
+    ar& boost::serialization::base_object<Object>(*this);
+    ar& waiting_threads;
+    // NB: hle_notifier *not* serialized since it's a callback!
+    // Fortunately it's only used in one place (DSP) so we can reconstruct it there
+}
+SERIALIZE_IMPL(WaitObject)
+
 void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
     auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
     if (itr == waiting_threads.end())
diff --git a/src/core/hle/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index c07290e8a..7f73eab9f 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -69,12 +69,7 @@ private:
 private:
     friend class boost::serialization::access;
     template <class Archive>
-    void serialize(Archive& ar, const unsigned int file_version) {
-        ar& boost::serialization::base_object<Object>(*this);
-        ar& waiting_threads;
-        // NB: hle_notifier *not* serialized since it's a callback!
-        // Fortunately it's only used in one place (DSP) so we can reconstruct it there
-    }
+    void serialize(Archive& ar, const unsigned int file_version);
 };
 
 // Specialization of DynamicObjectCast for WaitObjects
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 845319f62..981a4aa63 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -210,10 +210,6 @@ void Module::UpdateAccelerometerCallback(u64 userdata, s64 cycles_late) {
     next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
 
     Common::Vec3<float> accel;
-    if (!motion_device) {
-        is_device_reload_pending.store(true);
-        return;
-    }
     std::tie(accel, std::ignore) = motion_device->GetStatus();
     accel *= accelerometer_coef;
     // TODO(wwylele): do a time stretch like the one in UpdateGyroscopeCallback
@@ -261,10 +257,6 @@ void Module::UpdateGyroscopeCallback(u64 userdata, s64 cycles_late) {
     GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
 
     Common::Vec3<float> gyro;
-    if (!motion_device) {
-        is_device_reload_pending.store(true);
-        return;
-    }
     std::tie(std::ignore, gyro) = motion_device->GetStatus();
     double stretch = system.perf_stats->GetLastFrameTimeScale();
     gyro *= gyroscope_coef * static_cast<float>(stretch);
diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h
index 46c0fdca4..4b27fba9b 100644
--- a/src/core/hle/service/ir/extra_hid.h
+++ b/src/core/hle/service/ir/extra_hid.h
@@ -71,7 +71,9 @@ private:
     void serialize(Archive& ar, const unsigned int) {
         ar& hid_period;
         ar& calibration_data;        // This isn't writeable for now, but might be in future
-        RequestInputDevicesReload(); // zl, zr, c_stick are loaded here
+        if (Archive::is_loading::value) {
+            LoadInputDevices(); // zl, zr, c_stick are loaded here
+        }
     }
     friend class boost::serialization::access;
 };
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index c0c030de1..184b7f9bd 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -4,9 +4,9 @@
 
 #include <array>
 #include <cstring>
+#include <boost/serialization/array.hpp>
+#include <boost/serialization/binary_object.hpp>
 #include "audio_core/dsp_interface.h"
-#include "boost/serialization/array.hpp"
-#include "boost/serialization/binary_object.hpp"
 #include "common/archives.h"
 #include "common/assert.h"
 #include "common/common_types.h"
diff --git a/src/core/memory.h b/src/core/memory.h
index eb5b6d69c..66b28d87d 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -9,7 +9,6 @@
 #include <memory>
 #include <string>
 #include <vector>
-#include <boost/serialization/access.hpp>
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
@@ -86,12 +85,12 @@ struct PageTable {
         struct Entry {
             Entry(Pointers& pointers_, VAddr idx_) : pointers(pointers_), idx(idx_) {}
 
-            inline void operator=(MemoryRef value) {
+            void operator=(MemoryRef value) {
                 pointers.refs[idx] = value;
                 pointers.raw[idx] = value.GetPtr();
             }
 
-            inline operator u8*() {
+            operator u8*() {
                 return pointers.raw[idx];
             }
 
@@ -100,15 +99,15 @@ struct PageTable {
             VAddr idx;
         };
 
-        inline Entry operator[](VAddr idx) {
+        Entry operator[](VAddr idx) {
             return Entry(*this, idx);
         }
 
-        inline u8* operator[](VAddr idx) const {
+        u8* operator[](VAddr idx) const {
             return raw[idx];
         }
 
-        inline Entry operator[](std::size_t idx) {
+        Entry operator[](std::size_t idx) {
             return Entry(*this, static_cast<VAddr>(idx));
         }
 
@@ -133,7 +132,7 @@ struct PageTable {
      */
     std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
 
-    inline std::array<u8*, PAGE_TABLE_NUM_ENTRIES>& GetPointerArray() {
+    std::array<u8*, PAGE_TABLE_NUM_ENTRIES>& GetPointerArray() {
         return pointers.raw;
     }
 
diff --git a/src/video_core/geometry_pipeline.cpp b/src/video_core/geometry_pipeline.cpp
index 7e002d55d..0ddbda943 100644
--- a/src/video_core/geometry_pipeline.cpp
+++ b/src/video_core/geometry_pipeline.cpp
@@ -385,7 +385,6 @@ void GeometryPipeline::serialize(Archive& ar, const unsigned int version) {
 
 } // namespace Pica
 
-BOOST_SERIALIZATION_ASSUME_ABSTRACT(Pica::GeometryPipelineBackend)
 SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_Point)
 SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_VariablePrimitive)
 SERIALIZE_EXPORT_IMPL(Pica::GeometryPipeline_FixedPrimitive)
diff --git a/src/video_core/pica_state.h b/src/video_core/pica_state.h
index 3a9ec79c5..3c29ff84e 100644
--- a/src/video_core/pica_state.h
+++ b/src/video_core/pica_state.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <array>
+#include <boost/serialization/array.hpp>
 #include <boost/serialization/split_member.hpp>
 #include "common/bit_field.h"
 #include "common/common_types.h"

From f156fdd332f7f1089ec827e5ed756ae6b6e5548a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Tue, 31 Mar 2020 18:27:33 +0100
Subject: [PATCH 102/129] clang format fixes etc.

---
 .../serialization/boost_interval_set.hpp      | 28 +++++++++++++++----
 src/core/hle/kernel/memory.h                  |  1 -
 src/core/hle/kernel/mutex.h                   |  2 +-
 src/core/hle/kernel/server_port.cpp           |  2 +-
 src/core/hle/service/cecd/cecd.cpp            |  5 ++--
 src/core/hle/service/ir/extra_hid.h           |  2 +-
 src/tests/core/hle/kernel/hle_ipc.cpp         |  6 ++--
 7 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/src/common/serialization/boost_interval_set.hpp b/src/common/serialization/boost_interval_set.hpp
index 08e6a14f1..905e3f145 100644
--- a/src/common/serialization/boost_interval_set.hpp
+++ b/src/common/serialization/boost_interval_set.hpp
@@ -5,16 +5,34 @@
 #pragma once
 
 #include <boost/icl/interval_set.hpp>
+#include <boost/serialization/split_free.hpp>
 #include "common/serialization/boost_discrete_interval.hpp"
 
 namespace boost::serialization {
 
 template <class Archive, class T>
-void serialize(Archive& ar, boost::icl::interval_set<T>& obj, const unsigned int file_version) {
-    using IntervalSet = boost::icl::interval_set<T>;
-    // This works because interval_set has exactly one member of type ImplSetT
-    static_assert(std::is_standard_layout_v<IntervalSet>);
-    ar&*(reinterpret_cast<typename IntervalSet::ImplSetT*>(&obj));
+void save(Archive& ar, const boost::icl::interval_set<T>& set, const unsigned int file_version) {
+    ar << static_cast<u64>(set.size());
+    for (auto& v : set) {
+        ar << v;
+    }
+}
+
+template <class Archive, class T>
+void load(Archive& ar, boost::icl::interval_set<T>& set, const unsigned int file_version) {
+    u64 count{};
+    ar >> count;
+    set.clear();
+    for (u64 i = 0; i < count; i++) {
+        T value{};
+        ar >> value;
+        set.insert(value);
+    }
+}
+
+template <class Archive, class T>
+void serialize(Archive& ar, boost::icl::interval_set<T>& set, const unsigned int file_version) {
+    boost::serialization::split_free(ar, set, file_version);
 }
 
 } // namespace boost::serialization
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
index 0560b0bec..739369a9c 100644
--- a/src/core/hle/kernel/memory.h
+++ b/src/core/hle/kernel/memory.h
@@ -5,7 +5,6 @@
 #pragma once
 
 #include <optional>
-#include <type_traits>
 #include <boost/icl/interval_set.hpp>
 #include <boost/serialization/set.hpp>
 #include "common/common_types.h"
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 73ee2a0e6..db98aa8c9 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -6,8 +6,8 @@
 
 #include <memory>
 #include <string>
-#include <boost/serialization/export.hpp>
 #include <boost/serialization/base_object.hpp>
+#include <boost/serialization/export.hpp>
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/string.hpp>
 #include "common/common_types.h"
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 4d293be34..006403925 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -5,8 +5,8 @@
 #include <tuple>
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/shared_ptr.hpp>
-#include <boost/serialization/vector.hpp>
 #include <boost/serialization/string.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/archives.h"
 #include "common/assert.h"
 #include "core/hle/kernel/client_port.h"
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 31ecd990b..977a47842 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -2,8 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
-#include <boost/serialization/unique_ptr.hpp>
 #include <boost/serialization/shared_ptr.hpp>
+#include <boost/serialization/unique_ptr.hpp>
 #include <cryptopp/base64.h>
 #include <cryptopp/hmac.h>
 #include <cryptopp/sha.h>
@@ -1361,8 +1361,7 @@ void Module::CheckAndUpdateFile(const CecDataPathType path_type, const u32 ncch_
     case CecDataPathType::MboxData:
     case CecDataPathType::MboxIcon:
     case CecDataPathType::MboxTitle:
-    default: {
-    }
+    default: {}
     }
 }
 
diff --git a/src/core/hle/service/ir/extra_hid.h b/src/core/hle/service/ir/extra_hid.h
index 4b27fba9b..d498c471f 100644
--- a/src/core/hle/service/ir/extra_hid.h
+++ b/src/core/hle/service/ir/extra_hid.h
@@ -70,7 +70,7 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& hid_period;
-        ar& calibration_data;        // This isn't writeable for now, but might be in future
+        ar& calibration_data; // This isn't writeable for now, but might be in future
         if (Archive::is_loading::value) {
             LoadInputDevices(); // zl, zr, c_stick are loaded here
         }
diff --git a/src/tests/core/hle/kernel/hle_ipc.cpp b/src/tests/core/hle/kernel/hle_ipc.cpp
index 890343cd8..f5623c8c1 100644
--- a/src/tests/core/hle/kernel/hle_ipc.cpp
+++ b/src/tests/core/hle/kernel/hle_ipc.cpp
@@ -24,8 +24,7 @@ static std::shared_ptr<Object> MakeObject(Kernel::KernelSystem& kernel) {
 TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
     Core::Timing timing(1, 100);
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(
-        memory, timing, [] {}, 0, 1, 0);
+    Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 
@@ -240,8 +239,7 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
 TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
     Core::Timing timing(1, 100);
     Memory::MemorySystem memory;
-    Kernel::KernelSystem kernel(
-        memory, timing, [] {}, 0, 1, 0);
+    Kernel::KernelSystem kernel(memory, timing, [] {}, 0, 1, 0);
     auto [server, client] = kernel.CreateSessionPair();
     HLERequestContext context(kernel, std::move(server), nullptr);
 

From 5b6ee9a6abdf5546ad8d3a92101c8ee1059e5018 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 1 Apr 2020 22:06:22 +0100
Subject: [PATCH 103/129] Clear out state before deserialization - fixes many
 crashes.

---
 src/citra_qt/bootmanager.cpp                    |  4 +++-
 src/common/serialization/boost_interval_set.hpp |  6 +++---
 src/core/core.cpp                               | 11 +++++++----
 src/core/core.h                                 |  2 +-
 src/core/savestate.cpp                          | 10 ++++++++++
 5 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 78541e880..feab64906 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -132,7 +132,9 @@ void OpenGLWindow::Present() {
         return;
 
     context->makeCurrent(this);
-    VideoCore::g_renderer->TryPresent(100);
+    if (VideoCore::g_renderer) {
+        VideoCore::g_renderer->TryPresent(100);
+    }
     context->swapBuffers(this);
     auto f = context->versionFunctions<QOpenGLFunctions_3_3_Core>();
     f->glFinish();
diff --git a/src/common/serialization/boost_interval_set.hpp b/src/common/serialization/boost_interval_set.hpp
index 905e3f145..d4e48e62a 100644
--- a/src/common/serialization/boost_interval_set.hpp
+++ b/src/common/serialization/boost_interval_set.hpp
@@ -12,7 +12,7 @@ namespace boost::serialization {
 
 template <class Archive, class T>
 void save(Archive& ar, const boost::icl::interval_set<T>& set, const unsigned int file_version) {
-    ar << static_cast<u64>(set.size());
+    ar << static_cast<u64>(set.iterative_size());
     for (auto& v : set) {
         ar << v;
     }
@@ -24,9 +24,9 @@ void load(Archive& ar, boost::icl::interval_set<T>& set, const unsigned int file
     ar >> count;
     set.clear();
     for (u64 i = 0; i < count; i++) {
-        T value{};
+        typename boost::icl::interval_set<T>::interval_type value{};
         ar >> value;
-        set.insert(value);
+        set.add(value);
     }
 }
 
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 69223a05e..1e48c0c62 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -478,7 +478,7 @@ void System::RegisterImageInterface(std::shared_ptr<Frontend::ImageInterface> im
     registered_image_interface = std::move(image_interface);
 }
 
-void System::Shutdown() {
+void System::Shutdown(bool is_deserializing) {
     // Log last frame performance stats
     const auto perf_results = GetAndResetPerfStats();
     telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed",
@@ -494,17 +494,19 @@ void System::Shutdown() {
     GDBStub::Shutdown();
     VideoCore::Shutdown();
     HW::Shutdown();
+    if (!is_deserializing) {
+        perf_stats.reset();
+        cheat_engine.reset();
+        app_loader.reset();
+    }
     telemetry_session.reset();
-    perf_stats.reset();
     rpc_server.reset();
-    cheat_engine.reset();
     archive_manager.reset();
     service_manager.reset();
     dsp_core.reset();
     cpu_cores.clear();
     kernel.reset();
     timing.reset();
-    app_loader.reset();
 
     if (video_dumper->IsDumping()) {
         video_dumper->StopDumping();
@@ -565,6 +567,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     // This needs to be set from somewhere - might as well be here!
     if (Archive::is_loading::value) {
         Service::GSP::SetGlobalModule(*this);
+        memory->SetDSP(*dsp_core);
     }
 }
 
diff --git a/src/core/core.h b/src/core/core.h
index dfb6aee3e..9fe98f723 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -113,7 +113,7 @@ public:
     ResultStatus SingleStep();
 
     /// Shutdown the emulated system.
-    void Shutdown();
+    void Shutdown(bool is_deserializing = false);
 
     /// Shutdown and then load again
     void Reset();
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
index d52789b2c..ae5ba11a8 100644
--- a/src/core/savestate.cpp
+++ b/src/core/savestate.cpp
@@ -8,6 +8,7 @@
 #include "common/logging/log.h"
 #include "common/scm_rev.h"
 #include "common/zstd_compression.h"
+#include "core/cheats/cheats.h"
 #include "core/core.h"
 #include "core/savestate.h"
 #include "video_core/video_core.h"
@@ -158,6 +159,15 @@ void System::LoadState(u32 slot) {
         std::ios_base::binary};
     decompressed.clear();
 
+    // When loading, we want to make sure any lingering state gets cleared out before we begin.
+    // Shutdown, but persist a few things between loads...
+    Shutdown(true);
+
+    // Re-initialize everything like it was before
+    auto system_mode = this->app_loader->LoadKernelSystemMode();
+    auto n3ds_mode = this->app_loader->LoadKernelN3dsMode();
+    Init(*m_emu_window, *system_mode.first, *n3ds_mode.first);
+
     try {
 
         {

From 714a85119dbfb4858fd8138ca4b8506c5807fe1b Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Wed, 1 Apr 2020 22:50:19 +0100
Subject: [PATCH 104/129] Don't crash when getting perf stats

---
 src/core/core.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 1e48c0c62..2a99d3ccc 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -296,7 +296,8 @@ void System::PrepareReschedule() {
 }
 
 PerfStats::Results System::GetAndResetPerfStats() {
-    return perf_stats->GetAndResetStats(timing->GetGlobalTimeUs());
+    return (perf_stats && timing) ? perf_stats->GetAndResetStats(timing->GetGlobalTimeUs())
+                                  : PerfStats::Results{};
 }
 
 void System::Reschedule() {

From d4ccce13657da93eee49cb125766f368f3e9e266 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 2 Apr 2020 00:14:00 +0100
Subject: [PATCH 105/129] Add some member initializers in thread

---
 src/core/hle/kernel/thread.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 09179c0e9..233381f67 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -303,25 +303,25 @@ public:
     VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
 
     /// Mutexes currently held by this thread, which will be released when it exits.
-    boost::container::flat_set<std::shared_ptr<Mutex>> held_mutexes;
+    boost::container::flat_set<std::shared_ptr<Mutex>> held_mutexes{};
 
     /// Mutexes that this thread is currently waiting for.
-    boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes;
+    boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes{};
 
-    std::shared_ptr<Process> owner_process; ///< Process that owns this thread
+    std::shared_ptr<Process> owner_process{}; ///< Process that owns this thread
 
     /// Objects that the thread is waiting on, in the same order as they were
     // passed to WaitSynchronization1/N.
-    std::vector<std::shared_ptr<WaitObject>> wait_objects;
+    std::vector<std::shared_ptr<WaitObject>> wait_objects{};
 
     VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
 
-    std::string name;
+    std::string name{};
 
     // Callback that will be invoked when the thread is resumed from a waiting state. If the thread
     // was waiting via WaitSynchronizationN then the object will be the last object that became
     // available. In case of a timeout, the object will be nullptr.
-    std::shared_ptr<WakeupCallback> wakeup_callback;
+    std::shared_ptr<WakeupCallback> wakeup_callback{};
 
     const u32 core_id;
 

From 74c06bd13e8e2bb11a26ec224b5fb5f3d1193b5c Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 2 Apr 2020 01:43:27 +0100
Subject: [PATCH 106/129] Attempt to fix crashes with LLE applets

---
 src/core/memory.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 184b7f9bd..c6a213ff0 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -284,8 +284,10 @@ void MemorySystem::RegisterPageTable(std::shared_ptr<PageTable> page_table) {
 }
 
 void MemorySystem::UnregisterPageTable(std::shared_ptr<PageTable> page_table) {
-    impl->page_table_list.erase(
-        std::find(impl->page_table_list.begin(), impl->page_table_list.end(), page_table));
+    auto it = std::find(impl->page_table_list.begin(), impl->page_table_list.end(), page_table);
+    if (it != impl->page_table_list.end()) {
+        impl->page_table_list.erase(it);
+    }
 }
 
 /**

From b5f394dd129e67058c87d86bc7fb33fa63356a1b Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 5 Apr 2020 00:20:59 +0100
Subject: [PATCH 107/129] Use placeholders for serialized paths

---
 src/common/file_util.cpp | 27 +++++++++++++++++++++++++++
 src/common/file_util.h   |  9 ++++++++-
 src/core/core.cpp        |  1 +
 3 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index af4d18288..fd1a3fd30 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -729,6 +729,33 @@ void SetUserPath(const std::string& path) {
     g_paths.emplace(UserPath::StatesDir, user_path + STATES_DIR DIR_SEP);
 }
 
+std::string g_currentRomPath{};
+
+void SetCurrentRomPath(const std::string& path) {
+    g_currentRomPath = path;
+}
+
+bool StringReplace(std::string& haystack, const std::string& a, const std::string& b, bool swap) {
+    const auto& needle = swap ? b : a;
+    const auto& replacement = swap ? a : b;
+    if (needle.empty()) {
+        return false;
+    }
+    auto index = haystack.find(needle, 0);
+    if (index == std::string::npos) {
+        return false;
+    }
+    haystack.replace(index, needle.size(), replacement);
+    return true;
+}
+
+std::string SerializePath(const std::string& input, bool is_saving) {
+    auto result = input;
+    StringReplace(result, "%CITRA_ROM_FILE%", g_currentRomPath, is_saving);
+    StringReplace(result, "%CITRA_USER_DIR%", GetUserPath(UserPath::UserDir), is_saving);
+    return result;
+}
+
 const std::string& GetUserPath(UserPath path) {
     // Set up all paths and files on the first run
     if (g_paths.empty())
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 1b1e65609..9eafa2416 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -140,10 +140,15 @@ bool SetCurrentDir(const std::string& directory);
 
 void SetUserPath(const std::string& path = "");
 
+void SetCurrentRomPath(const std::string& path);
+
 // Returns a pointer to a string with a Citra data dir in the user's home
 // directory. To be used in "multi-user" mode (that is, installed).
 const std::string& GetUserPath(UserPath path);
 
+// Replaces install-specific paths with standard placeholders, and back again
+std::string SerializePath(const std::string& input, bool is_saving);
+
 // Returns the path to where the sys file are
 std::string GetSysDirectory();
 
@@ -318,7 +323,8 @@ private:
 
     template <class Archive>
     void save(Archive& ar, const unsigned int) const {
-        ar << filename;
+        auto s_filename = SerializePath(filename, true);
+        ar << s_filename;
         ar << openmode;
         ar << flags;
         ar << Tell();
@@ -327,6 +333,7 @@ private:
     template <class Archive>
     void load(Archive& ar, const unsigned int) {
         ar >> filename;
+        filename = SerializePath(filename, false);
         ar >> openmode;
         ar >> flags;
         u64 pos;
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 2a99d3ccc..41fcb6855 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -214,6 +214,7 @@ System::ResultStatus System::SingleStep() {
 }
 
 System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
+    FileUtil::SetCurrentRomPath(filepath);
     app_loader = Loader::GetLoader(filepath);
     if (!app_loader) {
         LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);

From ac37de10fc63a93838be270ec09e0e4c6df460ce Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 6 Apr 2020 20:26:41 +0100
Subject: [PATCH 108/129] Reconnect cheat_engine during load

---
 src/core/cheats/cheats.cpp | 4 ++++
 src/core/cheats/cheats.h   | 1 +
 src/core/savestate.cpp     | 1 +
 3 files changed, 6 insertions(+)

diff --git a/src/core/cheats/cheats.cpp b/src/core/cheats/cheats.cpp
index 8b4a30ca6..9053b5ca6 100644
--- a/src/core/cheats/cheats.cpp
+++ b/src/core/cheats/cheats.cpp
@@ -18,6 +18,10 @@ constexpr u64 run_interval_ticks = BASE_CLOCK_RATE_ARM11 / 60;
 
 CheatEngine::CheatEngine(Core::System& system_) : system(system_) {
     LoadCheatFile();
+    Connect();
+}
+
+void CheatEngine::Connect() {
     event = system.CoreTiming().RegisterEvent(
         "CheatCore::run_event",
         [this](u64 thread_id, s64 cycle_late) { RunCallback(thread_id, cycle_late); });
diff --git a/src/core/cheats/cheats.h b/src/core/cheats/cheats.h
index a8d373038..1dfed7ab8 100644
--- a/src/core/cheats/cheats.h
+++ b/src/core/cheats/cheats.h
@@ -26,6 +26,7 @@ class CheatEngine {
 public:
     explicit CheatEngine(Core::System& system);
     ~CheatEngine();
+    void Connect();
     std::vector<std::shared_ptr<CheatBase>> GetCheats() const;
     void AddCheat(const std::shared_ptr<CheatBase>& cheat);
     void RemoveCheat(int index);
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
index ae5ba11a8..6a87569c7 100644
--- a/src/core/savestate.cpp
+++ b/src/core/savestate.cpp
@@ -167,6 +167,7 @@ void System::LoadState(u32 slot) {
     auto system_mode = this->app_loader->LoadKernelSystemMode();
     auto n3ds_mode = this->app_loader->LoadKernelN3dsMode();
     Init(*m_emu_window, *system_mode.first, *n3ds_mode.first);
+    cheat_engine->Connect();
 
     try {
 

From 7ff985cef9602f85af170095d9ce69b662dd71a7 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 6 Apr 2020 21:23:39 +0100
Subject: [PATCH 109/129] Fixed TAS movie serialization

---
 src/core/core.cpp             | 14 ++++++++++++++
 src/core/movie.h              | 16 ++++++++++++++--
 src/core/savestate.cpp        | 28 ++++------------------------
 src/video_core/video_core.cpp | 14 +++++---------
 src/video_core/video_core.h   |  4 ++--
 5 files changed, 39 insertions(+), 37 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 41fcb6855..fa6d0c30d 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -534,6 +534,17 @@ void System::Reset() {
 
 template <class Archive>
 void System::serialize(Archive& ar, const unsigned int file_version) {
+    if (Archive::is_loading::value) {
+        // When loading, we want to make sure any lingering state gets cleared out before we begin.
+        // Shutdown, but persist a few things between loads...
+        Shutdown(true);
+
+        // Re-initialize everything like it was before
+        auto system_mode = this->app_loader->LoadKernelSystemMode();
+        auto n3ds_mode = this->app_loader->LoadKernelN3dsMode();
+        Init(*m_emu_window, *system_mode.first, *n3ds_mode.first);
+    }
+
     u32 num_cores;
     if (Archive::is_saving::value) {
         num_cores = this->GetNumCores();
@@ -565,11 +576,14 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
 
     ar&* memory.get();
     ar&* kernel.get();
+    VideoCore::serialize(ar, file_version);
+    ar& Movie::GetInstance();
 
     // This needs to be set from somewhere - might as well be here!
     if (Archive::is_loading::value) {
         Service::GSP::SetGlobalModule(*this);
         memory->SetDSP(*dsp_core);
+        cheat_engine->Connect();
     }
 }
 
diff --git a/src/core/movie.h b/src/core/movie.h
index f1be86946..e578b909c 100644
--- a/src/core/movie.h
+++ b/src/core/movie.h
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <functional>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 
 namespace Service {
@@ -41,8 +42,8 @@ public:
         return s_instance;
     }
 
-    void StartPlayback(const std::string& movie_file,
-                       std::function<void()> completion_callback = [] {});
+    void StartPlayback(
+        const std::string& movie_file, std::function<void()> completion_callback = [] {});
     void StartRecording(const std::string& movie_file);
 
     /// Prepare to override the clock before playing back movies
@@ -132,5 +133,16 @@ private:
     u64 init_time;
     std::function<void()> playback_completion_callback;
     std::size_t current_byte = 0;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        // Only serialize what's needed to make savestates useful for TAS:
+        u64 _current_byte = static_cast<u64>(current_byte);
+        ar& _current_byte;
+        current_byte = static_cast<std::size_t>(_current_byte);
+        ar& recorded_input;
+        ar& init_time;
+    }
+    friend class boost::serialization::access;
 };
 } // namespace Core
\ No newline at end of file
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
index 6a87569c7..ece6406a1 100644
--- a/src/core/savestate.cpp
+++ b/src/core/savestate.cpp
@@ -84,13 +84,8 @@ std::vector<SaveStateInfo> ListSaveStates(u64 program_id) {
 void System::SaveState(u32 slot) const {
     std::ostringstream sstream{std::ios_base::binary};
     try {
-
-        {
-            oarchive oa{sstream};
-            oa&* this;
-        }
-        VideoCore::Save(sstream);
-
+        oarchive oa{sstream};
+        oa&* this;
     } catch (const std::exception& e) {
         LOG_ERROR(Core, "Error saving: {}", e.what());
     }
@@ -159,24 +154,9 @@ void System::LoadState(u32 slot) {
         std::ios_base::binary};
     decompressed.clear();
 
-    // When loading, we want to make sure any lingering state gets cleared out before we begin.
-    // Shutdown, but persist a few things between loads...
-    Shutdown(true);
-
-    // Re-initialize everything like it was before
-    auto system_mode = this->app_loader->LoadKernelSystemMode();
-    auto n3ds_mode = this->app_loader->LoadKernelN3dsMode();
-    Init(*m_emu_window, *system_mode.first, *n3ds_mode.first);
-    cheat_engine->Connect();
-
     try {
-
-        {
-            iarchive ia{sstream};
-            ia&* this;
-        }
-        VideoCore::Load(sstream);
-
+        iarchive ia{sstream};
+        ia&* this;
     } catch (const std::exception& e) {
         LOG_ERROR(Core, "Error loading: {}", e.what());
     }
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 5eccd8c7e..f33ec7d57 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -88,15 +88,11 @@ u16 GetResolutionScaleFactor() {
     }
 }
 
-void Save(std::ostream& stream) {
-    oarchive oa{stream};
-    oa& Pica::g_state;
-}
-
-void Load(std::istream& stream) {
-    iarchive ia{stream};
-    ia& Pica::g_state;
-    // TODO: Flush/reset things
+template <class Archive>
+void serialize(Archive& ar, const unsigned int) {
+    ar& Pica::g_state;
 }
 
 } // namespace VideoCore
+
+SERIALIZE_IMPL(VideoCore)
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 10b0d39b6..46cf1e86d 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -62,7 +62,7 @@ void RequestScreenshot(void* data, std::function<void()> callback,
 
 u16 GetResolutionScaleFactor();
 
-void Save(std::ostream& stream);
-void Load(std::istream& stream);
+template <class Archive>
+void serialize(Archive& ar, const unsigned int file_version);
 
 } // namespace VideoCore

From e74b44042b0af4b130d016f8c2023719fa08ba4a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 6 Apr 2020 22:47:52 +0100
Subject: [PATCH 110/129] Added save + load hotkeys

---
 src/citra_qt/configuration/config.cpp | 4 +++-
 src/citra_qt/main.cpp                 | 6 +++++-
 src/core/core.cpp                     | 4 +++-
 src/core/core.h                       | 3 +++
 4 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp
index d139a89e9..d815c99f5 100644
--- a/src/citra_qt/configuration/config.cpp
+++ b/src/citra_qt/configuration/config.cpp
@@ -57,7 +57,7 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
 // This must be in alphabetical order according to action name as it must have the same order as
 // UISetting::values.shortcuts, which is alphabetically ordered.
 // clang-format off
-const std::array<UISettings::Shortcut, 21> default_hotkeys{
+const std::array<UISettings::Shortcut, 23> default_hotkeys{
     {{QStringLiteral("Advance Frame"),            QStringLiteral("Main Window"), {QStringLiteral("\\"), Qt::ApplicationShortcut}},
      {QStringLiteral("Capture Screenshot"),       QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), Qt::ApplicationShortcut}},
      {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), Qt::WindowShortcut}},
@@ -73,6 +73,8 @@ const std::array<UISettings::Shortcut, 21> default_hotkeys{
      {QStringLiteral("Rotate Screens Upright"),   QStringLiteral("Main Window"), {QStringLiteral("F8"), Qt::WindowShortcut}},
      {QStringLiteral("Stop Emulation"),           QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
      {QStringLiteral("Swap Screens"),             QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::WindowShortcut}},
+     {QStringLiteral("Save to Oldest Slot"),      QStringLiteral("Main Window"), {QStringLiteral("Ctrl+C"), Qt::WindowShortcut}},
+     {QStringLiteral("Load from Newest Slot"),    QStringLiteral("Main Window"), {QStringLiteral("Ctrl+V"), Qt::WindowShortcut}},
      {QStringLiteral("Toggle Filter Bar"),        QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
      {QStringLiteral("Toggle Frame Advancing"),   QStringLiteral("Main Window"), {QStringLiteral("Ctrl+A"), Qt::ApplicationShortcut}},
      {QStringLiteral("Toggle Screen Layout"),     QStringLiteral("Main Window"), {QStringLiteral("F10"), Qt::WindowShortcut}},
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index a583e903a..0ef1e5bb1 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -524,6 +524,10 @@ void GMainWindow::InitializeHotkeys() {
                     OnCaptureScreenshot();
                 }
             });
+    connect(hotkey_registry.GetHotkey(main_window, ui.action_Load_from_Newest_Slot->text(), this),
+            &QShortcut::activated, ui.action_Load_from_Newest_Slot, &QAction::trigger);
+    connect(hotkey_registry.GetHotkey(main_window, ui.action_Save_to_Oldest_Slot->text(), this),
+            &QShortcut::activated, ui.action_Save_to_Oldest_Slot, &QAction::trigger);
 }
 
 void GMainWindow::ShowUpdaterWidgets() {
@@ -1636,7 +1640,7 @@ void GMainWindow::OnSaveState() {
     assert(action);
 
     Core::System::GetInstance().SendSignal(Core::System::Signal::Save, action->data().toUInt());
-    UpdateSaveStates();
+    newest_slot = action->data().toUInt();
 }
 
 void GMainWindow::OnLoadState() {
diff --git a/src/core/core.cpp b/src/core/core.cpp
index fa6d0c30d..3d915b764 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -577,7 +577,9 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
     ar&* memory.get();
     ar&* kernel.get();
     VideoCore::serialize(ar, file_version);
-    ar& Movie::GetInstance();
+    if (file_version >= 1) {
+        ar& Movie::GetInstance();
+    }
 
     // This needs to be set from somewhere - might as well be here!
     if (Archive::is_loading::value) {
diff --git a/src/core/core.h b/src/core/core.h
index 9fe98f723..ee66ff5bf 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -7,6 +7,7 @@
 #include <memory>
 #include <mutex>
 #include <string>
+#include <boost/serialization/version.hpp>
 #include "common/common_types.h"
 #include "core/custom_tex_cache.h"
 #include "core/frontend/applets/mii_selector.h"
@@ -401,3 +402,5 @@ inline AudioCore::DspInterface& DSP() {
 }
 
 } // namespace Core
+
+BOOST_CLASS_VERSION(Core::System, 1)

From 3278a4d7ef255e90626a9dd7b321e4a0bf0bafea Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 10 Apr 2020 14:02:18 +0100
Subject: [PATCH 111/129] Fix crashes when loading with cameras active

---
 src/core/hle/service/cam/cam.cpp | 13 +++++++++++++
 src/core/hle/service/cam/cam.h   | 10 ++++++++--
 2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
index e247d998f..c093ed7e5 100644
--- a/src/core/hle/service/cam/cam.cpp
+++ b/src/core/hle/service/cam/cam.cpp
@@ -30,6 +30,19 @@ void Module::serialize(Archive& ar, const unsigned int) {
     ar& cameras;
     ar& ports;
     ar& is_camera_reload_pending;
+    if (Archive::is_loading::value) {
+        for (int i = 0; i < NumCameras; i++) {
+            LoadCameraImplementation(cameras[i], i);
+        }
+        for (std::size_t i = 0; i < ports.size(); i++) {
+            if (ports[i].is_busy) {
+                cameras[ports[i].camera_id].impl->StartCapture();
+            }
+            if (ports[i].is_receiving) {
+                StartReceiving(static_cast<int>(i));
+            }
+        }
+    }
 }
 
 SERIALIZE_IMPL(Module)
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
index 04dc0e2ea..7c36e02c5 100644
--- a/src/core/hle/service/cam/cam.h
+++ b/src/core/hle/service/cam/cam.h
@@ -13,6 +13,7 @@
 #include <boost/serialization/deque.hpp>
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/unique_ptr.hpp>
+#include <boost/serialization/version.hpp>
 #include "common/common_types.h"
 #include "common/swap.h"
 #include "core/global.h"
@@ -792,8 +793,12 @@ private:
 
     private:
         template <class Archive>
-        void serialize(Archive& ar, const unsigned int) {
-            ar& impl;
+        void serialize(Archive& ar, const unsigned int file_version) {
+            // For compatibility: put a nullptr here
+            if (file_version == 0) {
+                std::unique_ptr<Camera::CameraInterface> x;
+                ar& x;
+            }
             ar& contexts;
             ar& current_context;
             ar& frame_rate;
@@ -883,3 +888,4 @@ void InstallInterfaces(Core::System& system);
 } // namespace Service::CAM
 
 SERVICE_CONSTRUCT(Service::CAM::Module)
+BOOST_CLASS_VERSION(Service::CAM::Module::CameraConfig, 1)

From 432ac24503082b2ec718b6364555bea05ab336f8 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 10 Apr 2020 16:51:01 +0100
Subject: [PATCH 112/129] Fix memory region serialization (OSK crash)

---
 src/common/serialization/boost_discrete_interval.hpp | 3 ++-
 src/common/serialization/boost_interval_set.hpp      | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/common/serialization/boost_discrete_interval.hpp b/src/common/serialization/boost_discrete_interval.hpp
index 961a9a7ef..f04e3cabc 100644
--- a/src/common/serialization/boost_discrete_interval.hpp
+++ b/src/common/serialization/boost_discrete_interval.hpp
@@ -6,6 +6,7 @@
 
 #include <boost/icl/discrete_interval.hpp>
 #include "common/common_types.h"
+#include "common/logging/log.h"
 
 namespace boost::serialization {
 
@@ -25,7 +26,7 @@ void load(Archive& ar, boost::icl::discrete_interval<DomainT, Compare>& obj,
     ar >> lower;
     ar >> upper;
     ar >> bounds;
-    obj = boost::icl::discrete_interval(upper, lower, boost::icl::interval_bounds(bounds));
+    obj = boost::icl::discrete_interval(lower, upper, boost::icl::interval_bounds(bounds));
 }
 
 template <class Archive, class DomainT, ICL_COMPARE Compare>
diff --git a/src/common/serialization/boost_interval_set.hpp b/src/common/serialization/boost_interval_set.hpp
index d4e48e62a..73a560360 100644
--- a/src/common/serialization/boost_interval_set.hpp
+++ b/src/common/serialization/boost_interval_set.hpp
@@ -26,7 +26,7 @@ void load(Archive& ar, boost::icl::interval_set<T>& set, const unsigned int file
     for (u64 i = 0; i < count; i++) {
         typename boost::icl::interval_set<T>::interval_type value{};
         ar >> value;
-        set.add(value);
+        set += value;
     }
 }
 

From 79889786615fb5d37237b368341fa58998a24e3c Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 10 Apr 2020 19:36:38 +0100
Subject: [PATCH 113/129] Fix VFP registers serialization (0 fps when loading
 etc.)

---
 src/citra_qt/debugger/wait_tree.cpp |  1 +
 src/core/arm/arm_interface.h        | 16 ++++++++++++----
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index 15a7ada03..30c1b00b5 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -236,6 +236,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
         break;
     }
 
+    list.push_back(std::make_unique<WaitTreeText>(tr("object id = %1").arg(thread.GetObjectId())));
     list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor)));
     list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadId())));
     list.push_back(std::make_unique<WaitTreeText>(tr("priority = %1(current) / %2(normal)")
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index a6b8a279a..967c672e6 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/split_member.hpp>
+#include <boost/serialization/version.hpp>
 #include "common/common_types.h"
 #include "core/arm/skyeye_common/arm_regformat.h"
 #include "core/arm/skyeye_common/vfp/asm_vfp.h"
@@ -30,7 +31,8 @@ public:
                 const auto r = GetCpuRegister(i);
                 ar << r;
             }
-            for (std::size_t i = 0; i < 16; i++) {
+            std::size_t fpu_reg_count = file_version == 0 ? 16 : 64;
+            for (std::size_t i = 0; i < fpu_reg_count; i++) {
                 const auto r = GetFpuRegister(i);
                 ar << r;
             }
@@ -49,7 +51,8 @@ public:
                 ar >> r;
                 SetCpuRegister(i, r);
             }
-            for (std::size_t i = 0; i < 16; i++) {
+            std::size_t fpu_reg_count = file_version == 0 ? 16 : 64;
+            for (std::size_t i = 0; i < fpu_reg_count; i++) {
                 ar >> r;
                 SetFpuRegister(i, r);
             }
@@ -254,7 +257,8 @@ private:
         ar << pc;
         const auto cpsr = GetCPSR();
         ar << cpsr;
-        for (int i = 0; i < 32; i++) {
+        int vfp_reg_count = file_version == 0 ? 32 : 64;
+        for (int i = 0; i < vfp_reg_count; i++) {
             const auto r = GetVFPReg(i);
             ar << r;
         }
@@ -285,7 +289,8 @@ private:
         SetPC(r);
         ar >> r;
         SetCPSR(r);
-        for (int i = 0; i < 32; i++) {
+        int vfp_reg_count = file_version == 0 ? 32 : 64;
+        for (int i = 0; i < vfp_reg_count; i++) {
             ar >> r;
             SetVFPReg(i, r);
         }
@@ -301,3 +306,6 @@ private:
 
     BOOST_SERIALIZATION_SPLIT_MEMBER()
 };
+
+BOOST_CLASS_VERSION(ARM_Interface, 1)
+BOOST_CLASS_VERSION(ARM_Interface::ThreadContext, 1)

From 701cd8378623ea99b21c18e5eed8519fe9b78f4a Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 10 Apr 2020 20:20:54 +0100
Subject: [PATCH 114/129] Attempt to fix mac and linux builds

---
 .travis/linux/upload.sh | 6 +++---
 .travis/macos/upload.sh | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/.travis/linux/upload.sh b/.travis/linux/upload.sh
index 548ee4905..c40c0d71e 100755
--- a/.travis/linux/upload.sh
+++ b/.travis/linux/upload.sh
@@ -8,9 +8,9 @@ COMPRESSION_FLAGS="-cJvf"
 
 mkdir "$REV_NAME"
 
-cp build/bin/citra "$REV_NAME"
-cp build/bin/citra-room "$REV_NAME"
-cp build/bin/citra-qt "$REV_NAME"
+cp build/bin/Release/citra "$REV_NAME"
+cp build/bin/Release/citra-room "$REV_NAME"
+cp build/bin/Release/citra-qt "$REV_NAME"
 
 # We need icons on Linux for .desktop entries
 mkdir "$REV_NAME/dist"
diff --git a/.travis/macos/upload.sh b/.travis/macos/upload.sh
index bdd7d7da7..05760c0b4 100755
--- a/.travis/macos/upload.sh
+++ b/.travis/macos/upload.sh
@@ -8,9 +8,9 @@ COMPRESSION_FLAGS="-czvf"
 
 mkdir "$REV_NAME"
 
-cp build/bin/citra "$REV_NAME"
-cp -r build/bin/citra-qt.app "$REV_NAME"
-cp build/bin/citra-room "$REV_NAME"
+cp build/bin/Release/citra "$REV_NAME"
+cp -r build/bin/Release/citra-qt.app "$REV_NAME"
+cp build/bin/Release/citra-room "$REV_NAME"
 
 # move libs into folder for deployment
 macpack "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt" -d "../Frameworks"

From 7b3a8e9bf53eadf1c111db8b657a6dd236c04bd9 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 10 Apr 2020 20:22:40 +0100
Subject: [PATCH 115/129] Fix clang format

---
 src/core/movie.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/core/movie.h b/src/core/movie.h
index e578b909c..eff148090 100644
--- a/src/core/movie.h
+++ b/src/core/movie.h
@@ -42,8 +42,8 @@ public:
         return s_instance;
     }
 
-    void StartPlayback(
-        const std::string& movie_file, std::function<void()> completion_callback = [] {});
+    void StartPlayback(const std::string& movie_file,
+                       std::function<void()> completion_callback = [] {});
     void StartRecording(const std::string& movie_file);
 
     /// Prepare to override the clock before playing back movies

From a210e7e2bd9ad3bb296c3882aede790df8c77246 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 10:28:52 +0100
Subject: [PATCH 116/129] Sync GPU state after loading (fix FE terrain bug)

---
 src/core/core.cpp                              | 2 ++
 src/video_core/rasterizer_interface.h          | 2 ++
 src/video_core/renderer_base.cpp               | 4 ++++
 src/video_core/renderer_base.h                 | 1 +
 src/video_core/renderer_opengl/gl_rasterizer.h | 6 +++---
 5 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 3d915b764..bdcee4ebd 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -44,6 +44,7 @@
 #include "core/rpc/rpc_server.h"
 #include "core/settings.h"
 #include "network/network.h"
+#include "video_core/renderer_base.h"
 #include "video_core/video_core.h"
 
 namespace Core {
@@ -586,6 +587,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
         Service::GSP::SetGlobalModule(*this);
         memory->SetDSP(*dsp_core);
         cheat_engine->Connect();
+        VideoCore::g_renderer->Sync();
     }
 }
 
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index a2510292e..873e4273e 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -87,5 +87,7 @@ public:
 
     virtual void LoadDiskResources(const std::atomic_bool& stop_loading,
                                    const DiskResourceLoadCallback& callback) {}
+
+    virtual void SyncEntireState() {}
 };
 } // namespace VideoCore
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index 4065d1a7d..8d18b6800 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -28,3 +28,7 @@ void RendererBase::RefreshRasterizerSetting() {
         }
     }
 }
+
+void RendererBase::Sync() {
+    rasterizer->SyncEntireState();
+}
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 7fcaf5370..578939a6e 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -68,6 +68,7 @@ public:
     }
 
     void RefreshRasterizerSetting();
+    void Sync();
 
 protected:
     Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 92cca2e4e..fee8363b6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -61,6 +61,9 @@ public:
                            u32 pixel_stride, ScreenInfo& screen_info) override;
     bool AccelerateDrawBatch(bool is_indexed) override;
 
+    /// Syncs entire status to match PICA registers
+    void SyncEntireState() override;
+
 private:
     struct SamplerInfo {
         using TextureConfig = Pica::TexturingRegs::TextureConfig;
@@ -132,9 +135,6 @@ private:
         GLvec3 view;
     };
 
-    /// Syncs entire status to match PICA registers
-    void SyncEntireState();
-
     /// Syncs the clip enabled status to match the PICA register
     void SyncClipEnabled();
 

From e9ab8f82d4e4057889340cc45431de4f8b75ee2b Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 11:52:11 +0100
Subject: [PATCH 117/129] Add disk archive serialization (fix crash in driver
 renegade etc.)

---
 src/common/file_util.h             | 74 +++++++++++++++++++++---------
 src/core/file_sys/disk_archive.cpp |  4 ++
 src/core/file_sys/disk_archive.h   | 28 ++++++++++-
 3 files changed, 83 insertions(+), 23 deletions(-)

diff --git a/src/common/file_util.h b/src/common/file_util.h
index 9eafa2416..d5915b8b7 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -16,6 +16,7 @@
 #include <vector>
 #include <boost/serialization/split_member.hpp>
 #include <boost/serialization/string.hpp>
+#include <boost/serialization/wrapper.hpp>
 #include "common/common_types.h"
 #ifdef _MSC_VER
 #include "common/string_util.h"
@@ -41,6 +42,34 @@ enum class UserPath {
     UserDir,
 };
 
+// Replaces install-specific paths with standard placeholders, and back again
+std::string SerializePath(const std::string& input, bool is_saving);
+
+// A serializable path string
+struct Path : public boost::serialization::wrapper_traits<const Path> {
+    std::string& str;
+
+    explicit Path(std::string& _str) : str(_str) {}
+
+    static const Path make(std::string& str) {
+        return Path(str);
+    }
+
+    template <class Archive>
+    void save(Archive& ar, const unsigned int) const {
+        auto s_path = SerializePath(str, true);
+        ar << s_path;
+    }
+    template <class Archive>
+    void load(Archive& ar, const unsigned int) const {
+        ar >> str;
+        str = SerializePath(str, false);
+    }
+
+    BOOST_SERIALIZATION_SPLIT_MEMBER();
+    friend class boost::serialization::access;
+};
+
 // FileSystem tree node/
 struct FSTEntry {
     bool isDirectory;
@@ -48,6 +77,17 @@ struct FSTEntry {
     std::string physicalName; // name on disk
     std::string virtualName;  // name in FST names table
     std::vector<FSTEntry> children;
+
+private:
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& isDirectory;
+        ar& size;
+        ar& Path::make(physicalName);
+        ar& Path::make(virtualName);
+        ar& children;
+    }
+    friend class boost::serialization::access;
 };
 
 // Returns true if file filename exists
@@ -146,9 +186,6 @@ void SetCurrentRomPath(const std::string& path);
 // directory. To be used in "multi-user" mode (that is, installed).
 const std::string& GetUserPath(UserPath path);
 
-// Replaces install-specific paths with standard placeholders, and back again
-std::string SerializePath(const std::string& input, bool is_saving);
-
 // Returns the path to where the sys file are
 std::string GetSysDirectory();
 
@@ -322,27 +359,20 @@ private:
     u32 flags;
 
     template <class Archive>
-    void save(Archive& ar, const unsigned int) const {
-        auto s_filename = SerializePath(filename, true);
-        ar << s_filename;
-        ar << openmode;
-        ar << flags;
-        ar << Tell();
-    }
-
-    template <class Archive>
-    void load(Archive& ar, const unsigned int) {
-        ar >> filename;
-        filename = SerializePath(filename, false);
-        ar >> openmode;
-        ar >> flags;
+    void serialize(Archive& ar, const unsigned int) {
+        ar& Path::make(filename);
+        ar& openmode;
+        ar& flags;
         u64 pos;
-        ar >> pos;
-        Open();
-        Seek(pos, SEEK_SET);
+        if (Archive::is_saving::value) {
+            pos = Tell();
+        }
+        ar& pos;
+        if (Archive::is_loading::value) {
+            Open();
+            Seek(pos, SEEK_SET);
+        }
     }
-
-    BOOST_SERIALIZATION_SPLIT_MEMBER()
     friend class boost::serialization::access;
 };
 
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index 061460546..6ace314bf 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <cstdio>
 #include <memory>
+#include "common/archives.h"
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "common/logging/log.h"
@@ -14,6 +15,9 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // FileSys namespace
 
+SERIALIZE_EXPORT_IMPL(FileSys::DiskFile)
+SERIALIZE_EXPORT_IMPL(FileSys::DiskDirectory)
+
 namespace FileSys {
 
 ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length,
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index 9251749ce..2f0e5691a 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -10,6 +10,7 @@
 #include <vector>
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/unique_ptr.hpp>
+#include <boost/serialization/vector.hpp>
 #include "common/common_types.h"
 #include "common/file_util.h"
 #include "core/file_sys/archive_backend.h"
@@ -46,12 +47,16 @@ protected:
     Mode mode;
     std::unique_ptr<FileUtil::IOFile> file;
 
+private:
+    DiskFile() = default;
+
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
         ar& boost::serialization::base_object<FileBackend>(*this);
-        ar& mode;
+        ar& mode.hex;
         ar& file;
     }
+    friend class boost::serialization::access;
 };
 
 class DiskDirectory : public DirectoryBackend {
@@ -74,6 +79,27 @@ protected:
     // We need to remember the last entry we returned, so a subsequent call to Read will continue
     // from the next one.  This iterator will always point to the next unread entry.
     std::vector<FileUtil::FSTEntry>::iterator children_iterator;
+
+private:
+    DiskDirectory() = default;
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::base_object<DirectoryBackend>(*this);
+        ar& directory;
+        u64 child_index;
+        if (Archive::is_saving::value) {
+            child_index = children_iterator - directory.children.begin();
+        }
+        ar& child_index;
+        if (Archive::is_loading::value) {
+            children_iterator = directory.children.begin() + child_index;
+        }
+    }
+    friend class boost::serialization::access;
 };
 
 } // namespace FileSys
+
+BOOST_CLASS_EXPORT_KEY(FileSys::DiskFile)
+BOOST_CLASS_EXPORT_KEY(FileSys::DiskDirectory)

From 3871d74bc213e8fd8ef712ef4724df3fe629ad7f Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 19:33:21 +0100
Subject: [PATCH 118/129] Fix mic sharedmemory not being deallocated

---
 src/core/hle/service/mic_u.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index 08ef5473f..f0017ac4c 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 
+#include <boost/serialization/weak_ptr.hpp>
 #ifdef HAVE_CUBEB
 #include "audio_core/cubeb_input.h"
 #endif
@@ -69,7 +70,7 @@ constexpr u64 GetBufferUpdateRate(SampleRate sample_rate) {
 
 // Variables holding the current mic buffer writing state
 struct State {
-    std::shared_ptr<Kernel::SharedMemory> memory_ref = nullptr;
+    std::weak_ptr<Kernel::SharedMemory> memory_ref{};
     u8* sharedmem_buffer = nullptr;
     u32 sharedmem_size = 0;
     std::size_t size = 0;
@@ -110,7 +111,9 @@ struct State {
 private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int) {
-        ar& memory_ref;
+        std::shared_ptr<Kernel::SharedMemory> _memory_ref = memory_ref.lock();
+        ar& _memory_ref;
+        memory_ref = _memory_ref;
         ar& sharedmem_size;
         ar& size;
         ar& offset;
@@ -118,7 +121,7 @@ private:
         ar& looped_buffer;
         ar& sample_size;
         ar& sample_rate;
-        sharedmem_buffer = memory_ref ? memory_ref->GetPointer() : nullptr;
+        sharedmem_buffer = _memory_ref ? _memory_ref->GetPointer() : nullptr;
     }
     friend class boost::serialization::access;
 };

From e6b40486c52142adfa7c4bd9e471280c1c600c60 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 19:47:06 +0100
Subject: [PATCH 119/129] Add a couple of useful SVC logs

---
 src/core/hle/kernel/svc.cpp       |  1 +
 src/core/hle/kernel/svc_wrapper.h | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 8f1ba5e01..25eb9bb4e 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1607,6 +1607,7 @@ void SVC::CallSVC(u32 immediate) {
                      "Running threads from exiting processes is unimplemented");
 
     const FunctionDef* info = GetSVCInfo(immediate);
+    LOG_TRACE(Kernel_SVC, "calling {}", info->name);
     if (info) {
         if (info->func) {
             (this->*(info->func))();
diff --git a/src/core/hle/kernel/svc_wrapper.h b/src/core/hle/kernel/svc_wrapper.h
index b4fbbe0de..77334152d 100644
--- a/src/core/hle/kernel/svc_wrapper.h
+++ b/src/core/hle/kernel/svc_wrapper.h
@@ -280,6 +280,26 @@ private:
         }
     };
 
+    template <typename SVCT>
+    struct WrapPass<SVCT, ResultCode /*empty for T, Ts...*/> {
+        // Call function R(Context::svc)(Us...) and transfer the return value to registers
+        template <typename... Us>
+        static void Call(Context& context, SVCT svc, Us... u) {
+            static_assert(std::is_same_v<SVCT, ResultCode (Context::*)(Us...)>);
+            if constexpr (std::is_void_v<ResultCode>) {
+                (context.*svc)(u...);
+            } else {
+                ResultCode r = (context.*svc)(u...);
+                if (r.IsError()) {
+                    LOG_ERROR(Kernel_SVC, "level={} summary={} module={} description={}",
+                              r.level.ExtractValue(r.raw), r.summary.ExtractValue(r.raw),
+                              r.module.ExtractValue(r.raw), r.description.ExtractValue(r.raw));
+                }
+                SetParam<INDEX_RETURN, ResultCode, ResultCode, Us...>(context, r);
+            }
+        }
+    };
+
     template <typename T>
     struct WrapHelper;
 

From 4be752dd980a18b922939acbd92a12f599cedf04 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 19:47:31 +0100
Subject: [PATCH 120/129] Allow GDB debugging through loads

---
 src/core/core.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index bdcee4ebd..8768ba3e6 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -494,10 +494,10 @@ void System::Shutdown(bool is_deserializing) {
                                 perf_stats->GetMeanFrametime());
 
     // Shutdown emulation session
-    GDBStub::Shutdown();
     VideoCore::Shutdown();
     HW::Shutdown();
     if (!is_deserializing) {
+        GDBStub::Shutdown();
         perf_stats.reset();
         cheat_engine.reset();
         app_loader.reset();

From 34af0d3452192a5d880a0b305d7fd31e9375da52 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 20:33:38 +0100
Subject: [PATCH 121/129] Attempt to fix network bug

---
 src/core/hle/service/nwm/nwm_uds.cpp |  3 +++
 src/core/savestate.cpp               | 12 ++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 1a95d2295..8ebb8a6e3 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -504,6 +504,9 @@ void NWM_UDS::HandleDataFrame(const Network::WifiPacket& packet) {
 
 /// Callback to parse and handle a received wifi packet.
 void NWM_UDS::OnWifiPacketReceived(const Network::WifiPacket& packet) {
+    if (!initialized) {
+        return;
+    }
     switch (packet.type) {
     case Network::WifiPacket::PacketType::Beacon:
         HandleBeaconFrame(packet);
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
index ece6406a1..2a6fb92cb 100644
--- a/src/core/savestate.cpp
+++ b/src/core/savestate.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <chrono>
+#include <boost/serialization/binary_object.hpp>
 #include <cryptopp/hex.h>
 #include "common/archives.h"
 #include "common/logging/log.h"
@@ -11,6 +12,7 @@
 #include "core/cheats/cheats.h"
 #include "core/core.h"
 #include "core/savestate.h"
+#include "network/network.h"
 #include "video_core/video_core.h"
 
 namespace Core {
@@ -23,6 +25,11 @@ struct CSTHeader {
     u64_le time;                 /// The time when this save state was created
 
     std::array<u8, 216> reserved; /// Make heading 256 bytes so it has consistent size
+
+    template <class Archive>
+    void serialize(Archive& ar, const unsigned int) {
+        ar& boost::serialization::binary_object(this, sizeof(CSTHeader));
+    }
 };
 static_assert(sizeof(CSTHeader) == 256, "CSTHeader should be 256 bytes");
 #pragma pack(pop)
@@ -127,6 +134,11 @@ void System::SaveState(u32 slot) const {
 }
 
 void System::LoadState(u32 slot) {
+    if (Network::GetRoomMember().lock()->IsConnected()) {
+        LOG_ERROR(Core, "Unable to load while connected to multiplayer");
+        return;
+    }
+
     const auto path = GetSaveStatePath(title_id, slot);
     if (!FileUtil::Exists(path)) {
         LOG_ERROR(Core, "File not exist {}", path);

From 19872b599baa824ff26716a502a4c6ca441c1347 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 20:47:14 +0100
Subject: [PATCH 122/129] Fix button state not persisting between loads

---
 src/core/hle/service/hid/hid.cpp | 6 ++++--
 src/core/hle/service/hid/hid.h   | 2 ++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 981a4aa63..4c8718276 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -30,7 +30,7 @@ SERIALIZE_EXPORT_IMPL(Service::HID::Module)
 namespace Service::HID {
 
 template <class Archive>
-void Module::serialize(Archive& ar, const unsigned int) {
+void Module::serialize(Archive& ar, const unsigned int file_version) {
     ar& shared_mem;
     ar& event_pad_or_touch_1;
     ar& event_pad_or_touch_2;
@@ -46,7 +46,9 @@ void Module::serialize(Archive& ar, const unsigned int) {
     if (Archive::is_loading::value) {
         LoadInputDevices();
     }
-    // Pad state not needed as it's always updated
+    if (file_version >= 1) {
+        ar& state.hex;
+    }
     // Update events are set in the constructor
     // Devices are set from the implementation (and are stateless afaik)
 }
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index ad526ac6f..58a3c68a5 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -8,6 +8,7 @@
 #include <atomic>
 #include <cstddef>
 #include <memory>
+#include <boost/serialization/version.hpp>
 #include "common/bit_field.h"
 #include "common/common_funcs.h"
 #include "common/common_types.h"
@@ -348,3 +349,4 @@ void InstallInterfaces(Core::System& system);
 
 SERVICE_CONSTRUCT(Service::HID::Module)
 BOOST_CLASS_EXPORT_KEY(Service::HID::Module)
+BOOST_CLASS_VERSION(Service::HID::Module, 1)

From 77c4b26e6ce4d4c35b0789c361a9dda69c5a0d06 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sat, 11 Apr 2020 22:25:57 +0100
Subject: [PATCH 123/129] Attempt to improve save/load during frame advance

---
 src/citra_qt/main.cpp   |  3 ++
 src/core/core.cpp       | 67 +++++++++++++++++++++--------------------
 src/core/perf_stats.cpp | 12 +++++---
 src/core/perf_stats.h   |  1 +
 4 files changed, 46 insertions(+), 37 deletions(-)

diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 0ef1e5bb1..bd1c95c52 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -706,6 +706,7 @@ void GMainWindow::ConnectMenuEvents() {
         if (emulation_running) {
             ui.action_Enable_Frame_Advancing->setChecked(true);
             ui.action_Advance_Frame->setEnabled(true);
+            Core::System::GetInstance().frame_limiter.SetFrameAdvancing(true);
             Core::System::GetInstance().frame_limiter.AdvanceFrame();
         }
     });
@@ -1640,6 +1641,7 @@ void GMainWindow::OnSaveState() {
     assert(action);
 
     Core::System::GetInstance().SendSignal(Core::System::Signal::Save, action->data().toUInt());
+    Core::System::GetInstance().frame_limiter.AdvanceFrame();
     newest_slot = action->data().toUInt();
 }
 
@@ -1648,6 +1650,7 @@ void GMainWindow::OnLoadState() {
     assert(action);
 
     Core::System::GetInstance().SendSignal(Core::System::Signal::Load, action->data().toUInt());
+    Core::System::GetInstance().frame_limiter.AdvanceFrame();
 }
 
 void GMainWindow::OnConfigure() {
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 8768ba3e6..58f1ddefe 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -89,6 +89,40 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
         }
     }
 
+    Signal signal{Signal::None};
+    u32 param{};
+    {
+        std::lock_guard lock{signal_mutex};
+        if (current_signal != Signal::None) {
+            signal = current_signal;
+            param = signal_param;
+            current_signal = Signal::None;
+        }
+    }
+    switch (signal) {
+    case Signal::Reset:
+        Reset();
+        return ResultStatus::Success;
+    case Signal::Shutdown:
+        return ResultStatus::ShutdownRequested;
+    case Signal::Load: {
+        LOG_INFO(Core, "Begin load");
+        System::LoadState(param);
+        LOG_INFO(Core, "Load completed");
+        frame_limiter.WaitOnce();
+        return ResultStatus::Success;
+    }
+    case Signal::Save: {
+        LOG_INFO(Core, "Begin save");
+        System::SaveState(param);
+        LOG_INFO(Core, "Save completed");
+        frame_limiter.WaitOnce();
+        return ResultStatus::Success;
+    }
+    default:
+        break;
+    }
+
     // All cores should have executed the same amount of ticks. If this is not the case an event was
     // scheduled with a cycles_into_future smaller then the current downcount.
     // So we have to get those cores to the same global time first
@@ -163,39 +197,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
     HW::Update();
     Reschedule();
 
-    Signal signal{Signal::None};
-    u32 param{};
-    {
-        std::lock_guard lock{signal_mutex};
-        if (current_signal != Signal::None) {
-            signal = current_signal;
-            param = signal_param;
-            current_signal = Signal::None;
-        }
-    }
-    switch (signal) {
-    case Signal::Reset:
-        Reset();
-        break;
-    case Signal::Shutdown:
-        return ResultStatus::ShutdownRequested;
-        break;
-    case Signal::Load: {
-        LOG_INFO(Core, "Begin load");
-        System::LoadState(param);
-        LOG_INFO(Core, "Load completed");
-        break;
-    }
-    case Signal::Save: {
-        LOG_INFO(Core, "Begin save");
-        System::SaveState(param);
-        LOG_INFO(Core, "Save completed");
-        break;
-    }
-    default:
-        break;
-    }
-
     return status;
 }
 
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index 94d6c17ca..00ab24dbc 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -117,6 +117,14 @@ double PerfStats::GetLastFrameTimeScale() {
     return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
 }
 
+void FrameLimiter::WaitOnce() {
+    if (frame_advancing_enabled) {
+        // Frame advancing is enabled: wait on event instead of doing framelimiting
+        frame_advance_event.Wait();
+        frame_advance_event.Reset();
+    }
+}
+
 void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
     if (frame_advancing_enabled) {
         // Frame advancing is enabled: wait on event instead of doing framelimiting
@@ -164,10 +172,6 @@ void FrameLimiter::SetFrameAdvancing(bool value) {
 }
 
 void FrameLimiter::AdvanceFrame() {
-    if (!frame_advancing_enabled) {
-        // Start frame advancing
-        frame_advancing_enabled = true;
-    }
     frame_advance_event.Set();
 }
 
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index 0ef5168fa..c7d22ef8e 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -98,6 +98,7 @@ public:
      */
     void SetFrameAdvancing(bool value);
     void AdvanceFrame();
+    void WaitOnce();
 
 private:
     /// Emulated system time (in microseconds) at the last limiter invocation

From d53e94db88d18178ed73a5bc48b8df8e2fa4c992 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Sun, 12 Apr 2020 23:12:15 +0100
Subject: [PATCH 124/129] Show save/load errors to the user

---
 src/citra_qt/main.cpp  |  3 +++
 src/core/core.cpp      | 20 +++++++++++++----
 src/core/core.h        |  1 +
 src/core/savestate.cpp | 49 ++++++++++++------------------------------
 4 files changed, 34 insertions(+), 39 deletions(-)

diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index f6dc3f2ef..7389b8c23 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -2079,6 +2079,9 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
 
         title = tr("System Archive Not Found");
         status_message = tr("System Archive Missing");
+    } else if (result == Core::System::ResultStatus::ErrorSavestate) {
+        title = tr("Save/load Error");
+        message = QString::fromStdString(details);
     } else {
         title = tr("Fatal Error");
         message =
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 1421d7f70..14b41207a 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -107,15 +107,27 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
         return ResultStatus::ShutdownRequested;
     case Signal::Load: {
         LOG_INFO(Core, "Begin load");
-        System::LoadState(param);
-        LOG_INFO(Core, "Load completed");
+        try {
+            System::LoadState(param);
+            LOG_INFO(Core, "Load completed");
+        } catch (const std::exception& e) {
+            LOG_ERROR(Core, "Error loading: {}", e.what());
+            status_details = e.what();
+            return ResultStatus::ErrorSavestate;
+        }
         frame_limiter.WaitOnce();
         return ResultStatus::Success;
     }
     case Signal::Save: {
         LOG_INFO(Core, "Begin save");
-        System::SaveState(param);
-        LOG_INFO(Core, "Save completed");
+        try {
+            System::SaveState(param);
+            LOG_INFO(Core, "Save completed");
+        } catch (const std::exception& e) {
+            LOG_ERROR(Core, "Error saving: {}", e.what());
+            status_details = e.what();
+            return ResultStatus::ErrorSavestate;
+        }
         frame_limiter.WaitOnce();
         return ResultStatus::Success;
     }
diff --git a/src/core/core.h b/src/core/core.h
index eb3dc01b3..dca6a6888 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -89,6 +89,7 @@ public:
                                             /// generic drivers installed
         ErrorVideoCore_ErrorBelowGL33,      ///< Error in the video core due to the user not having
                                             /// OpenGL 3.3 or higher
+        ErrorSavestate,                     ///< Error saving or loading
         ShutdownRequested,                  ///< Emulated program requested a system shutdown
         ErrorUnknown                        ///< Any other error
     };
diff --git a/src/core/savestate.cpp b/src/core/savestate.cpp
index 2a6fb92cb..26fc0cbed 100644
--- a/src/core/savestate.cpp
+++ b/src/core/savestate.cpp
@@ -90,26 +90,22 @@ std::vector<SaveStateInfo> ListSaveStates(u64 program_id) {
 
 void System::SaveState(u32 slot) const {
     std::ostringstream sstream{std::ios_base::binary};
-    try {
-        oarchive oa{sstream};
-        oa&* this;
-    } catch (const std::exception& e) {
-        LOG_ERROR(Core, "Error saving: {}", e.what());
-    }
+    // Serialize
+    oarchive oa{sstream};
+    oa&* this;
+
     const std::string& str{sstream.str()};
     auto buffer = Common::Compression::CompressDataZSTDDefault(
         reinterpret_cast<const u8*>(str.data()), str.size());
 
     const auto path = GetSaveStatePath(title_id, slot);
     if (!FileUtil::CreateFullPath(path)) {
-        LOG_ERROR(Core, "Could not create path {}", path);
-        return;
+        throw std::runtime_error("Could not create path " + path);
     }
 
     FileUtil::IOFile file(path, "wb");
     if (!file) {
-        LOG_ERROR(Core, "Could not open file {}", path);
-        return;
+        throw std::runtime_error("Could not open file " + path);
     }
 
     CSTHeader header{};
@@ -123,41 +119,27 @@ void System::SaveState(u32 slot) const {
                       std::chrono::system_clock::now().time_since_epoch())
                       .count();
 
-    if (file.WriteBytes(&header, sizeof(header)) != sizeof(header)) {
-        LOG_ERROR(Core, "Could not write to file {}", path);
-        return;
-    }
-    if (file.WriteBytes(buffer.data(), buffer.size()) != buffer.size()) {
-        LOG_ERROR(Core, "Could not write to file {}", path);
-        return;
+    if (file.WriteBytes(&header, sizeof(header)) != sizeof(header) ||
+        file.WriteBytes(buffer.data(), buffer.size()) != buffer.size()) {
+        throw std::runtime_error("Could not write to file " + path);
     }
 }
 
 void System::LoadState(u32 slot) {
     if (Network::GetRoomMember().lock()->IsConnected()) {
-        LOG_ERROR(Core, "Unable to load while connected to multiplayer");
-        return;
+        throw std::runtime_error("Unable to load while connected to multiplayer");
     }
 
     const auto path = GetSaveStatePath(title_id, slot);
-    if (!FileUtil::Exists(path)) {
-        LOG_ERROR(Core, "File not exist {}", path);
-        return;
-    }
 
     std::vector<u8> decompressed;
     {
         std::vector<u8> buffer(FileUtil::GetSize(path) - sizeof(CSTHeader));
 
         FileUtil::IOFile file(path, "rb");
-        if (!file) {
-            LOG_ERROR(Core, "Could not open file {}", path);
-            return;
-        }
         file.Seek(sizeof(CSTHeader), SEEK_SET); // Skip header
         if (file.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
-            LOG_ERROR(Core, "Could not read from file {}", path);
-            return;
+            throw std::runtime_error("Could not read from file at " + path);
         }
         decompressed = Common::Compression::DecompressDataZSTD(buffer);
     }
@@ -166,12 +148,9 @@ void System::LoadState(u32 slot) {
         std::ios_base::binary};
     decompressed.clear();
 
-    try {
-        iarchive ia{sstream};
-        ia&* this;
-    } catch (const std::exception& e) {
-        LOG_ERROR(Core, "Error loading: {}", e.what());
-    }
+    // Deserialize
+    iarchive ia{sstream};
+    ia&* this;
 }
 
 } // namespace Core

From 4d6bd9b569fca16325d6c3968bd68d4a6290c172 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 13 Apr 2020 11:50:27 +0100
Subject: [PATCH 125/129] Fix the merge

---
 src/citra_qt/debugger/wait_tree.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index 66b047e75..32ee7a1df 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -216,7 +216,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
     std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
 
     const auto& thread = static_cast<const Kernel::Thread&>(object);
-    const auto* process = thread.owner_process;
+    const auto& process = thread.owner_process;
 
     QString processor;
     switch (thread.processor_id) {

From 3a651ac9fcb1630ebedc7668b43612815f078f11 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Mon, 13 Apr 2020 18:08:15 +0100
Subject: [PATCH 126/129] Fix clang format

---
 src/core/core.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/core/core.h b/src/core/core.h
index dca6a6888..e7fbd8ee3 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -316,7 +316,8 @@ private:
      * @param system_mode The system mode.
      * @return ResultStatus code, indicating if the operation succeeded.
      */
-    ResultStatus Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode, u32 num_cores);
+    ResultStatus Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode,
+                      u32 num_cores);
 
     /// Reschedule the core emulation
     void Reschedule();

From 824453b133f1873a1113c2c6f7fdc901116ebbad Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 16 Apr 2020 19:04:04 +0100
Subject: [PATCH 127/129] Remove the build type from the bin path

---
 .travis/linux/upload.sh | 6 +++---
 .travis/macos/upload.sh | 6 +++---
 CMakeLists.txt          | 2 +-
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/.travis/linux/upload.sh b/.travis/linux/upload.sh
index c40c0d71e..548ee4905 100755
--- a/.travis/linux/upload.sh
+++ b/.travis/linux/upload.sh
@@ -8,9 +8,9 @@ COMPRESSION_FLAGS="-cJvf"
 
 mkdir "$REV_NAME"
 
-cp build/bin/Release/citra "$REV_NAME"
-cp build/bin/Release/citra-room "$REV_NAME"
-cp build/bin/Release/citra-qt "$REV_NAME"
+cp build/bin/citra "$REV_NAME"
+cp build/bin/citra-room "$REV_NAME"
+cp build/bin/citra-qt "$REV_NAME"
 
 # We need icons on Linux for .desktop entries
 mkdir "$REV_NAME/dist"
diff --git a/.travis/macos/upload.sh b/.travis/macos/upload.sh
index 05760c0b4..bdd7d7da7 100755
--- a/.travis/macos/upload.sh
+++ b/.travis/macos/upload.sh
@@ -8,9 +8,9 @@ COMPRESSION_FLAGS="-czvf"
 
 mkdir "$REV_NAME"
 
-cp build/bin/Release/citra "$REV_NAME"
-cp -r build/bin/Release/citra-qt.app "$REV_NAME"
-cp build/bin/Release/citra-room "$REV_NAME"
+cp build/bin/citra "$REV_NAME"
+cp -r build/bin/citra-qt.app "$REV_NAME"
+cp build/bin/citra-room "$REV_NAME"
 
 # move libs into folder for deployment
 macpack "${REV_NAME}/citra-qt.app/Contents/MacOS/citra-qt" -d "../Frameworks"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 50153c808..e85534e8f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -126,7 +126,7 @@ set(CMAKE_CXX_STANDARD 17)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 # set up output paths for executable binaries
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
 
 
 # System imported libraries

From d6c84227d85a9a2935c991b49513e26379c24600 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Thu, 16 Apr 2020 20:44:25 +0100
Subject: [PATCH 128/129] Fixed NWM not responding

---
 src/core/hle/service/nwm/nwm_uds.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 8ebb8a6e3..cba699f25 100644
--- a/src/core/hle/service/nwm/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -552,8 +552,7 @@ boost::optional<Network::MacAddress> NWM_UDS::GetNodeMacAddress(u16 dest_node_id
 void NWM_UDS::Shutdown(Kernel::HLERequestContext& ctx) {
     IPC::RequestParser rp(ctx, 0x03, 0, 0);
 
-    if (auto room_member = Network::GetRoomMember().lock())
-        room_member->Unbind(wifi_packet_received);
+    initialized = false;
 
     for (auto bind_node : channel_data) {
         bind_node.second.event->Signal();

From f5b23eff4b9593f3212b16b964ec481565cf7fe9 Mon Sep 17 00:00:00 2001
From: Hamish Milne <hamishmilne83@gmail.com>
Date: Fri, 17 Apr 2020 14:11:58 +0100
Subject: [PATCH 129/129] Correctly register AddressArbiter as a type of
 WakeupCallback

---
 src/core/hle/kernel/address_arbiter.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 059ff1400..c7a263d9e 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -11,6 +11,7 @@
 #include <boost/serialization/shared_ptr.hpp>
 #include <boost/serialization/string.hpp>
 #include <boost/serialization/vector.hpp>
+#include <boost/serialization/version.hpp>
 #include "common/common_types.h"
 #include "core/hle/kernel/object.h"
 #include "core/hle/kernel/thread.h"
@@ -81,6 +82,9 @@ private:
     template <class Archive>
     void serialize(Archive& ar, const unsigned int file_version) {
         ar& boost::serialization::base_object<Object>(*this);
+        if (file_version > 0) {
+            ar& boost::serialization::base_object<WakeupCallback>(*this);
+        }
         ar& name;
         ar& waiting_threads;
     }
@@ -89,4 +93,5 @@ private:
 } // namespace Kernel
 
 BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter)
+BOOST_CLASS_VERSION(Kernel::AddressArbiter, 1)
 CONSTRUCT_KERNEL_OBJECT(Kernel::AddressArbiter)