diff --git a/libraries/config/templates/exosphere.mk b/libraries/config/templates/exosphere.mk index bb994cb8d..47436386b 100644 --- a/libraries/config/templates/exosphere.mk +++ b/libraries/config/templates/exosphere.mk @@ -26,7 +26,7 @@ CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) endif -export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-exceptions -fno-rtti -fno-use-cxa-atexit -nostdlib -nostartfiles -g -gdwarf-4 $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now +export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-exceptions -fno-rtti -fno-use-cxa-atexit -nostdlib -nostartfiles -g -gdwarf-4 $(CXXFLAGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ -Wl,--wrap,__cxa_throw \ diff --git a/libraries/config/templates/mesosphere.mk b/libraries/config/templates/mesosphere.mk index c55a23dbf..84be73254 100644 --- a/libraries/config/templates/mesosphere.mk +++ b/libraries/config/templates/mesosphere.mk @@ -12,7 +12,7 @@ export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) -export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -nostdlib -nostartfiles -g -gdwarf-4 $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now +export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -nostdlib -nostartfiles -g -gdwarf-4 $(CXXFLAGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ -Wl,--wrap,__cxa_throw \ diff --git a/libraries/config/templates/stratosphere.mk b/libraries/config/templates/stratosphere.mk index aff1007b4..0753e3d0a 100644 --- a/libraries/config/templates/stratosphere.mk +++ b/libraries/config/templates/stratosphere.mk @@ -21,6 +21,15 @@ export CFLAGS = $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export CXXFLAGS = $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) export ASFLAGS = $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) +export CXXREQUIRED := -Wl,--require-defined,__libnx_initheap \ + -Wl,--require-defined,__libnx_exception_handler \ + -Wl,--require-defined,__libnx_alloc \ + -Wl,--require-defined,__libnx_aligned_alloc \ + -Wl,--require-defined,__libnx_free \ + -Wl,--require-defined,__appInit \ + -Wl,--require-defined,__appExit \ + -Wl,--require-defined,argvSetup + export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ -Wl,--wrap,__cxa_throw \ -Wl,--wrap,__cxa_rethrow \ @@ -37,7 +46,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \ -Wl,--wrap,_ZNSt11logic_errorC2EPKc \ -Wl,--wrap,exit -export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(SETTINGS) $(CXXWRAPS) -Wl,-Map,$(notdir $*.map) +export LDFLAGS = -specs=$(ATMOSPHERE_LIBRARIES_DIR)/libstratosphere/stratosphere.specs -specs=$(DEVKITPRO)/libnx/switch.specs $(CXXFLAGS) $(CXXWRAPS) $(CXXREQUIRED) -Wl,-Map,$(notdir $*.map) export LIBS = -lstratosphere -lnx diff --git a/libraries/libstratosphere/Makefile b/libraries/libstratosphere/Makefile index 82a45017f..a01800fc5 100644 --- a/libraries/libstratosphere/Makefile +++ b/libraries/libstratosphere/Makefile @@ -126,6 +126,9 @@ ams_environment_weak.o: CXXFLAGS += -fno-lto pm_info_api_weak.o: CXXFLAGS += -fno-lto hos_stratosphere_api.o: CXXFLAGS += -fno-lto +init_operator_new.o: CXXFLAGS += -fno-lto +init_libnx_shim.os.horizon.o: CXXFLAGS += -fno-lto + #--------------------------------------------------------------------------------- %_bin.h %.bin.o : %.bin #--------------------------------------------------------------------------------- diff --git a/libraries/libstratosphere/include/stratosphere.hpp b/libraries/libstratosphere/include/stratosphere.hpp index 05847e4b0..3bd4ed1ee 100644 --- a/libraries/libstratosphere/include/stratosphere.hpp +++ b/libraries/libstratosphere/include/stratosphere.hpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp index 037033053..7e97397f9 100644 --- a/libraries/libstratosphere/include/stratosphere/fs.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -62,3 +62,4 @@ #include #include #include +#include diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_api.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_api.hpp new file mode 100644 index 000000000..48243f87b --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_api.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 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::fs { + + void InitializeForSystem(); + void InitializeWithMultiSessionForSystem(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/init.hpp b/libraries/libstratosphere/include/stratosphere/init.hpp new file mode 100644 index 000000000..6860a5ca5 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/init.hpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 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 diff --git a/libraries/libstratosphere/include/stratosphere/init/init_malloc.hpp b/libraries/libstratosphere/include/stratosphere/init/init_malloc.hpp new file mode 100644 index 000000000..f1b585962 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/init/init_malloc.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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::mem { + + class StandardAllocator; + +} + +namespace ams::init { + + void InitializeAllocator(void *address, size_t size, bool cache_enabled); + void InitializeAllocator(void *address, size_t size); + + mem::StandardAllocator *GetAllocator(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 605cbe12f..c1e05ba46 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -52,3 +52,4 @@ #include #include #include +#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_argument.hpp b/libraries/libstratosphere/include/stratosphere/os/os_argument.hpp new file mode 100644 index 000000000..a43102a58 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_argument.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 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::os { + + int GetHostArgc(); + char **GetHostArgv(); + +} diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp index a84dc3d4e..9a29d41d9 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_main.cpp @@ -75,7 +75,9 @@ namespace ams::erpt::srv { g_heap_handle = lmem::CreateExpHeap(mem, mem_size, lmem::CreateOption_ThreadSafe); AMS_ABORT_UNLESS(g_heap_handle != nullptr); + fs::InitializeForSystem(); fs::SetAllocator(Allocate, DeallocateWithSize); + fs::SetEnabledAutoAbort(false); R_ABORT_UNLESS(fs::MountSdCardErrorReportDirectoryForAtmosphere(ReportOnSdStoragePath)); diff --git a/libraries/libstratosphere/source/fs/fs_api.cpp b/libraries/libstratosphere/source/fs/fs_api.cpp new file mode 100644 index 000000000..c9d8ce726 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_api.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 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 + +extern "C" { + + extern u32 __nx_fs_num_sessions; + +} + +namespace ams::fs { + + /* TODO: FileSystemProxySessionSetting */ + + void InitializeForSystem() { + __nx_fs_num_sessions = 1; + R_ABORT_UNLESS(::fsInitialize()); + } + + void InitializeWithMultiSessionForSystem() { + __nx_fs_num_sessions = 2; + R_ABORT_UNLESS(::fsInitialize()); + } + +} diff --git a/libraries/libstratosphere/source/init/init_libnx_shim.os.horizon.cpp b/libraries/libstratosphere/source/init/init_libnx_shim.os.horizon.cpp new file mode 100644 index 000000000..5f2d21285 --- /dev/null +++ b/libraries/libstratosphere/source/init/init_libnx_shim.os.horizon.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 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 + +extern "C" { + + constinit u32 __nx_fs_num_sessions = 1; + constinit u32 __nx_applet_type = AppletType_None; + + extern int __system_argc; + extern char** __system_argv; + + alignas(16) constinit u8 __nx_exception_stack[::ams::os::MemoryPageSize]; + constinit u64 __nx_exception_stack_size = sizeof(__nx_exception_stack); + +} + +namespace ams { + + namespace hos { + + void InitializeForStratosphere(); + + } + + namespace init { + + void InitializeSystemModule(); + void FinalizeSystemModule(); + + void Startup(); + + } + + void Main(); + +} + +namespace { + + constinit char *g_empty_argv = nullptr; + +} + +extern "C" void __libnx_exception_handler(ThreadExceptionDump *ctx) { + ::ams::CrashHandler(ctx); +} + +extern "C" void __libnx_initheap(void) { + /* Stratosphere system modules do not support newlib heap. */ +} + +extern "C" void __appInit(void) { + /* The very first thing all stratosphere code must do is initialize the os library. */ + ::ams::hos::InitializeForStratosphere(); +} + +extern "C" void __appExit(void) { + /* ... */ +} + +extern "C" void argvSetup(void) { + /* We don't use newlib argc/argv, so we can clear these. */ + __system_argc = 0; + __system_argv = std::addressof(g_empty_argv); +} + +extern "C" int main(int argc, char **argv) { + /* We don't use newlib argc/argv. */ + AMS_UNUSED(argc, argv); + + /* Perform remainder of logic with system module initialized. */ + { + ::ams::init::InitializeSystemModule(); + ON_SCOPE_EXIT { ::ams::init::FinalizeSystemModule(); }; + + /* Perform miscellaneous startup. */ + ::ams::init::Startup(); + + /* Invoke ams main. */ + ::ams::Main(); + } +} + +extern "C" WEAK_SYMBOL void *__libnx_alloc(size_t) { + AMS_ABORT("__libnx_alloc was called"); +} + +extern "C" WEAK_SYMBOL void *__libnx_aligned_alloc(size_t, size_t) { + AMS_ABORT("__libnx_aligned_alloc was called"); +} + +extern "C" WEAK_SYMBOL void __libnx_free(void *) { + AMS_ABORT("__libnx_free was called"); +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/init/init_malloc.cpp b/libraries/libstratosphere/source/init/init_malloc.cpp new file mode 100644 index 000000000..9d0515514 --- /dev/null +++ b/libraries/libstratosphere/source/init/init_malloc.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (c) 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 + +namespace ams::init { + + namespace { + + constinit void *g_malloc_region_address = nullptr; + constinit size_t g_malloc_region_size = 0; + + constinit util::TypedStorage g_malloc_allocator; + + } + + void InitializeAllocator(void *address, size_t size, bool cache_enabled) { + /* Check pre-conditions. */ + AMS_ABORT_UNLESS(g_malloc_region_size == 0); + AMS_ABORT_UNLESS(size > 0); + + /* Construct malloc allocator. */ + util::ConstructAt(g_malloc_allocator); + + /* Initialize allocator. */ + util::GetReference(g_malloc_allocator).Initialize(address, size, cache_enabled); + + /* Set malloc globals. */ + g_malloc_region_address = address; + g_malloc_region_size = size; + } + + void InitializeAllocator(void *address, size_t size) { + return InitializeAllocator(address, size, false); + } + + mem::StandardAllocator *GetAllocator() { + /* Check pre-conditions. */ + AMS_ASSERT(g_malloc_region_size > 0); + + return util::GetPointer(g_malloc_allocator); + } + +} + +extern "C" void *malloc(size_t size) { + /* We require that an allocator region exists. */ + if (::ams::init::g_malloc_region_size == 0) { + return nullptr; + } + + /* Try to allocate. */ + void *ptr = ::ams::util::GetReference(::ams::init::g_malloc_allocator).Allocate(size); + if (ptr == nullptr) { + errno = ENOMEM; + } + + return ptr; +} + +extern "C" void free(void *ptr) { + /* We require that an allocator region exists. */ + if (::ams::init::g_malloc_region_size == 0) { + return; + } + + if (ptr != nullptr) { + ::ams::util::GetReference(::ams::init::g_malloc_allocator).Free(ptr); + } +} + +extern "C" void *calloc(size_t num, size_t size) { + /* We require that an allocator region exists. */ + if (::ams::init::g_malloc_region_size == 0) { + return nullptr; + } + + /* Allocate the total needed space. */ + const size_t total = num * size; + void *ptr = std::malloc(total); + + /* Zero the memory if needed. */ + if (ptr != nullptr) { + std::memset(ptr, 0, total); + } else { + errno = ENOMEM; + } + + return ptr; +} + +extern "C" void *realloc(void *ptr, size_t new_size) { + /* We require that an allocator region exists. */ + if (::ams::init::g_malloc_region_size == 0) { + return nullptr; + } + + /* Try to reallocate. */ + void *r = ::ams::util::GetReference(::ams::init::g_malloc_allocator).Reallocate(ptr, new_size); + if (r == nullptr) { + errno = ENOMEM; + } + + return r; +} + +extern "C" void *aligned_alloc(size_t align, size_t size) { + /* We require that an allocator region exists. */ + if (::ams::init::g_malloc_region_size == 0) { + return nullptr; + } + + /* Try to allocate. */ + void *ptr = ::ams::util::GetReference(::ams::init::g_malloc_allocator).Allocate(size, align); + if (ptr == nullptr) { + errno = ENOMEM; + } + + return ptr; +} + +extern "C" size_t malloc_usable_size(void *ptr) { + /* We require that an allocator region exists. */ + if (::ams::init::g_malloc_region_size == 0) { + return 0; + } + + /* Try to get the usable size. */ + if (ptr == nullptr) { + errno = ENOMEM; + return 0; + } + + return ::ams::util::GetReference(::ams::init::g_malloc_allocator).GetSizeOf(ptr); +} diff --git a/libraries/libstratosphere/source/init/init_operator_new.cpp b/libraries/libstratosphere/source/init/init_operator_new.cpp new file mode 100644 index 000000000..d7c55c15c --- /dev/null +++ b/libraries/libstratosphere/source/init/init_operator_new.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 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 + +WEAK_SYMBOL void *operator new(size_t size) { + return std::malloc(size); +} + +WEAK_SYMBOL void *operator new(size_t size, const std::nothrow_t &) { + return std::malloc(size); +} + +WEAK_SYMBOL void operator delete(void *p) { + return std::free(p); +} + +WEAK_SYMBOL void operator delete(void *p, size_t) { + return std::free(p); +} + +WEAK_SYMBOL void *operator new[](size_t size) { + return std::malloc(size); +} + +WEAK_SYMBOL void *operator new[](size_t size, const std::nothrow_t &) { + return std::malloc(size); +} + +WEAK_SYMBOL void operator delete[](void *p) { + return std::free(p); +} + +WEAK_SYMBOL void operator delete[](void *p, size_t) { + return std::free(p); +} diff --git a/libraries/libstratosphere/source/init/init_system_module.cpp b/libraries/libstratosphere/source/init/init_system_module.cpp new file mode 100644 index 000000000..75ccce4ac --- /dev/null +++ b/libraries/libstratosphere/source/init/init_system_module.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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 + +namespace ams::init { + + WEAK_SYMBOL void InitializeSystemModule() { + /* TODO: What should we do here, if anything? */ + /* Nintendo does nndiagStartup(); nn::diag::InitializeSystemProcessAbortObserver(); */ + } + + WEAK_SYMBOL void FinalizeSystemModule() { + /* Do nothing by default. */ + } + + WEAK_SYMBOL void Startup() { + /* TODO: What should we do here, if anything? */ + /* Nintendo determines heap size and does init::InitializeAllocator, as relevant. */ + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp b/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp index b8c966c3f..8fac0c1b3 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp +++ b/libraries/libstratosphere/source/lm/srv/lm_flush_thread.cpp @@ -103,14 +103,15 @@ namespace ams::lm::srv { } void FlushThreadFunction(void *) { - /* Disable abort. */ + /* Initialize fs. */ + fs::InitializeWithMultiSessionForSystem(); fs::SetEnabledAutoAbort(false); /* Create fs heap. */ g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap, sizeof(g_fs_heap), lmem::CreateOption_None); AMS_ABORT_UNLESS(g_fs_heap_handle != nullptr); - /* Set fs allocation functions. */ + /* Set fs allocator functions. */ fs::SetAllocator(AllocateForFs, DeallocateForFs); /* Create SD card detection event notifier. */ diff --git a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.hpp b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.hpp index 288f934be..3564de76c 100644 --- a/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.hpp +++ b/libraries/libstratosphere/source/mem/impl/heap/mem_impl_heap_tls_heap_central.hpp @@ -353,7 +353,7 @@ namespace ams::mem::impl::heap { std::scoped_lock lk(this->lock); if (Span *span = GetSpanFromPointer(std::addressof(this->span_table), ptr); span != nullptr && !span->page_class) { - *out = (span->aux.large.color[0] << 0) | (span->aux.large.color[1] << 0) | (span->aux.large.color[2] << 16); + *out = (span->aux.large.color[0] << 0) | (span->aux.large.color[1] << 8) | (span->aux.large.color[2] << 16); return 0; } else { return EINVAL; @@ -387,7 +387,7 @@ namespace ams::mem::impl::heap { errno_t GetName(const void *ptr, char *dst, size_t dst_size) { std::scoped_lock lk(this->lock); if (Span *span = GetSpanFromPointer(std::addressof(this->span_table), ptr); span != nullptr && !span->page_class) { - strlcpy(dst, span->aux.large.name, dst_size); + util::Strlcpy(dst, span->aux.large.name, dst_size); return 0; } else { return EINVAL; @@ -397,7 +397,7 @@ namespace ams::mem::impl::heap { errno_t SetName(const void *ptr, const char *name) { std::scoped_lock lk(this->lock); if (Span *span = GetSpanFromPointer(std::addressof(this->span_table), ptr); span != nullptr && !span->page_class) { - strlcpy(span->aux.large.name, name, sizeof(span->aux.large.name)); + util::Strlcpy(span->aux.large.name, name, sizeof(span->aux.large.name)); return 0; } else { return EINVAL; diff --git a/libraries/libstratosphere/source/os/os_argument.cpp b/libraries/libstratosphere/source/os/os_argument.cpp new file mode 100644 index 000000000..df83598d9 --- /dev/null +++ b/libraries/libstratosphere/source/os/os_argument.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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 + +namespace ams::os { + + namespace { + + struct CommandLineParameter { + int argc; + char **argv; + }; + + constinit const char *g_command_line_parameter_argv[2] = { "", nullptr }; + constinit CommandLineParameter g_command_line_parameter = { + 1, + const_cast(g_command_line_parameter_argv), + }; + + } + + void SetHostArgc(int argc) { + g_command_line_parameter.argc = argc; + } + + void SetHostArgv(char **argv) { + g_command_line_parameter.argv = argv; + } + + int GetHostArgc() { + return g_command_line_parameter.argc; + } + + char **GetHostArgv() { + return g_command_line_parameter.argv; + } + +} diff --git a/libraries/libstratosphere/source/os/os_stratosphere_api.os.horizon.cpp b/libraries/libstratosphere/source/os/os_stratosphere_api.os.horizon.cpp new file mode 100644 index 000000000..7651ae886 --- /dev/null +++ b/libraries/libstratosphere/source/os/os_stratosphere_api.os.horizon.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 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 "impl/os_resource_manager.hpp" + +extern "C" { extern u8 __argdata__[]; } + +namespace ams::os { + + namespace { + + class MemoryArranger { + private: + uintptr_t m_address; + public: + constexpr MemoryArranger(uintptr_t address) : m_address(address) { /* ... */ } + + template + T *Arrange() { + this->Align(alignof(T)); + return static_cast(this->Arrange(sizeof(T))); + } + + void *Arrange(size_t size) { + const auto address = m_address; + m_address += size; + return reinterpret_cast(address); + } + + void Align(size_t align) { + m_address = util::AlignUp(m_address, align); + } + + char *ArrangeCharArray(size_t size) { + return reinterpret_cast(Arrange(size)); + } + }; + + bool HasArguments(uintptr_t args_region) { + /* Check that the arguments region is read-write. */ + svc::MemoryInfo mi; + svc::PageInfo pi; + + if (R_FAILED(svc::QueryMemory(std::addressof(mi), std::addressof(pi), args_region))) { + return false; + } + + return mi.permission == svc::MemoryPermission_ReadWrite; + } + + const char *SkipSpace(const char *p, const char *end) { + while (p < end && std::isspace(*p)) { ++p; } + return p; + } + + const char *GetTokenEnd(const char *p, const char *end) { + while (p < end && !std::isspace(*p)) { ++p; } + return p; + } + + const char *GetQuotedTokenEnd(const char *p, const char *end) { + while (p < end && *p != '"') { ++p; } + return p; + } + + int MakeArgv(char **out_argv_buf, char *arg_buf, const char *cmd_line, size_t cmd_line_size, int arg_max) { + /* Prepare to parse arguments. */ + auto idx = 0; + auto src = cmd_line; + auto dst = arg_buf; + const auto end = src + cmd_line_size; + + /* Parse all tokens. */ + while (true) { + /* Advance past any spaces. */ + src = SkipSpace(src, end); + if (src >= end) { + break; + } + + /* Check that we don't have too many arguments. */ + if (idx >= arg_max) { + break; + } + + /* Find the start/end of the current argument token. */ + const char *arg_end; + const char *src_next; + if (*src == '"') { + ++src; + arg_end = GetQuotedTokenEnd(src, end); + src_next = arg_end + 1; + } else { + arg_end = GetTokenEnd(src, end); + src_next = arg_end; + } + + /* Determine token size. */ + const auto arg_size = arg_end - src; + + /* Set the argv pointer. */ + out_argv_buf[idx++] = dst; + + /* Copy the argument. */ + std::memcpy(dst, src, arg_size); + dst += arg_size; + + /* Null-terminate the argument token. */ + *(dst++) = '\x00'; + + /* Advance to next token. */ + src = src_next; + } + + /* Null terminate the final token. */ + *(dst++) = '\x00'; + + /* Null terminate argv. */ + out_argv_buf[idx] = nullptr; + + return idx; + } + + + } + + void SetHostArgc(int argc); + void SetHostArgv(char **argv); + + void InitializeForStratosphereInternal() { + /* Initialize the global os resource manager. */ + os::impl::ResourceManagerHolder::InitializeResourceManagerInstance(); + + /* Setup host argc/argv as needed. */ + const uintptr_t args_region = reinterpret_cast(__argdata__); + if (HasArguments(args_region)) { + /* Create arguments memory arranger. */ + MemoryArranger arranger(args_region); + + /* Arrange. */ + const auto &header = *arranger.Arrange(); + const char *cmd_line = arranger.ArrangeCharArray(header.arguments_size); + char *arg_buf = arranger.ArrangeCharArray(header.arguments_size + 2); + char **argv_buf = arranger.Arrange(); + + /* Determine extents. */ + const auto arg_buf_size = reinterpret_cast(argv_buf) - args_region; + const auto arg_max = (header.allocated_size - arg_buf_size) / sizeof(char *); + + /* Make argv. */ + const auto arg_count = MakeArgv(argv_buf, arg_buf, cmd_line, header.arguments_size, arg_max); + + /* Set host argc/argv. */ + os::SetHostArgc(arg_count); + os::SetHostArgv(argv_buf); + } + } + +} diff --git a/stratosphere/LogManager/source/lm_main.cpp b/stratosphere/LogManager/source/lm_main.cpp index 298533b04..243645c67 100644 --- a/stratosphere/LogManager/source/lm_main.cpp +++ b/stratosphere/LogManager/source/lm_main.cpp @@ -15,151 +15,66 @@ */ #include -extern "C" { - extern u32 __start__; - - u32 __nx_applet_type = AppletType_None; - u32 __nx_fs_num_sessions = 2; - - #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); -} - -using namespace ams; - -#define AMS_LM_USE_FATAL_ERROR 1 - -#if AMS_LM_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 - -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()); - - R_ABORT_UNLESS(::fsInitialize()); - R_ABORT_UNLESS(::setsysInitialize()); - R_ABORT_UNLESS(::pscmInitialize()); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - fsExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace lm::srv { + + void StartLogServerProxy(); + void StopLogServerProxy(); + + void InitializeFlushThread(); + void FinalizeFlushThread(); + + void InitializeIpcServer(); + void LoopIpcServer(); + void FinalizeIpcServer(); + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize services we need. */ + R_ABORT_UNLESS(::setsysInitialize()); + R_ABORT_UNLESS(::pscmInitialize()); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Check thread priority. */ + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(LogManager, MainThread)); + + /* Set thread name. */ + os::ChangeThreadPriority(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_PRIORITY(lm, IpcServer)); + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(lm, IpcServer)); + + /* Start log server proxy. */ + lm::srv::StartLogServerProxy(); + + /* Initialize flush thread. */ + lm::srv::InitializeFlushThread(); + + /* Process IPC server. */ + lm::srv::InitializeIpcServer(); + lm::srv::LoopIpcServer(); + lm::srv::FinalizeIpcServer(); + + /* Finalize flush thread. */ + lm::srv::FinalizeFlushThread(); + + /* Stop log server proxy. */ + lm::srv::StopLogServerProxy(); } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -namespace ams::lm::srv { - - void StartLogServerProxy(); - void StopLogServerProxy(); - - void InitializeFlushThread(); - void FinalizeFlushThread(); - - void InitializeIpcServer(); - void LoopIpcServer(); - void FinalizeIpcServer(); - -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Check thread priority. */ - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(LogManager, MainThread)); - - /* Set thread name. */ - os::ChangeThreadPriority(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_PRIORITY(lm, IpcServer)); - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(lm, IpcServer)); - - /* Start log server proxy. */ - lm::srv::StartLogServerProxy(); - - /* Initialize flush thread. */ - lm::srv::InitializeFlushThread(); - - /* Process IPC server. */ - lm::srv::InitializeIpcServer(); - lm::srv::LoopIpcServer(); - lm::srv::FinalizeIpcServer(); - - /* Finalize flush thread. */ - lm::srv::FinalizeFlushThread(); - - /* Stop log server proxy. */ - lm::srv::StopLogServerProxy(); - - return 0; -} diff --git a/stratosphere/TioServer/source/tio_main.cpp b/stratosphere/TioServer/source/tio_main.cpp index 7582d8f74..0c33d7630 100644 --- a/stratosphere/TioServer/source/tio_main.cpp +++ b/stratosphere/TioServer/source/tio_main.cpp @@ -16,165 +16,78 @@ #include #include "tio_file_server.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); -} - -using namespace ams; - -#define AMS_TIO_SERVER_USE_FATAL_ERROR 1 - -#if AMS_TIO_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::tio { - - namespace { - - alignas(0x40) constinit u8 g_fs_heap_buffer[64_KB]; - alignas(0x40) constinit u8 g_htcs_buffer[1_KB]; - lmem::HeapHandle g_fs_heap_handle; - - void *AllocateForFs(size_t size) { - return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); - } - - void DeallocateForFs(void *p, size_t size) { - AMS_UNUSED(size); - - return lmem::FreeToExpHeap(g_fs_heap_handle, p); - } - - void InitializeFsHeap() { - /* Setup fs allocator. */ - g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_buffer, sizeof(g_fs_heap_buffer), lmem::CreateOption_ThreadSafe); - } - - } - -} - -void __libnx_initheap(void) { - void* addr = nx_inner_heap; - size_t size = nx_inner_heap_size; - - /* Newlib */ - extern char* fake_heap_start; - extern char* fake_heap_end; - - fake_heap_start = (char*)addr; - fake_heap_end = (char*)addr + size; - - ams::tio::InitializeFsHeap(); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - /* Initialize FS heap. */ - fs::SetAllocator(tio::AllocateForFs, tio::DeallocateForFs); - - /* Disable FS auto-abort. */ - fs::SetEnabledAutoAbort(false); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsInitialize()); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - fsExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace tio { + + namespace { + + alignas(0x40) constinit u8 g_fs_heap_buffer[64_KB]; + alignas(0x40) constinit u8 g_htcs_buffer[1_KB]; + lmem::HeapHandle g_fs_heap_handle; + + void *AllocateForFs(size_t size) { + return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); + } + + void DeallocateForFs(void *p, size_t size) { + AMS_UNUSED(size); + + return lmem::FreeToExpHeap(g_fs_heap_handle, p); + } + + void InitializeFsHeap() { + /* Setup fs allocator. */ + g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_buffer, sizeof(g_fs_heap_buffer), lmem::CreateOption_ThreadSafe); + } + + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + tio::InitializeFsHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(tio::AllocateForFs, tio::DeallocateForFs); + fs::SetEnabledAutoAbort(false); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(TioServer, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(TioServer, Main)); + + /* Initialize htcs. */ + constexpr auto HtcsSocketCountMax = 2; + const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax); + AMS_ABORT_UNLESS(sizeof(tio::g_htcs_buffer) >= buffer_size); + htcs::InitializeForSystem(tio::g_htcs_buffer, buffer_size, HtcsSocketCountMax); + + /* Initialize the file server. */ + tio::InitializeFileServer(); + + /* Start the file server. */ + tio::StartFileServer(); + + /* Wait for the file server to finish. */ + tio::WaitFileServer(); } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(TioServer, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(TioServer, Main)); - - /* Initialize htcs. */ - constexpr auto HtcsSocketCountMax = 2; - const size_t buffer_size = htcs::GetWorkingMemorySize(HtcsSocketCountMax); - AMS_ABORT_UNLESS(sizeof(tio::g_htcs_buffer) >= buffer_size); - htcs::InitializeForSystem(tio::g_htcs_buffer, buffer_size, HtcsSocketCountMax); - - /* Initialize the file server. */ - tio::InitializeFileServer(); - - /* Start the file server. */ - tio::StartFileServer(); - - /* Wait for the file server to finish. */ - tio::WaitFileServer(); - - return 0; -} diff --git a/stratosphere/ams_mitm/source/amsmitm_main.cpp b/stratosphere/ams_mitm/source/amsmitm_main.cpp index 8763e91ee..2bcfde694 100644 --- a/stratosphere/ams_mitm/source/amsmitm_main.cpp +++ b/stratosphere/ams_mitm/source/amsmitm_main.cpp @@ -19,123 +19,76 @@ #include "bpc_mitm/bpc_ams_power_utils.hpp" #include "sysupdater/sysupdater_fs_utils.hpp" -extern "C" { - extern u32 __start__; - - u32 __nx_applet_type = AppletType_None; - u32 __nx_fs_num_sessions = 1; - - #define INNER_HEAP_SIZE 0x1000000 - 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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - namespace ams { - /* Override. */ + namespace { + + /* TODO: we really shouldn't be using malloc just to avoid dealing with real allocator separation. */ + constexpr size_t MallocBufferSize = 16_MB; + alignas(os::MemoryPageSize) constinit u8 g_malloc_buffer[MallocBufferSize]; + + } + + namespace init { + + void InitializeSystemModule() { + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services. */ + R_ABORT_UNLESS(pmdmntInitialize()); + R_ABORT_UNLESS(pminfoInitialize()); + ncm::Initialize(); + spl::InitializeForFs(); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { + /* Initialize the global malloc allocator. */ + init::InitializeAllocator(g_malloc_buffer, sizeof(g_malloc_buffer)); + } + + } + void ExceptionHandler(FatalErrorContext *ctx) { /* We're bpc-mitm (or ams_mitm, anyway), so manually reboot to fatal error. */ mitm::bpc::RebootForFatalError(ctx); } -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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()); - - R_ABORT_UNLESS(fsInitialize()); - R_ABORT_UNLESS(pmdmntInitialize()); - R_ABORT_UNLESS(pminfoInitialize()); - ncm::Initialize(); - spl::InitializeForFs(); - - /* Disable auto-abort in fs operations. */ - fs::SetEnabledAutoAbort(false); - - /* Initialize fssystem library. */ - fssystem::InitializeForFileSystemProxy(); - - /* Configure ncm to use fssystem library to mount content from the sd card. */ - ncm::SetMountContentMetaFunction(mitm::sysupdater::MountSdCardContentMeta); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* Cleanup services. */ - spl::Finalize(); - ncm::Finalize(); - pminfoExit(); - pmdmntExit(); - fsExit(); -} - -void *__libnx_alloc(size_t size) { - AMS_UNUSED(size); - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t alignment, size_t size) { - AMS_UNUSED(alignment, size); - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *mem) { - AMS_UNUSED(mem); - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) { - AMS_UNUSED(argc, argv); - - /* Register "ams" port, use up its session. */ - { - svc::Handle ams_port; - R_ABORT_UNLESS(svc::ManageNamedPort(std::addressof(ams_port), "ams", 1)); - - svc::Handle ams_session; - R_ABORT_UNLESS(svc::ConnectToNamedPort(std::addressof(ams_session), "ams")); + void NORETURN Exit(int rc) { + AMS_UNUSED(rc); + AMS_ABORT("Exit called by immortal process"); } - /* Launch all mitm modules in sequence. */ - mitm::LaunchAllModules(); + void Main() { + /* Register "ams" port, use up its session. */ + { + svc::Handle ams_port; + R_ABORT_UNLESS(svc::ManageNamedPort(std::addressof(ams_port), "ams", 1)); - /* Wait for all mitm modules to end. */ - mitm::WaitAllModules(); + svc::Handle ams_session; + R_ABORT_UNLESS(svc::ConnectToNamedPort(std::addressof(ams_session), "ams")); + } + + /* Initialize fssystem library. */ + fssystem::InitializeForFileSystemProxy(); + + /* Configure ncm to use fssystem library to mount content from the sd card. */ + ncm::SetMountContentMetaFunction(mitm::sysupdater::MountSdCardContentMeta); + + /* Launch all mitm modules in sequence. */ + mitm::LaunchAllModules(); + + /* Wait for all mitm modules to end. */ + mitm::WaitAllModules(); + } - return 0; } - diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp index 8a8f23630..2e3547bd8 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_romfs.cpp @@ -324,11 +324,11 @@ namespace ams::mitm::fs { AMS_ABORT_UNLESS(num_child_dirs >= 0); { - BuildDirectoryContext **child_dirs = reinterpret_cast(std::malloc(sizeof(BuildDirectoryContext *) * num_child_dirs)); + BuildDirectoryContext **child_dirs = num_child_dirs != 0 ? reinterpret_cast(std::malloc(sizeof(BuildDirectoryContext *) * num_child_dirs)) : nullptr; + AMS_ABORT_UNLESS(num_child_dirs == 0 || child_dirs != nullptr); ON_SCOPE_EXIT { std::free(child_dirs); }; - AMS_ABORT_UNLESS(child_dirs != nullptr); - s64 cur_child_dir_ind = 0; + s64 cur_child_dir_ind = 0; { OpenFileSystemRomfsDirectory(&dir, this->program_id, parent, OpenDirectoryMode_All, fs); ON_SCOPE_EXIT { fsDirClose(&dir); }; @@ -342,6 +342,8 @@ namespace ams::mitm::fs { AMS_ABORT_UNLESS(this->dir_entry.type == FsDirEntryType_Dir || this->dir_entry.type == FsDirEntryType_File); if (this->dir_entry.type == FsDirEntryType_Dir) { + AMS_ABORT_UNLESS(child_dirs != nullptr); + BuildDirectoryContext *real_child = nullptr; this->AddDirectory(&real_child, parent, std::make_unique(this->dir_entry.name, strlen(this->dir_entry.name))); AMS_ABORT_UNLESS(real_child != nullptr); diff --git a/stratosphere/boot/source/boot_main.cpp b/stratosphere/boot/source/boot_main.cpp index 605117545..04ee916e4 100644 --- a/stratosphere/boot/source/boot_main.cpp +++ b/stratosphere/boot/source/boot_main.cpp @@ -24,258 +24,190 @@ #include "boot_pinmux_initial_configuration.hpp" #include "boot_repair_boot_images.hpp" #include "boot_splash_screen.hpp" - #include "boot_power_utils.hpp" -using namespace ams; - -extern "C" { - extern u32 __start__; - - u32 __nx_applet_type = AppletType_None; - u32 __nx_fs_num_sessions = 1; - - /* TODO: Evaluate to what extent this can be reduced further. */ - #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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - namespace ams { + namespace boot { + + namespace { + + constinit u8 g_exp_heap_memory[20_KB]; + constinit u8 g_unit_heap_memory[5_KB]; + constinit lmem::HeapHandle g_exp_heap_handle; + constinit lmem::HeapHandle g_unit_heap_handle; + + constinit sf::ExpHeapMemoryResource g_exp_heap_memory_resource; + constinit sf::UnitHeapMemoryResource g_unit_heap_memory_resource; + + void *Allocate(size_t size) { + void *mem = lmem::AllocateFromExpHeap(g_exp_heap_handle, size); + return mem; + } + + void Deallocate(void *p, size_t size) { + AMS_UNUSED(size); + lmem::FreeToExpHeap(g_exp_heap_handle, p); + } + + void InitializeHeaps() { + /* Create the heaps. */ + g_exp_heap_handle = lmem::CreateExpHeap(g_exp_heap_memory, sizeof(g_exp_heap_memory), lmem::CreateOption_ThreadSafe); + g_unit_heap_handle = lmem::CreateUnitHeap(g_unit_heap_memory, sizeof(g_unit_heap_memory), sizeof(ddsf::DeviceCodeEntryHolder), lmem::CreateOption_ThreadSafe); + + /* Attach the memory resources. */ + g_exp_heap_memory_resource.Attach(g_exp_heap_handle); + g_unit_heap_memory_resource.Attach(g_unit_heap_handle); + + /* Register with ddsf. */ + ddsf::SetMemoryResource(std::addressof(g_exp_heap_memory_resource)); + ddsf::SetDeviceCodeEntryHolderMemoryResource(std::addressof(g_unit_heap_memory_resource)); + } + + } + + } + + namespace init { + + void InitializeSystemModule() { + /* Initialize heaps. */ + boot::InitializeHeaps(); + + /* Set fs allocator. */ + fs::SetAllocator(boot::Allocate, boot::Deallocate); + + /* Initialize services we need. */ + R_ABORT_UNLESS(sm::Initialize()); + + fs::InitializeForSystem(); + spl::Initialize(); + R_ABORT_UNLESS(pmshellInitialize()); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + void ExceptionHandler(FatalErrorContext *ctx) { /* We're boot sysmodule, so manually reboot to fatal error. */ boot::RebootForFatalError(ctx); } -} + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(boot, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(boot, Main)); -using namespace ams; + /* Perform atmosphere-specific init. */ + ams::InitializeForBoot(); -namespace { + /* Set the reboot payload with ams.mitm. */ + boot::SetInitialRebootPayload(); - constinit u8 g_exp_heap_memory[20_KB]; - constinit u8 g_unit_heap_memory[5_KB]; - constinit lmem::HeapHandle g_exp_heap_handle; - constinit lmem::HeapHandle g_unit_heap_handle; + /* Change voltage from 3.3v to 1.8v for select devices. */ + boot::ChangeGpioVoltageTo1_8v(); - constinit sf::ExpHeapMemoryResource g_exp_heap_memory_resource; - constinit sf::UnitHeapMemoryResource g_unit_heap_memory_resource; + /* Setup gpio. */ + gpio::driver::SetInitialGpioConfig(); - void *Allocate(size_t size) { - void *mem = lmem::AllocateFromExpHeap(g_exp_heap_handle, size); - return mem; - } + /* Initialize the gpio server library. */ + boot::InitializeGpioDriverLibrary(); - void Deallocate(void *p, size_t size) { - AMS_UNUSED(size); - lmem::FreeToExpHeap(g_exp_heap_handle, p); - } + /* Initialize the i2c server library. */ + boot::InitializeI2cDriverLibrary(); - void InitializeHeaps() { - /* Create the heaps. */ - g_exp_heap_handle = lmem::CreateExpHeap(g_exp_heap_memory, sizeof(g_exp_heap_memory), lmem::CreateOption_ThreadSafe); - g_unit_heap_handle = lmem::CreateUnitHeap(g_unit_heap_memory, sizeof(g_unit_heap_memory), sizeof(ddsf::DeviceCodeEntryHolder), lmem::CreateOption_ThreadSafe); + /* Get the hardware type. */ + const auto hw_type = spl::GetHardwareType(); - /* Attach the memory resources. */ - g_exp_heap_memory_resource.Attach(g_exp_heap_handle); - g_unit_heap_memory_resource.Attach(g_unit_heap_handle); + /* Initialize the power control library without interrupt event handling. */ + if (hw_type != spl::HardwareType::Calcio) { + powctl::Initialize(false); + } - /* Register with ddsf. */ - ddsf::SetMemoryResource(std::addressof(g_exp_heap_memory_resource)); - ddsf::SetDeviceCodeEntryHolderMemoryResource(std::addressof(g_unit_heap_memory_resource)); + /* Check USB PLL/UTMIP clock. */ + boot::CheckClock(); + + /* Talk to PMIC/RTC, set boot reason with SPL. */ + boot::DetectBootReason(); + + /* Display the splash screen and check the battery charge. */ + if (hw_type != spl::HardwareType::Calcio) { + /* Display splash screen for two seconds. */ + boot::ShowSplashScreen(); + + /* Check that the battery has enough to boot. */ + boot::CheckBatteryCharge(); + } + + /* Configure pinmux + drive pads. */ + boot::SetInitialPinmuxConfiguration(); + + /* Configure the PMC wake pin settings. */ + gpio::driver::SetInitialWakePinConfig(); + + /* Configure output clock. */ + if (hw_type != spl::HardwareType::Calcio) { + boot::SetInitialClockConfiguration(); + } + + /* Set Fan enable config (Copper only). */ + boot::SetFanPowerEnabled(); + + /* Repair boot partitions in NAND if needed. */ + boot::CheckAndRepairBootImages(); + + /* Finalize the power control library. */ + if (hw_type != spl::HardwareType::Calcio) { + powctl::Finalize(); + } + + /* Finalize the i2c server library. */ + boot::FinalizeI2cDriverLibrary(); + + /* Finalize the gpio server library. */ + boot::FinalizeGpioDriverLibrary(); + + /* Tell PM to start boot2. */ + R_ABORT_UNLESS(pmshellNotifyBootFinished()); } } -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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; - - InitializeHeaps(); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - fs::SetAllocator(Allocate, Deallocate); - - /* Initialize services we need. */ - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsInitialize()); - spl::Initialize(); - R_ABORT_UNLESS(pmshellInitialize()); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* Cleanup services. */ - pmshellExit(); - spl::Finalize(); - fsExit(); -} - -namespace ams { - - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); - } - - void Free(void *) { - AMS_ABORT("ams::Free was called"); - } - -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - +/* Override operator new. */ void *operator new(size_t size) { - return Allocate(size); + return ams::boot::Allocate(size); } void *operator new(size_t size, const std::nothrow_t &) { - return Allocate(size); + return ams::boot::Allocate(size); } void operator delete(void *p) { - return Deallocate(p, 0); + return ams::boot::Deallocate(p, 0); } void operator delete(void *p, size_t size) { - return Deallocate(p, size); + return ams::boot::Deallocate(p, size); } void *operator new[](size_t size) { - return Allocate(size); + return ams::boot::Allocate(size); } void *operator new[](size_t size, const std::nothrow_t &) { - return Allocate(size); + return ams::boot::Allocate(size); } void operator delete[](void *p) { - return Deallocate(p, 0); + return ams::boot::Deallocate(p, 0); } void operator delete[](void *p, size_t size) { - return Deallocate(p, size); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(boot, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(boot, Main)); - - /* Perform atmosphere-specific init. */ - ams::InitializeForBoot(); - - /* Set the reboot payload with ams.mitm. */ - boot::SetInitialRebootPayload(); - - /* Change voltage from 3.3v to 1.8v for select devices. */ - boot::ChangeGpioVoltageTo1_8v(); - - /* Setup gpio. */ - gpio::driver::SetInitialGpioConfig(); - - /* Initialize the gpio server library. */ - boot::InitializeGpioDriverLibrary(); - - /* Initialize the i2c server library. */ - boot::InitializeI2cDriverLibrary(); - - /* Get the hardware type. */ - const auto hw_type = spl::GetHardwareType(); - - /* Initialize the power control library without interrupt event handling. */ - if (hw_type != spl::HardwareType::Calcio) { - powctl::Initialize(false); - } - - /* Check USB PLL/UTMIP clock. */ - boot::CheckClock(); - - /* Talk to PMIC/RTC, set boot reason with SPL. */ - boot::DetectBootReason(); - - /* Display the splash screen and check the battery charge. */ - if (hw_type != spl::HardwareType::Calcio) { - /* Display splash screen for two seconds. */ - boot::ShowSplashScreen(); - - /* Check that the battery has enough to boot. */ - boot::CheckBatteryCharge(); - } - - /* Configure pinmux + drive pads. */ - boot::SetInitialPinmuxConfiguration(); - - /* Configure the PMC wake pin settings. */ - gpio::driver::SetInitialWakePinConfig(); - - /* Configure output clock. */ - if (hw_type != spl::HardwareType::Calcio) { - boot::SetInitialClockConfiguration(); - } - - /* Set Fan enable config (Copper only). */ - boot::SetFanPowerEnabled(); - - /* Repair boot partitions in NAND if needed. */ - boot::CheckAndRepairBootImages(); - - /* Finalize the power control library. */ - if (hw_type != spl::HardwareType::Calcio) { - powctl::Finalize(); - } - - /* Finalize the i2c server library. */ - boot::FinalizeI2cDriverLibrary(); - - /* Finalize the gpio server library. */ - boot::FinalizeGpioDriverLibrary(); - - /* Tell PM to start boot2. */ - R_ABORT_UNLESS(pmshellNotifyBootFinished()); - - return 0; + return ams::boot::Deallocate(p, size); } diff --git a/stratosphere/boot2/source/boot2_main.cpp b/stratosphere/boot2/source/boot2_main.cpp index 61b7edc58..57ef0453f 100644 --- a/stratosphere/boot2/source/boot2_main.cpp +++ b/stratosphere/boot2/source/boot2_main.cpp @@ -15,148 +15,73 @@ */ #include -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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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; -} - -namespace { - - - constinit u8 g_fs_heap_memory[2_KB]; - lmem::HeapHandle g_fs_heap_handle; - - void *AllocateForFs(size_t size) { - return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); - } - - void DeallocateForFs(void *p, size_t size) { - AMS_UNUSED(size); - return lmem::FreeToExpHeap(g_fs_heap_handle, p); - } - - void InitializeFsHeap() { - g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_None); - } - -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - InitializeFsHeap(); - fs::SetAllocator(AllocateForFs, DeallocateForFs); - - /* Initialize services we need. */ - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsInitialize()); - R_ABORT_UNLESS(pmbmInitialize()); - R_ABORT_UNLESS(pminfoInitialize()); - R_ABORT_UNLESS(pmshellInitialize()); - R_ABORT_UNLESS(setsysInitialize()); - gpio::Initialize(); - - /* Mount the SD card. */ - R_ABORT_UNLESS(fs::MountSdCard("sdmc")); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - fs::Unmount("sdmc"); - gpio::Finalize(); - setsysExit(); - pmshellExit(); - pminfoExit(); - pmbmExit(); - fsExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace boot2 { + + namespace { + + constinit u8 g_fs_heap_memory[2_KB]; + constinit lmem::HeapHandle g_fs_heap_handle; + + void *AllocateForFs(size_t size) { + return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); + } + + void DeallocateForFs(void *p, size_t size) { + AMS_UNUSED(size); + return lmem::FreeToExpHeap(g_fs_heap_handle, p); + } + + void InitializeFsHeap() { + g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_None); + } + + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + boot2::InitializeFsHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(boot2::AllocateForFs, boot2::DeallocateForFs); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services we need. */ + R_ABORT_UNLESS(pmbmInitialize()); + R_ABORT_UNLESS(pminfoInitialize()); + R_ABORT_UNLESS(pmshellInitialize()); + R_ABORT_UNLESS(setsysInitialize()); + gpio::Initialize(); + + /* Mount the SD card. */ + R_ABORT_UNLESS(fs::MountSdCard("sdmc")); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(boot2, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(boot2, Main)); + + /* Launch all programs off of SYSTEM/the SD. */ + boot2::LaunchPostSdCardBootPrograms(); } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(boot2, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(boot2, Main)); - - /* Launch all programs off of SYSTEM/the SD. */ - boot2::LaunchPostSdCardBootPrograms(); - - return 0; -} - diff --git a/stratosphere/creport/source/creport_main.cpp b/stratosphere/creport/source/creport_main.cpp index 842886348..bd24020ad 100644 --- a/stratosphere/creport/source/creport_main.cpp +++ b/stratosphere/creport/source/creport_main.cpp @@ -17,198 +17,140 @@ #include "creport_crash_report.hpp" #include "creport_utils.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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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; -} - -namespace { - - - constinit u8 g_fs_heap_memory[4_KB]; - lmem::HeapHandle g_fs_heap_handle; - - void *AllocateForFs(size_t size) { - return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); - } - - void DeallocateForFs(void *p, size_t size) { - AMS_UNUSED(size); - return lmem::FreeToExpHeap(g_fs_heap_handle, p); - } - - void InitializeFsHeap() { - g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_None); - } - -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - InitializeFsHeap(); - fs::SetAllocator(AllocateForFs, DeallocateForFs); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsInitialize()); - - R_ABORT_UNLESS(fs::MountSdCard("sdmc")); -} - -void __appExit(void) { - /* Cleanup services. */ - fsExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); - } + namespace creport { - void Free(void *) { - AMS_ABORT("ams::Free was called"); - } + namespace { -} + constinit u8 g_fs_heap_memory[4_KB]; + lmem::HeapHandle g_fs_heap_handle; -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -namespace { - - constinit creport::CrashReport g_crash_report; - -} - -int main(int argc, char **argv) { - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(creport, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(creport, Main)); - - /* Validate arguments. */ - if (argc < 2) { - return EXIT_FAILURE; - } - for (int i = 0; i < argc; i++) { - if (argv[i] == NULL) { - return EXIT_FAILURE; - } - } - - /* Parse arguments. */ - const os::ProcessId crashed_pid = creport::ParseProcessIdArgument(argv[0]); - const bool has_extra_info = argv[1][0] == '1'; - const bool enable_screenshot = argc >= 3 && argv[2][0] == '1'; - const bool enable_jit_debug = argc >= 4 && argv[3][0] == '1'; - - /* Initialize the crash report. */ - g_crash_report.Initialize(); - - /* Try to debug the crashed process. */ - g_crash_report.BuildReport(crashed_pid, has_extra_info); - if (!g_crash_report.IsComplete()) { - return EXIT_FAILURE; - } - - /* Save report to file. */ - g_crash_report.SaveReport(enable_screenshot); - - /* If we should, try to terminate the process. */ - if (hos::GetVersion() < hos::Version_11_0_0 || !enable_jit_debug) { - if (hos::GetVersion() >= hos::Version_10_0_0) { - /* On 10.0.0+, use pgl to terminate. */ - if (R_SUCCEEDED(pgl::Initialize())) { - ON_SCOPE_EXIT { pgl::Finalize(); }; - - pgl::TerminateProcess(crashed_pid); + void *AllocateForFs(size_t size) { + return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); } - } else { - /* On < 10.0.0, use ns:dev to terminate. */ - if (R_SUCCEEDED(::nsdevInitialize())) { - ON_SCOPE_EXIT { ::nsdevExit(); }; - nsdevTerminateProcess(static_cast(crashed_pid)); + void DeallocateForFs(void *p, size_t size) { + AMS_UNUSED(size); + return lmem::FreeToExpHeap(g_fs_heap_handle, p); + } + + void InitializeFsHeap() { + g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_None); + } + + } + + } + + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + creport::InitializeFsHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(creport::AllocateForFs, creport::DeallocateForFs); + fs::SetEnabledAutoAbort(false); + + /* Mount the SD card. */ + R_ABORT_UNLESS(fs::MountSdCard("sdmc")); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + namespace { + + constinit creport::CrashReport g_crash_report; + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(creport, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(creport, Main)); + + /* Get arguments. */ + const int num_args = os::GetHostArgc(); + char ** const args = os::GetHostArgv(); + + /* Validate arguments. */ + if (num_args < 2) { + return; + } + + for (auto i = 0; i < num_args; ++i) { + if (args[i] == nullptr) { + return; } } - } - /* Don't fatal if we have extra info, or if we're 5.0.0+ and an application crashed. */ - if (hos::GetVersion() >= hos::Version_5_0_0) { - if (g_crash_report.IsApplication()) { - return EXIT_SUCCESS; + /* Parse arguments. */ + const os::ProcessId crashed_pid = creport::ParseProcessIdArgument(args[0]); + const bool has_extra_info = args[1][0] == '1'; + const bool enable_screenshot = num_args >= 3 && args[2][0] == '1'; + const bool enable_jit_debug = num_args >= 4 && args[3][0] == '1'; + + /* Initialize the crash report. */ + g_crash_report.Initialize(); + + /* Try to debug the crashed process. */ + g_crash_report.BuildReport(crashed_pid, has_extra_info); + if (!g_crash_report.IsComplete()) { + return; + } + + /* Save report to file. */ + g_crash_report.SaveReport(enable_screenshot); + + /* Try to terminate the process, if we should. */ + const auto fw_ver = hos::GetVersion(); + if (fw_ver < hos::Version_11_0_0 || !enable_jit_debug) { + if (fw_ver >= hos::Version_10_0_0) { + /* Use pgl to terminate. */ + if (R_SUCCEEDED(pgl::Initialize())) { + ON_SCOPE_EXIT { pgl::Finalize(); }; + + pgl::TerminateProcess(crashed_pid); + } + } else { + /* Use ns to terminate. */ + if (R_SUCCEEDED(::nsdevInitialize())) { + ON_SCOPE_EXIT { ::nsdevExit(); }; + + nsdevTerminateProcess(crashed_pid.value); + } + } + } + + /* If we're on 5.0.0+ and an application crashed, or if we have extra info, we don't need to fatal. */ + if (fw_ver >= hos::Version_5_0_0) { + if (g_crash_report.IsApplication()) { + return; + } + } else if (has_extra_info) { + return; + } + + /* We also don't need to fatal on user break. */ + if (g_crash_report.IsUserBreak()) { + return; + } + + /* Throw fatal error. */ + { + ::FatalCpuContext ctx; + g_crash_report.GetFatalContext(std::addressof(ctx)); + fatalThrowWithContext(g_crash_report.GetResult().GetValue(), FatalPolicy_ErrorScreen, std::addressof(ctx)); } - } else if (has_extra_info) { - return EXIT_SUCCESS; } - /* Also don't fatal if we're a user break. */ - if (g_crash_report.IsUserBreak()) { - return EXIT_SUCCESS; - } - - /* Throw fatal error. */ - ::FatalCpuContext ctx; - g_crash_report.GetFatalContext(&ctx); - fatalThrowWithContext(g_crash_report.GetResult().GetValue(), FatalPolicy_ErrorScreen, &ctx); } diff --git a/stratosphere/cs/source/cs_main.cpp b/stratosphere/cs/source/cs_main.cpp index 778e4d80e..44e9e30f7 100644 --- a/stratosphere/cs/source/cs_main.cpp +++ b/stratosphere/cs/source/cs_main.cpp @@ -15,222 +15,137 @@ */ #include -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); -} - -using namespace ams; - -#define AMS_CS_SERVER_USE_FATAL_ERROR 1 - -#if AMS_CS_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::cs { - - namespace { - - alignas(os::ThreadStackAlignment) constinit u8 g_shell_stack[4_KB]; - alignas(os::ThreadStackAlignment) constinit u8 g_runner_stack[4_KB]; - - alignas(os::MemoryPageSize) constinit u8 g_heap_memory[32_KB]; - - alignas(0x40) constinit u8 g_htcs_buffer[2_KB]; - - constinit os::SdkMutex g_heap_mutex; - constinit lmem::HeapHandle g_heap_handle; - - void *Allocate(size_t size) { - std::scoped_lock lk(g_heap_mutex); - void *mem = lmem::AllocateFromExpHeap(g_heap_handle, size); - return mem; - } - - void Deallocate(void *p, size_t size) { - AMS_UNUSED(size); - - std::scoped_lock lk(g_heap_mutex); - lmem::FreeToExpHeap(g_heap_handle, p); - } - - void InitializeHeap() { - std::scoped_lock lk(g_heap_mutex); - g_heap_handle = lmem::CreateExpHeap(g_heap_memory, sizeof(g_heap_memory), lmem::CreateOption_None); - } - - } - -} - -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; - - cs::InitializeHeap(); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - fs::SetAllocator(cs::Allocate, cs::Deallocate); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsInitialize()); - lr::Initialize(); - R_ABORT_UNLESS(ldr::InitializeForShell()); - R_ABORT_UNLESS(pgl::Initialize()); - R_ABORT_UNLESS(setsysInitialize()); - /* TODO: Other services? */ - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* TODO: Other services? */ - setsysExit(); - pgl::Finalize(); - ldr::FinalizeForShell(); - lr::Finalize(); - fsExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); - } + namespace cs { - void Free(void *) { - AMS_ABORT("ams::Free was called"); - } + namespace { -} + alignas(os::ThreadStackAlignment) constinit u8 g_shell_stack[4_KB]; + alignas(os::ThreadStackAlignment) constinit u8 g_runner_stack[4_KB]; -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} + alignas(os::MemoryPageSize) constinit u8 g_heap_memory[32_KB]; -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} + alignas(0x40) constinit u8 g_htcs_buffer[2_KB]; -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} + constinit os::SdkMutex g_heap_mutex; + constinit lmem::HeapHandle g_heap_handle; -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} + void *Allocate(size_t size) { + std::scoped_lock lk(g_heap_mutex); + void *mem = lmem::AllocateFromExpHeap(g_heap_handle, size); + return mem; + } -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} + void Deallocate(void *p, size_t size) { + AMS_UNUSED(size); -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} + std::scoped_lock lk(g_heap_mutex); + lmem::FreeToExpHeap(g_heap_handle, p); + } -namespace ams::cs { + void InitializeHeap() { + std::scoped_lock lk(g_heap_mutex); + g_heap_handle = lmem::CreateExpHeap(g_heap_memory, sizeof(g_heap_memory), lmem::CreateOption_None); + } - namespace { + } - constinit ::ams::cs::CommandProcessor g_command_processor; + namespace { - constinit ::ams::scs::ShellServer g_shell_server; - constinit ::ams::scs::ShellServer g_runner_server; + constinit ::ams::cs::CommandProcessor g_command_processor; - constinit sf::UnmanagedServiceObject g_tenv_service_manager; + constinit ::ams::scs::ShellServer g_shell_server; + constinit ::ams::scs::ShellServer g_runner_server; + + constinit sf::UnmanagedServiceObject g_tenv_service_manager; + + void InitializeCommandProcessor() { + g_command_processor.Initialize(); + } + + void InitializeShellServers() { + g_shell_server.Initialize("iywys@$cs", g_shell_stack, sizeof(g_shell_stack), std::addressof(g_command_processor)); + g_shell_server.Start(); + + g_runner_server.Initialize("iywys@$csForRunnerTools", g_runner_stack, sizeof(g_runner_stack), std::addressof(g_command_processor)); + g_runner_server.Start(); + } + + } } -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - using namespace ams::cs; - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(cs, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(cs, Main)); - - /* Initialize htcs. */ - constexpr auto HtcsSocketCountMax = 6; - const size_t buffer_size = htcs::GetWorkingMemorySize(2 * HtcsSocketCountMax); - AMS_ABORT_UNLESS(sizeof(g_htcs_buffer) >= buffer_size); - htcs::InitializeForSystem(g_htcs_buffer, buffer_size, HtcsSocketCountMax); - - /* Initialize audio server. */ - cs::InitializeAudioServer(); - - /* Initialize remote video server. */ - cs::InitializeRemoteVideoServer(); - - /* Initialize hid server. */ - cs::InitializeHidServer(); - - /* Initialize target io server. */ - cs::InitializeTargetIoServer(); - - /* Initialize command processor. */ - g_command_processor.Initialize(); - - /* Setup scs. */ - scs::InitializeShell(); - - /* Setup target environment service. */ - scs::InitializeTenvServiceManager(); - - /* Initialize the shell servers. */ - g_shell_server.Initialize("iywys@$cs", g_shell_stack, sizeof(g_shell_stack), std::addressof(g_command_processor)); - g_shell_server.Start(); - - g_runner_server.Initialize("iywys@$csForRunnerTools", g_runner_stack, sizeof(g_runner_stack), std::addressof(g_command_processor)); - g_runner_server.Start(); - - /* Register htc:tenv. */ - R_ABORT_UNLESS(scs::GetServerManager()->RegisterObjectForServer(g_tenv_service_manager.GetShared(), htc::tenv::ServiceName, scs::SessionCount[scs::Port_HtcTenv])); - - /* Start the scs ipc server. */ - scs::StartServer(); - - return 0; + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + cs::InitializeHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(cs::Allocate, cs::Deallocate); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services we need. */ + lr::Initialize(); + R_ABORT_UNLESS(ldr::InitializeForShell()); + R_ABORT_UNLESS(pgl::Initialize()); + R_ABORT_UNLESS(setsysInitialize()); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(cs, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(cs, Main)); + + /* Initialize htcs. */ + constexpr auto HtcsSocketCountMax = 6; + const size_t buffer_size = htcs::GetWorkingMemorySize(2 * HtcsSocketCountMax); + AMS_ABORT_UNLESS(sizeof(cs::g_htcs_buffer) >= buffer_size); + htcs::InitializeForSystem(cs::g_htcs_buffer, buffer_size, HtcsSocketCountMax); + + /* Initialize audio server. */ + cs::InitializeAudioServer(); + + /* Initialize remote video server. */ + cs::InitializeRemoteVideoServer(); + + /* Initialize hid server. */ + cs::InitializeHidServer(); + + /* Initialize target io server. */ + cs::InitializeTargetIoServer(); + + /* Initialize command processor. */ + cs::InitializeCommandProcessor(); + + /* Setup scs. */ + scs::InitializeShell(); + + /* Setup target environment service. */ + scs::InitializeTenvServiceManager(); + + /* Initialize the shell servers. */ + cs::InitializeShellServers(); + + /* Register htc:tenv. */ + R_ABORT_UNLESS(scs::GetServerManager()->RegisterObjectForServer(cs::g_tenv_service_manager.GetShared(), htc::tenv::ServiceName, scs::SessionCount[scs::Port_HtcTenv])); + + /* Start the scs ipc server. */ + scs::StartServer(); + } + } diff --git a/stratosphere/dmnt.gen2/source/dmnt2_main.cpp b/stratosphere/dmnt.gen2/source/dmnt2_main.cpp index aac9adb83..6336cc23f 100644 --- a/stratosphere/dmnt.gen2/source/dmnt2_main.cpp +++ b/stratosphere/dmnt.gen2/source/dmnt2_main.cpp @@ -17,140 +17,55 @@ #include "dmnt2_debug_log.hpp" #include "dmnt2_gdb_server.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); -} - -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) { - AMS_ABORT("ams::Malloc was called"); + namespace dmnt { + + namespace { + + alignas(0x40) constinit u8 g_htcs_buffer[4_KB]; + + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main)); + + /* 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(); + + /* Start GdbServer. */ + dmnt::InitializeGdbServer(); + + /* TODO */ + while (true) { + os::SleepThread(TimeSpan::FromDays(1)); + } } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, 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(); - - /* Start GdbServer. */ - dmnt::InitializeGdbServer(); - - /* TODO */ - while (true) { - os::SleepThread(TimeSpan::FromDays(1)); - } - - return 0; -} diff --git a/stratosphere/dmnt/source/dmnt_main.cpp b/stratosphere/dmnt/source/dmnt_main.cpp index 69ebf57c8..baca39d33 100644 --- a/stratosphere/dmnt/source/dmnt_main.cpp +++ b/stratosphere/dmnt/source/dmnt_main.cpp @@ -17,213 +17,149 @@ #include "cheat/dmnt_cheat_service.hpp" #include "cheat/impl/dmnt_cheat_api.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); -} - -using namespace ams; - -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; -} - -namespace { - - - constinit u8 g_fs_heap_memory[4_KB]; - lmem::HeapHandle g_fs_heap_handle; - - void *AllocateForFs(size_t size) { - return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); - } - - void DeallocateForFs(void *p, size_t size) { - AMS_UNUSED(size); - return lmem::FreeToExpHeap(g_fs_heap_handle, p); - } - - void InitializeFsHeap() { - g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_None); - } - -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - InitializeFsHeap(); - fs::SetAllocator(AllocateForFs, DeallocateForFs); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(pmdmntInitialize()); - R_ABORT_UNLESS(pminfoInitialize()); - R_ABORT_UNLESS(ldrDmntInitialize()); - R_ABORT_UNLESS(roDmntInitialize()); - R_ABORT_UNLESS(nsdevInitialize()); - lr::Initialize(); - R_ABORT_UNLESS(setInitialize()); - R_ABORT_UNLESS(setsysInitialize()); - R_ABORT_UNLESS(hidInitialize()); - R_ABORT_UNLESS(fsInitialize()); - - R_ABORT_UNLESS(fs::MountSdCard("sdmc")); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* Cleanup services. */ - fsExit(); - hidExit(); - setsysExit(); - setExit(); - lr::Finalize(); - nsdevExit(); - roDmntExit(); - ldrDmntExit(); - pminfoExit(); - pmdmntExit(); -} - -namespace { - - using ServerOptions = sf::hipc::DefaultServerManagerOptions; - - constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("dmnt:-"); - constexpr size_t DebugMonitorMaxSessions = 4; - - constexpr sm::ServiceName CheatServiceName = sm::ServiceName::Encode("dmnt:cht"); - constexpr size_t CheatMaxSessions = 2; - - /* dmnt:-, dmnt:cht. */ - constexpr size_t NumServers = 2; - constexpr size_t NumSessions = DebugMonitorMaxSessions + CheatMaxSessions; - - sf::hipc::ServerManager g_server_manager; - - constinit sf::UnmanagedServiceObject g_cheat_service; - - void LoopServerThread(void *) { - g_server_manager.LoopProcess(); - } - - constexpr size_t TotalThreads = DebugMonitorMaxSessions + 1; - static_assert(TotalThreads >= 1, "TotalThreads"); - constexpr size_t NumExtraThreads = TotalThreads - 1; - constexpr size_t ThreadStackSize = 0x4000; - alignas(os::MemoryPageSize) u8 g_extra_thread_stacks[NumExtraThreads][ThreadStackSize]; - - os::ThreadType g_extra_threads[NumExtraThreads]; - -} - - - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace dmnt { + + namespace { + + constinit u8 g_fs_heap_memory[4_KB]; + lmem::HeapHandle g_fs_heap_handle; + + void *AllocateForFs(size_t size) { + return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); + } + + void DeallocateForFs(void *p, size_t size) { + AMS_UNUSED(size); + return lmem::FreeToExpHeap(g_fs_heap_handle, p); + } + + void InitializeFsHeap() { + g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_None); + } + + } + + namespace { + + using ServerOptions = sf::hipc::DefaultServerManagerOptions; + + constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("dmnt:-"); + constexpr size_t DebugMonitorMaxSessions = 4; + + constexpr sm::ServiceName CheatServiceName = sm::ServiceName::Encode("dmnt:cht"); + constexpr size_t CheatMaxSessions = 2; + + /* dmnt:-, dmnt:cht. */ + constexpr size_t NumServers = 2; + constexpr size_t NumSessions = DebugMonitorMaxSessions + CheatMaxSessions; + + sf::hipc::ServerManager g_server_manager; + + constinit sf::UnmanagedServiceObject g_cheat_service; + + void LoopServerThread(void *) { + g_server_manager.LoopProcess(); + } + + /* NOTE: Nintendo loops four threads processing on the manager -- we'll loop an extra fifth for our cheat service. */ + constexpr size_t TotalThreads = DebugMonitorMaxSessions + 1; + static_assert(TotalThreads >= 1, "TotalThreads"); + constexpr size_t NumExtraThreads = TotalThreads - 1; + constexpr size_t ThreadStackSize = 0x4000; + alignas(os::MemoryPageSize) u8 g_extra_thread_stacks[NumExtraThreads][ThreadStackSize]; + + os::ThreadType g_extra_threads[NumExtraThreads]; + + void InitializeIpcServer() { + /* Create services. */ + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_cheat_service.GetShared(), CheatServiceName, CheatMaxSessions)); + } + + void LoopProcessIpcServer() { + /* Initialize threads. */ + if constexpr (NumExtraThreads > 0) { + static_assert(AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Ipc)); + for (size_t i = 0; i < NumExtraThreads; i++) { + R_ABORT_UNLESS(os::CreateThread(std::addressof(g_extra_threads[i]), LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Ipc))); + os::SetThreadNamePointer(std::addressof(g_extra_threads[i]), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Ipc)); + } + } + + /* Start extra threads. */ + if constexpr (NumExtraThreads > 0) { + for (size_t i = 0; i < NumExtraThreads; i++) { + os::StartThread(std::addressof(g_extra_threads[i])); + } + } + + /* Loop this thread. */ + LoopServerThread(nullptr); + + /* Wait for extra threads to finish. */ + if constexpr (NumExtraThreads > 0) { + for (size_t i = 0; i < NumExtraThreads; i++) { + os::WaitThread(std::addressof(g_extra_threads[i])); + } + } + } + + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + dmnt::InitializeFsHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(dmnt::AllocateForFs, dmnt::DeallocateForFs); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services we need. */ + R_ABORT_UNLESS(pmdmntInitialize()); + R_ABORT_UNLESS(pminfoInitialize()); + R_ABORT_UNLESS(ldrDmntInitialize()); + R_ABORT_UNLESS(roDmntInitialize()); + R_ABORT_UNLESS(nsdevInitialize()); + lr::Initialize(); + R_ABORT_UNLESS(setInitialize()); + R_ABORT_UNLESS(setsysInitialize()); + R_ABORT_UNLESS(hidInitialize()); + + /* Mount the SD card. */ + R_ABORT_UNLESS(fs::MountSdCard("sdmc")); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main)); + + /* Initialize the cheat manager. */ + dmnt::cheat::impl::InitializeCheatManager(); + + /* Initialize ipc server. */ + dmnt::InitializeIpcServer(); + + /* Loop processing ipc server. */ + dmnt::LoopProcessIpcServer(); } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main)); - - /* Initialize the cheat manager. */ - ams::dmnt::cheat::impl::InitializeCheatManager(); - - /* Create services. */ - R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_cheat_service.GetShared(), CheatServiceName, CheatMaxSessions)); - - /* Loop forever, servicing our services. */ - /* Nintendo loops four threads processing on the manager -- we'll loop an extra fifth for our cheat service. */ - { - - /* Initialize threads. */ - if constexpr (NumExtraThreads > 0) { - static_assert(AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Main) == AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Ipc)); - for (size_t i = 0; i < NumExtraThreads; i++) { - R_ABORT_UNLESS(os::CreateThread(std::addressof(g_extra_threads[i]), LoopServerThread, nullptr, g_extra_thread_stacks[i], ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, Ipc))); - os::SetThreadNamePointer(std::addressof(g_extra_threads[i]), AMS_GET_SYSTEM_THREAD_NAME(dmnt, Ipc)); - } - } - - /* Start extra threads. */ - if constexpr (NumExtraThreads > 0) { - for (size_t i = 0; i < NumExtraThreads; i++) { - os::StartThread(std::addressof(g_extra_threads[i])); - } - } - - /* Loop this thread. */ - LoopServerThread(nullptr); - - /* Wait for extra threads to finish. */ - if constexpr (NumExtraThreads > 0) { - for (size_t i = 0; i < NumExtraThreads; i++) { - os::WaitThread(std::addressof(g_extra_threads[i])); - } - } - } - - return 0; -} - diff --git a/stratosphere/eclct.stub/source/eclct_stub.cpp b/stratosphere/eclct.stub/source/eclct_stub.cpp index bb4cec567..36bb07d75 100644 --- a/stratosphere/eclct.stub/source/eclct_stub.cpp +++ b/stratosphere/eclct.stub/source/eclct_stub.cpp @@ -15,54 +15,21 @@ */ #include -extern "C" { - extern u32 __start__; +namespace ams { - u32 __nx_applet_type = AppletType_None; + namespace init { - #define INNER_HEAP_SIZE 0x2000 - size_t nx_inner_heap_size = INNER_HEAP_SIZE; - char nx_inner_heap[INNER_HEAP_SIZE]; + void InitializeSystemModule() { /* ... */ } - void __libnx_initheap(void); - void __appInit(void); - void __appExit(void); + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* ... */ + } - /* 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); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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) { - /* nothing to do */ -} - -void __appExit(void) { - /* nothing to do */ -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - return 0; } diff --git a/stratosphere/erpt/source/erpt_main.cpp b/stratosphere/erpt/source/erpt_main.cpp index 0b65bd52d..41577b9a9 100644 --- a/stratosphere/erpt/source/erpt_main.cpp +++ b/stratosphere/erpt/source/erpt_main.cpp @@ -15,208 +15,127 @@ */ #include -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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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()); - - R_ABORT_UNLESS(setInitialize()); - R_ABORT_UNLESS(setsysInitialize()); - R_ABORT_UNLESS(pscmInitialize()); - R_ABORT_UNLESS(time::Initialize()); - if (hos::GetVersion() >= hos::Version_11_0_0) { - R_ABORT_UNLESS(ectxrInitialize()); - } - R_ABORT_UNLESS(fsInitialize()); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - fsExit(); - time::Finalize(); - pscmExit(); - setsysExit(); - setExit(); -} - -namespace ams::erpt { - - namespace { - - constexpr size_t MemoryHeapSize = 196_KB; - alignas(os::MemoryPageSize) u8 g_memory_heap[MemoryHeapSize]; - - } - - int MakeProductModelString(char *dst, size_t dst_size, settings::system::ProductModel model) { - switch (model) { - case settings::system::ProductModel_Invalid: return util::Strlcpy(dst, "Invalid", static_cast(dst_size)); - case settings::system::ProductModel_Nx: return util::Strlcpy(dst, "NX", static_cast(dst_size)); - default: return util::SNPrintf(dst, dst_size, "%d", static_cast(model)); - } - } - - const char *GetRegionString(settings::system::RegionCode code) { - switch (code) { - case settings::system::RegionCode_Japan: return "Japan"; - case settings::system::RegionCode_Usa: return "Usa"; - case settings::system::RegionCode_Europe: return "Europe"; - case settings::system::RegionCode_Australia: return "Australia"; - case settings::system::RegionCode_HongKongTaiwanKorea: return "HongKongTaiwanKorea"; - case settings::system::RegionCode_China: return "China"; - default: return "RegionUnknown"; - } - } - -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace erpt { + + namespace { + + constexpr size_t MemoryHeapSize = 196_KB; + alignas(os::MemoryPageSize) u8 g_memory_heap[MemoryHeapSize]; + + } + + int MakeProductModelString(char *dst, size_t dst_size, settings::system::ProductModel model) { + switch (model) { + case settings::system::ProductModel_Invalid: return util::Strlcpy(dst, "Invalid", static_cast(dst_size)); + case settings::system::ProductModel_Nx: return util::Strlcpy(dst, "NX", static_cast(dst_size)); + default: return util::SNPrintf(dst, dst_size, "%d", static_cast(model)); + } + } + + const char *GetRegionString(settings::system::RegionCode code) { + switch (code) { + case settings::system::RegionCode_Japan: return "Japan"; + case settings::system::RegionCode_Usa: return "Usa"; + case settings::system::RegionCode_Europe: return "Europe"; + case settings::system::RegionCode_Australia: return "Australia"; + case settings::system::RegionCode_HongKongTaiwanKorea: return "HongKongTaiwanKorea"; + case settings::system::RegionCode_China: return "China"; + default: return "RegionUnknown"; + } + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize services we need (which won't be initialized later). */ + R_ABORT_UNLESS(setInitialize()); + R_ABORT_UNLESS(setsysInitialize()); + R_ABORT_UNLESS(pscmInitialize()); + R_ABORT_UNLESS(time::Initialize()); + if (hos::GetVersion() >= hos::Version_11_0_0) { + R_ABORT_UNLESS(ectxrInitialize()); + } + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(erpt, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(erpt, Main)); + + /* Set the memory heap for erpt::srv namespace. */ + R_ABORT_UNLESS(erpt::srv::Initialize(erpt::g_memory_heap, erpt::MemoryHeapSize)); + + /* Atmosphere always wants to redirect new reports to the SD card, to prevent them from being logged. */ + erpt::srv::SetRedirectNewReportsToSdCard(true); + + /* Configure the OS version. */ + { + settings::system::FirmwareVersion firmware_version = {}; + settings::system::SerialNumber serial_number = {}; + settings::system::GetFirmwareVersion(std::addressof(firmware_version)); + settings::system::GetSerialNumber(std::addressof(serial_number)); + + char os_private[0x60]; + const auto os_priv_len = util::SNPrintf(os_private, sizeof(os_private), "%s (%.8s)", firmware_version.display_name, firmware_version.revision); + AMS_ASSERT(static_cast(os_priv_len) < sizeof(os_private)); + AMS_UNUSED(os_priv_len); + + R_ABORT_UNLESS(erpt::srv::SetSerialNumberAndOsVersion(serial_number.str, + strnlen(serial_number.str, sizeof(serial_number.str) - 1) + 1, + firmware_version.display_version, + strnlen(firmware_version.display_version, sizeof(firmware_version.display_version) - 1) + 1, + os_private, + strnlen(os_private, sizeof(os_private) - 1) + 1)); + } + + /* Configure the product model. */ + { + char product_model[0x10]; + const auto pm_len = erpt::MakeProductModelString(product_model, sizeof(product_model), settings::system::GetProductModel()); + AMS_ASSERT(static_cast(pm_len) < sizeof(product_model)); + AMS_UNUSED(pm_len); + + R_ABORT_UNLESS(erpt::srv::SetProductModel(product_model, static_cast(std::strlen(product_model)))); + } + + /* Configure the region. */ + { + settings::system::RegionCode code; + settings::system::GetRegionCode(std::addressof(code)); + const char *region_str = erpt::GetRegionString(code); + R_ABORT_UNLESS(erpt::srv::SetRegionSetting(region_str, static_cast(std::strlen(region_str)))); + } + + /* Start the erpt server. */ + R_ABORT_UNLESS(erpt::srv::InitializeAndStartService()); + + /* Launch sprofile on 13.0.0+ */ + if (hos::GetVersion() >= hos::Version_13_0_0) { + /* Initialize the sprofile server. */ + sprofile::srv::Initialize(); + + /* Start the sprofile ipc server. */ + sprofile::srv::StartIpcServer(); + } + + /* Wait forever. */ + erpt::srv::Wait(); } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(erpt, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(erpt, Main)); - - /* Set the memory heap for erpt::srv namespace. */ - R_ABORT_UNLESS(erpt::srv::Initialize(erpt::g_memory_heap, erpt::MemoryHeapSize)); - - /* Atmosphere always wants to redirect new reports to the SD card, to prevent them from being logged. */ - erpt::srv::SetRedirectNewReportsToSdCard(true); - - /* Configure the OS version. */ - { - settings::system::FirmwareVersion firmware_version = {}; - settings::system::SerialNumber serial_number = {}; - settings::system::GetFirmwareVersion(std::addressof(firmware_version)); - settings::system::GetSerialNumber(std::addressof(serial_number)); - - char os_private[0x60]; - const auto os_priv_len = util::SNPrintf(os_private, sizeof(os_private), "%s (%.8s)", firmware_version.display_name, firmware_version.revision); - AMS_ASSERT(static_cast(os_priv_len) < sizeof(os_private)); - AMS_UNUSED(os_priv_len); - - R_ABORT_UNLESS(erpt::srv::SetSerialNumberAndOsVersion(serial_number.str, - strnlen(serial_number.str, sizeof(serial_number.str) - 1) + 1, - firmware_version.display_version, - strnlen(firmware_version.display_version, sizeof(firmware_version.display_version) - 1) + 1, - os_private, - strnlen(os_private, sizeof(os_private) - 1) + 1)); - } - - /* Configure the product model. */ - { - char product_model[0x10]; - const auto pm_len = erpt::MakeProductModelString(product_model, sizeof(product_model), settings::system::GetProductModel()); - AMS_ASSERT(static_cast(pm_len) < sizeof(product_model)); - AMS_UNUSED(pm_len); - - R_ABORT_UNLESS(erpt::srv::SetProductModel(product_model, static_cast(std::strlen(product_model)))); - } - - /* Configure the region. */ - { - settings::system::RegionCode code; - settings::system::GetRegionCode(std::addressof(code)); - const char *region_str = erpt::GetRegionString(code); - R_ABORT_UNLESS(erpt::srv::SetRegionSetting(region_str, static_cast(std::strlen(region_str)))); - } - - /* Start the erpt server. */ - R_ABORT_UNLESS(erpt::srv::InitializeAndStartService()); - - /* Launch sprofile on 13.0.0+ */ - if (hos::GetVersion() >= hos::Version_13_0_0) { - /* Initialize the sprofile server. */ - sprofile::srv::Initialize(); - - /* Start the sprofile ipc server. */ - sprofile::srv::StartIpcServer(); - } - - /* Wait forever. */ - erpt::srv::Wait(); - - /* Cleanup */ - return 0; -} - diff --git a/stratosphere/fatal/source/fatal_config.cpp b/stratosphere/fatal/source/fatal_config.cpp index c07b84ec4..c8e252b31 100644 --- a/stratosphere/fatal/source/fatal_config.cpp +++ b/stratosphere/fatal/source/fatal_config.cpp @@ -21,7 +21,24 @@ namespace ams::fatal::srv { namespace { /* Global config. */ - FatalConfig g_config; + constinit os::SdkMutex g_config_mutex; + constinit bool g_initialized_config; + constinit util::TypedStorage g_config; + + FatalConfig &GetFatalConfigImpl() { + if (AMS_UNLIKELY(!g_initialized_config)) { + std::scoped_lock lk(g_config_mutex); + + if (AMS_LIKELY(!g_initialized_config)) { + util::ConstructAt(g_config); + + g_initialized_config = true; + } + } + + return util::GetReference(g_config); + } + /* Event creator. */ os::NativeHandle GetFatalDirtyEventReadableHandle() { @@ -31,18 +48,18 @@ namespace ams::fatal::srv { } /* Global event. */ - os::SystemEventType g_fatal_dirty_event; - os::MultiWaitHolderType g_fatal_dirty_multi_wait_holder; - bool g_initialized; + constinit os::SystemEventType g_fatal_dirty_event; + constinit os::MultiWaitHolderType g_fatal_dirty_multi_wait_holder; + constinit bool g_initialized_fatal_dirty_event; } os::MultiWaitHolderType *GetFatalDirtyMultiWaitHolder() { - if (AMS_UNLIKELY(!g_initialized)) { + if (AMS_UNLIKELY(!g_initialized_fatal_dirty_event)) { os::AttachReadableHandleToSystemEvent(std::addressof(g_fatal_dirty_event), GetFatalDirtyEventReadableHandle(), true, os::EventClearMode_ManualClear); os::InitializeMultiWaitHolder(std::addressof(g_fatal_dirty_multi_wait_holder), std::addressof(g_fatal_dirty_event)); os::SetMultiWaitHolderUserData(std::addressof(g_fatal_dirty_multi_wait_holder), reinterpret_cast(std::addressof(g_fatal_dirty_multi_wait_holder))); - g_initialized = true; + g_initialized_fatal_dirty_event = true; } return std::addressof(g_fatal_dirty_multi_wait_holder); } @@ -52,7 +69,7 @@ namespace ams::fatal::srv { u64 flags_0, flags_1; if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) { - g_config.UpdateLanguageCode(); + GetFatalConfigImpl().UpdateLanguageCode(); } } @@ -103,7 +120,7 @@ namespace ams::fatal::srv { } const FatalConfig &GetFatalConfig() { - return g_config; + return GetFatalConfigImpl(); } } diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 7821a3417..0e94de3b2 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -19,222 +19,140 @@ #include "fatal_repair.hpp" #include "fatal_font.hpp" +/* Set libnx graphics globals. */ 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]; u32 __nx_nv_transfermem_size = 0x40000; ViLayerFlags __nx_vi_stray_layer_flags = (ViLayerFlags)0; - void __libnx_initheap(void); - void __appInit(void); - void __appExit(void); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -namespace ams::fatal { - - namespace { - - constinit u8 g_fs_heap_memory[2_KB]; - lmem::HeapHandle g_fs_heap_handle; - - void *AllocateForFs(size_t size) { - return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); - } - - void DeallocateForFs(void *p, size_t size) { - AMS_UNUSED(size); - return lmem::FreeToExpHeap(g_fs_heap_handle, p); - } - - void InitializeFsHeap() { - g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_ThreadSafe); - } - - } - -} - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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(); - - fatal::InitializeFsHeap(); - fs::SetAllocator(fatal::AllocateForFs, fatal::DeallocateForFs); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(setInitialize()); - R_ABORT_UNLESS(setsysInitialize()); - R_ABORT_UNLESS(pminfoInitialize()); - R_ABORT_UNLESS(i2cInitialize()); - R_ABORT_UNLESS(bpcInitialize()); - - if (hos::GetVersion() >= hos::Version_8_0_0) { - R_ABORT_UNLESS(clkrstInitialize()); - } else { - R_ABORT_UNLESS(pcvInitialize()); - } - - R_ABORT_UNLESS(lblInitialize()); - R_ABORT_UNLESS(psmInitialize()); - R_ABORT_UNLESS(spsmInitialize()); - R_ABORT_UNLESS(plInitialize(::PlServiceType_User)); - gpio::Initialize(); - R_ABORT_UNLESS(fsInitialize()); - - R_ABORT_UNLESS(fs::MountSdCard("sdmc")); - - /* fatal cannot throw fatal, so don't do: ams::CheckApiVersion(); */ -} - -void __appExit(void) { - /* Cleanup services. */ - fsExit(); - plExit(); - gpio::Finalize(); - spsmExit(); - psmExit(); - lblExit(); - if (hos::GetVersion() >= hos::Version_8_0_0) { - clkrstExit(); - } else { - pcvExit(); - } - bpcExit(); - i2cExit(); - pminfoExit(); - setsysExit(); - setExit(); -} - -namespace { - - using ServerOptions = sf::hipc::DefaultServerManagerOptions; - - constexpr sm::ServiceName UserServiceName = sm::ServiceName::Encode("fatal:u"); - constexpr size_t UserMaxSessions = 4; - - constexpr sm::ServiceName PrivateServiceName = sm::ServiceName::Encode("fatal:p"); - constexpr size_t PrivateMaxSessions = 4; - - /* fatal:u, fatal:p. */ - constexpr size_t NumServers = 2; - constexpr size_t NumSessions = UserMaxSessions + PrivateMaxSessions; - - sf::hipc::ServerManager g_server_manager; - - constinit sf::UnmanagedServiceObject g_user_service_object; - constinit sf::UnmanagedServiceObject g_private_service_object; - } namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); - } + namespace fatal::srv { - void Free(void *) { - AMS_ABORT("ams::Free was called"); - } + namespace { -} + constinit u8 g_fs_heap_memory[2_KB]; + lmem::HeapHandle g_fs_heap_handle; -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} + void *AllocateForFs(size_t size) { + return lmem::AllocateFromExpHeap(g_fs_heap_handle, size); + } -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} + void DeallocateForFs(void *p, size_t size) { + AMS_UNUSED(size); + return lmem::FreeToExpHeap(g_fs_heap_handle, p); + } -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} + void InitializeFsHeap() { + g_fs_heap_handle = lmem::CreateExpHeap(g_fs_heap_memory, sizeof(g_fs_heap_memory), lmem::CreateOption_ThreadSafe); + } -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Disable auto-abort in fs operations. */ - fs::SetEnabledAutoAbort(false); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(fatal, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(fatal, Main)); - - /* Load shared font. */ - R_ABORT_UNLESS(fatal::srv::font::InitializeSharedFont()); - - /* Check whether we should throw fatal due to repair process. */ - fatal::srv::CheckRepairStatus(); - - /* Create services. */ - R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_user_service_object.GetShared(), UserServiceName, UserMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_private_service_object.GetShared(), PrivateServiceName, PrivateMaxSessions)); - - /* Add dirty event holder. */ - auto *dirty_event_holder = ams::fatal::srv::GetFatalDirtyMultiWaitHolder(); - g_server_manager.AddUserMultiWaitHolder(dirty_event_holder); - - /* Loop forever, servicing our services. */ - /* Because fatal has a user wait holder, we need to specify how to process manually. */ - while (auto *signaled_holder = g_server_manager.WaitSignaled()) { - if (signaled_holder == dirty_event_holder) { - /* Dirty event holder was signaled. */ - fatal::srv::OnFatalDirtyEvent(); - g_server_manager.AddUserMultiWaitHolder(signaled_holder); - } else { - /* A server/session was signaled. Have the manager handle it. */ - R_ABORT_UNLESS(g_server_manager.Process(signaled_holder)); } + + namespace { + + using ServerOptions = sf::hipc::DefaultServerManagerOptions; + + constexpr sm::ServiceName UserServiceName = sm::ServiceName::Encode("fatal:u"); + constexpr size_t UserMaxSessions = 4; + + constexpr sm::ServiceName PrivateServiceName = sm::ServiceName::Encode("fatal:p"); + constexpr size_t PrivateMaxSessions = 4; + + /* fatal:u, fatal:p. */ + constexpr size_t NumServers = 2; + constexpr size_t NumSessions = UserMaxSessions + PrivateMaxSessions; + + sf::hipc::ServerManager g_server_manager; + + constinit sf::UnmanagedServiceObject g_user_service_object; + constinit sf::UnmanagedServiceObject g_private_service_object; + + void InitializeAndLoopIpcServer() { + /* Create services. */ + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_user_service_object.GetShared(), UserServiceName, UserMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_private_service_object.GetShared(), PrivateServiceName, PrivateMaxSessions)); + + /* Add dirty event holder. */ + auto *dirty_event_holder = fatal::srv::GetFatalDirtyMultiWaitHolder(); + g_server_manager.AddUserMultiWaitHolder(dirty_event_holder); + + /* Loop forever, servicing our services. */ + /* Because fatal has a user wait holder, we need to specify how to process manually. */ + while (auto *signaled_holder = g_server_manager.WaitSignaled()) { + if (signaled_holder == dirty_event_holder) { + /* Dirty event holder was signaled. */ + fatal::srv::OnFatalDirtyEvent(); + g_server_manager.AddUserMultiWaitHolder(signaled_holder); + } else { + /* A server/session was signaled. Have the manager handle it. */ + R_ABORT_UNLESS(g_server_manager.Process(signaled_holder)); + } + } + } + + } + } - return 0; -} + namespace init { + void InitializeSystemModule() { + /* Initialize heap. */ + fatal::srv::InitializeFsHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(fatal::srv::AllocateForFs, fatal::srv::DeallocateForFs); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services we need. */ + R_ABORT_UNLESS(setInitialize()); + R_ABORT_UNLESS(setsysInitialize()); + R_ABORT_UNLESS(pminfoInitialize()); + R_ABORT_UNLESS(i2cInitialize()); + R_ABORT_UNLESS(bpcInitialize()); + + if (hos::GetVersion() >= hos::Version_8_0_0) { + R_ABORT_UNLESS(clkrstInitialize()); + } else { + R_ABORT_UNLESS(pcvInitialize()); + } + + R_ABORT_UNLESS(lblInitialize()); + R_ABORT_UNLESS(psmInitialize()); + R_ABORT_UNLESS(spsmInitialize()); + R_ABORT_UNLESS(plInitialize(::PlServiceType_User)); + gpio::Initialize(); + + /* Mount the SD card. */ + R_ABORT_UNLESS(fs::MountSdCard("sdmc")); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(fatal, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(fatal, Main)); + + /* Load shared font. */ + R_ABORT_UNLESS(fatal::srv::font::InitializeSharedFont()); + + /* Check whether we should throw fatal due to repair process. */ + fatal::srv::CheckRepairStatus(); + + /* Loop processing the IPC server. */ + fatal::srv::InitializeAndLoopIpcServer(); + } + +} diff --git a/stratosphere/htc/source/htc_main.cpp b/stratosphere/htc/source/htc_main.cpp index abd9c54ff..5477bc113 100644 --- a/stratosphere/htc/source/htc_main.cpp +++ b/stratosphere/htc/source/htc_main.cpp @@ -15,315 +15,217 @@ */ #include -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); -} - -using namespace ams; - -#define AMS_HTC_USE_FATAL_ERROR 1 - -#if AMS_HTC_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::htc { - - namespace { - - alignas(0x40) constinit u8 g_heap_buffer[4_KB]; - lmem::HeapHandle g_heap_handle; - - void *Allocate(size_t size) { - return lmem::AllocateFromExpHeap(g_heap_handle, size); - } - - void Deallocate(void *p, size_t size) { - AMS_UNUSED(size); - - return lmem::FreeToExpHeap(g_heap_handle, p); - } - - void InitializeHeap() { - /* Setup server allocator. */ - g_heap_handle = lmem::CreateExpHeap(g_heap_buffer, sizeof(g_heap_buffer), lmem::CreateOption_ThreadSafe); - } - - } - -} - -void __libnx_initheap(void) { - void* addr = nx_inner_heap; - size_t size = nx_inner_heap_size; - - /* Newlib */ - extern char* fake_heap_start; - extern char* fake_heap_end; - - fake_heap_start = (char*)addr; - fake_heap_end = (char*)addr + size; - - ams::htc::InitializeHeap(); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - fs::SetAllocator(htc::Allocate, htc::Deallocate); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(setsysInitialize()); - R_ABORT_UNLESS(setcalInitialize()); - R_ABORT_UNLESS(pscmInitialize()); - R_ABORT_UNLESS(fsInitialize()); - - R_ABORT_UNLESS(fs::MountSdCard("sdmc")); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - fsExit(); - setsysExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); - } + namespace htc { - void Free(void *) { - AMS_ABORT("ams::Free was called"); - } + namespace { - void *MallocForRapidJson(size_t) { - AMS_ABORT("ams::MallocForRapidJson was called"); - } + alignas(0x40) constinit u8 g_heap_buffer[4_KB]; + lmem::HeapHandle g_heap_handle; - void *ReallocForRapidJson(void *, size_t) { - AMS_ABORT("ams::ReallocForRapidJson was called"); - } - - void FreeForRapidJson(void *ptr) { - if (ptr != nullptr) { - AMS_ABORT("ams::FreeForRapidJson was called"); - } - } - -} - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -namespace ams::htc { - - namespace { - - constexpr htclow::impl::DriverType DefaultHtclowDriverType = htclow::impl::DriverType::Usb; - - constexpr inline size_t NumHtcsIpcThreads = 8; - - alignas(os::ThreadStackAlignment) u8 g_htc_ipc_thread_stack[4_KB]; - alignas(os::ThreadStackAlignment) u8 g_htcfs_ipc_thread_stack[4_KB]; - alignas(os::ThreadStackAlignment) u8 g_htcs_ipc_thread_stack[NumHtcsIpcThreads][4_KB]; - - htclow::impl::DriverType GetHtclowDriverType() { - /* Get the transport type. */ - char transport[0x10]; - if (settings::fwdbg::GetSettingsItemValue(transport, sizeof(transport), "bsp0", "tm_transport") == 0) { - return DefaultHtclowDriverType; + void *Allocate(size_t size) { + return lmem::AllocateFromExpHeap(g_heap_handle, size); } - /* Make the transport type case insensitive. */ - transport[util::size(transport) - 1] = '\x00'; - for (size_t i = 0; i < util::size(transport); ++i) { - transport[i] = std::tolower(static_cast(transport[i])); + void Deallocate(void *p, size_t size) { + AMS_UNUSED(size); + + return lmem::FreeToExpHeap(g_heap_handle, p); } - /* Select the transport. */ - if (std::strstr(transport, "usb")) { - return htclow::impl::DriverType::Usb; - } else if (std::strstr(transport, "hb")) { - return htclow::impl::DriverType::HostBridge; - } else if (std::strstr(transport, "plainchannel")) { - return htclow::impl::DriverType::PlainChannel; - } else if (std::strstr(transport, "socket")) { - /* NOTE: Nintendo does not actually allow socket driver to be selected. */ - /* Should we disallow this? Undesirable, because people will want to use docked tma. */ - - /* TODO: Right now, SocketDriver causes a hang on init. This is because */ - /* the socket driver requires wi-fi, but wi-fi can't happen until the system is fully up. */ - /* The system can't initialize fully until we acknowledge power state events. */ - /* We can't acknowledge power state events until our driver is online. */ - /* Resolving this chicken-and-egg problem without compromising design will require thought. */ - - //return htclow::impl::DriverType::Socket; - return DefaultHtclowDriverType; - } else { - return DefaultHtclowDriverType; + void InitializeHeap() { + /* Setup server allocator. */ + g_heap_handle = lmem::CreateExpHeap(g_heap_buffer, sizeof(g_heap_buffer), lmem::CreateOption_ThreadSafe); } + } - void HtcIpcThreadFunction(void *) { - htc::server::LoopHtcmiscServer(); + namespace { + + constexpr htclow::impl::DriverType DefaultHtclowDriverType = htclow::impl::DriverType::Usb; + + constexpr inline size_t NumHtcsIpcThreads = 8; + + alignas(os::ThreadStackAlignment) u8 g_htc_ipc_thread_stack[4_KB]; + alignas(os::ThreadStackAlignment) u8 g_htcfs_ipc_thread_stack[4_KB]; + alignas(os::ThreadStackAlignment) u8 g_htcs_ipc_thread_stack[NumHtcsIpcThreads][4_KB]; + + htclow::impl::DriverType GetHtclowDriverType() { + /* Get the transport type. */ + char transport[0x10]; + if (settings::fwdbg::GetSettingsItemValue(transport, sizeof(transport), "bsp0", "tm_transport") == 0) { + return DefaultHtclowDriverType; + } + + /* Make the transport type case insensitive. */ + transport[util::size(transport) - 1] = '\x00'; + for (size_t i = 0; i < util::size(transport); ++i) { + transport[i] = std::tolower(static_cast(transport[i])); + } + + /* Select the transport. */ + if (std::strstr(transport, "usb")) { + return htclow::impl::DriverType::Usb; + } else if (std::strstr(transport, "hb")) { + return htclow::impl::DriverType::HostBridge; + } else if (std::strstr(transport, "plainchannel")) { + return htclow::impl::DriverType::PlainChannel; + } else if (std::strstr(transport, "socket")) { + /* NOTE: Nintendo does not actually allow socket driver to be selected. */ + /* Should we disallow this? Undesirable, because people will want to use docked tma. */ + + /* TODO: Right now, SocketDriver causes a hang on init. This is because */ + /* the socket driver requires wi-fi, but wi-fi can't happen until the system is fully up. */ + /* The system can't initialize fully until we acknowledge power state events. */ + /* We can't acknowledge power state events until our driver is online. */ + /* Resolving this chicken-and-egg problem without compromising design will require thought. */ + + //return htclow::impl::DriverType::Socket; + return DefaultHtclowDriverType; + } else { + return DefaultHtclowDriverType; + } + } + + void HtcIpcThreadFunction(void *) { + htc::server::LoopHtcmiscServer(); + } + + void HtcfsIpcThreadFunction(void *) { + htcfs::LoopHipcServer(); + } + + void HtcsIpcThreadFunction(void *) { + htcs::server::LoopHipcServer(); + } + } - void HtcfsIpcThreadFunction(void *) { - htcfs::LoopHipcServer(); - } + namespace server { + + void InitializePowerStateMonitor(htclow::impl::DriverType driver_type, htclow::HtclowManager *htclow_manager); + void FinalizePowerStateMonitor(); + + void LoopMonitorPowerState(); - void HtcsIpcThreadFunction(void *) { - htcs::server::LoopHipcServer(); } } - namespace server { + namespace htclow::driver { - void InitializePowerStateMonitor(htclow::impl::DriverType driver_type, htclow::HtclowManager *htclow_manager); - void FinalizePowerStateMonitor(); + void InitializeSocketApiForSocketDriver(); - void LoopMonitorPowerState(); + } + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + htc::InitializeHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(htc::Allocate, htc::Deallocate); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services we need. */ + R_ABORT_UNLESS(setsysInitialize()); + R_ABORT_UNLESS(setcalInitialize()); + R_ABORT_UNLESS(pscmInitialize()); + + /* Mount the SD card. */ + R_ABORT_UNLESS(fs::MountSdCard("sdmc")); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(htc, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(htc, Main)); + + /* Get and set the default driver type. */ + const auto driver_type = htc::GetHtclowDriverType(); + htclow::HtclowManagerHolder::SetDefaultDriver(driver_type); + + /* If necessary, initialize the socket driver. */ + if (driver_type == htclow::impl::DriverType::Socket) { + htclow::driver::InitializeSocketApiForSocketDriver(); + } + + /* Initialize the htclow manager. */ + htclow::HtclowManagerHolder::AddReference(); + ON_SCOPE_EXIT { htclow::HtclowManagerHolder::Release(); }; + + /* Get the htclow manager. */ + auto *htclow_manager = htclow::HtclowManagerHolder::GetHtclowManager(); + + /* Initialize the htc misc server. */ + htc::server::InitializeHtcmiscServer(htclow_manager); + + /* Create the htc misc ipc thread. */ + os::ThreadType htc_ipc_thread; + os::CreateThread(std::addressof(htc_ipc_thread), htc::HtcIpcThreadFunction, nullptr, htc::g_htc_ipc_thread_stack, sizeof(htc::g_htc_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcIpc)); + os::SetThreadNamePointer(std::addressof(htc_ipc_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcIpc)); + + /* Initialize the htcfs server. */ + htcfs::Initialize(htclow_manager); + htcfs::RegisterHipcServer(); + + /* Create the htcfs ipc thread. */ + os::ThreadType htcfs_ipc_thread; + os::CreateThread(std::addressof(htcfs_ipc_thread), htc::HtcfsIpcThreadFunction, nullptr, htc::g_htcfs_ipc_thread_stack, sizeof(htc::g_htcfs_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcfsIpc)); + os::SetThreadNamePointer(std::addressof(htcfs_ipc_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcfsIpc)); + + /* Initialize the htcs server. */ + htcs::server::Initialize(); + htcs::server::RegisterHipcServer(); + + /* Create the htcs ipc threads. */ + os::ThreadType htcs_ipc_threads[htc::NumHtcsIpcThreads]; + for (size_t i = 0; i < htc::NumHtcsIpcThreads; ++i) { + os::CreateThread(std::addressof(htcs_ipc_threads[i]), htc::HtcsIpcThreadFunction, nullptr, htc::g_htcs_ipc_thread_stack[i], sizeof(htc::g_htcs_ipc_thread_stack[i]), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcsIpc)); + os::SetThreadNamePointer(std::addressof(htcs_ipc_threads[i]), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcsIpc)); + } + + /* Initialize psc. */ + htc::server::InitializePowerStateMonitor(driver_type, htclow_manager); + + /* Start all threads. */ + os::StartThread(std::addressof(htc_ipc_thread)); + os::StartThread(std::addressof(htcfs_ipc_thread)); + for (size_t i = 0; i < htc::NumHtcsIpcThreads; ++i) { + os::StartThread(std::addressof(htcs_ipc_threads[i])); + } + + /* Loop psc monitor. */ + htc::server::LoopMonitorPowerState(); + + /* Destroy all threads. */ + for (size_t i = 0; i < htc::NumHtcsIpcThreads; ++i) { + os::WaitThread(std::addressof(htcs_ipc_threads[i])); + os::DestroyThread(std::addressof(htcs_ipc_threads[i])); + } + + os::WaitThread(std::addressof(htcfs_ipc_thread)); + os::DestroyThread(std::addressof(htcfs_ipc_thread)); + os::WaitThread(std::addressof(htc_ipc_thread)); + os::DestroyThread(std::addressof(htc_ipc_thread)); + + /* Finalize psc monitor. */ + htc::server::FinalizePowerStateMonitor(); } } - -namespace ams::htclow::driver { - - void InitializeSocketApiForSocketDriver(); - -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(htc, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(htc, Main)); - - /* Get and set the default driver type. */ - const auto driver_type = htc::GetHtclowDriverType(); - htclow::HtclowManagerHolder::SetDefaultDriver(driver_type); - - /* If necessary, initialize the socket driver. */ - if (driver_type == htclow::impl::DriverType::Socket) { - htclow::driver::InitializeSocketApiForSocketDriver(); - } - - /* Initialize the htclow manager. */ - htclow::HtclowManagerHolder::AddReference(); - ON_SCOPE_EXIT { htclow::HtclowManagerHolder::Release(); }; - - /* Get the htclow manager. */ - auto *htclow_manager = htclow::HtclowManagerHolder::GetHtclowManager(); - - /* Initialize the htc misc server. */ - htc::server::InitializeHtcmiscServer(htclow_manager); - - /* Create the htc misc ipc thread. */ - os::ThreadType htc_ipc_thread; - os::CreateThread(std::addressof(htc_ipc_thread), htc::HtcIpcThreadFunction, nullptr, htc::g_htc_ipc_thread_stack, sizeof(htc::g_htc_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcIpc)); - os::SetThreadNamePointer(std::addressof(htc_ipc_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcIpc)); - - /* Initialize the htcfs server. */ - htcfs::Initialize(htclow_manager); - htcfs::RegisterHipcServer(); - - /* Create the htcfs ipc thread. */ - os::ThreadType htcfs_ipc_thread; - os::CreateThread(std::addressof(htcfs_ipc_thread), htc::HtcfsIpcThreadFunction, nullptr, htc::g_htcfs_ipc_thread_stack, sizeof(htc::g_htcfs_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcfsIpc)); - os::SetThreadNamePointer(std::addressof(htcfs_ipc_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcfsIpc)); - - /* Initialize the htcs server. */ - htcs::server::Initialize(); - htcs::server::RegisterHipcServer(); - - /* Create the htcs ipc threads. */ - os::ThreadType htcs_ipc_threads[htc::NumHtcsIpcThreads]; - for (size_t i = 0; i < htc::NumHtcsIpcThreads; ++i) { - os::CreateThread(std::addressof(htcs_ipc_threads[i]), htc::HtcsIpcThreadFunction, nullptr, htc::g_htcs_ipc_thread_stack[i], sizeof(htc::g_htcs_ipc_thread_stack[i]), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcsIpc)); - os::SetThreadNamePointer(std::addressof(htcs_ipc_threads[i]), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcsIpc)); - } - - /* Initialize psc. */ - htc::server::InitializePowerStateMonitor(driver_type, htclow_manager); - - /* Start all threads. */ - os::StartThread(std::addressof(htc_ipc_thread)); - os::StartThread(std::addressof(htcfs_ipc_thread)); - for (size_t i = 0; i < htc::NumHtcsIpcThreads; ++i) { - os::StartThread(std::addressof(htcs_ipc_threads[i])); - } - - /* Loop psc monitor. */ - htc::server::LoopMonitorPowerState(); - - /* Destroy all threads. */ - for (size_t i = 0; i < htc::NumHtcsIpcThreads; ++i) { - os::WaitThread(std::addressof(htcs_ipc_threads[i])); - os::DestroyThread(std::addressof(htcs_ipc_threads[i])); - } - os::WaitThread(std::addressof(htcfs_ipc_thread)); - os::DestroyThread(std::addressof(htcfs_ipc_thread)); - os::WaitThread(std::addressof(htc_ipc_thread)); - os::DestroyThread(std::addressof(htc_ipc_thread)); - - /* Finalize psc monitor. */ - htc::server::FinalizePowerStateMonitor(); - - return 0; -} diff --git a/stratosphere/jpegdec/Makefile b/stratosphere/jpegdec/Makefile index b590eef9e..a8a83ada1 100644 --- a/stratosphere/jpegdec/Makefile +++ b/stratosphere/jpegdec/Makefile @@ -4,10 +4,18 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/stratosphere.mk #--------------------------------------------------------------------------------- -# jpegdec uses libjpeg. +# jpegdec uses libjpeg-turbo. #--------------------------------------------------------------------------------- LIBS += -ljpeg +#--------------------------------------------------------------------------------- +# jpegdec overrides libjpeg-turbo's memory allocation routines. +#--------------------------------------------------------------------------------- +CXXWRAPS += -Wl,--wrap,jpeg_get_small +CXXWRAPS += -Wl,--wrap,jpeg_get_large +CXXWRAPS += -Wl,--wrap,jpeg_free_small +CXXWRAPS += -Wl,--wrap,jpeg_free_large + #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional # rules for different file extensions diff --git a/stratosphere/jpegdec/source/jpegdec_main.cpp b/stratosphere/jpegdec/source/jpegdec_main.cpp index 762a4d276..712b98234 100644 --- a/stratosphere/jpegdec/source/jpegdec_main.cpp +++ b/stratosphere/jpegdec/source/jpegdec_main.cpp @@ -14,78 +14,46 @@ * along with this program. If not, see . */ #include +#include "jpegdec_memory_management.hpp" -/* TODO: Update libjpeg-turbo to include Nintendo's changes (support for work buffer, rather than malloc) */ +namespace ams { -extern "C" { - extern u32 __start__; + namespace init { - u32 __nx_applet_type = AppletType_None; + void InitializeSystemModule() { + /* Initialize heap. */ + jpegdec::InitializeJpegHeap(); - #define INNER_HEAP_SIZE 0x18000 - size_t nx_inner_heap_size = INNER_HEAP_SIZE; - char nx_inner_heap[INNER_HEAP_SIZE]; + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); - void __libnx_initheap(void); - void __appInit(void); - void __appExit(void); + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(jpegdec, Main)); + + /* Official jpegdec changes its thread priority to 21 in main. */ + /* This is because older versions of the sysmodule had priority 20 in npdm. */ + os::ChangeThreadPriority(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_PRIORITY(jpegdec, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(jpegdec, Main)); + + /* Initialize the capsrv library. */ + R_ABORT_UNLESS(capsrv::server::InitializeForDecoderServer()); + + /* Service the decoder server. */ + capsrv::server::DecoderControlServerThreadFunction(nullptr); + + /* Finalize the capsrv library. */ + capsrv::server::FinalizeForDecoderServer(); + } - /* 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); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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(); - ams::CheckApiVersion(); - - R_ABORT_UNLESS(sm::Initialize()); -} - -void __appExit(void) { - /* ... */ -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(jpegdec, Main)); - - /* Official jpegdec changes its thread priority to 21 in main. */ - /* This is because older versions of the sysmodule had priority 20 in npdm. */ - os::ChangeThreadPriority(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_PRIORITY(jpegdec, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(jpegdec, Main)); - - /* Initialize the capsrv library. */ - R_ABORT_UNLESS(capsrv::server::InitializeForDecoderServer()); - - /* Service the decoder server. */ - capsrv::server::DecoderControlServerThreadFunction(nullptr); - - /* Finalize the capsrv library. */ - capsrv::server::FinalizeForDecoderServer(); - - /* Cleanup */ - return 0; } diff --git a/stratosphere/jpegdec/source/jpegdec_memory_management.cpp b/stratosphere/jpegdec/source/jpegdec_memory_management.cpp new file mode 100644 index 000000000..965db07e8 --- /dev/null +++ b/stratosphere/jpegdec/source/jpegdec_memory_management.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 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 "jpegdec_memory_management.hpp" + +namespace ams::jpegdec { + + namespace { + + /* TODO: Update libjpeg-turbo to include Nintendo's changes (support for work buffer, rather than malloc) */ + constexpr size_t JpegHeapSize = 96_KB; + alignas(0x10) constinit u8 g_jpeg_heap_memory[JpegHeapSize]; + + constinit lmem::HeapHandle g_jpeg_heap_handle; + + } + + void InitializeJpegHeap() { + g_jpeg_heap_handle = lmem::CreateExpHeap(g_jpeg_heap_memory, sizeof(g_jpeg_heap_memory), lmem::CreateOption_None); + } + +} + +extern "C" void *__wrap_jpeg_get_small(void *cinfo, size_t size) { + AMS_UNUSED(cinfo); + return ::ams::lmem::AllocateFromExpHeap(::ams::jpegdec::g_jpeg_heap_handle, size); +} + +extern "C" void __wrap_jpeg_free_small(void *cinfo, void *ptr, size_t size) { + AMS_UNUSED(cinfo, size); + return ::ams::lmem::FreeToExpHeap(::ams::jpegdec::g_jpeg_heap_handle, ptr); +} + +extern "C" void *__wrap_jpeg_get_large(void *cinfo, size_t size) { + AMS_UNUSED(cinfo); + return ::ams::lmem::AllocateFromExpHeap(::ams::jpegdec::g_jpeg_heap_handle, size); +} + +extern "C" void __wrap_jpeg_free_large(void *cinfo, void *ptr, size_t size) { + AMS_UNUSED(cinfo, size); + return ::ams::lmem::FreeToExpHeap(::ams::jpegdec::g_jpeg_heap_handle, ptr); +} diff --git a/libraries/libstratosphere/source/os/os_stratosphere_api.cpp b/stratosphere/jpegdec/source/jpegdec_memory_management.hpp similarity index 72% rename from libraries/libstratosphere/source/os/os_stratosphere_api.cpp rename to stratosphere/jpegdec/source/jpegdec_memory_management.hpp index bbeac1032..4b24fb1c3 100644 --- a/libraries/libstratosphere/source/os/os_stratosphere_api.cpp +++ b/stratosphere/jpegdec/source/jpegdec_memory_management.hpp @@ -14,13 +14,9 @@ * along with this program. If not, see . */ #include -#include "impl/os_resource_manager.hpp" -namespace ams::os { +namespace ams::jpegdec { - void InitializeForStratosphereInternal() { - /* Initialize the global os resource manager. */ - os::impl::ResourceManagerHolder::InitializeResourceManagerInstance(); - } + void InitializeJpegHeap(); } diff --git a/stratosphere/loader/source/ldr_main.cpp b/stratosphere/loader/source/ldr_main.cpp index f0c67c4d1..03ba52601 100644 --- a/stratosphere/loader/source/ldr_main.cpp +++ b/stratosphere/loader/source/ldr_main.cpp @@ -17,206 +17,152 @@ #include "ldr_development_manager.hpp" #include "ldr_loader_service.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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -namespace ams::ldr { - - namespace { - - constinit u8 g_heap_memory[16_KB]; - lmem::HeapHandle g_server_heap_handle; - constinit ams::sf::ExpHeapAllocator g_server_allocator; - - void *Allocate(size_t size) { - return lmem::AllocateFromExpHeap(g_server_heap_handle, size); - } - - void Deallocate(void *p, size_t size) { - AMS_UNUSED(size); - return lmem::FreeToExpHeap(g_server_heap_handle, p); - } - - void InitializeHeap() { - g_server_heap_handle = lmem::CreateExpHeap(g_heap_memory, sizeof(g_heap_memory), lmem::CreateOption_None); - g_server_allocator.Attach(g_server_heap_handle); - } - - } - - namespace { - - struct ServerOptions { - static constexpr size_t PointerBufferSize = 0x400; - static constexpr size_t MaxDomains = 0; - static constexpr size_t MaxDomainObjects = 0; - }; - - /* ldr:pm, ldr:shel, ldr:dmnt. */ - enum PortIndex { - PortIndex_ProcessManager, - PortIndex_Shell, - PortIndex_DebugMonitor, - PortIndex_Count, - }; - - constexpr sm::ServiceName ProcessManagerServiceName = sm::ServiceName::Encode("ldr:pm"); - constexpr size_t ProcessManagerMaxSessions = 1; - - constexpr sm::ServiceName ShellServiceName = sm::ServiceName::Encode("ldr:shel"); - constexpr size_t ShellMaxSessions = 3; - - constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("ldr:dmnt"); - constexpr size_t DebugMonitorMaxSessions = 3; - - constinit sf::UnmanagedServiceObject g_pm_service; - constinit sf::UnmanagedServiceObject g_shell_service; - constinit sf::UnmanagedServiceObject g_dmnt_service; - - constexpr size_t MaxSessions = ProcessManagerMaxSessions + ShellMaxSessions + DebugMonitorMaxSessions + 1; - - using ServerManager = ams::sf::hipc::ServerManager; - - ServerManager g_server_manager; - - void RegisterServiceSessions() { - R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_pm_service.GetShared(), ProcessManagerServiceName, ProcessManagerMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_shell_service.GetShared(), ShellServiceName, ShellMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_dmnt_service.GetShared(), DebugMonitorServiceName, DebugMonitorMaxSessions)); - } - - void LoopProcess() { - g_server_manager.LoopProcess(); - } - - } - -} - -void __libnx_initheap(void) { - void* addr = nx_inner_heap; - size_t size = nx_inner_heap_size; - - /* Newlib */ - extern char* fake_heap_start; - extern char* fake_heap_end; - - fake_heap_start = (char*)addr; - fake_heap_end = (char*)addr + size; - - ams::ldr::InitializeHeap(); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - fs::SetAllocator(ldr::Allocate, ldr::Deallocate); - - /* Initialize services we need. */ - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsInitialize()); - lr::Initialize(); - R_ABORT_UNLESS(fsldrInitialize()); - spl::Initialize(); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* Cleanup services. */ - spl::Finalize(); - fsldrExit(); - lr::Finalize(); - fsExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace ldr { + + namespace { + + constinit u8 g_heap_memory[16_KB]; + lmem::HeapHandle g_server_heap_handle; + constinit ams::sf::ExpHeapAllocator g_server_allocator; + + void *Allocate(size_t size) { + return lmem::AllocateFromExpHeap(g_server_heap_handle, size); + } + + void Deallocate(void *p, size_t size) { + AMS_UNUSED(size); + return lmem::FreeToExpHeap(g_server_heap_handle, p); + } + + void InitializeHeap() { + g_server_heap_handle = lmem::CreateExpHeap(g_heap_memory, sizeof(g_heap_memory), lmem::CreateOption_None); + g_server_allocator.Attach(g_server_heap_handle); + } + + } + + namespace { + + struct ServerOptions { + static constexpr size_t PointerBufferSize = 0x400; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; + }; + + /* ldr:pm, ldr:shel, ldr:dmnt. */ + enum PortIndex { + PortIndex_ProcessManager, + PortIndex_Shell, + PortIndex_DebugMonitor, + PortIndex_Count, + }; + + constexpr sm::ServiceName ProcessManagerServiceName = sm::ServiceName::Encode("ldr:pm"); + constexpr size_t ProcessManagerMaxSessions = 1; + + constexpr sm::ServiceName ShellServiceName = sm::ServiceName::Encode("ldr:shel"); + constexpr size_t ShellMaxSessions = 3; + + constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("ldr:dmnt"); + constexpr size_t DebugMonitorMaxSessions = 3; + + constinit sf::UnmanagedServiceObject g_pm_service; + constinit sf::UnmanagedServiceObject g_shell_service; + constinit sf::UnmanagedServiceObject g_dmnt_service; + + constexpr size_t MaxSessions = ProcessManagerMaxSessions + ShellMaxSessions + DebugMonitorMaxSessions + 1; + + using ServerManager = ams::sf::hipc::ServerManager; + + ServerManager g_server_manager; + + void RegisterServiceSessions() { + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_pm_service.GetShared(), ProcessManagerServiceName, ProcessManagerMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_shell_service.GetShared(), ShellServiceName, ShellMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_dmnt_service.GetShared(), DebugMonitorServiceName, DebugMonitorMaxSessions)); + } + + void LoopProcess() { + g_server_manager.LoopProcess(); + } + + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + ldr::InitializeHeap(); + + /* Set fs allocator. */ + fs::SetAllocator(ldr::Allocate, ldr::Deallocate); + + /* Initialize services we need. */ + R_ABORT_UNLESS(sm::Initialize()); + + fs::InitializeForSystem(); + lr::Initialize(); + R_ABORT_UNLESS(fsldrInitialize()); + spl::Initialize(); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void NORETURN Exit(int rc) { + AMS_UNUSED(rc); + AMS_ABORT("Exit called by immortal process"); + } + + void Main() { + /* Disable auto-abort in fs operations. */ + fs::SetEnabledAutoAbort(false); + + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ldr, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ldr, Main)); + + /* Configure development. */ + /* NOTE: Nintendo really does call the getter function three times instead of caching the value. */ + ldr::SetDevelopmentForAcidProductionCheck(spl::IsDevelopment()); + ldr::SetDevelopmentForAntiDowngradeCheck(spl::IsDevelopment()); + ldr::SetDevelopmentForAcidSignatureCheck(spl::IsDevelopment()); + + /* Register the loader services. */ + ldr::RegisterServiceSessions(); + + /* Loop forever, servicing our services. */ + ldr::LoopProcess(); + + /* This can never be reached. */ + AMS_ASSUME(false); } } +/* Override operator new. */ void *operator new(size_t size) { - return ldr::Allocate(size); + return ams::ldr::Allocate(size); +} + +void *operator new(size_t size, const std::nothrow_t &) { + return ams::ldr::Allocate(size); } void operator delete(void *p) { - return ldr::Deallocate(p, 0); + return ams::ldr::Deallocate(p, 0); } void operator delete(void *p, size_t size) { - return ldr::Deallocate(p, size); + return ams::ldr::Deallocate(p, size); } - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Disable auto-abort in fs operations. */ - fs::SetEnabledAutoAbort(false); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ldr, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ldr, Main)); - - /* Configure development. */ - /* NOTE: Nintendo really does call the getter function three times instead of caching the value. */ - ldr::SetDevelopmentForAcidProductionCheck(spl::IsDevelopment()); - ldr::SetDevelopmentForAntiDowngradeCheck(spl::IsDevelopment()); - ldr::SetDevelopmentForAcidSignatureCheck(spl::IsDevelopment()); - - /* Register the loader services. */ - ldr::RegisterServiceSessions(); - - /* Loop forever, servicing our services. */ - ldr::LoopProcess(); - - return 0; -} - diff --git a/stratosphere/ncm/source/ncm_main.cpp b/stratosphere/ncm/source/ncm_main.cpp index a026962cd..fa371a898 100644 --- a/stratosphere/ncm/source/ncm_main.cpp +++ b/stratosphere/ncm/source/ncm_main.cpp @@ -15,291 +15,245 @@ */ #include -extern "C" { - extern u32 __start__; - - u32 __nx_applet_type = AppletType_None; - u32 __nx_fs_num_sessions = 2; - - #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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -namespace { - - u8 g_heap_memory[1_MB]; - lmem::HeapHandle g_heap_handle; - - void *Allocate(size_t size) { - void *mem = lmem::AllocateFromExpHeap(g_heap_handle, size); - ncm::GetHeapState().Allocate(size); - return mem; - } - - void Deallocate(void *p, size_t size) { - ncm::GetHeapState().Free(size != 0 ? size : lmem::GetExpHeapMemoryBlockSize(p)); - lmem::FreeToExpHeap(g_heap_handle, p); - } - - void InitializeHeap() { - g_heap_handle = lmem::CreateExpHeap(g_heap_memory, sizeof(g_heap_memory), lmem::CreateOption_ThreadSafe); - ncm::GetHeapState().Initialize(g_heap_handle); - } - -} - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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; - - InitializeHeap(); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - fs::SetAllocator(Allocate, Deallocate); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsInitialize()); - spl::Initialize(); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* Cleanup services. */ - spl::Finalize(); - fsExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace ncm { + + namespace { + + u8 g_heap_memory[1_MB]; + lmem::HeapHandle g_heap_handle; + + void *Allocate(size_t size) { + void *mem = lmem::AllocateFromExpHeap(g_heap_handle, size); + ncm::GetHeapState().Allocate(size); + return mem; + } + + void Deallocate(void *p, size_t size) { + ncm::GetHeapState().Free(size != 0 ? size : lmem::GetExpHeapMemoryBlockSize(p)); + lmem::FreeToExpHeap(g_heap_handle, p); + } + + void InitializeHeap() { + g_heap_handle = lmem::CreateExpHeap(g_heap_memory, sizeof(g_heap_memory), lmem::CreateOption_ThreadSafe); + ncm::GetHeapState().Initialize(g_heap_handle); + } + + } + + namespace { + + struct ContentManagerServerOptions { + static constexpr size_t PointerBufferSize = 0x400; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; + }; + + constexpr inline size_t ContentManagerNumServers = 1; + constexpr inline size_t ContentManagerManagerSessions = 16; + constexpr inline size_t ContentManagerExtraSessions = 16; + constexpr inline size_t ContentManagerMaxSessions = ContentManagerManagerSessions + ContentManagerExtraSessions; + + constexpr inline sm::ServiceName ContentManagerServiceName = sm::ServiceName::Encode("ncm"); + + alignas(os::ThreadStackAlignment) u8 g_content_manager_thread_stack[16_KB]; + alignas(os::ThreadStackAlignment) u8 g_location_resolver_thread_stack[16_KB]; + + class ContentManagerServerManager : public sf::hipc::ServerManager { + private: + using ServiceImpl = ncm::ContentManagerImpl; + private: + os::ThreadType m_thread; + sf::SharedPointer m_manager; + private: + static void ThreadFunction(void *_this) { + reinterpret_cast(_this)->LoopProcess(); + } + public: + explicit ContentManagerServerManager(sf::SharedPointer manager) : m_manager(manager) { /* ... */ } + + ams::Result Initialize() { + return this->RegisterObjectForServer(m_manager, ContentManagerServiceName, ContentManagerManagerSessions); + } + + ams::Result StartThreads() { + R_TRY(os::CreateThread(std::addressof(m_thread), ThreadFunction, this, g_content_manager_thread_stack, sizeof(g_content_manager_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, ContentManagerServerIpcSession))); + os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(ncm, ContentManagerServerIpcSession)); + os::StartThread(std::addressof(m_thread)); + return ResultSuccess(); + } + + void Wait() { + os::WaitThread(std::addressof(m_thread)); + } + }; + + struct LocationResolverServerOptions { + static constexpr size_t PointerBufferSize = 0x400; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; + }; + + constexpr inline size_t LocationResolverNumServers = 1; + constexpr inline size_t LocationResolverManagerSessions = 16; + constexpr inline size_t LocationResolverExtraSessions = 16; + constexpr inline size_t LocationResolverMaxSessions = LocationResolverManagerSessions + LocationResolverExtraSessions; + + constexpr inline sm::ServiceName LocationResolverServiceName = sm::ServiceName::Encode("lr"); + + class LocationResolverServerManager : public sf::hipc::ServerManager { + private: + using ServiceImpl = lr::LocationResolverManagerImpl; + private: + os::ThreadType m_thread; + sf::SharedPointer m_manager; + private: + static void ThreadFunction(void *_this) { + reinterpret_cast(_this)->LoopProcess(); + } + public: + LocationResolverServerManager(sf::SharedPointer manager) : m_manager(manager) { /* ... */ } + + ams::Result Initialize() { + return this->RegisterObjectForServer(m_manager, LocationResolverServiceName, LocationResolverManagerSessions); + } + + ams::Result StartThreads() { + R_TRY(os::CreateThread(std::addressof(m_thread), ThreadFunction, this, g_location_resolver_thread_stack, sizeof(g_location_resolver_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, LocationResolverServerIpcSession))); + os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(ncm, LocationResolverServerIpcSession)); + os::StartThread(std::addressof(m_thread)); + return ResultSuccess(); + } + + void Wait() { + os::WaitThread(std::addressof(m_thread)); + } + }; + + sf::UnmanagedServiceObject g_ncm_manager_service_object; + ContentManagerServerManager g_ncm_server_manager(g_ncm_manager_service_object.GetShared()); + + sf::UnmanagedServiceObject g_lr_manager_service_object; + LocationResolverServerManager g_lr_server_manager(g_lr_manager_service_object.GetShared()); + + /* Compile-time configuration. */ + #ifdef NCM_BUILD_FOR_INTITIALIZE + constexpr inline bool BuildSystemDatabase = true; + #else + constexpr inline bool BuildSystemDatabase = false; + #endif + + #ifdef NCM_BUILD_FOR_SAFEMODE + constexpr inline bool ImportSystemDatabaseFromSignedSystemPartitionOnSdCard = true; + #else + constexpr inline bool ImportSystemDatabaseFromSignedSystemPartitionOnSdCard = false; + #endif + + static_assert(!(BuildSystemDatabase && ImportSystemDatabaseFromSignedSystemPartitionOnSdCard), "Invalid NCM build configuration!"); + + constexpr inline ncm::ContentManagerConfig ManagerConfig = { BuildSystemDatabase, ImportSystemDatabaseFromSignedSystemPartitionOnSdCard }; + + } + + void NcmMain() { + /* Initialize spl. */ + spl::Initialize(); + ON_SCOPE_EXIT { spl::Finalize(); }; + + /* Initialize fs. */ + fs::InitializeWithMultiSessionForSystem(); + fs::SetAllocator(Allocate, Deallocate); + fs::SetEnabledAutoAbort(false); + + /* Create and initialize the content manager. */ + R_ABORT_UNLESS(g_ncm_manager_service_object.GetImpl().Initialize(ManagerConfig)); + + /* Initialize ncm's server and start threads. */ + R_ABORT_UNLESS(g_ncm_server_manager.Initialize()); + R_ABORT_UNLESS(g_ncm_server_manager.StartThreads()); + + /* Initialize ncm api. */ + ncm::InitializeWithObject(g_ncm_manager_service_object.GetShared()); + + /* Initialize lr's server and start threads. */ + R_ABORT_UNLESS(g_lr_server_manager.Initialize()); + R_ABORT_UNLESS(g_lr_server_manager.StartThreads()); + + /* Wait indefinitely. */ + g_ncm_server_manager.Wait(); + g_lr_server_manager.Wait(); + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + ncm::InitializeHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void NORETURN Exit(int rc) { + AMS_UNUSED(rc); + AMS_ABORT("Exit called by immortal process"); + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ncm, MainWaitThreads)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, MainWaitThreads)); + + /* Invoke NCM main. */ + ncm::NcmMain(); + + /* This can never be reached. */ + AMS_ASSUME(false); } } -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - +/* Override operator new. */ void *operator new(size_t size) { - return Allocate(size); + return ams::ncm::Allocate(size); } void *operator new(size_t size, const std::nothrow_t &) { - return Allocate(size); + return ams::ncm::Allocate(size); } void operator delete(void *p) { - return Deallocate(p, 0); + return ams::ncm::Deallocate(p, 0); } void operator delete(void *p, size_t size) { - return Deallocate(p, size); + return ams::ncm::Deallocate(p, size); } void *operator new[](size_t size) { - return Allocate(size); + return ams::ncm::Allocate(size); } void *operator new[](size_t size, const std::nothrow_t &) { - return Allocate(size); + return ams::ncm::Allocate(size); } void operator delete[](void *p) { - return Deallocate(p, 0); + return ams::ncm::Deallocate(p, 0); } void operator delete[](void *p, size_t size) { - return Deallocate(p, size); -} - - -namespace { - - struct ContentManagerServerOptions { - static constexpr size_t PointerBufferSize = 0x400; - static constexpr size_t MaxDomains = 0; - static constexpr size_t MaxDomainObjects = 0; - }; - - constexpr inline size_t ContentManagerNumServers = 1; - constexpr inline size_t ContentManagerManagerSessions = 16; - constexpr inline size_t ContentManagerExtraSessions = 16; - constexpr inline size_t ContentManagerMaxSessions = ContentManagerManagerSessions + ContentManagerExtraSessions; - - constexpr inline sm::ServiceName ContentManagerServiceName = sm::ServiceName::Encode("ncm"); - - alignas(os::ThreadStackAlignment) u8 g_content_manager_thread_stack[16_KB]; - alignas(os::ThreadStackAlignment) u8 g_location_resolver_thread_stack[16_KB]; - - class ContentManagerServerManager : public sf::hipc::ServerManager { - private: - using ServiceImpl = ncm::ContentManagerImpl; - private: - os::ThreadType m_thread; - sf::SharedPointer m_manager; - private: - static void ThreadFunction(void *_this) { - reinterpret_cast(_this)->LoopProcess(); - } - public: - explicit ContentManagerServerManager(sf::SharedPointer manager) : m_manager(manager) { /* ... */ } - - ams::Result Initialize() { - return this->RegisterObjectForServer(m_manager, ContentManagerServiceName, ContentManagerManagerSessions); - } - - ams::Result StartThreads() { - R_TRY(os::CreateThread(std::addressof(m_thread), ThreadFunction, this, g_content_manager_thread_stack, sizeof(g_content_manager_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, ContentManagerServerIpcSession))); - os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(ncm, ContentManagerServerIpcSession)); - os::StartThread(std::addressof(m_thread)); - return ResultSuccess(); - } - - void Wait() { - os::WaitThread(std::addressof(m_thread)); - } - }; - - struct LocationResolverServerOptions { - static constexpr size_t PointerBufferSize = 0x400; - static constexpr size_t MaxDomains = 0; - static constexpr size_t MaxDomainObjects = 0; - }; - - constexpr inline size_t LocationResolverNumServers = 1; - constexpr inline size_t LocationResolverManagerSessions = 16; - constexpr inline size_t LocationResolverExtraSessions = 16; - constexpr inline size_t LocationResolverMaxSessions = LocationResolverManagerSessions + LocationResolverExtraSessions; - - constexpr inline sm::ServiceName LocationResolverServiceName = sm::ServiceName::Encode("lr"); - - class LocationResolverServerManager : public sf::hipc::ServerManager { - private: - using ServiceImpl = lr::LocationResolverManagerImpl; - private: - os::ThreadType m_thread; - sf::SharedPointer m_manager; - private: - static void ThreadFunction(void *_this) { - reinterpret_cast(_this)->LoopProcess(); - } - public: - LocationResolverServerManager(sf::SharedPointer manager) : m_manager(manager) { /* ... */ } - - ams::Result Initialize() { - return this->RegisterObjectForServer(m_manager, LocationResolverServiceName, LocationResolverManagerSessions); - } - - ams::Result StartThreads() { - R_TRY(os::CreateThread(std::addressof(m_thread), ThreadFunction, this, g_location_resolver_thread_stack, sizeof(g_location_resolver_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, LocationResolverServerIpcSession))); - os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(ncm, LocationResolverServerIpcSession)); - os::StartThread(std::addressof(m_thread)); - return ResultSuccess(); - } - - void Wait() { - os::WaitThread(std::addressof(m_thread)); - } - }; - - sf::UnmanagedServiceObject g_ncm_manager_service_object; - ContentManagerServerManager g_ncm_server_manager(g_ncm_manager_service_object.GetShared()); - - sf::UnmanagedServiceObject g_lr_manager_service_object; - LocationResolverServerManager g_lr_server_manager(g_lr_manager_service_object.GetShared()); - - /* Compile-time configuration. */ -#ifdef NCM_BUILD_FOR_INTITIALIZE - constexpr inline bool BuildSystemDatabase = true; -#else - constexpr inline bool BuildSystemDatabase = false; -#endif - -#ifdef NCM_BUILD_FOR_SAFEMODE - constexpr inline bool ImportSystemDatabaseFromSignedSystemPartitionOnSdCard = true; -#else - constexpr inline bool ImportSystemDatabaseFromSignedSystemPartitionOnSdCard = false; -#endif - - static_assert(!(BuildSystemDatabase && ImportSystemDatabaseFromSignedSystemPartitionOnSdCard), "Invalid NCM build configuration!"); - - constexpr inline ncm::ContentManagerConfig ManagerConfig = { BuildSystemDatabase, ImportSystemDatabaseFromSignedSystemPartitionOnSdCard }; - -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Disable auto-abort in fs operations. */ - fs::SetEnabledAutoAbort(false); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ncm, MainWaitThreads)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ncm, MainWaitThreads)); - - /* Create and initialize the content manager. */ - R_ABORT_UNLESS(g_ncm_manager_service_object.GetImpl().Initialize(ManagerConfig)); - - /* Initialize ncm's server and start threads. */ - R_ABORT_UNLESS(g_ncm_server_manager.Initialize()); - R_ABORT_UNLESS(g_ncm_server_manager.StartThreads()); - - /* Initialize ncm api. */ - ncm::InitializeWithObject(g_ncm_manager_service_object.GetShared()); - - /* Initialize lr's server and start threads. */ - R_ABORT_UNLESS(g_lr_server_manager.Initialize()); - R_ABORT_UNLESS(g_lr_server_manager.StartThreads()); - - /* Wait indefinitely. */ - g_ncm_server_manager.Wait(); - g_lr_server_manager.Wait(); - - return 0; + return ams::ncm::Deallocate(p, size); } diff --git a/stratosphere/pgl/source/pgl_main.cpp b/stratosphere/pgl/source/pgl_main.cpp index c7d6aeb05..50d5ca114 100644 --- a/stratosphere/pgl/source/pgl_main.cpp +++ b/stratosphere/pgl/source/pgl_main.cpp @@ -15,127 +15,46 @@ */ #include -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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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(); - - ams::pgl::srv::InitializeHeap(); - - fs::SetAllocator(pgl::srv::Allocate, pgl::srv::Deallocate); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(setInitialize()); - R_ABORT_UNLESS(setsysInitialize()); - R_ABORT_UNLESS(pmshellInitialize()); - R_ABORT_UNLESS(ldrShellInitialize()); - R_ABORT_UNLESS(lrInitialize()); - R_ABORT_UNLESS(fsInitialize()); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - fsExit(); - lrExit(); - ldrShellExit(); - pmshellExit(); - setsysExit(); - setExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + pgl::srv::InitializeHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(pgl::srv::Allocate, pgl::srv::Deallocate); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services we need. */ + R_ABORT_UNLESS(setInitialize()); + R_ABORT_UNLESS(setsysInitialize()); + R_ABORT_UNLESS(pmshellInitialize()); + R_ABORT_UNLESS(ldrShellInitialize()); + R_ABORT_UNLESS(lrInitialize()); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(pgl, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(pgl, Main)); + + /* Initialize and start the server. */ + pgl::srv::StartServer(); } } - -void *operator new(size_t size) { - return pgl::srv::Allocate(size); -} - -void operator delete(void *p) { - return pgl::srv::Deallocate(p, 0); -} - -void operator delete(void *p, size_t size) { - return pgl::srv::Deallocate(p, size); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Disable auto-abort in fs operations. */ - fs::SetEnabledAutoAbort(false); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(pgl, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(pgl, Main)); - - /* Initialize and start the server. */ - pgl::srv::StartServer(); - - /* Cleanup */ - return 0; -} - diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp index 005a6d50e..085daaa92 100644 --- a/stratosphere/pm/source/pm_main.cpp +++ b/stratosphere/pm/source/pm_main.cpp @@ -18,263 +18,205 @@ #include "pm_debug_monitor_service.hpp" #include "pm_info_service.hpp" #include "pm_shell_service.hpp" - #include "impl/pm_process_manager.hpp" -extern "C" { - extern u32 __start__; - - u32 __nx_applet_type = AppletType_None; - - #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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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; -} - -namespace { - - constexpr u32 PrivilegedFileAccessHeader[0x1C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000}; - constexpr u32 PrivilegedFileAccessControl[0x2C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}; - constexpr u8 PrivilegedServiceAccessControl[] = {0x80, '*', 0x00, '*'}; - constexpr size_t ProcessCountMax = 0x40; - - /* This uses debugging SVCs to retrieve a process's program id. */ - ncm::ProgramId GetProcessProgramId(os::ProcessId process_id) { - /* Get a debug handle. */ - svc::Handle debug_handle; - R_ABORT_UNLESS(svc::DebugActiveProcess(std::addressof(debug_handle), process_id.value)); - ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(debug_handle)); }; - - /* Loop until we get the event that tells us about the process. */ - svc::DebugEventInfo d; - while (true) { - R_ABORT_UNLESS(svc::GetDebugEvent(std::addressof(d), debug_handle)); - if (d.type == svc::DebugEvent_CreateProcess) { - return ncm::ProgramId{d.info.create_process.program_id}; - } - } - } - - /* This works around a bug fixed by FS in 4.0.0. */ - /* Not doing so will cause KIPs with higher process IDs than 7 to be unable to use filesystem services. */ - /* It also registers privileged processes with SM, so that their program ids can be known. */ - void RegisterPrivilegedProcess(os::ProcessId process_id, ncm::ProgramId program_id) { - fsprUnregisterProgram(process_id.value); - fsprRegisterProgram(process_id.value, process_id.value, NcmStorageId_BuiltInSystem, PrivilegedFileAccessHeader, sizeof(PrivilegedFileAccessHeader), PrivilegedFileAccessControl, sizeof(PrivilegedFileAccessControl)); - sm::manager::UnregisterProcess(process_id); - sm::manager::RegisterProcess(process_id, program_id, cfg::OverrideStatus{}, PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl), PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl)); - } - - void RegisterPrivilegedProcesses() { - /* Get privileged process range. */ - os::ProcessId min_priv_process_id = os::InvalidProcessId, max_priv_process_id = os::InvalidProcessId; - cfg::GetInitialProcessRange(&min_priv_process_id, &max_priv_process_id); - - /* Get current process id/program id. */ - const auto cur_process_id = os::GetCurrentProcessId(); - const auto cur_program_id = os::GetCurrentProgramId(); - - /* Get list of processes, register all privileged ones. */ - s32 num_pids; - os::ProcessId pids[ProcessCountMax]; - R_ABORT_UNLESS(svc::GetProcessList(&num_pids, reinterpret_cast(pids), ProcessCountMax)); - for (s32 i = 0; i < num_pids; i++) { - if (min_priv_process_id <= pids[i] && pids[i] <= max_priv_process_id) { - RegisterPrivilegedProcess(pids[i], pids[i] == cur_process_id ? cur_program_id : GetProcessProgramId(pids[i])); - } - } - } - -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(fsprInitialize()); - R_ABORT_UNLESS(smManagerInitialize()); - - /* This works around a bug with process permissions on < 4.0.0. */ - /* It also informs SM of privileged process information. */ - RegisterPrivilegedProcesses(); - - /* Use AMS manager extension to tell SM that FS has been worked around. */ - R_ABORT_UNLESS(sm::manager::EndInitialDefers()); - - R_ABORT_UNLESS(ldrPmInitialize()); - spl::Initialize(); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* Cleanup services. */ - spl::Finalize(); - ldrPmExit(); - smManagerExit(); - fsprExit(); -} - -namespace { - - /* pm:shell, pm:dmnt, pm:bm, pm:info. */ - enum PortIndex { - PortIndex_Shell, - PortIndex_DebugMonitor, - PortIndex_BootMode, - PortIndex_Information, - PortIndex_Count, - }; - - using ServerOptions = sf::hipc::DefaultServerManagerOptions; - - constexpr sm::ServiceName ShellServiceName = sm::ServiceName::Encode("pm:shell"); - constexpr size_t ShellMaxSessions = 8; /* Official maximum is 3. */ - - constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("pm:dmnt"); - constexpr size_t DebugMonitorMaxSessions = 16; - - constexpr sm::ServiceName BootModeServiceName = sm::ServiceName::Encode("pm:bm"); - constexpr size_t BootModeMaxSessions = 8; /* Official maximum is 4. */ - - constexpr sm::ServiceName InformationServiceName = sm::ServiceName::Encode("pm:info"); - constexpr size_t InformationMaxSessions = 48 - (ShellMaxSessions + DebugMonitorMaxSessions + BootModeMaxSessions); - - static_assert(InformationMaxSessions >= 16, "InformationMaxSessions"); - - constexpr size_t MaxSessions = ShellMaxSessions + DebugMonitorMaxSessions + BootModeMaxSessions + InformationMaxSessions; - static_assert(MaxSessions == 48, "MaxSessions"); - - class ServerManager final : public sf::hipc::ServerManager { - private: - virtual ams::Result OnNeedsToAccept(int port_index, Server *server) override; - }; - - ServerManager g_server_manager; - - /* NOTE: Nintendo only uses an unmanaged object for boot mode service, but no pm service has any class members/state, so we'll do it for all. */ - sf::UnmanagedServiceObject g_shell_service; - sf::UnmanagedServiceObject g_deprecated_shell_service; - - sf::UnmanagedServiceObject g_dmnt_service; - sf::UnmanagedServiceObject g_deprecated_dmnt_service; - - sf::UnmanagedServiceObject g_boot_mode_service; - sf::UnmanagedServiceObject g_information_service; - - ams::Result ServerManager::OnNeedsToAccept(int port_index, Server *server) { - switch (port_index) { - case PortIndex_Shell: - if (hos::GetVersion() >= hos::Version_5_0_0) { - return this->AcceptImpl(server, g_shell_service.GetShared()); - } else { - return this->AcceptImpl(server, g_deprecated_shell_service.GetShared()); - } - case PortIndex_DebugMonitor: - if (hos::GetVersion() >= hos::Version_5_0_0) { - return this->AcceptImpl(server, g_dmnt_service.GetShared()); - } else { - return this->AcceptImpl(server, g_deprecated_dmnt_service.GetShared()); - } - case PortIndex_BootMode: - return this->AcceptImpl(server, g_boot_mode_service.GetShared()); - case PortIndex_Information: - return this->AcceptImpl(server, g_information_service.GetShared()); - AMS_UNREACHABLE_DEFAULT_CASE(); - } - } - -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace pm { + + namespace { + + constexpr u32 PrivilegedFileAccessHeader[0x1C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000}; + constexpr u32 PrivilegedFileAccessControl[0x2C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}; + constexpr u8 PrivilegedServiceAccessControl[] = {0x80, '*', 0x00, '*'}; + constexpr size_t ProcessCountMax = 0x40; + + /* This uses debugging SVCs to retrieve a process's program id. */ + ncm::ProgramId GetProcessProgramId(os::ProcessId process_id) { + /* Get a debug handle. */ + svc::Handle debug_handle; + R_ABORT_UNLESS(svc::DebugActiveProcess(std::addressof(debug_handle), process_id.value)); + ON_SCOPE_EXIT { R_ABORT_UNLESS(svc::CloseHandle(debug_handle)); }; + + /* Loop until we get the event that tells us about the process. */ + svc::DebugEventInfo d; + while (true) { + R_ABORT_UNLESS(svc::GetDebugEvent(std::addressof(d), debug_handle)); + if (d.type == svc::DebugEvent_CreateProcess) { + return ncm::ProgramId{d.info.create_process.program_id}; + } + } + } + + /* This works around a bug fixed by FS in 4.0.0. */ + /* Not doing so will cause KIPs with higher process IDs than 7 to be unable to use filesystem services. */ + /* It also registers privileged processes with SM, so that their program ids can be known. */ + void RegisterPrivilegedProcess(os::ProcessId process_id, ncm::ProgramId program_id) { + fsprUnregisterProgram(process_id.value); + fsprRegisterProgram(process_id.value, process_id.value, NcmStorageId_BuiltInSystem, PrivilegedFileAccessHeader, sizeof(PrivilegedFileAccessHeader), PrivilegedFileAccessControl, sizeof(PrivilegedFileAccessControl)); + sm::manager::UnregisterProcess(process_id); + sm::manager::RegisterProcess(process_id, program_id, cfg::OverrideStatus{}, PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl), PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl)); + } + + void RegisterPrivilegedProcesses() { + /* Get privileged process range. */ + os::ProcessId min_priv_process_id = os::InvalidProcessId, max_priv_process_id = os::InvalidProcessId; + cfg::GetInitialProcessRange(&min_priv_process_id, &max_priv_process_id); + + /* Get current process id/program id. */ + const auto cur_process_id = os::GetCurrentProcessId(); + const auto cur_program_id = os::GetCurrentProgramId(); + + /* Get list of processes, register all privileged ones. */ + s32 num_pids; + os::ProcessId pids[ProcessCountMax]; + R_ABORT_UNLESS(svc::GetProcessList(&num_pids, reinterpret_cast(pids), ProcessCountMax)); + for (s32 i = 0; i < num_pids; i++) { + if (min_priv_process_id <= pids[i] && pids[i] <= max_priv_process_id) { + RegisterPrivilegedProcess(pids[i], pids[i] == cur_process_id ? cur_program_id : GetProcessProgramId(pids[i])); + } + } + } + + } + + namespace { + + /* pm:shell, pm:dmnt, pm:bm, pm:info. */ + enum PortIndex { + PortIndex_Shell, + PortIndex_DebugMonitor, + PortIndex_BootMode, + PortIndex_Information, + PortIndex_Count, + }; + + using ServerOptions = sf::hipc::DefaultServerManagerOptions; + + constexpr sm::ServiceName ShellServiceName = sm::ServiceName::Encode("pm:shell"); + constexpr size_t ShellMaxSessions = 8; /* Official maximum is 3. */ + + constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("pm:dmnt"); + constexpr size_t DebugMonitorMaxSessions = 16; + + constexpr sm::ServiceName BootModeServiceName = sm::ServiceName::Encode("pm:bm"); + constexpr size_t BootModeMaxSessions = 8; /* Official maximum is 4. */ + + constexpr sm::ServiceName InformationServiceName = sm::ServiceName::Encode("pm:info"); + constexpr size_t InformationMaxSessions = 48 - (ShellMaxSessions + DebugMonitorMaxSessions + BootModeMaxSessions); + + static_assert(InformationMaxSessions >= 16, "InformationMaxSessions"); + + constexpr size_t MaxSessions = ShellMaxSessions + DebugMonitorMaxSessions + BootModeMaxSessions + InformationMaxSessions; + static_assert(MaxSessions == 48, "MaxSessions"); + + class ServerManager final : public sf::hipc::ServerManager { + private: + virtual ams::Result OnNeedsToAccept(int port_index, Server *server) override; + }; + + ServerManager g_server_manager; + + /* NOTE: Nintendo only uses an unmanaged object for boot mode service, but no pm service has any class members/state, so we'll do it for all. */ + sf::UnmanagedServiceObject g_shell_service; + sf::UnmanagedServiceObject g_deprecated_shell_service; + + sf::UnmanagedServiceObject g_dmnt_service; + sf::UnmanagedServiceObject g_deprecated_dmnt_service; + + sf::UnmanagedServiceObject g_boot_mode_service; + sf::UnmanagedServiceObject g_information_service; + + ams::Result ServerManager::OnNeedsToAccept(int port_index, Server *server) { + switch (port_index) { + case PortIndex_Shell: + if (hos::GetVersion() >= hos::Version_5_0_0) { + return this->AcceptImpl(server, g_shell_service.GetShared()); + } else { + return this->AcceptImpl(server, g_deprecated_shell_service.GetShared()); + } + case PortIndex_DebugMonitor: + if (hos::GetVersion() >= hos::Version_5_0_0) { + return this->AcceptImpl(server, g_dmnt_service.GetShared()); + } else { + return this->AcceptImpl(server, g_deprecated_dmnt_service.GetShared()); + } + case PortIndex_BootMode: + return this->AcceptImpl(server, g_boot_mode_service.GetShared()); + case PortIndex_Information: + return this->AcceptImpl(server, g_information_service.GetShared()); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + void RegisterServices() { + /* NOTE: Extra sessions have been added to pm:bm and pm:info to facilitate access by the rest of stratosphere. */ + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Shell, ShellServiceName, ShellMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_DebugMonitor, DebugMonitorServiceName, DebugMonitorMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_BootMode, BootModeServiceName, BootModeMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Information, InformationServiceName, InformationMaxSessions)); + } + + void LoopProcess() { + g_server_manager.LoopProcess(); + } + + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize manager interfaces for fs and sm. */ + R_ABORT_UNLESS(fsprInitialize()); + R_ABORT_UNLESS(smManagerInitialize()); + + /* Work around a bug with process permissions on < 4.0.0. */ + /* This registers all initial processes explicitly with both fs and sm. */ + pm::RegisterPrivilegedProcesses(); + + /* Use our manager extension to tell SM that the FS bug has been worked around. */ + R_ABORT_UNLESS(sm::manager::EndInitialDefers()); + + /* Initialize remaining services we need. */ + R_ABORT_UNLESS(ldrPmInitialize()); + spl::Initialize(); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void NORETURN Exit(int rc) { + AMS_UNUSED(rc); + AMS_ABORT("Exit called by immortal process"); + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(pm, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(pm, Main)); + + /* Initialize process manager implementation. */ + R_ABORT_UNLESS(pm::impl::InitializeProcessManager()); + + /* Create Services. */ + pm::RegisterServices(); + + /* Loop forever, servicing our services. */ + pm::LoopProcess(); + + /* This can never be reached. */ + AMS_ASSUME(false); } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(pm, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(pm, Main)); - - /* Initialize process manager implementation. */ - R_ABORT_UNLESS(pm::impl::InitializeProcessManager()); - - /* Create Services. */ - /* NOTE: Extra sessions have been added to pm:bm and pm:info to facilitate access by the rest of stratosphere. */ - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Shell, ShellServiceName, ShellMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_DebugMonitor, DebugMonitorServiceName, DebugMonitorMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_BootMode, BootModeServiceName, BootModeMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Information, InformationServiceName, InformationMaxSessions)); - - /* Loop forever, servicing our services. */ - g_server_manager.LoopProcess(); - - return 0; -} - diff --git a/stratosphere/ro/source/ro_main.cpp b/stratosphere/ro/source/ro_main.cpp index f3d8b3daa..c4a9ea41a 100644 --- a/stratosphere/ro/source/ro_main.cpp +++ b/stratosphere/ro/source/ro_main.cpp @@ -17,209 +17,141 @@ #include "ro_debug_monitor_service.hpp" #include "ro_ro_service.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); -} - -using namespace ams; - -namespace ams::ro { - - namespace { - - /* ldr:ro, ro:dmnt, ro:1. */ - enum PortIndex { - PortIndex_DebugMonitor, - PortIndex_User, - PortIndex_JitPlugin, - PortIndex_Count, - }; - - constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("ro:dmnt"); - constexpr size_t DebugMonitorMaxSessions = 2; - - /* NOTE: Official code passes 32 for ldr:ro max sessions. We will pass 2, because that's the actual limit. */ - constexpr sm::ServiceName UserServiceName = sm::ServiceName::Encode("ldr:ro"); - constexpr size_t UserMaxSessions = 2; - - constexpr sm::ServiceName JitPluginServiceName = sm::ServiceName::Encode("ro:1"); - constexpr size_t JitPluginMaxSessions = 2; - - static constexpr size_t MaxSessions = DebugMonitorMaxSessions + UserMaxSessions + JitPluginMaxSessions; - - using ServerOptions = sf::hipc::DefaultServerManagerOptions; - - class ServerManager final : public sf::hipc::ServerManager { - private: - virtual ams::Result OnNeedsToAccept(int port_index, Server *server) override; - }; - - using Allocator = sf::ExpHeapAllocator; - using ObjectFactory = sf::ObjectFactory; - - alignas(0x40) constinit u8 g_server_allocator_buffer[4_KB]; - lmem::HeapHandle g_server_heap_handle; - Allocator g_server_allocator; - - ServerManager g_server_manager; - - ams::Result ServerManager::OnNeedsToAccept(int port_index, Server *server) { - switch (port_index) { - case PortIndex_DebugMonitor: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(std::addressof(g_server_allocator))); - case PortIndex_User: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(std::addressof(g_server_allocator), ro::NrrKind_User)); - case PortIndex_JitPlugin: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(std::addressof(g_server_allocator), ro::NrrKind_JitPlugin)); - AMS_UNREACHABLE_DEFAULT_CASE(); - } - } - - void *Allocate(size_t size) { - return lmem::AllocateFromExpHeap(g_server_heap_handle, size); - } - - void Deallocate(void *p, size_t size) { - AMS_UNUSED(size); - - return lmem::FreeToExpHeap(g_server_heap_handle, p); - } - - void InitializeHeap() { - /* Setup server allocator. */ - g_server_heap_handle = lmem::CreateExpHeap(g_server_allocator_buffer, sizeof(g_server_allocator_buffer), lmem::CreateOption_None); - } - - void LoopServer() { - /* Create services. */ - R_ABORT_UNLESS(ro::g_server_manager.RegisterServer(PortIndex_DebugMonitor, DebugMonitorServiceName, DebugMonitorMaxSessions)); - - R_ABORT_UNLESS(ro::g_server_manager.RegisterServer(PortIndex_User, UserServiceName, UserMaxSessions)); - if (hos::GetVersion() >= hos::Version_7_0_0) { - R_ABORT_UNLESS(ro::g_server_manager.RegisterServer(PortIndex_JitPlugin, JitPluginServiceName, JitPluginMaxSessions)); - } - - /* Loop forever, servicing our services. */ - ro::g_server_manager.LoopProcess(); - } - - } - -} - -void __libnx_initheap(void) { - void* addr = nx_inner_heap; - size_t size = nx_inner_heap_size; - - /* Newlib */ - extern char* fake_heap_start; - extern char* fake_heap_end; - - fake_heap_start = (char*)addr; - fake_heap_end = (char*)addr + size; - - ams::ro::InitializeHeap(); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - fs::SetAllocator(ro::Allocate, ro::Deallocate); - - R_ABORT_UNLESS(sm::Initialize()); - - R_ABORT_UNLESS(setsysInitialize()); - R_ABORT_UNLESS(fsInitialize()); - spl::Initialize(); - - R_ABORT_UNLESS(fs::MountSdCard("sdmc")); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - fsExit(); - - setsysExit(); -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); + namespace ro { + + namespace { + + /* ldr:ro, ro:dmnt, ro:1. */ + enum PortIndex { + PortIndex_DebugMonitor, + PortIndex_User, + PortIndex_JitPlugin, + PortIndex_Count, + }; + + constexpr sm::ServiceName DebugMonitorServiceName = sm::ServiceName::Encode("ro:dmnt"); + constexpr size_t DebugMonitorMaxSessions = 2; + + /* NOTE: Official code passes 32 for ldr:ro max sessions. We will pass 2, because that's the actual limit. */ + constexpr sm::ServiceName UserServiceName = sm::ServiceName::Encode("ldr:ro"); + constexpr size_t UserMaxSessions = 2; + + constexpr sm::ServiceName JitPluginServiceName = sm::ServiceName::Encode("ro:1"); + constexpr size_t JitPluginMaxSessions = 2; + + static constexpr size_t MaxSessions = DebugMonitorMaxSessions + UserMaxSessions + JitPluginMaxSessions; + + using ServerOptions = sf::hipc::DefaultServerManagerOptions; + + class ServerManager final : public sf::hipc::ServerManager { + private: + virtual ams::Result OnNeedsToAccept(int port_index, Server *server) override; + }; + + using Allocator = sf::ExpHeapAllocator; + using ObjectFactory = sf::ObjectFactory; + + alignas(0x40) constinit u8 g_server_allocator_buffer[4_KB]; + lmem::HeapHandle g_server_heap_handle; + Allocator g_server_allocator; + + ServerManager g_server_manager; + + ams::Result ServerManager::OnNeedsToAccept(int port_index, Server *server) { + switch (port_index) { + case PortIndex_DebugMonitor: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(std::addressof(g_server_allocator))); + case PortIndex_User: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(std::addressof(g_server_allocator), ro::NrrKind_User)); + case PortIndex_JitPlugin: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(std::addressof(g_server_allocator), ro::NrrKind_JitPlugin)); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + void *Allocate(size_t size) { + return lmem::AllocateFromExpHeap(g_server_heap_handle, size); + } + + void Deallocate(void *p, size_t size) { + AMS_UNUSED(size); + + return lmem::FreeToExpHeap(g_server_heap_handle, p); + } + + void InitializeHeap() { + /* Setup server allocator. */ + g_server_heap_handle = lmem::CreateExpHeap(g_server_allocator_buffer, sizeof(g_server_allocator_buffer), lmem::CreateOption_None); + } + + void LoopServer() { + /* Create services. */ + R_ABORT_UNLESS(ro::g_server_manager.RegisterServer(PortIndex_DebugMonitor, DebugMonitorServiceName, DebugMonitorMaxSessions)); + + R_ABORT_UNLESS(ro::g_server_manager.RegisterServer(PortIndex_User, UserServiceName, UserMaxSessions)); + if (hos::GetVersion() >= hos::Version_7_0_0) { + R_ABORT_UNLESS(ro::g_server_manager.RegisterServer(PortIndex_JitPlugin, JitPluginServiceName, JitPluginMaxSessions)); + } + + /* Loop forever, servicing our services. */ + ro::g_server_manager.LoopProcess(); + } + + } + } - void Free(void *) { - AMS_ABORT("ams::Free was called"); + namespace init { + + void InitializeSystemModule() { + /* Initialize heap. */ + ro::InitializeHeap(); + + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Initialize fs. */ + fs::InitializeForSystem(); + fs::SetAllocator(ro::Allocate, ro::Deallocate); + fs::SetEnabledAutoAbort(false); + + /* Initialize other services we need. */ + R_ABORT_UNLESS(setsysInitialize()); + + /* Mount the SD card. */ + R_ABORT_UNLESS(fs::MountSdCard("sdmc")); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ro, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ro, Main)); + + /* Attach the server allocator. */ + ro::g_server_allocator.Attach(ro::g_server_heap_handle); + + /* Initialize Debug config. */ + { + spl::Initialize(); + ON_SCOPE_EXIT { spl::Finalize(); }; + + ro::SetDevelopmentHardware(spl::IsDevelopment()); + ro::SetDevelopmentFunctionEnabled(spl::IsDevelopmentFunctionEnabled()); + } + + /* Run the ro server. */ + ro::LoopServer(); } } - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(ro, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(ro, Main)); - - /* Attach the server allocator. */ - ro::g_server_allocator.Attach(ro::g_server_heap_handle); - - /* Disable auto-abort in fs operations. */ - fs::SetEnabledAutoAbort(false); - - /* Initialize Debug config. */ - { - ON_SCOPE_EXIT { spl::Finalize(); }; - - ro::SetDevelopmentHardware(spl::IsDevelopment()); - ro::SetDevelopmentFunctionEnabled(spl::IsDevelopmentFunctionEnabled()); - } - - /* Run the ro server. */ - ro::LoopServer(); - - /* Cleanup */ - return 0; -} - diff --git a/stratosphere/sm/source/sm_main.cpp b/stratosphere/sm/source/sm_main.cpp index 279944005..1c026e46c 100644 --- a/stratosphere/sm/source/sm_main.cpp +++ b/stratosphere/sm/source/sm_main.cpp @@ -16,121 +16,36 @@ #include #include "sm_tipc_server.hpp" -extern "C" { - extern u32 __start__; - - extern int __system_argc; - extern char** __system_argv; - - u32 __nx_applet_type = AppletType_None; - - #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 argvSetup(void); - void __appInit(void); - void __appExit(void); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -namespace { - - constinit char *g_empty_argv = nullptr; - -} - namespace ams { + namespace init { + + void InitializeSystemModule() { /* ... */ } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + void NORETURN Exit(int rc) { AMS_UNUSED(rc); AMS_ABORT("Exit called by immortal process"); } -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - - -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 argvSetup(void) { - /* We don't need argc/argv, so set them to empty defaults. */ - __system_argc = 0; - __system_argv = std::addressof(g_empty_argv); -} - -void __appInit(void) { - hos::InitializeForStratosphere(); - - /* We must do no service setup here, because we are sm. */ -} - -void __appExit(void) { - /* Nothing to clean up, because we're sm. */ -} - -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} - -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} - -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} - -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} - -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} - -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} - -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); - - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(sm, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(sm, Main)); - - /* Initialize the server. */ - sm::InitializeTipcServer(); - - /* Loop forever, processing our services. */ - sm::LoopProcessTipcServer(); - - /* This can never be reached. */ - AMS_ASSUME(false); + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(sm, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(sm, Main)); + + /* Initialize the server. */ + sm::InitializeTipcServer(); + + /* Loop forever, processing our services. */ + sm::LoopProcessTipcServer(); + + /* This can never be reached. */ + AMS_ASSUME(false); + } + } diff --git a/stratosphere/spl/source/spl_main.cpp b/stratosphere/spl/source/spl_main.cpp index 4676d13a8..3129c6aa3 100644 --- a/stratosphere/spl/source/spl_main.cpp +++ b/stratosphere/spl/source/spl_main.cpp @@ -26,221 +26,163 @@ #include "spl_deprecated_service.hpp" -extern "C" { - extern u32 __start__; - - u32 __nx_applet_type = AppletType_None; - - #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); - - /* 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_alloc(size_t size); - void *__libnx_aligned_alloc(size_t alignment, size_t size); - void __libnx_free(void *mem); -} - -using namespace ams; - -void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -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(); - - /* SPL doesn't really access any services... */ - R_ABORT_UNLESS(sm::Initialize()); - - ams::CheckApiVersion(); -} - -void __appExit(void) { - /* SPL doesn't really access any services... */ -} - -namespace { - - struct SplServerOptions { - static constexpr size_t PointerBufferSize = 0x800; - static constexpr size_t MaxDomains = 0; - static constexpr size_t MaxDomainObjects = 0; - }; - - enum PortIndex { - PortIndex_General, - PortIndex_Random, - PortIndex_Crypto, - PortIndex_Fs, - PortIndex_Ssl, - PortIndex_Es, - PortIndex_Manu, - PortIndex_Count, - }; - - constexpr sm::ServiceName RandomServiceName = sm::ServiceName::Encode("csrng"); - constexpr size_t RandomMaxSessions = 3; - - constexpr sm::ServiceName GeneralServiceName = sm::ServiceName::Encode("spl:"); - constexpr size_t DeprecatedMaxSessions = 13; - constexpr size_t GeneralMaxSessions = 7; - - constexpr sm::ServiceName CryptoServiceName = sm::ServiceName::Encode("spl:mig"); - constexpr size_t CryptoMaxSessions = 7; - - constexpr sm::ServiceName SslServiceName = sm::ServiceName::Encode("spl:ssl"); - constexpr size_t SslMaxSessions = 2; - - constexpr sm::ServiceName EsServiceName = sm::ServiceName::Encode("spl:es"); - constexpr size_t EsMaxSessions = 2; - - constexpr sm::ServiceName FsServiceName = sm::ServiceName::Encode("spl:fs"); - constexpr size_t FsMaxSessions = 3; - - constexpr sm::ServiceName ManuServiceName = sm::ServiceName::Encode("spl:manu"); - constexpr size_t ManuMaxSessions = 1; - - /* csrng, spl:, spl:mig, spl:ssl, spl:es, spl:fs, spl:manu. */ - /* TODO: Consider max sessions enforcement? */ - constexpr size_t ModernMaxSessions = GeneralMaxSessions + CryptoMaxSessions + SslMaxSessions + EsMaxSessions + FsMaxSessions + ManuMaxSessions; - constexpr size_t NumSessions = RandomMaxSessions + std::max(DeprecatedMaxSessions, ModernMaxSessions) + 1; - - class ServerManager final : public sf::hipc::ServerManager { - private: - sf::ExpHeapAllocator *m_allocator; - spl::GeneralService m_general_service; - sf::UnmanagedServiceObjectByPointer m_general_service_object; - spl::RandomService m_random_service; - sf::UnmanagedServiceObjectByPointer m_random_service_object; - public: - ServerManager(sf::ExpHeapAllocator *allocator) : m_allocator(allocator), m_general_service(), m_general_service_object(std::addressof(m_general_service)), m_random_service(), m_random_service_object(std::addressof(m_random_service)) { - /* ... */ - } - private: - virtual ams::Result OnNeedsToAccept(int port_index, Server *server) override; - }; - - using Allocator = sf::ExpHeapAllocator; - using ObjectFactory = sf::ObjectFactory; - - alignas(0x40) constinit u8 g_server_allocator_buffer[8_KB]; - Allocator g_server_allocator; - - ServerManager g_server_manager(std::addressof(g_server_allocator)); - - ams::Result ServerManager::OnNeedsToAccept(int port_index, Server *server) { - switch (port_index) { - case PortIndex_General: - if (hos::GetVersion() >= hos::Version_4_0_0) { - return this->AcceptImpl(server, m_general_service_object.GetShared()); - } else { - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); - } - case PortIndex_Random: - return this->AcceptImpl(server, m_random_service_object.GetShared()); - case PortIndex_Crypto: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); - case PortIndex_Fs: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); - case PortIndex_Ssl: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); - case PortIndex_Es: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); - case PortIndex_Manu: - return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); - AMS_UNREACHABLE_DEFAULT_CASE(); - } - } - -} - namespace ams { - void *Malloc(size_t) { - AMS_ABORT("ams::Malloc was called"); - } + namespace spl { - void Free(void *) { - AMS_ABORT("ams::Free was called"); - } + namespace { -} + struct SplServerOptions { + static constexpr size_t PointerBufferSize = 0x800; + static constexpr size_t MaxDomains = 0; + static constexpr size_t MaxDomainObjects = 0; + }; -void *operator new(size_t) { - AMS_ABORT("operator new(size_t) was called"); -} + enum PortIndex { + PortIndex_General, + PortIndex_Random, + PortIndex_Crypto, + PortIndex_Fs, + PortIndex_Ssl, + PortIndex_Es, + PortIndex_Manu, + PortIndex_Count, + }; -void operator delete(void *) { - AMS_ABORT("operator delete(void *) was called"); -} + constexpr sm::ServiceName RandomServiceName = sm::ServiceName::Encode("csrng"); + constexpr size_t RandomMaxSessions = 3; -void operator delete(void *, size_t) { - AMS_ABORT("operator delete(void *, size_t) was called"); -} + constexpr sm::ServiceName GeneralServiceName = sm::ServiceName::Encode("spl:"); + constexpr size_t DeprecatedMaxSessions = 13; + constexpr size_t GeneralMaxSessions = 7; -void *__libnx_alloc(size_t) { - AMS_ABORT("__libnx_alloc was called"); -} + constexpr sm::ServiceName CryptoServiceName = sm::ServiceName::Encode("spl:mig"); + constexpr size_t CryptoMaxSessions = 7; -void *__libnx_aligned_alloc(size_t, size_t) { - AMS_ABORT("__libnx_aligned_alloc was called"); -} + constexpr sm::ServiceName SslServiceName = sm::ServiceName::Encode("spl:ssl"); + constexpr size_t SslMaxSessions = 2; -void __libnx_free(void *) { - AMS_ABORT("__libnx_free was called"); -} + constexpr sm::ServiceName EsServiceName = sm::ServiceName::Encode("spl:es"); + constexpr size_t EsMaxSessions = 2; -int main(int argc, char **argv) -{ - AMS_UNUSED(argc, argv); + constexpr sm::ServiceName FsServiceName = sm::ServiceName::Encode("spl:fs"); + constexpr size_t FsMaxSessions = 3; - /* Set thread name. */ - os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(spl, Main)); - AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(spl, Main)); + constexpr sm::ServiceName ManuServiceName = sm::ServiceName::Encode("spl:manu"); + constexpr size_t ManuMaxSessions = 1; - /* Setup server allocator. */ - g_server_allocator.Attach(lmem::CreateExpHeap(g_server_allocator_buffer, sizeof(g_server_allocator_buffer), lmem::CreateOption_None)); + /* csrng, spl:, spl:mig, spl:ssl, spl:es, spl:fs, spl:manu. */ + /* TODO: Consider max sessions enforcement? */ + constexpr size_t ModernMaxSessions = GeneralMaxSessions + CryptoMaxSessions + SslMaxSessions + EsMaxSessions + FsMaxSessions + ManuMaxSessions; + constexpr size_t NumSessions = RandomMaxSessions + std::max(DeprecatedMaxSessions, ModernMaxSessions) + 1; - /* Initialize global context. */ - spl::impl::Initialize(); + class ServerManager final : public sf::hipc::ServerManager { + private: + sf::ExpHeapAllocator *m_allocator; + spl::GeneralService m_general_service; + sf::UnmanagedServiceObjectByPointer m_general_service_object; + spl::RandomService m_random_service; + sf::UnmanagedServiceObjectByPointer m_random_service_object; + public: + ServerManager(sf::ExpHeapAllocator *allocator) : m_allocator(allocator), m_general_service(), m_general_service_object(std::addressof(m_general_service)), m_random_service(), m_random_service_object(std::addressof(m_random_service)) { + /* ... */ + } + private: + virtual ams::Result OnNeedsToAccept(int port_index, Server *server) override; + }; + + using Allocator = sf::ExpHeapAllocator; + using ObjectFactory = sf::ObjectFactory; + + alignas(0x40) constinit u8 g_server_allocator_buffer[8_KB]; + Allocator g_server_allocator; + + ServerManager g_server_manager(std::addressof(g_server_allocator)); + + ams::Result ServerManager::OnNeedsToAccept(int port_index, Server *server) { + switch (port_index) { + case PortIndex_General: + if (hos::GetVersion() >= hos::Version_4_0_0) { + return this->AcceptImpl(server, m_general_service_object.GetShared()); + } else { + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); + } + case PortIndex_Random: + return this->AcceptImpl(server, m_random_service_object.GetShared()); + case PortIndex_Crypto: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); + case PortIndex_Fs: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); + case PortIndex_Ssl: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); + case PortIndex_Es: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); + case PortIndex_Manu: + return this->AcceptImpl(server, ObjectFactory::CreateSharedEmplaced(m_allocator)); + AMS_UNREACHABLE_DEFAULT_CASE(); + } + } + + void SplMain() { + /* Setup server allocator. */ + g_server_allocator.Attach(lmem::CreateExpHeap(g_server_allocator_buffer, sizeof(g_server_allocator_buffer), lmem::CreateOption_None)); + + /* Initialize global context. */ + spl::impl::Initialize(); + + /* Create services. */ + const auto fw_ver = hos::GetVersion(); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_General, GeneralServiceName, fw_ver >= hos::Version_4_0_0 ? GeneralMaxSessions : DeprecatedMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Random, RandomServiceName, RandomMaxSessions)); + if (fw_ver >= hos::Version_4_0_0) { + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Crypto, CryptoServiceName, CryptoMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Fs, FsServiceName, FsMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Ssl, SslServiceName, SslMaxSessions)); + R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Es, EsServiceName, EsMaxSessions)); + if (fw_ver >= hos::Version_5_0_0) { + g_server_manager.RegisterServer(PortIndex_Manu, ManuServiceName, ManuMaxSessions); + } + } + + /* Loop forever, servicing our services. */ + g_server_manager.LoopProcess(); + } - /* Create services. */ - const auto fw_ver = hos::GetVersion(); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_General, GeneralServiceName, fw_ver >= hos::Version_4_0_0 ? GeneralMaxSessions : DeprecatedMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Random, RandomServiceName, RandomMaxSessions)); - if (fw_ver >= hos::Version_4_0_0) { - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Crypto, CryptoServiceName, CryptoMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Fs, FsServiceName, FsMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Ssl, SslServiceName, SslMaxSessions)); - R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Es, EsServiceName, EsMaxSessions)); - if (fw_ver >= hos::Version_5_0_0) { - g_server_manager.RegisterServer(PortIndex_Manu, ManuServiceName, ManuMaxSessions); } + } - /* Loop forever, servicing our services. */ - g_server_manager.LoopProcess(); + namespace init { + + void InitializeSystemModule() { + /* Initialize our connection to sm. */ + R_ABORT_UNLESS(sm::Initialize()); + + /* Verify that we can sanely execute. */ + ams::CheckApiVersion(); + } + + void FinalizeSystemModule() { /* ... */ } + + void Startup() { /* ... */ } + + } + + void NORETURN Exit(int rc) { + AMS_UNUSED(rc); + AMS_ABORT("Exit called by immortal process"); + } + + void Main() { + /* Set thread name. */ + os::SetThreadNamePointer(os::GetCurrentThread(), AMS_GET_SYSTEM_THREAD_NAME(spl, Main)); + AMS_ASSERT(os::GetThreadPriority(os::GetCurrentThread()) == AMS_GET_SYSTEM_THREAD_PRIORITY(spl, Main)); + + /* Invoke SPL main. */ + spl::SplMain(); + + /* This can never be reached. */ + AMS_ASSUME(false); + } - return 0; }