diff --git a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_memory_region_device_types.inc b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_memory_region_device_types.inc index 0a81445bd..7fc77b6c1 100644 --- a/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_memory_region_device_types.inc +++ b/libraries/libmesosphere/include/mesosphere/board/nintendo/nx/kern_k_memory_region_device_types.inc @@ -15,13 +15,32 @@ */ /* All architectures must define NumBoardDeviceRegions. */ -constexpr inline const auto NumBoardDeviceRegions = 5; +constexpr inline const auto NumBoardDeviceRegions = 6; /* UNUSED: .Derive(NumBoardDeviceRegions, 0); */ constexpr inline const auto KMemoryRegionType_MemoryController = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_MemoryController1 = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_MemoryController0 = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3).SetAttribute(KMemoryRegionAttr_NoUserMap); constexpr inline const auto KMemoryRegionType_PowerManagementController = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition(); +constexpr inline const auto KMemoryRegionType_LegacyLpsDevices = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5); static_assert(KMemoryRegionType_MemoryController .GetValue() == (0x55 | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_MemoryController1 .GetValue() == (0x65 | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_MemoryController0 .GetValue() == (0x95 | KMemoryRegionAttr_NoUserMap)); static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5)); + +static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5); + +constexpr inline const auto NumLegacyLpsDevices = 7; +constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0); +constexpr inline const auto KMemoryRegionType_LegacyLpsIram = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1); +constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2); +constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3); +constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4); +constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5); +constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6); +static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5); +static_assert(KMemoryRegionType_LegacyLpsIram .GetValue() == 0x5C5); +static_assert(KMemoryRegionType_LegacyLpsFlowController .GetValue() == 0x6C5); +static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr .GetValue() == 0x9C5); +static_assert(KMemoryRegionType_LegacyLpsSemaphore .GetValue() == 0xAC5); +static_assert(KMemoryRegionType_LegacyLpsAtomics .GetValue() == 0xCC5); +static_assert(KMemoryRegionType_LegacyLpsClkRst .GetValue() == 0x11C5); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp index 0e3f4f602..96817b1a4 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.cpp @@ -16,6 +16,7 @@ #include #include "kern_k_sleep_manager.hpp" #include "kern_secure_monitor.hpp" +#include "kern_lps_driver.hpp" namespace ams::kern::board::nintendo::nx { @@ -472,7 +473,8 @@ namespace ams::kern::board::nintendo::nx { } void KSleepManager::ProcessRequests(uintptr_t buffer) { - const s32 core_id = GetCurrentCoreId(); + const auto target_fw = GetTargetFirmware(); + const s32 core_id = GetCurrentCoreId(); KPhysicalAddress resume_entry_phys_addr = Null; /* Get the physical addresses we'll need. */ @@ -484,6 +486,8 @@ namespace ams::kern::board::nintendo::nx { const KPhysicalAddress sleep_buffer_phys_addr = g_sleep_buffer_phys_addrs[core_id]; const u64 target_core_mask = (1ul << core_id); + const bool use_legacy_lps_driver = target_fw < TargetFirmware_2_0_0; + /* Loop, processing sleep when requested. */ while (true) { /* Wait for a request. */ @@ -494,6 +498,11 @@ namespace ams::kern::board::nintendo::nx { } } + /* If on core 0, ensure the legacy lps driver is initialized. */ + if (use_legacy_lps_driver && core_id == 0) { + lps::Initialize(); + } + /* Perform Sleep/Wake sequence. */ { /* Disable interrupts. */ @@ -550,6 +559,11 @@ namespace ams::kern::board::nintendo::nx { /* Wait for all other cores to be powered off. */ WaitOtherCpuPowerOff(); + /* If we're using the legacy lps driver, enable suspend. */ + if (use_legacy_lps_driver) { + MESOSPHERE_R_ABORT_UNLESS(lps::EnableSuspend()); + } + /* Log that we're about to enter SC7. */ MESOSPHERE_LOG("Entering SC7\n"); @@ -557,7 +571,12 @@ namespace ams::kern::board::nintendo::nx { KDebugLog::Save(); /* Invoke the sleep handler. */ - CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr)); + if (!use_legacy_lps_driver) { + /* When not using the legacy driver, invoke directly. */ + CpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr)); + } else { + lps::InvokeCpuSleepHandler(GetInteger(sleep_buffer_phys_addr), GetInteger(resume_entry_phys_addr)); + } /* Restore the debug log state. */ KDebugLog::Restore(); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp index f39ce7b67..64f3ddcb6 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_sleep_manager.hpp @@ -20,7 +20,6 @@ namespace ams::kern::board::nintendo::nx { class KSleepManager { private: - static void CpuSleepHandler(uintptr_t arg, uintptr_t entry); static void ResumeEntry(uintptr_t arg); static void InvalidateDataCacheForResumeEntry(uintptr_t level); @@ -29,6 +28,8 @@ namespace ams::kern::board::nintendo::nx { public: static void Initialize(); static void SleepSystem(); + public: + static void CpuSleepHandler(uintptr_t arg, uintptr_t entry); }; diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp new file mode 100644 index 000000000..74c3b8ab7 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "kern_lps_driver.hpp" +#include "kern_k_sleep_manager.hpp" + +namespace ams::kern::board::nintendo::nx::lps { + + namespace { + + constinit bool g_lps_init_done = false; + + } + + void Initialize() { + if (!g_lps_init_done) { + MESOSPHERE_UNIMPLEMENTED(); + + g_lps_init_done = true; + } + } + + Result EnableSuspend() { + MESOSPHERE_UNIMPLEMENTED(); + } + + void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry) { + MESOSPHERE_ABORT_UNLESS(g_lps_init_done); + MESOSPHERE_ABORT_UNLESS(GetCurrentCoreId() == 0); + + MESOSPHERE_UNIMPLEMENTED(); + + /* Invoke the sleep hander. */ + KSleepManager::CpuSleepHandler(arg, entry); + } + +} \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp new file mode 100644 index 000000000..e63e409b7 --- /dev/null +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_lps_driver.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::kern::board::nintendo::nx { + + namespace lps { + + void Initialize(); + Result EnableSuspend(); + void InvokeCpuSleepHandler(uintptr_t arg, uintptr_t entry); + + } + +} \ No newline at end of file diff --git a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp index f592f0716..91f86486b 100644 --- a/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp +++ b/libraries/libmesosphere/source/kern_k_memory_layout.board.nintendo_nx.cpp @@ -63,16 +63,29 @@ namespace ams::kern { /* TODO: Give these constexpr defines somewhere? */ MESOSPHERE_INIT_ABORT_UNLESS(SetupUartPhysicalMemoryRegion()); MESOSPHERE_INIT_ABORT_UNLESS(SetupPowerManagementControllerMemoryRegion()); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50041000, 0x1000, KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50042000, 0x1000, KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70019000, 0x1000, KMemoryRegionType_MemoryController | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001C000, 0x1000, KMemoryRegionType_MemoryController0 | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x7001D000, 0x1000, KMemoryRegionType_MemoryController1 | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50040000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50041000, 0x1000, KMemoryRegionType_InterruptDistributor | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50042000, 0x1000, KMemoryRegionType_InterruptCpuInterface | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x50043000, 0x1D000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + + /* Map IRAM unconditionally, to support debug-logging-to-iram build config. */ + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x40000000, 0x40000, KMemoryRegionType_LegacyLpsIram | KMemoryRegionAttr_ShouldKernelMap)); + if (GetTargetFirmware() >= TargetFirmware_2_0_0) { - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); - MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + /* Prevent mapping the bpmp exception vectors or the ipatch region. */ + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6001DC00, 0x400, KMemoryRegionType_None | KMemoryRegionAttr_NoUserMap)); + } else { + /* Map devices required for legacy lps driver. */ + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x6000F000, 0x1000, KMemoryRegionType_LegacyLpsExceptionVectors | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60007000, 0x1000, KMemoryRegionType_LegacyLpsFlowController | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60004000, 0x1000, KMemoryRegionType_LegacyLpsPrimaryICtlr | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60001000, 0x1000, KMemoryRegionType_LegacyLpsSemaphore | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70016000, 0x1000, KMemoryRegionType_LegacyLpsAtomics | KMemoryRegionAttr_ShouldKernelMap)); + MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x60006000, 0x1000, KMemoryRegionType_LegacyLpsClkRst | KMemoryRegionAttr_ShouldKernelMap)); } }