diff --git a/exosphere/program/source/boot/secmon_boot_setup.cpp b/exosphere/program/source/boot/secmon_boot_setup.cpp index 7db091a1d..9452d70fd 100644 --- a/exosphere/program/source/boot/secmon_boot_setup.cpp +++ b/exosphere/program/source/boot/secmon_boot_setup.cpp @@ -48,7 +48,12 @@ namespace ams::secmon::boot { const auto pmc = MemoryRegionVirtualDevicePmc.GetAddress(); /* Set the physical address of the warmboot binary to scratch 1. */ - reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress())); + if (GetSocType() == fuse::SocType_Mariko) { + reg::Write(pmc + APBDEV_PMC_SECURE_SCRATCH119, static_cast(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress())); + } else /* if (GetSocType() == fuse::SocType_Erista) */ { + reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress())); + } + /* Configure logging by setting bits 18-19 of scratch 20. */ reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH20, REG_BITS_VALUE(18, 2, 0)); @@ -66,6 +71,7 @@ namespace ams::secmon::boot { /* The warmboot key as a parameter. The latter is a better solution, but it would be nice to take */ /* care of it here. Perhaps we should read the number of anti-downgrade fuses burnt, and translate that */ /* to the warmboot key? To be decided during the process of implementing ams-on-mariko support. */ + reg::Write(pmc + APBDEV_PMC_SECURE_SCRATCH32, 0x129); } constinit const u8 DeviceMasterKeySourceKekSource[se::AesBlockSize] = { @@ -92,6 +98,10 @@ namespace ams::secmon::boot { 0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE }; + constinit const u8 MasterKeySource[se::AesBlockSize] = { + 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C + }; + void DeriveMasterKekAndDeviceKeyMariko(bool is_prod) { /* Clear all keyslots other than KEK and SBK in SE1. */ for (int i = 0; i < pkg1::AesKeySlot_Count; ++i) { @@ -123,6 +133,14 @@ namespace ams::secmon::boot { } } + void DeriveMasterKey() { + if (GetSocType() == fuse::SocType_Mariko) { + se::SetEncryptedAesKey128(pkg1::AesKeySlot_Master, pkg1::AesKeySlot_MasterKek, MasterKeySource, se::AesBlockSize); + } else /* if (GetSocType() == fuse::SocType_Erista) */ { + /* Nothing to do here; erista bootloader will have derived master key already. */ + } + } + void SetupRandomKey(int slot, se::KeySlotLockFlags flags) { /* Create an aligned buffer to hold the key. */ constexpr size_t KeySize = se::AesBlockSize; @@ -312,6 +330,9 @@ namespace ams::secmon::boot { /* Derive the master keys. */ DeriveAllMasterKeys(is_prod, work_block); + /* Lock the master key as a kek. */ + se::LockAesKeySlot(pkg1::AesKeySlot_Master, se::KeySlotLockFlags_AllLockKek); + /* Derive the device master keys. */ DeriveAllDeviceMasterKeys(is_prod, work_block); @@ -357,7 +378,10 @@ namespace ams::secmon::boot { /* Lock the device key as only usable as a kek. */ se::LockAesKeySlot(pkg1::AesKeySlot_Device, se::KeySlotLockFlags_AllLockKek); - /* Derive all keys. */ + /* Derive the master key. */ + DeriveMasterKey(); + + /* Derive all other keys. */ DeriveAllKeys(is_prod); } diff --git a/exosphere/program/source/secmon_error.cpp b/exosphere/program/source/secmon_error.cpp index 5b576294b..4c7d7752c 100644 --- a/exosphere/program/source/secmon_error.cpp +++ b/exosphere/program/source/secmon_error.cpp @@ -16,10 +16,24 @@ #include #include "secmon_error.hpp" -namespace { +namespace ams { - constexpr bool SaveSystemStateForDebug = false; + namespace { + constexpr bool SaveSystemStateForDebug = false; + constexpr bool LogSystemStateForDebug = false; + + void LogU64(u64 value) { + char buffer[2 * sizeof(value)]; + for (size_t i = 0; i < sizeof(value); ++i) { + buffer[sizeof(buffer) - 1 - (2 * i) - 0] = "0123456789ABCDEF"[(value >> 0) & 0xF]; + buffer[sizeof(buffer) - 1 - (2 * i) - 1] = "0123456789ABCDEF"[(value >> 4) & 0xF]; + value >>= 8; + } + log::SendText(buffer, sizeof(buffer)); + } + + } } namespace ams::diag { @@ -98,6 +112,57 @@ namespace ams::secmon { util::WaitMicroSeconds(1000); } + ALWAYS_INLINE void LogSystemStateForDebugErrorReboot(u64 lr, u64 sp) { + log::SendText("*** Error Reboot ***\n", 21); + log::Flush(); + + u64 temp_reg; + + __asm__ __volatile__("mrs %0, esr_el3" : "=r"(temp_reg) :: "memory"); + log::SendText("ESR_EL3: ", 9); + LogU64(temp_reg); + log::SendText("\n", 1); + log::Flush(); + + __asm__ __volatile__("mrs %0, elr_el3" : "=r"(temp_reg) :: "memory"); + log::SendText("ELR_EL3: ", 9); + LogU64(temp_reg); + log::SendText("\n", 1); + log::Flush(); + + __asm__ __volatile__("mrs %0, far_el3" : "=r"(temp_reg) :: "memory"); + log::SendText("FAR_EL3: ", 9); + LogU64(temp_reg); + log::SendText("\n", 1); + log::Flush(); + + log::SendText("LR: ", 9); + LogU64(lr); + log::SendText("\n", 1); + log::Flush(); + + log::SendText("SP: ", 9); + LogU64(sp); + log::SendText("\n", 1); + log::Flush(); + + log::SendText("Stack:\n", 7); + log::Flush(); + + char buf[2]; + for (int i = 0; i < 0x100; ++i) { + const u8 byte = *(volatile u8 *)(sp + i); + buf[0] = "0123456789ABCDEF"[(byte >> 4) & 0xF]; + buf[1] = "0123456789ABCDEF"[(byte >> 0) & 0xF]; + log::SendText(buf, 2); + log::Flush(); + if (util::IsAligned(i + 1, 0x10)) { + log::SendText("\n", 1); + log::Flush(); + } + } + } + } void SetError(pkg1::ErrorInfo info) { @@ -114,6 +179,14 @@ namespace ams::secmon { SaveSystemStateForDebugErrorReboot(); } + if constexpr (LogSystemStateForDebug) { + u64 lr, sp; + __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); + __asm__ __volatile__("mov %0, sp" : "=r"(sp) :: "memory"); + + LogSystemStateForDebugErrorReboot(lr, sp); + } + /* Lockout the security engine. */ se::Lockout(); diff --git a/exosphere/program/source/secmon_setup.cpp b/exosphere/program/source/secmon_setup.cpp index a87539e72..b5580c1b2 100644 --- a/exosphere/program/source/secmon_setup.cpp +++ b/exosphere/program/source/secmon_setup.cpp @@ -51,27 +51,27 @@ namespace ams::secmon { constinit bool g_is_cold_boot = true; - constinit const se::StickyBits ExpectedSeStickyBits = { + constinit se::StickyBits ExpectedSeStickyBits = { .se_security = (1 << 0), /* SE_HARD_SETTING */ .tzram_security = 0, .crypto_security_perkey = (1 << pkg1::AesKeySlot_UserEnd) - 1, .crypto_keytable_access = { - (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 0: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ - (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 1: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ - (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 2: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ - (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 3: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ - (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 4: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ - (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 5: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 6: Unused keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 7: Unused keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ - (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 8: Temp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */ - (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 9: SmcTemp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 14: Unused keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ - (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 0: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ + (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 1: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ + (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 2: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ + (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 3: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ + (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 4: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ + (0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 5: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */ + (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 6: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 7: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 8: Temp keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */ + (0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 9: SmcTemp keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */ + (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1 keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (0 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2 keyslot. KEY. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 14: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ + (1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */ }, .rsa_security_perkey = 0, .rsa_keytable_access = { @@ -139,6 +139,16 @@ namespace ams::secmon { } void VerifySecurityEngineStickyBits() { + /* On mariko, an extra sticky bit is set. */ + if (GetSocType() == fuse::SocType_Mariko) { + ExpectedSeStickyBits.se_security |= (1 << 5); + } else /* if (GetSocType() == fuse::SocType_Erista) */ { + /* Erista does not support DST_KEYTABLE_ONLY, and so all keys will have the bit clear. */ + for (size_t i = 0; i < util::size(ExpectedSeStickyBits.crypto_keytable_access); ++i) { + ExpectedSeStickyBits.crypto_keytable_access[i] &= ~(1 << 7); + } + } + if (!se::ValidateStickyBits(ExpectedSeStickyBits)) { SetError(pkg1::ErrorInfo_InvalidSecurityEngineStickyBits); AMS_ABORT("Invalid sticky bits"); @@ -938,12 +948,16 @@ namespace ams::secmon { return reg::Read(MC + MC_SECURITY_CFG3) == 0; } + void SetupLogForBoot() { + log::Initialize(); + log::SendText("OHAYO\n", 6); + log::Flush(); + } + void LogExitLp0() { /* NOTE: Nintendo only does this on dev, but we will always do it. */ if (true /* !pkg1::IsProduction() */) { - log::Initialize(); - log::SendText("OHAYO\n", 6); - log::Flush(); + SetupLogForBoot(); } } @@ -969,7 +983,7 @@ namespace ams::secmon { InitializeConfigurationContext(); /* Initialize uart for logging. */ - log::Initialize(); + SetupLogForBoot(); /* Initialize the security engine. */ se::Initialize(); @@ -1017,12 +1031,16 @@ namespace ams::secmon { /* Overwrite keys that we want to be random with random contents. */ se::InitializeRandom(); + se::ConfigureAutomaticContextSave(); se::SetRandomKey(pkg1::AesKeySlot_Temporary); se::GenerateSrk(); se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek); /* Initialize pmc secure scratch. */ - pmc::InitializeRandomScratch(); + if (GetSocType() == fuse::SocType_Erista) { + pmc::InitializeRandomScratch(); + } + pmc::LockSecureRegister(pmc::SecureRegister_Srk); /* Setup secure registers. */ SetupSecureRegisters(); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp index 6934c8ccb..ecd8d1860 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp @@ -114,6 +114,7 @@ #define APBDEV_PMC_SECURE_SCRATCH113 (0xB1C) #define APBDEV_PMC_SECURE_SCRATCH114 (0xB20) #define APBDEV_PMC_SECURE_SCRATCH115 (0xB24) +#define APBDEV_PMC_SECURE_SCRATCH119 (0xB34) #define PMC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (APBDEV_PMC, NAME) diff --git a/libraries/libexosphere/source/clkrst/clkrst_api.cpp b/libraries/libexosphere/source/clkrst/clkrst_api.cpp index c0ae50b25..8b3967804 100644 --- a/libraries/libexosphere/source/clkrst/clkrst_api.cpp +++ b/libraries/libexosphere/source/clkrst/clkrst_api.cpp @@ -38,7 +38,7 @@ namespace ams::clkrst { reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0)); /* Set the clock source. */ - if (param.clk_src != 0) { + if (param.clk_src_offset != 0) { reg::Write(g_register_address + param.clk_src_offset, (param.clk_src << 29) | (param.clk_div << 0)); } @@ -89,11 +89,11 @@ namespace ams::clkrst { } void EnableUartBClock() { - EnableClock(UartAClock); + EnableClock(UartBClock); } void EnableUartCClock() { - EnableClock(UartAClock); + EnableClock(UartCClock); } void EnableActmonClock() { diff --git a/libraries/libexosphere/source/log/log_api.cpp b/libraries/libexosphere/source/log/log_api.cpp index ad1d89ea2..b6c96ed02 100644 --- a/libraries/libexosphere/source/log/log_api.cpp +++ b/libraries/libexosphere/source/log/log_api.cpp @@ -48,12 +48,14 @@ namespace ams::log { clkrst::EnableUartAClock(); } else if constexpr (UartLogPort == uart::Port_LeftJoyCon) { /* Logging to left joy-con (e.g. with Joyless). */ - pinmux::SetupUartB(); - clkrst::EnableUartBClock(); - } else if constexpr (UartLogPort == uart::Port_RightJoyCon) { - /* Logging to right 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) { + /* Logging to right joy-con (e.g. with Joyless). */ + static_assert(uart::Port_RightJoyCon == uart::Port_B); + pinmux::SetupUartB(); + clkrst::EnableUartBClock(); } else { __builtin_unreachable(); } diff --git a/libraries/libexosphere/source/pinmux/pinmux_api.cpp b/libraries/libexosphere/source/pinmux/pinmux_api.cpp index 276c9c8b8..3559541cd 100644 --- a/libraries/libexosphere/source/pinmux/pinmux_api.cpp +++ b/libraries/libexosphere/source/pinmux/pinmux_api.cpp @@ -104,7 +104,7 @@ namespace ams::pinmux { /* Get the registers. */ const uintptr_t PINMUX = g_pinmux_address; - /* Configure Uart-B. */ + /* Configure Uart-C. */ reg::Write(PINMUX + PINMUX_AUX_UART3_TX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), @@ -114,13 +114,13 @@ namespace ams::pinmux { reg::Write(PINMUX + PINMUX_AUX_UART3_RX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), - PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), + PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); reg::Write(PINMUX + PINMUX_AUX_UART3_RTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), - PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), + PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN), PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), @@ -128,13 +128,16 @@ namespace ams::pinmux { reg::Write(PINMUX + PINMUX_AUX_UART3_CTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC), PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE), - PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH), + PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE), PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE), PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE), PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE)); /* Configure GPIO for Uart-C. */ - reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 4, 0)); + reg::ReadWrite(g_gpio_address + 0x118, REG_BITS_VALUE(0, 1, 1)); + reg::Read(g_gpio_address + 0x118); + reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 1, 0)); + reg::Read(g_gpio_address + 0x00C); } void SetupI2c1() { diff --git a/libraries/libexosphere/source/uart/uart_api.cpp b/libraries/libexosphere/source/uart/uart_api.cpp index 02e6d59a3..aaeaf2a1e 100644 --- a/libraries/libexosphere/source/uart/uart_api.cpp +++ b/libraries/libexosphere/source/uart/uart_api.cpp @@ -33,11 +33,11 @@ namespace ams::uart { } void WaitSymbols(int baud, u32 num) { - util::WaitMicroSeconds(util::DivideUp(1'000'000, baud) * num); + util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, baud)); } void WaitCycles(int baud, u32 num) { - util::WaitMicroSeconds(util::DivideUp(1'000'000, 16 * baud) * num); + util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, 16 * baud)); } ALWAYS_INLINE void WaitFifoNotFull(volatile UartRegisters *uart) { @@ -60,26 +60,6 @@ namespace ams::uart { constexpr inline u32 LockBit = (1 << 6); - void Lock(volatile UartRegisters *reg) { - while (true) { - if (reg->mie != 0) { - continue; - } - - reg->irda_csr = LockBit; - - if (reg->mie == 0) { - break; - } - - reg->irda_csr = 0; - } - } - - void Unlock(volatile UartRegisters *reg) { - reg->irda_csr = 0; - } - } void SetRegisterAddress(uintptr_t address) { @@ -97,7 +77,13 @@ namespace ams::uart { constexpr u32 UartClock = 408000000; const u32 divisor = (UartClock + (baud_rate * 16) / 2) / (baud_rate * 16); - /* Disable DLAB and all interrupts. */ + /* Wait for idle state. */ + WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE); + + /* Wait 100 us. */ + util::WaitMicroSeconds(100); + + /* Disable interrupts. */ uart->lcr = uart->lcr & ~UART_LCR_DLAB; uart->ier = 0; uart->mcr = 0; @@ -128,8 +114,8 @@ namespace ams::uart { /* Wait for idle state. */ WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE); - /* Set scratch register to 0. */ - uart->spr = 0; + /* Wait 100 us. */ + util::WaitMicroSeconds(100); } void SendText(Port port, const void *data, size_t size) { @@ -139,10 +125,6 @@ namespace ams::uart { /* Get pointer to data. */ const u8 *p = static_cast(data); - /* Lock the uart registers. */ - Lock(uart); - ON_SCOPE_EXIT { Unlock(uart); }; - /* Send each byte. */ for (size_t i = 0; i < size; ++i) { WaitFifoNotFull(uart);