Merge pull request #7932 from bunnei/extended-mem-layout
Add extended memory layout (6GB) support and improve KResourceLimit management
This commit is contained in:
		| @@ -167,6 +167,7 @@ void RestoreGlobalState(bool is_powered_on) { | ||||
|  | ||||
|     // Core | ||||
|     values.use_multi_core.SetGlobal(true); | ||||
|     values.use_extended_memory_layout.SetGlobal(true); | ||||
|  | ||||
|     // CPU | ||||
|     values.cpu_accuracy.SetGlobal(true); | ||||
|   | ||||
| @@ -466,6 +466,7 @@ struct Values { | ||||
|  | ||||
|     // Core | ||||
|     Setting<bool> use_multi_core{true, "use_multi_core"}; | ||||
|     Setting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"}; | ||||
|  | ||||
|     // Cpu | ||||
|     RangedSetting<CPUAccuracy> cpu_accuracy{CPUAccuracy::Auto, CPUAccuracy::Auto, | ||||
|   | ||||
| @@ -28,7 +28,9 @@ | ||||
| #include "core/file_sys/vfs_real.h" | ||||
| #include "core/hardware_interrupt_manager.h" | ||||
| #include "core/hid/hid_core.h" | ||||
| #include "core/hle/kernel/k_memory_manager.h" | ||||
| #include "core/hle/kernel/k_process.h" | ||||
| #include "core/hle/kernel/k_resource_limit.h" | ||||
| #include "core/hle/kernel/k_scheduler.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/kernel/physical_core.h" | ||||
| @@ -252,9 +254,16 @@ struct System::Impl { | ||||
|         } | ||||
|  | ||||
|         telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); | ||||
|  | ||||
|         // Create a resource limit for the process. | ||||
|         const auto physical_memory_size = | ||||
|             kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application); | ||||
|         auto* resource_limit = Kernel::CreateResourceLimitForProcess(system, physical_memory_size); | ||||
|  | ||||
|         // Create the process. | ||||
|         auto main_process = Kernel::KProcess::Create(system.Kernel()); | ||||
|         ASSERT(Kernel::KProcess::Initialize(main_process, system, "main", | ||||
|                                             Kernel::KProcess::ProcessType::Userland) | ||||
|                                             Kernel::KProcess::ProcessType::Userland, resource_limit) | ||||
|                    .IsSuccess()); | ||||
|         const auto [load_result, load_parameters] = app_loader->Load(*main_process, system); | ||||
|         if (load_result != Loader::ResultStatus::Success) { | ||||
|   | ||||
| @@ -3,10 +3,13 @@ | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "core/device_memory.h" | ||||
| #include "hle/kernel/board/nintendo/nx/k_system_control.h" | ||||
|  | ||||
| namespace Core { | ||||
|  | ||||
| DeviceMemory::DeviceMemory() : buffer{DramMemoryMap::Size, 1ULL << 39} {} | ||||
| DeviceMemory::DeviceMemory() | ||||
|     : buffer{Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize(), | ||||
|              1ULL << 39} {} | ||||
| DeviceMemory::~DeviceMemory() = default; | ||||
|  | ||||
| } // namespace Core | ||||
|   | ||||
| @@ -12,12 +12,8 @@ namespace Core { | ||||
| namespace DramMemoryMap { | ||||
| enum : u64 { | ||||
|     Base = 0x80000000ULL, | ||||
|     Size = 0x100000000ULL, | ||||
|     End = Base + Size, | ||||
|     KernelReserveBase = Base + 0x60000, | ||||
|     SlabHeapBase = KernelReserveBase + 0x85000, | ||||
|     SlapHeapSize = 0xa21000, | ||||
|     SlabHeapEnd = SlabHeapBase + SlapHeapSize, | ||||
| }; | ||||
| }; // namespace DramMemoryMap | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,7 @@ | ||||
| #include <random> | ||||
|  | ||||
| #include "common/literals.h" | ||||
| #include "common/settings.h" | ||||
|  | ||||
| #include "core/hle/kernel/board/nintendo/nx/k_system_control.h" | ||||
| #include "core/hle/kernel/board/nintendo/nx/secure_monitor.h" | ||||
| @@ -28,30 +29,13 @@ namespace { | ||||
|  | ||||
| using namespace Common::Literals; | ||||
|  | ||||
| u32 GetMemoryModeForInit() { | ||||
|     return 0x01; | ||||
| } | ||||
|  | ||||
| u32 GetMemorySizeForInit() { | ||||
|     return 0; | ||||
|     return Settings::values.use_extended_memory_layout ? Smc::MemorySize_6GB : Smc::MemorySize_4GB; | ||||
| } | ||||
|  | ||||
| Smc::MemoryArrangement GetMemoryArrangeForInit() { | ||||
|     switch (GetMemoryModeForInit() & 0x3F) { | ||||
|     case 0x01: | ||||
|     default: | ||||
|         return Smc::MemoryArrangement_4GB; | ||||
|     case 0x02: | ||||
|         return Smc::MemoryArrangement_4GBForAppletDev; | ||||
|     case 0x03: | ||||
|         return Smc::MemoryArrangement_4GBForSystemDev; | ||||
|     case 0x11: | ||||
|         return Smc::MemoryArrangement_6GB; | ||||
|     case 0x12: | ||||
|         return Smc::MemoryArrangement_6GBForAppletDev; | ||||
|     case 0x21: | ||||
|         return Smc::MemoryArrangement_8GB; | ||||
|     } | ||||
|     return Settings::values.use_extended_memory_layout ? Smc::MemoryArrangement_6GB | ||||
|                                                        : Smc::MemoryArrangement_4GB; | ||||
| } | ||||
| } // namespace | ||||
|  | ||||
|   | ||||
| @@ -14,7 +14,7 @@ KEvent::KEvent(KernelCore& kernel_) | ||||
|  | ||||
| KEvent::~KEvent() = default; | ||||
|  | ||||
| void KEvent::Initialize(std::string&& name_) { | ||||
| void KEvent::Initialize(std::string&& name_, KProcess* owner_) { | ||||
|     // Increment reference count. | ||||
|     // Because reference count is one on creation, this will result | ||||
|     // in a reference count of two. Thus, when both readable and | ||||
| @@ -30,10 +30,8 @@ void KEvent::Initialize(std::string&& name_) { | ||||
|     writable_event.Initialize(this, name_ + ":Writable"); | ||||
|  | ||||
|     // Set our owner process. | ||||
|     owner = kernel.CurrentProcess(); | ||||
|     if (owner) { | ||||
|     owner = owner_; | ||||
|     owner->Open(); | ||||
|     } | ||||
|  | ||||
|     // Mark initialized. | ||||
|     name = std::move(name_); | ||||
| @@ -47,10 +45,8 @@ void KEvent::Finalize() { | ||||
| void KEvent::PostDestroy(uintptr_t arg) { | ||||
|     // Release the event count resource the owner process holds. | ||||
|     KProcess* owner = reinterpret_cast<KProcess*>(arg); | ||||
|     if (owner) { | ||||
|     owner->GetResourceLimit()->Release(LimitableResource::Events, 1); | ||||
|     owner->Close(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -22,7 +22,7 @@ public: | ||||
|     explicit KEvent(KernelCore& kernel_); | ||||
|     ~KEvent() override; | ||||
|  | ||||
|     void Initialize(std::string&& name); | ||||
|     void Initialize(std::string&& name, KProcess* owner_); | ||||
|  | ||||
|     void Finalize() override; | ||||
|  | ||||
|   | ||||
| @@ -123,12 +123,11 @@ private: | ||||
| }; | ||||
|  | ||||
| ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::string process_name, | ||||
|                                 ProcessType type) { | ||||
|                                 ProcessType type, KResourceLimit* res_limit) { | ||||
|     auto& kernel = system.Kernel(); | ||||
|  | ||||
|     process->name = std::move(process_name); | ||||
|  | ||||
|     process->resource_limit = kernel.GetSystemResourceLimit(); | ||||
|     process->resource_limit = res_limit; | ||||
|     process->status = ProcessStatus::Created; | ||||
|     process->program_id = 0; | ||||
|     process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() | ||||
| @@ -143,9 +142,6 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st | ||||
|  | ||||
|     kernel.AppendNewProcess(process); | ||||
|  | ||||
|     // Open a reference to the resource limit. | ||||
|     process->resource_limit->Open(); | ||||
|  | ||||
|     // Clear remaining fields. | ||||
|     process->num_running_threads = 0; | ||||
|     process->is_signaled = false; | ||||
| @@ -153,6 +149,9 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st | ||||
|     process->is_suspended = false; | ||||
|     process->schedule_count = 0; | ||||
|  | ||||
|     // Open a reference to the resource limit. | ||||
|     process->resource_limit->Open(); | ||||
|  | ||||
|     return ResultSuccess; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -91,7 +91,7 @@ public: | ||||
|     static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4; | ||||
|  | ||||
|     static ResultCode Initialize(KProcess* process, Core::System& system, std::string process_name, | ||||
|                                  ProcessType type); | ||||
|                                  ProcessType type, KResourceLimit* res_limit); | ||||
|  | ||||
|     /// Gets a reference to the process' page table. | ||||
|     KPageTable& PageTable() { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "common/assert.h" | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/k_resource_limit.h" | ||||
| #include "core/hle/kernel/svc_results.h" | ||||
| @@ -151,4 +152,22 @@ void KResourceLimit::Release(LimitableResource which, s64 value, s64 hint) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size) { | ||||
|     auto* resource_limit = KResourceLimit::Create(system.Kernel()); | ||||
|     resource_limit->Initialize(&system.CoreTiming()); | ||||
|  | ||||
|     // Initialize default resource limit values. | ||||
|     // TODO(bunnei): These values are the system defaults, the limits for service processes are | ||||
|     // lower. These should use the correct limit values. | ||||
|  | ||||
|     ASSERT(resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, physical_memory_size) | ||||
|                .IsSuccess()); | ||||
|     ASSERT(resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); | ||||
|     ASSERT(resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess()); | ||||
|     ASSERT(resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200).IsSuccess()); | ||||
|     ASSERT(resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess()); | ||||
|  | ||||
|     return resource_limit; | ||||
| } | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -67,4 +67,7 @@ private: | ||||
|     KLightConditionVariable cond_var; | ||||
|     const Core::Timing::CoreTiming* core_timing{}; | ||||
| }; | ||||
|  | ||||
| KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical_memory_size); | ||||
|  | ||||
| } // namespace Kernel | ||||
|   | ||||
| @@ -240,13 +240,6 @@ struct KernelCore::Impl { | ||||
|         constexpr u64 secure_applet_memory_size{4_MiB}; | ||||
|         ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, | ||||
|                                               secure_applet_memory_size)); | ||||
|  | ||||
|         // This memory seems to be reserved on hardware, but is not reserved/used by yuzu. | ||||
|         // Likely Horizon OS reserved memory | ||||
|         // TODO(ameerj): Derive the memory rather than hardcode it. | ||||
|         constexpr u64 unknown_reserved_memory{0x2f896000}; | ||||
|         ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, | ||||
|                                               unknown_reserved_memory)); | ||||
|     } | ||||
|  | ||||
|     void InitializePreemption(KernelCore& kernel) { | ||||
|   | ||||
| @@ -2332,7 +2332,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* out_write, Handle* o | ||||
|     R_UNLESS(event != nullptr, ResultOutOfResource); | ||||
|  | ||||
|     // Initialize the event. | ||||
|     event->Initialize("CreateEvent"); | ||||
|     event->Initialize("CreateEvent", kernel.CurrentProcess()); | ||||
|  | ||||
|     // Commit the thread reservation. | ||||
|     event_reservation.Commit(); | ||||
|   | ||||
| @@ -3,7 +3,9 @@ | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include "core/core.h" | ||||
| #include "core/core_timing.h" | ||||
| #include "core/hle/kernel/k_event.h" | ||||
| #include "core/hle/kernel/k_memory_manager.h" | ||||
| #include "core/hle/kernel/k_process.h" | ||||
| #include "core/hle/kernel/k_readable_event.h" | ||||
| #include "core/hle/kernel/k_resource_limit.h" | ||||
| @@ -15,10 +17,21 @@ namespace Service::KernelHelpers { | ||||
|  | ||||
| ServiceContext::ServiceContext(Core::System& system_, std::string name_) | ||||
|     : kernel(system_.Kernel()) { | ||||
|  | ||||
|     // Create a resource limit for the process. | ||||
|     const auto physical_memory_size = | ||||
|         kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::System); | ||||
|     auto* resource_limit = Kernel::CreateResourceLimitForProcess(system_, physical_memory_size); | ||||
|  | ||||
|     // Create the process. | ||||
|     process = Kernel::KProcess::Create(kernel); | ||||
|     ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_), | ||||
|                                         Kernel::KProcess::ProcessType::Userland) | ||||
|                                         Kernel::KProcess::ProcessType::KernelInternal, | ||||
|                                         resource_limit) | ||||
|                .IsSuccess()); | ||||
|  | ||||
|     // Close reference to our resource limit, as the process opens one. | ||||
|     resource_limit->Close(); | ||||
| } | ||||
|  | ||||
| ServiceContext::~ServiceContext() { | ||||
| @@ -43,7 +56,7 @@ Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) { | ||||
|     } | ||||
|  | ||||
|     // Initialize the event. | ||||
|     event->Initialize(std::move(name)); | ||||
|     event->Initialize(std::move(name), process); | ||||
|  | ||||
|     // Commit the thread reservation. | ||||
|     event_reservation.Commit(); | ||||
|   | ||||
| @@ -39,8 +39,7 @@ struct Memory::Impl { | ||||
|     void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target) { | ||||
|         ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); | ||||
|         ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); | ||||
|         ASSERT_MSG(target >= DramMemoryMap::Base && target < DramMemoryMap::End, | ||||
|                    "Out of bounds target: {:016X}", target); | ||||
|         ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", target); | ||||
|         MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); | ||||
|  | ||||
|         if (Settings::IsFastmemEnabled()) { | ||||
|   | ||||
| @@ -445,6 +445,7 @@ void Config::ReadCoreValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("Core")); | ||||
|  | ||||
|     ReadGlobalSetting(Settings::values.use_multi_core); | ||||
|     ReadGlobalSetting(Settings::values.use_extended_memory_layout); | ||||
|  | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
| @@ -1019,6 +1020,7 @@ void Config::SaveCoreValues() { | ||||
|     qt_config->beginGroup(QStringLiteral("Core")); | ||||
|  | ||||
|     WriteGlobalSetting(Settings::values.use_multi_core); | ||||
|     WriteGlobalSetting(Settings::values.use_extended_memory_layout); | ||||
|  | ||||
|     qt_config->endGroup(); | ||||
| } | ||||
|   | ||||
| @@ -42,6 +42,9 @@ void ConfigureGeneral::SetConfiguration() { | ||||
|  | ||||
|     ui->use_multi_core->setEnabled(runtime_lock); | ||||
|     ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue()); | ||||
|     ui->use_extended_memory_layout->setEnabled(runtime_lock); | ||||
|     ui->use_extended_memory_layout->setChecked( | ||||
|         Settings::values.use_extended_memory_layout.GetValue()); | ||||
|  | ||||
|     ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing.GetValue()); | ||||
|     ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot.GetValue()); | ||||
| @@ -91,6 +94,9 @@ void ConfigureGeneral::ResetDefaults() { | ||||
| void ConfigureGeneral::ApplyConfiguration() { | ||||
|     ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core, | ||||
|                                              use_multi_core); | ||||
|     ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_extended_memory_layout, | ||||
|                                              ui->use_extended_memory_layout, | ||||
|                                              use_extended_memory_layout); | ||||
|  | ||||
|     if (Settings::IsConfiguringGlobal()) { | ||||
|         UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); | ||||
| @@ -160,6 +166,9 @@ void ConfigureGeneral::SetupPerGameUI() { | ||||
|                                             Settings::values.use_speed_limit, use_speed_limit); | ||||
|     ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, | ||||
|                                             use_multi_core); | ||||
|     ConfigurationShared::SetColoredTristate(ui->use_extended_memory_layout, | ||||
|                                             Settings::values.use_extended_memory_layout, | ||||
|                                             use_extended_memory_layout); | ||||
|  | ||||
|     connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() { | ||||
|         ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() && | ||||
|   | ||||
| @@ -48,6 +48,7 @@ private: | ||||
|  | ||||
|     ConfigurationShared::CheckState use_speed_limit; | ||||
|     ConfigurationShared::CheckState use_multi_core; | ||||
|     ConfigurationShared::CheckState use_extended_memory_layout; | ||||
|  | ||||
|     const Core::System& system; | ||||
| }; | ||||
|   | ||||
| @@ -142,6 +142,13 @@ | ||||
|             </property> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item> | ||||
|            <widget class="QCheckBox" name="use_extended_memory_layout"> | ||||
|             <property name="text"> | ||||
|              <string>Extended memory layout (6GB DRAM)</string> | ||||
|             </property> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item> | ||||
|            <widget class="QCheckBox" name="toggle_check_exit"> | ||||
|             <property name="text"> | ||||
|   | ||||
| @@ -266,6 +266,7 @@ void Config::ReadValues() { | ||||
|  | ||||
|     // Core | ||||
|     ReadSetting("Core", Settings::values.use_multi_core); | ||||
|     ReadSetting("Core", Settings::values.use_extended_memory_layout); | ||||
|  | ||||
|     // Cpu | ||||
|     ReadSetting("Cpu", Settings::values.cpu_accuracy); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bunnei
					bunnei