diff --git a/stratosphere/Makefile b/stratosphere/Makefile
index 4bb30a81a..082453c83 100644
--- a/stratosphere/Makefile
+++ b/stratosphere/Makefile
@@ -1,4 +1,4 @@
-MODULES := loader ncm pm sm boot ams_mitm spl eclct.stub ro creport fatal dmnt boot2 erpt pgl jpegdec LogManager cs htc TioServer
+MODULES := loader ncm pm sm boot ams_mitm spl eclct.stub ro creport fatal dmnt boot2 erpt pgl jpegdec LogManager cs htc TioServer dmnt.gen2
SUBFOLDERS := $(MODULES)
diff --git a/stratosphere/dmnt.gen2/Makefile b/stratosphere/dmnt.gen2/Makefile
new file mode 100644
index 000000000..aab86a63a
--- /dev/null
+++ b/stratosphere/dmnt.gen2/Makefile
@@ -0,0 +1,113 @@
+#---------------------------------------------------------------------------------
+# pull in common stratosphere sysmodule configuration
+#---------------------------------------------------------------------------------
+include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk
+
+#---------------------------------------------------------------------------------
+# no real need to edit anything past this point unless you need to add additional
+# rules for different file extensions
+#---------------------------------------------------------------------------------
+ifneq ($(BUILD),$(notdir $(CURDIR)))
+#---------------------------------------------------------------------------------
+
+export OUTPUT := $(CURDIR)/$(TARGET)
+export TOPDIR := $(CURDIR)
+
+export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
+ $(foreach dir,$(DATA),$(CURDIR)/$(dir))
+
+export DEPSDIR := $(CURDIR)/$(BUILD)
+
+CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
+CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
+SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
+
+BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
+
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+ifeq ($(strip $(CPPFILES)),)
+#---------------------------------------------------------------------------------
+ export LD := $(CC)
+#---------------------------------------------------------------------------------
+else
+#---------------------------------------------------------------------------------
+ export LD := $(CXX)
+#---------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------
+
+export OFILES := $(addsuffix .o,$(BINFILES)) \
+ $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
+
+export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
+ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+ -I$(CURDIR)/$(BUILD)
+
+export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
+
+export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
+
+ifeq ($(strip $(CONFIG_JSON)),)
+ jsons := $(wildcard *.json)
+ ifneq (,$(findstring $(TARGET).json,$(jsons)))
+ export APP_JSON := $(TOPDIR)/$(TARGET).json
+ else
+ ifneq (,$(findstring config.json,$(jsons)))
+ export APP_JSON := $(TOPDIR)/config.json
+ endif
+ endif
+else
+ export APP_JSON := $(TOPDIR)/$(CONFIG_JSON)
+endif
+
+.PHONY: $(BUILD) clean all
+
+#---------------------------------------------------------------------------------
+all: $(BUILD)
+
+$(BUILD):
+ @[ -d $@ ] || mkdir -p $@
+ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+
+#---------------------------------------------------------------------------------
+clean:
+ @echo clean ...
+ @rm -fr $(BUILD) $(TARGET).nsp $(TARGET).npdm $(TARGET).nso $(TARGET).elf
+
+
+#---------------------------------------------------------------------------------
+else
+.PHONY: all
+
+DEPENDS := $(OFILES:.o=.d)
+
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+all : $(OUTPUT).nsp
+
+ifeq ($(strip $(APP_JSON)),)
+$(OUTPUT).nsp : $(OUTPUT).nso
+else
+$(OUTPUT).nsp : $(OUTPUT).nso $(OUTPUT).npdm
+endif
+
+$(OUTPUT).nso : $(OUTPUT).elf
+
+$(OUTPUT).elf : $(OFILES)
+
+#---------------------------------------------------------------------------------
+# you need a rule like this for each extension you use as binary data
+#---------------------------------------------------------------------------------
+%.bin.o : %.bin
+#---------------------------------------------------------------------------------
+ @echo $(notdir $<)
+ @$(bin2o)
+
+-include $(DEPENDS)
+
+#---------------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------------
diff --git a/stratosphere/dmnt.gen2/dmnt.gen2.json b/stratosphere/dmnt.gen2/dmnt.gen2.json
new file mode 100644
index 000000000..b6dc58e4e
--- /dev/null
+++ b/stratosphere/dmnt.gen2/dmnt.gen2.json
@@ -0,0 +1,103 @@
+{
+ "name": "dmnt.gen2",
+ "title_id": "0x010000000000D609",
+ "title_id_range_min": "0x010000000000D609",
+ "title_id_range_max": "0x010000000000D609",
+ "main_thread_stack_size": "0x00001000",
+ "main_thread_priority": 39,
+ "default_cpu_id": 3,
+ "process_category": 0,
+ "is_retail": true,
+ "pool_partition": 2,
+ "is_64_bit": true,
+ "address_space_type": 3,
+ "disable_device_address_space_merge": true,
+ "filesystem_access": {
+ "permissions": "0xFFFFFFFFFFFFFFFF"
+ },
+ "service_access": ["pm:dmnt", "ldr:dmnt", "ro:dmnt", "ns:dev", "lr", "fsp-srv", "fatal:u", "pgl", "htcs"],
+ "service_host": [],
+ "kernel_capabilities": [{
+ "type": "kernel_flags",
+ "value": {
+ "highest_thread_priority": 63,
+ "lowest_thread_priority": 24,
+ "lowest_cpu_id": 3,
+ "highest_cpu_id": 3
+ }
+ }, {
+ "type": "syscalls",
+ "value": {
+ "svcSetHeapSize": "0x01",
+ "svcSetMemoryPermission": "0x02",
+ "svcSetMemoryAttribute": "0x03",
+ "svcMapMemory": "0x04",
+ "svcUnmapMemory": "0x05",
+ "svcQueryMemory": "0x06",
+ "svcExitProcess": "0x07",
+ "svcCreateThread": "0x08",
+ "svcStartThread": "0x09",
+ "svcExitThread": "0x0a",
+ "svcSleepThread": "0x0b",
+ "svcGetThreadPriority": "0x0c",
+ "svcSetThreadPriority": "0x0d",
+ "svcGetThreadCoreMask": "0x0e",
+ "svcSetThreadCoreMask": "0x0f",
+ "svcGetCurrentProcessorNumber": "0x10",
+ "svcSignalEvent": "0x11",
+ "svcClearEvent": "0x12",
+ "svcMapSharedMemory": "0x13",
+ "svcUnmapSharedMemory": "0x14",
+ "svcCreateTransferMemory": "0x15",
+ "svcCloseHandle": "0x16",
+ "svcResetSignal": "0x17",
+ "svcWaitSynchronization": "0x18",
+ "svcCancelSynchronization": "0x19",
+ "svcArbitrateLock": "0x1a",
+ "svcArbitrateUnlock": "0x1b",
+ "svcWaitProcessWideKeyAtomic": "0x1c",
+ "svcSignalProcessWideKey": "0x1d",
+ "svcGetSystemTick": "0x1e",
+ "svcConnectToNamedPort": "0x1f",
+ "svcSendSyncRequestLight": "0x20",
+ "svcSendSyncRequest": "0x21",
+ "svcSendSyncRequestWithUserBuffer": "0x22",
+ "svcSendAsyncRequestWithUserBuffer": "0x23",
+ "svcGetProcessId": "0x24",
+ "svcGetThreadId": "0x25",
+ "svcBreak": "0x26",
+ "svcOutputDebugString": "0x27",
+ "svcReturnFromException": "0x28",
+ "svcGetInfo": "0x29",
+ "svcWaitForAddress": "0x34",
+ "svcSignalToAddress": "0x35",
+ "svcCreateSession": "0x40",
+ "svcAcceptSession": "0x41",
+ "svcReplyAndReceiveLight": "0x42",
+ "svcReplyAndReceive": "0x43",
+ "svcReplyAndReceiveWithUserBuffer": "0x44",
+ "svcCreateEvent": "0x45",
+ "svcDebugActiveProcess": "0x60",
+ "svcBreakDebugProcess": "0x61",
+ "svcTerminateDebugProcess": "0x62",
+ "svcGetDebugEvent": "0x63",
+ "svcContinueDebugEvent": "0x64",
+ "svcGetProcessList": "0x65",
+ "svcGetThreadList": "0x66",
+ "svcGetDebugThreadContext": "0x67",
+ "svcSetDebugThreadContext": "0x68",
+ "svcQueryDebugProcessMemory": "0x69",
+ "svcReadDebugProcessMemory": "0x6a",
+ "svcWriteDebugProcessMemory": "0x6b",
+ "svcSetHardwareBreakPoint": "0x6c",
+ "svcGetDebugThreadParam": "0x6d",
+ "svcCallSecureMonitor": "0x7f"
+ }
+ }, {
+ "type": "min_kernel_version",
+ "value": "0x0030"
+ }, {
+ "type": "handle_table_size",
+ "value": 0
+ }]
+}
\ No newline at end of file
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_debug_log.cpp b/stratosphere/dmnt.gen2/source/dmnt2_debug_log.cpp
new file mode 100644
index 000000000..3ec85eddd
--- /dev/null
+++ b/stratosphere/dmnt.gen2/source/dmnt2_debug_log.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "dmnt2_debug_log.hpp"
+
+#define AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG
+
+#if defined(AMS_DMNT2_ENABLE_HTCS_DEBUG_LOG)
+
+namespace ams::dmnt {
+
+ namespace {
+
+ constexpr size_t NumLogBuffers = 16;
+ constexpr size_t LogBufferSize = 0x100;
+
+ /* TODO: This shouldn't be so high priority. Come up with a better number? */
+ constexpr inline auto LogThreadPriority = 10;
+
+ constinit os::MessageQueueType g_buf_mq;
+ constinit os::MessageQueueType g_req_mq;
+
+ alignas(os::ThreadStackAlignment) u8 g_log_thread_stack[os::MemoryPageSize];
+
+ constinit char g_log_buffers[NumLogBuffers][LogBufferSize];
+
+ constinit uintptr_t g_buf_mq_storage[NumLogBuffers];
+ constinit uintptr_t g_req_mq_storage[NumLogBuffers];
+
+ constinit os::ThreadType g_log_thread;
+
+ util::optional GetLogBuffer() {
+ /* Try to get a log buffer. */
+ uintptr_t address;
+ if (os::TryReceiveMessageQueue(std::addressof(address), std::addressof(g_buf_mq))) {
+ return reinterpret_cast(address);
+ } else {
+ return util::nullopt;
+ }
+ }
+
+ /* TODO: This is a hack because we don't have a proper LogManager system module. */
+ /* Eventually, this should be refactored to use normal logging. */
+ void DebugLogThreadFunction(void *) {
+ /* Loop forever, servicing our log server. */
+ while (true) {
+ /* Get a socket. */
+ int fd;
+ while ((fd = htcs::Socket()) == -1) {
+ os::SleepThread(TimeSpan::FromSeconds(1));
+ }
+
+ /* Ensure we cleanup the socket when we're done with it. */
+ ON_SCOPE_EXIT {
+ htcs::Close(fd);
+ os::SleepThread(TimeSpan::FromSeconds(1));
+ };
+
+ /* Create a sock addr for our server. */
+ htcs::SockAddrHtcs addr;
+ addr.family = htcs::HTCS_AF_HTCS;
+ addr.peer_name = htcs::GetPeerNameAny();
+ std::strcpy(addr.port_name.name, "iywys@$dmnt2_log");
+
+ /* Bind. */
+ if (htcs::Bind(fd, std::addressof(addr)) == -1) {
+ continue;
+ }
+
+ /* Listen on our port. */
+ while (htcs::Listen(fd, 0) == 0) {
+ /* Continue accepting clients, so long as we can. */
+ int client_fd;
+ while (true) {
+ /* Try to accept a client. */
+ if (client_fd = htcs::Accept(fd, std::addressof(addr)); client_fd < 0) {
+ break;
+ }
+
+ /* Handle the client. */
+ while (true) {
+ /* Receive a log request. */
+ uintptr_t log_buffer_address;
+ os::ReceiveMessageQueue(std::addressof(log_buffer_address), std::addressof(g_req_mq));
+
+ /* Ensure we manage our request properly. */
+ ON_SCOPE_EXIT { os::SendMessageQueue(std::addressof(g_buf_mq), log_buffer_address); };
+
+ /* Send the data. */
+ const char * const log_buffer = reinterpret_cast(log_buffer_address);
+ if (htcs::Send(client_fd, log_buffer, std::strlen(log_buffer), 0) < 0) {
+ break;
+ }
+ }
+
+ /* Close the client socket. */
+ htcs::Close(client_fd);
+ }
+ }
+ }
+ }
+
+
+ }
+
+
+ void InitializeDebugLog() {
+ /* Initialize logging message queues. */
+ os::InitializeMessageQueue(std::addressof(g_buf_mq), g_buf_mq_storage, NumLogBuffers);
+ os::InitializeMessageQueue(std::addressof(g_req_mq), g_req_mq_storage, NumLogBuffers);
+
+ /* Initially make all log buffers available. */
+ for (size_t i = 0; i < NumLogBuffers; ++i) {
+ os::SendMessageQueue(std::addressof(g_buf_mq), reinterpret_cast(g_log_buffers[i]));
+ }
+
+ /* Create and start the debug log thread. */
+ R_ABORT_UNLESS(os::CreateThread(std::addressof(g_log_thread), DebugLogThreadFunction, nullptr, g_log_thread_stack, sizeof(g_log_thread_stack), LogThreadPriority));
+
+ os::StartThread(std::addressof(g_log_thread));
+ }
+
+ void DebugLog(const char *prefix, const char *fmt, ...) {
+ /* Try to get a log buffer. */
+ const auto log_buffer_holder = GetLogBuffer();
+ if (!log_buffer_holder) {
+ return;
+ }
+
+
+ /* Format into the log buffer. */
+ char * const log_buffer = *log_buffer_holder;
+ {
+ const auto prefix_len = std::strlen(prefix);
+ std::memcpy(log_buffer, prefix, prefix_len);
+
+ {
+ std::va_list vl;
+ va_start(vl, fmt);
+ util::VSNPrintf(log_buffer + prefix_len, LogBufferSize - prefix_len, fmt, vl);
+ va_end(vl);
+ }
+ }
+
+ /* Request to log. */
+ os::SendMessageQueue(std::addressof(g_req_mq), reinterpret_cast(log_buffer));
+ }
+
+}
+
+#else
+
+namespace ams::dmnt {
+
+
+ void InitializeDebugLog() {
+ /* Do nothing. */
+ }
+
+ void DebugLog(const char *prefix, const char *fmt, ...) {
+ /* Do nothing. */
+ }
+
+}
+
+
+#endif
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_debug_log.hpp b/stratosphere/dmnt.gen2/source/dmnt2_debug_log.hpp
new file mode 100644
index 000000000..ed8aa2a79
--- /dev/null
+++ b/stratosphere/dmnt.gen2/source/dmnt2_debug_log.hpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#pragma once
+#include
+
+namespace ams::dmnt {
+
+ void InitializeDebugLog();
+
+ void DebugLog(const char *prefix, const char *fmt, ...);
+
+ #define AMS_DMNT2_DEBUG_LOG(fmt, ...) ::ams::dmnt::DebugLog("[dmnt2] ", fmt, ## __VA_ARGS__)
+
+}
\ No newline at end of file
diff --git a/stratosphere/dmnt.gen2/source/dmnt2_main.cpp b/stratosphere/dmnt.gen2/source/dmnt2_main.cpp
new file mode 100644
index 000000000..a2e037f16
--- /dev/null
+++ b/stratosphere/dmnt.gen2/source/dmnt2_main.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018-2020 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include "dmnt2_debug_log.hpp"
+
+extern "C" {
+ extern u32 __start__;
+
+ u32 __nx_applet_type = AppletType_None;
+ u32 __nx_fs_num_sessions = 1;
+
+ #define INNER_HEAP_SIZE 0x0
+ size_t nx_inner_heap_size = INNER_HEAP_SIZE;
+ char nx_inner_heap[INNER_HEAP_SIZE];
+
+ void __libnx_initheap(void);
+ void __appInit(void);
+ void __appExit(void);
+
+ void *__libnx_alloc(size_t size);
+ void *__libnx_aligned_alloc(size_t alignment, size_t size);
+ void __libnx_free(void *mem);
+}
+
+namespace ams {
+
+ ncm::ProgramId CurrentProgramId = ncm::SystemProgramId::DmntGen2;
+
+}
+
+using namespace ams;
+
+#define AMS_DMNT2_SERVER_USE_FATAL_ERROR 1
+
+#if AMS_DMNT2_SERVER_USE_FATAL_ERROR
+
+extern "C" {
+
+ /* Exception handling. */
+ alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize];
+ u64 __nx_exception_stack_size = sizeof(__nx_exception_stack);
+ void __libnx_exception_handler(ThreadExceptionDump *ctx);
+
+}
+
+void __libnx_exception_handler(ThreadExceptionDump *ctx) {
+ ams::CrashHandler(ctx);
+}
+
+#endif
+
+namespace ams::dmnt {
+
+ namespace {
+
+ alignas(0x40) constinit u8 g_htcs_buffer[4_KB];
+
+ }
+
+}
+
+void __libnx_initheap(void) {
+ void* addr = nx_inner_heap;
+ size_t size = nx_inner_heap_size;
+
+ /* Newlib */
+ extern char* fake_heap_start;
+ extern char* fake_heap_end;
+
+ fake_heap_start = (char*)addr;
+ fake_heap_end = (char*)addr + size;
+}
+
+void __appInit(void) {
+ hos::InitializeForStratosphere();
+
+ R_ABORT_UNLESS(sm::Initialize());
+
+ /* TODO */
+
+ ams::CheckApiVersion();
+}
+
+void __appExit(void) {
+ /* TODO */
+}
+
+namespace ams {
+
+ void *Malloc(size_t size) {
+ AMS_ABORT("ams::Malloc was called");
+ }
+
+ void Free(void *ptr) {
+ AMS_ABORT("ams::Free was called");
+ }
+
+}
+
+void *operator new(size_t size) {
+ AMS_ABORT("operator new(size_t) was called");
+}
+
+void operator delete(void *p) {
+ AMS_ABORT("operator delete(void *) was called");
+}
+
+void *__libnx_alloc(size_t size) {
+ AMS_ABORT("__libnx_alloc was called");
+}
+
+void *__libnx_aligned_alloc(size_t alignment, size_t size) {
+ AMS_ABORT("__libnx_aligned_alloc was called");
+}
+
+void __libnx_free(void *mem) {
+ AMS_ABORT("__libnx_free was called");
+}
+
+int main(int argc, char **argv)
+{
+ /* TODO ThreadName */
+
+ /* Initialize htcs. */
+ constexpr auto HtcsSocketCountMax = 8;
+ const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax);
+ AMS_ABORT_UNLESS(sizeof(dmnt::g_htcs_buffer) >= buffer_size);
+ htcs::InitializeForSystem(dmnt::g_htcs_buffer, buffer_size, HtcsSocketCountMax);
+
+ /* Initialize debug log thread. */
+ dmnt::InitializeDebugLog();
+
+ /* TODO: Start GdbServer. */
+
+ /* TODO */
+ u64 i = 0;
+ while (true) {
+ AMS_DMNT2_DEBUG_LOG("Log #%llu\n", i++);
+ os::SleepThread(TimeSpan::FromSeconds(1));
+ }
+
+ return 0;
+}