From 3355f97275c63a370b907cf5b8ab4a917b1947bb Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 7 Dec 2020 19:25:06 -0800 Subject: [PATCH] exo/meso/fusee: support dynamic control of log port/baud rate --- libexosphere/include/exosphere/log.hpp | 1 + ...ecmon_configuration_context.arch.arm64.hpp | 8 +++ .../secmon/secmon_monitor_context.hpp | 20 ++++-- libexosphere/source/log/log_api.cpp | 69 +++++++++--------- .../nintendo/nx/kern_k_system_control.hpp | 1 + .../include/mesosphere/kern_debug_log.hpp | 2 +- .../nintendo/nx/kern_k_system_control.cpp | 9 +++ .../board/nintendo/nx/kern_secure_monitor.hpp | 19 ++--- .../kern_debug_log_impl.board.nintendo_nx.cpp | 70 ++++++++++--------- ...kern_k_memory_layout.board.nintendo_nx.cpp | 16 ++--- 10 files changed, 128 insertions(+), 87 deletions(-) diff --git a/libexosphere/include/exosphere/log.hpp b/libexosphere/include/exosphere/log.hpp index 7ddde611..cecf8d15 100644 --- a/libexosphere/include/exosphere/log.hpp +++ b/libexosphere/include/exosphere/log.hpp @@ -35,6 +35,7 @@ namespace ams::log { #endif void Initialize(); + void Initialize(uart::Port port, u32 baud_rate); void Finalize(); void Printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); diff --git a/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp b/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp index bddcf1b7..aa231787 100644 --- a/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp +++ b/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp @@ -116,6 +116,14 @@ namespace ams::secmon { return GetSecmonConfiguration().GetLcdVendor(); } + ALWAYS_INLINE uart::Port GetLogPort() { + return GetSecmonConfiguration().GetLogPort(); + } + + ALWAYS_INLINE u32 GetLogBaudRate() { + return GetSecmonConfiguration().GetLogBaudRate(); + } + ALWAYS_INLINE bool IsProduction() { return GetSecmonConfiguration().IsProduction(); } diff --git a/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp b/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp index c2970801..f53a633d 100644 --- a/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp +++ b/libexosphere/include/exosphere/secmon/secmon_monitor_context.hpp @@ -16,6 +16,7 @@ #pragma once #include #include +#include #include namespace ams::secmon { @@ -39,8 +40,10 @@ namespace ams::secmon { ams::TargetFirmware target_firmware; u32 flags[2]; u16 lcd_vendor; - u16 reserved0; - u32 reserved1[3]; + u8 reserved0; + u8 log_port; + u32 log_baud_rate; + u32 reserved1[2]; EmummcConfiguration emummc_cfg; constexpr bool IsValid() const { return this->magic == Magic; } @@ -54,17 +57,20 @@ namespace ams::secmon { u8 hardware_type; u8 soc_type; u8 hardware_state; - u8 pad_0B[1]; + u8 log_port; u32 flags[2]; u16 lcd_vendor; u16 reserved0; - u32 reserved1[(0x80 - 0x18) / sizeof(u32)]; + u32 log_baud_rate; + u32 reserved1[(0x80 - 0x1C) / sizeof(u32)]; constexpr void CopyFrom(const SecureMonitorStorageConfiguration &storage) { this->target_firmware = storage.target_firmware; this->flags[0] = storage.flags[0]; this->flags[1] = storage.flags[1]; this->lcd_vendor = storage.lcd_vendor; + this->log_port = storage.log_port; + this->log_baud_rate = storage.log_baud_rate != 0 ? storage.log_baud_rate : 115200; } void SetFuseInfo() { @@ -78,9 +84,12 @@ namespace ams::secmon { constexpr fuse::HardwareType GetHardwareType() const { return static_cast(this->hardware_type); } constexpr fuse::SocType GetSocType() const { return static_cast(this->soc_type); } constexpr fuse::HardwareState GetHardwareState() const { return static_cast(this->hardware_state); } + constexpr uart::Port GetLogPort() const { return static_cast(this->log_port); } constexpr u16 GetLcdVendor() const { return this->lcd_vendor; } + constexpr u32 GetLogBaudRate() const { return this->log_baud_rate; } + constexpr bool IsProduction() const { return this->GetHardwareState() != fuse::HardwareState_Development; } constexpr bool IsDevelopmentFunctionEnabledForKernel() const { return (this->flags[0] & SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel) != 0; } @@ -101,10 +110,11 @@ namespace ams::secmon { .hardware_type = {}, .soc_type = {}, .hardware_state = {}, - .pad_0B = {}, + .log_port = uart::Port_ReservedDebug, .flags = { SecureMonitorConfigurationFlag_Default, SecureMonitorConfigurationFlag_None }, .lcd_vendor = {}, .reserved0 = {}, + .log_baud_rate = 115200, .reserved1 = {}, }; diff --git a/libexosphere/source/log/log_api.cpp b/libexosphere/source/log/log_api.cpp index 068dddc2..5ce2831c 100644 --- a/libexosphere/source/log/log_api.cpp +++ b/libexosphere/source/log/log_api.cpp @@ -19,58 +19,63 @@ namespace ams::log { namespace { - constexpr inline uart::Port UartLogPort = uart::Port_ReservedDebug; - constexpr inline int UartBaudRate = 115200; + constexpr inline uart::Port DefaultLogPort = uart::Port_ReservedDebug; + constexpr inline int DefaultBaudRate = 115200; + constinit uart::Port g_log_port = DefaultLogPort; constinit bool g_initialized_uart = false; - constexpr inline u32 UartPortFlags = [] { - if constexpr (UartLogPort == uart::Port_ReservedDebug) { - /* Logging to the debug port. */ - /* Don't invert transactions. */ - return uart::Flag_None; - } else if constexpr (UartLogPort == uart::Port_LeftJoyCon) { - /* Logging to left joy-con (e.g. with Joyless). */ - /* Invert transactions. */ - return uart::Flag_Inverted; - } else if constexpr (UartLogPort == uart::Port_RightJoyCon) { - /* Logging to right joy-con (e.g. with Joyless). */ - /* Invert transactions. */ - return uart::Flag_Inverted; - } else { - __builtin_unreachable(); + ALWAYS_INLINE u32 GetPortFlags(uart::Port port) { + switch (port) { + case uart::Port_ReservedDebug: + /* Logging to the debug port. */ + /* Don't invert transactions. */ + return uart::Flag_None; + case uart::Port_LeftJoyCon: + /* Logging to left joy-con (e.g. with Joyless). */ + /* Invert transactions. */ + return uart::Flag_Inverted; + case uart::Port_RightJoyCon: + /* Logging to right joy-con (e.g. with Joyless). */ + /* Invert transactions. */ + return uart::Flag_Inverted; + AMS_UNREACHABLE_DEFAULT_CASE(); } - }(); + } - ALWAYS_INLINE void SetupUart() { - if constexpr (UartLogPort == uart::Port_ReservedDebug) { - /* Logging to the debug port. */ - pinmux::SetupUartA(); - clkrst::EnableUartAClock(); - } else if constexpr (UartLogPort == uart::Port_LeftJoyCon) { + ALWAYS_INLINE void SetupUartClock(uart::Port port) { + /* The debug port must always be set up, for compatibility with official hos. */ + pinmux::SetupUartA(); + clkrst::EnableUartAClock(); + + /* If logging to a joy-con port, configure appropriately. */ + if (port == uart::Port_LeftJoyCon) { /* Logging to left joy-con (e.g. with Joyless). */ static_assert(uart::Port_LeftJoyCon == uart::Port_C); pinmux::SetupUartC(); clkrst::EnableUartCClock(); - } else if constexpr (UartLogPort == uart::Port_RightJoyCon) { + } else if (port == uart::Port_RightJoyCon) { /* Logging to right joy-con (e.g. with Joyless). */ static_assert(uart::Port_RightJoyCon == uart::Port_B); pinmux::SetupUartB(); clkrst::EnableUartBClock(); - } else { - __builtin_unreachable(); } } } void Initialize() { + return Initialize(DefaultLogPort, DefaultBaudRate); + } + + void Initialize(uart::Port port, u32 baud_rate) { /* Initialize pinmux and clock for the target uart port. */ - SetupUart(); + SetupUartClock(port); /* Initialize the target uart port. */ - uart::Initialize(UartLogPort, UartBaudRate, UartPortFlags); + uart::Initialize(port, baud_rate, GetPortFlags(port)); /* Note that we've initialized. */ + g_log_port = port; g_initialized_uart = true; } @@ -84,7 +89,7 @@ namespace ams::log { const auto len = util::TVSNPrintf(log_buf, sizeof(log_buf), fmt, vl); if (g_initialized_uart) { - uart::SendText(UartLogPort, log_buf, len); + uart::SendText(g_log_port, log_buf, len); } } @@ -115,13 +120,13 @@ namespace ams::log { void SendText(const void *text, size_t size) { if (g_initialized_uart) { - uart::SendText(UartLogPort, text, size); + uart::SendText(g_log_port, text, size); } } void Flush() { if (g_initialized_uart) { - uart::WaitFlush(UartLogPort); + uart::WaitFlush(g_log_port); } } diff --git a/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp b/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp index c72015d0..f9d99aec 100644 --- a/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp +++ b/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_system_control.hpp @@ -30,6 +30,7 @@ namespace ams::kern::board::nintendo::nx { static size_t GetApplicationPoolSize(); static size_t GetAppletPoolSize(); static size_t GetMinimumNonSecureSystemPoolSize(); + static u8 GetDebugLogUartPort(); /* Randomness. */ static void GenerateRandomBytes(void *dst, size_t size); diff --git a/libmesosphere/include/mesosphere/kern_debug_log.hpp b/libmesosphere/include/mesosphere/kern_debug_log.hpp index e2cde134..4f19c19a 100644 --- a/libmesosphere/include/mesosphere/kern_debug_log.hpp +++ b/libmesosphere/include/mesosphere/kern_debug_log.hpp @@ -40,7 +40,7 @@ namespace ams::kern { #ifndef MESOSPHERE_DEBUG_LOG_SELECTED #ifdef ATMOSPHERE_BOARD_NINTENDO_NX - #define MESOSPHERE_DEBUG_LOG_USE_UART_A + #define MESOSPHERE_DEBUG_LOG_USE_UART #else #error "Unknown board for Default Debug Log Source" #endif diff --git a/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index a54bf2c1..df41785d 100644 --- a/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp +++ b/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -409,6 +409,15 @@ namespace ams::kern::board::nintendo::nx { return MinimumSize; } + u8 KSystemControl::Init::GetDebugLogUartPort() { + /* Get the log configuration. */ + u64 value = 0; + smc::init::GetConfig(std::addressof(value), 1, smc::ConfigItem::ExosphereLogConfiguration); + + /* Extract the port. */ + return static_cast((value >> 32) & 0xFF); + } + void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { smc::init::CpuOn(core_id, entrypoint, arg); } diff --git a/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp b/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp index b7d17072..22233b78 100644 --- a/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp +++ b/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp @@ -55,15 +55,16 @@ namespace ams::kern::board::nintendo::nx::smc { Package2Hash = 17, /* Extension config items for exosphere. */ - ExosphereApiVersion = 65000, - ExosphereNeedsReboot = 65001, - ExosphereNeedsShutdown = 65002, - ExosphereGitCommitHash = 65003, - ExosphereHasRcmBugPatch = 65004, - ExosphereBlankProdInfo = 65005, - ExosphereAllowCalWrites = 65006, - ExosphereEmummcType = 65007, - ExospherePayloadAddress = 65008, + ExosphereApiVersion = 65000, + ExosphereNeedsReboot = 65001, + ExosphereNeedsShutdown = 65002, + ExosphereGitCommitHash = 65003, + ExosphereHasRcmBugPatch = 65004, + ExosphereBlankProdInfo = 65005, + ExosphereAllowCalWrites = 65006, + ExosphereEmummcType = 65007, + ExospherePayloadAddress = 65008, + ExosphereLogConfiguration = 65009, }; enum class SmcResult { diff --git a/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp b/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp index 470287b9..9b516e29 100644 --- a/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp +++ b/libmesosphere/source/kern_debug_log_impl.board.nintendo_nx.cpp @@ -18,10 +18,12 @@ namespace ams::kern { -#if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_D) +#if defined(MESOSPHERE_DEBUG_LOG_USE_UART) namespace { + constexpr bool DoSaveAndRestore = false; + enum UartRegister { UartRegister_THR = 0, UartRegister_IER = 1, @@ -38,13 +40,13 @@ namespace ams::kern { KVirtualAddress g_uart_address = 0; - constinit u32 g_saved_registers[5]; + [[maybe_unused]] constinit u32 g_saved_registers[5]; - NOINLINE u32 ReadUartRegister(UartRegister which) { + ALWAYS_INLINE u32 ReadUartRegister(UartRegister which) { return GetPointer(g_uart_address)[which]; } - NOINLINE void WriteUartRegister(UartRegister which, u32 value) { + ALWAYS_INLINE void WriteUartRegister(UartRegister which, u32 value) { GetPointer(g_uart_address)[which] = value; } @@ -86,43 +88,47 @@ namespace ams::kern { } void KDebugLogImpl::Save() { - /* Save LCR, IER, FCR. */ - g_saved_registers[0] = ReadUartRegister(UartRegister_LCR); - g_saved_registers[1] = ReadUartRegister(UartRegister_IER); - g_saved_registers[2] = ReadUartRegister(UartRegister_FCR); + if constexpr (DoSaveAndRestore) { + /* Save LCR, IER, FCR. */ + g_saved_registers[0] = ReadUartRegister(UartRegister_LCR); + g_saved_registers[1] = ReadUartRegister(UartRegister_IER); + g_saved_registers[2] = ReadUartRegister(UartRegister_FCR); - /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ - WriteUartRegister(UartRegister_LCR, 0x80); - ReadUartRegister(UartRegister_LCR); + /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ + WriteUartRegister(UartRegister_LCR, 0x80); + ReadUartRegister(UartRegister_LCR); - /* Save DLL/DLH. */ - g_saved_registers[3] = ReadUartRegister(UartRegister_DLL); - g_saved_registers[4] = ReadUartRegister(UartRegister_DLH); + /* Save DLL/DLH. */ + g_saved_registers[3] = ReadUartRegister(UartRegister_DLL); + g_saved_registers[4] = ReadUartRegister(UartRegister_DLH); - /* Restore Divisor Latch Access bit. */ - WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); - ReadUartRegister(UartRegister_LCR); + /* Restore Divisor Latch Access bit. */ + WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); + ReadUartRegister(UartRegister_LCR); + } } void KDebugLogImpl::Restore() { - /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ - WriteUartRegister(UartRegister_LCR, 0x80); - ReadUartRegister(UartRegister_LCR); + if constexpr (DoSaveAndRestore) { + /* Set Divisor Latch Access bit, to allow access to DLL/DLH */ + WriteUartRegister(UartRegister_LCR, 0x80); + ReadUartRegister(UartRegister_LCR); - /* Restore DLL/DLH. */ - WriteUartRegister(UartRegister_DLL, g_saved_registers[3]); - WriteUartRegister(UartRegister_DLH, g_saved_registers[4]); - ReadUartRegister(UartRegister_DLH); + /* Restore DLL/DLH. */ + WriteUartRegister(UartRegister_DLL, g_saved_registers[3]); + WriteUartRegister(UartRegister_DLH, g_saved_registers[4]); + ReadUartRegister(UartRegister_DLH); - /* Restore Divisor Latch Access bit. */ - WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); - ReadUartRegister(UartRegister_LCR); + /* Restore Divisor Latch Access bit. */ + WriteUartRegister(UartRegister_LCR, g_saved_registers[0]); + ReadUartRegister(UartRegister_LCR); - /* Restore IER and FCR. */ - WriteUartRegister(UartRegister_IER, g_saved_registers[1]); - WriteUartRegister(UartRegister_FCR, g_saved_registers[2] | 2); - WriteUartRegister(UartRegister_IRDA_CSR, 0x02); - ReadUartRegister(UartRegister_FCR); + /* Restore IER and FCR. */ + WriteUartRegister(UartRegister_IER, g_saved_registers[1]); + WriteUartRegister(UartRegister_FCR, g_saved_registers[2] | 2); + WriteUartRegister(UartRegister_IRDA_CSR, 0x02); + ReadUartRegister(UartRegister_FCR); + } } #elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER) diff --git a/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp b/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp index 8c051a15..129edaba 100644 --- a/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp +++ b/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp @@ -26,14 +26,14 @@ namespace ams::kern { constexpr size_t CarveoutSizeMax = 512_MB - CarveoutAlignment; ALWAYS_INLINE bool SetupUartPhysicalMemoryRegion() { - #if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006000, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006040, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); - #elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D) - return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + #if defined(MESOSPHERE_DEBUG_LOG_USE_UART) + switch (KSystemControl::Init::GetDebugLogUartPort()) { + case 0: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006000, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + case 1: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006040, 0x40, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + case 2: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + case 3: return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap); + default: return false; + } #elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER) return true; #else