summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/kernel/k_page_table.cpp105
-rw-r--r--src/core/hle/kernel/k_page_table.h7
-rw-r--r--src/core/hle/kernel/k_process.cpp12
-rw-r--r--src/core/hle/kernel/physical_core.cpp18
-rw-r--r--src/core/hle/kernel/svc.cpp8
-rw-r--r--src/core/hle/service/ldr/ldr.cpp38
6 files changed, 107 insertions, 81 deletions
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 6077985b5..27d86c9a4 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -298,7 +298,7 @@ ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemory
298 return ResultSuccess; 298 return ResultSuccess;
299} 299}
300 300
301ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { 301ResultCode KPageTable::MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
302 std::lock_guard lock{page_table_lock}; 302 std::lock_guard lock{page_table_lock};
303 303
304 const std::size_t num_pages{size / PageSize}; 304 const std::size_t num_pages{size / PageSize};
@@ -307,7 +307,7 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:
307 KMemoryPermission perm{}; 307 KMemoryPermission perm{};
308 CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size, 308 CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, nullptr, src_addr, size,
309 KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All, 309 KMemoryState::All, KMemoryState::Normal, KMemoryPermission::All,
310 KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, 310 KMemoryPermission::UserReadWrite, KMemoryAttribute::Mask,
311 KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); 311 KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
312 312
313 if (IsRegionMapped(dst_addr, size)) { 313 if (IsRegionMapped(dst_addr, size)) {
@@ -335,7 +335,7 @@ ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:
335 return ResultSuccess; 335 return ResultSuccess;
336} 336}
337 337
338ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { 338ResultCode KPageTable::UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) {
339 std::lock_guard lock{page_table_lock}; 339 std::lock_guard lock{page_table_lock};
340 340
341 if (!size) { 341 if (!size) {
@@ -361,7 +361,7 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st
361 361
362 block_manager->Update(dst_addr, num_pages, KMemoryState::Free); 362 block_manager->Update(dst_addr, num_pages, KMemoryState::Free);
363 block_manager->Update(src_addr, num_pages, KMemoryState::Normal, 363 block_manager->Update(src_addr, num_pages, KMemoryState::Normal,
364 KMemoryPermission::ReadAndWrite); 364 KMemoryPermission::UserReadWrite);
365 365
366 system.InvalidateCpuInstructionCacheRange(dst_addr, size); 366 system.InvalidateCpuInstructionCacheRange(dst_addr, size);
367 367
@@ -416,7 +416,7 @@ void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr star
416 } 416 }
417 417
418 const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; 418 const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)};
419 Operate(dst_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::Map, 419 Operate(dst_addr, num_pages, KMemoryPermission::UserReadWrite, OperationType::Map,
420 map_addr); 420 map_addr);
421 421
422 dst_addr += num_pages * PageSize; 422 dst_addr += num_pages * PageSize;
@@ -470,7 +470,7 @@ ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) {
470 const std::size_t num_pages{size / PageSize}; 470 const std::size_t num_pages{size / PageSize};
471 block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, 471 block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
472 KMemoryAttribute::None, KMemoryState::Normal, 472 KMemoryAttribute::None, KMemoryState::Normal,
473 KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); 473 KMemoryPermission::UserReadWrite, KMemoryAttribute::None);
474 474
475 return ResultSuccess; 475 return ResultSuccess;
476} 476}
@@ -554,7 +554,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
554 KMemoryState src_state{}; 554 KMemoryState src_state{};
555 CASCADE_CODE(CheckMemoryState( 555 CASCADE_CODE(CheckMemoryState(
556 &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, 556 &src_state, nullptr, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias,
557 KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::ReadAndWrite, 557 KMemoryState::FlagCanAlias, KMemoryPermission::All, KMemoryPermission::UserReadWrite,
558 KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); 558 KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped));
559 559
560 if (IsRegionMapped(dst_addr, size)) { 560 if (IsRegionMapped(dst_addr, size)) {
@@ -568,13 +568,13 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
568 568
569 { 569 {
570 auto block_guard = detail::ScopeExit([&] { 570 auto block_guard = detail::ScopeExit([&] {
571 Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, 571 Operate(src_addr, num_pages, KMemoryPermission::UserReadWrite,
572 OperationType::ChangePermissions); 572 OperationType::ChangePermissions);
573 }); 573 });
574 574
575 CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, 575 CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None,
576 OperationType::ChangePermissions)); 576 OperationType::ChangePermissions));
577 CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::ReadAndWrite)); 577 CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::UserReadWrite));
578 578
579 block_guard.Cancel(); 579 block_guard.Cancel();
580 } 580 }
@@ -582,7 +582,7 @@ ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) {
582 block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None, 582 block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None,
583 KMemoryAttribute::Locked); 583 KMemoryAttribute::Locked);
584 block_manager->Update(dst_addr, num_pages, KMemoryState::Stack, 584 block_manager->Update(dst_addr, num_pages, KMemoryState::Stack,
585 KMemoryPermission::ReadAndWrite); 585 KMemoryPermission::UserReadWrite);
586 586
587 return ResultSuccess; 587 return ResultSuccess;
588} 588}
@@ -617,13 +617,13 @@ ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) {
617 auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); }); 617 auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); });
618 618
619 CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); 619 CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap));
620 CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, 620 CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::UserReadWrite,
621 OperationType::ChangePermissions)); 621 OperationType::ChangePermissions));
622 622
623 block_guard.Cancel(); 623 block_guard.Cancel();
624 } 624 }
625 625
626 block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::ReadAndWrite); 626 block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::UserReadWrite);
627 block_manager->Update(dst_addr, num_pages, KMemoryState::Free); 627 block_manager->Update(dst_addr, num_pages, KMemoryState::Free);
628 628
629 return ResultSuccess; 629 return ResultSuccess;
@@ -713,50 +713,61 @@ ResultCode KPageTable::UnmapPages(VAddr addr, KPageLinkedList& page_linked_list,
713} 713}
714 714
715ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size, 715ResultCode KPageTable::SetProcessMemoryPermission(VAddr addr, std::size_t size,
716 KMemoryPermission perm) { 716 Svc::MemoryPermission svc_perm) {
717 const size_t num_pages = size / PageSize;
717 718
719 // Lock the table.
718 std::lock_guard lock{page_table_lock}; 720 std::lock_guard lock{page_table_lock};
719 721
720 KMemoryState prev_state{}; 722 // Verify we can change the memory permission.
721 KMemoryPermission prev_perm{}; 723 KMemoryState old_state;
722 724 KMemoryPermission old_perm;
723 CASCADE_CODE(CheckMemoryState( 725 size_t num_allocator_blocks;
724 &prev_state, &prev_perm, nullptr, nullptr, addr, size, KMemoryState::FlagCode, 726 R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), nullptr,
725 KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, 727 std::addressof(num_allocator_blocks), addr, size,
726 KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); 728 KMemoryState::FlagCode, KMemoryState::FlagCode,
727 729 KMemoryPermission::None, KMemoryPermission::None,
728 KMemoryState state{prev_state}; 730 KMemoryAttribute::All, KMemoryAttribute::None));
729 731
730 // Ensure state is mutable if permission allows write 732 // Determine new perm/state.
731 if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) { 733 const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm);
732 if (prev_state == KMemoryState::Code) { 734 KMemoryState new_state = old_state;
733 state = KMemoryState::CodeData; 735 const bool is_w = (new_perm & KMemoryPermission::UserWrite) == KMemoryPermission::UserWrite;
734 } else if (prev_state == KMemoryState::AliasCode) { 736 const bool is_x = (new_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute;
735 state = KMemoryState::AliasCodeData; 737 const bool was_x =
736 } else { 738 (old_perm & KMemoryPermission::UserExecute) == KMemoryPermission::UserExecute;
739 ASSERT(!(is_w && is_x));
740
741 if (is_w) {
742 switch (old_state) {
743 case KMemoryState::Code:
744 new_state = KMemoryState::CodeData;
745 break;
746 case KMemoryState::AliasCode:
747 new_state = KMemoryState::AliasCodeData;
748 break;
749 default:
737 UNREACHABLE(); 750 UNREACHABLE();
738 } 751 }
739 } 752 }
740 753
741 // Return early if there is nothing to change 754 // Succeed if there's nothing to do.
742 if (state == prev_state && perm == prev_perm) { 755 R_SUCCEED_IF(old_perm == new_perm && old_state == new_state);
743 return ResultSuccess;
744 }
745 756
746 if ((prev_perm & KMemoryPermission::Execute) != (perm & KMemoryPermission::Execute)) { 757 // Perform mapping operation.
758 const auto operation =
759 was_x ? OperationType::ChangePermissionsAndRefresh : OperationType::ChangePermissions;
760 R_TRY(Operate(addr, num_pages, new_perm, operation));
761
762 // Update the blocks.
763 block_manager->Update(addr, num_pages, new_state, new_perm, KMemoryAttribute::None);
764
765 // Ensure cache coherency, if we're setting pages as executable.
766 if (is_x) {
747 // Memory execution state is changing, invalidate CPU cache range 767 // Memory execution state is changing, invalidate CPU cache range
748 system.InvalidateCpuInstructionCacheRange(addr, size); 768 system.InvalidateCpuInstructionCacheRange(addr, size);
749 } 769 }
750 770
751 const std::size_t num_pages{size / PageSize};
752 const OperationType operation{(perm & KMemoryPermission::Execute) != KMemoryPermission::None
753 ? OperationType::ChangePermissionsAndRefresh
754 : OperationType::ChangePermissions};
755
756 CASCADE_CODE(Operate(addr, num_pages, perm, operation));
757
758 block_manager->Update(addr, num_pages, state, perm);
759
760 return ResultSuccess; 771 return ResultSuccess;
761} 772}
762 773
@@ -785,7 +796,7 @@ ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemo
785 &state, nullptr, &attribute, nullptr, addr, size, 796 &state, nullptr, &attribute, nullptr, addr, size,
786 KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, 797 KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted,
787 KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All, 798 KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::All,
788 KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, 799 KMemoryPermission::UserReadWrite, KMemoryAttribute::Mask, KMemoryAttribute::None,
789 KMemoryAttribute::IpcAndDeviceMapped)); 800 KMemoryAttribute::IpcAndDeviceMapped));
790 801
791 block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked); 802 block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked);
@@ -805,7 +816,7 @@ ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) {
805 KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, 816 KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask,
806 KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); 817 KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped));
807 818
808 block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); 819 block_manager->Update(addr, size / PageSize, state, KMemoryPermission::UserReadWrite);
809 return ResultSuccess; 820 return ResultSuccess;
810} 821}
811 822
@@ -906,7 +917,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
906 R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), 917 R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks),
907 heap_region_start + size, GetHeapSize() - size, 918 heap_region_start + size, GetHeapSize() - size,
908 KMemoryState::All, KMemoryState::Normal, 919 KMemoryState::All, KMemoryState::Normal,
909 KMemoryPermission::All, KMemoryPermission::ReadAndWrite, 920 KMemoryPermission::All, KMemoryPermission::UserReadWrite,
910 KMemoryAttribute::All, KMemoryAttribute::None)); 921 KMemoryAttribute::All, KMemoryAttribute::None));
911 922
912 // Unmap the end of the heap. 923 // Unmap the end of the heap.
@@ -981,7 +992,7 @@ ResultCode KPageTable::SetHeapSize(VAddr* out, std::size_t size) {
981 992
982 // Apply the memory block update. 993 // Apply the memory block update.
983 block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal, 994 block_manager->Update(current_heap_end, num_pages, KMemoryState::Normal,
984 KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); 995 KMemoryPermission::UserReadWrite, KMemoryAttribute::None);
985 996
986 // Update the current heap end. 997 // Update the current heap end.
987 current_heap_end = heap_region_start + size; 998 current_heap_end = heap_region_start + size;
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 9235b822a..274644181 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -31,8 +31,8 @@ public:
31 KMemoryManager::Pool pool); 31 KMemoryManager::Pool pool);
32 ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, 32 ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
33 KMemoryPermission perm); 33 KMemoryPermission perm);
34 ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); 34 ResultCode MapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
35 ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); 35 ResultCode UnmapCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size);
36 ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, 36 ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
37 VAddr src_addr); 37 VAddr src_addr);
38 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); 38 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
@@ -43,7 +43,8 @@ public:
43 ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, 43 ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state,
44 KMemoryPermission perm); 44 KMemoryPermission perm);
45 ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state); 45 ResultCode UnmapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state);
46 ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); 46 ResultCode SetProcessMemoryPermission(VAddr addr, std::size_t size,
47 Svc::MemoryPermission svc_perm);
47 KMemoryInfo QueryInfo(VAddr addr); 48 KMemoryInfo QueryInfo(VAddr addr);
48 ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); 49 ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm);
49 ResultCode ResetTransferMemory(VAddr addr, std::size_t size); 50 ResultCode ResetTransferMemory(VAddr addr, std::size_t size);
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index bf98a51e2..cca405fed 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -509,7 +509,7 @@ VAddr KProcess::CreateTLSRegion() {
509 const VAddr tls_page_addr{page_table 509 const VAddr tls_page_addr{page_table
510 ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, 510 ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize,
511 KMemoryState::ThreadLocal, 511 KMemoryState::ThreadLocal,
512 KMemoryPermission::ReadAndWrite, 512 KMemoryPermission::UserReadWrite,
513 tls_map_addr) 513 tls_map_addr)
514 .ValueOr(0)}; 514 .ValueOr(0)};
515 515
@@ -541,16 +541,16 @@ void KProcess::FreeTLSRegion(VAddr tls_address) {
541 541
542void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) { 542void KProcess::LoadModule(CodeSet code_set, VAddr base_addr) {
543 const auto ReprotectSegment = [&](const CodeSet::Segment& segment, 543 const auto ReprotectSegment = [&](const CodeSet::Segment& segment,
544 KMemoryPermission permission) { 544 Svc::MemoryPermission permission) {
545 page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission); 545 page_table->SetProcessMemoryPermission(segment.addr + base_addr, segment.size, permission);
546 }; 546 };
547 547
548 kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(), 548 kernel.System().Memory().WriteBlock(*this, base_addr, code_set.memory.data(),
549 code_set.memory.size()); 549 code_set.memory.size());
550 550
551 ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); 551 ReprotectSegment(code_set.CodeSegment(), Svc::MemoryPermission::ReadExecute);
552 ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); 552 ReprotectSegment(code_set.RODataSegment(), Svc::MemoryPermission::Read);
553 ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite); 553 ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
554} 554}
555 555
556bool KProcess::IsSignaled() const { 556bool KProcess::IsSignaled() const {
@@ -587,7 +587,7 @@ ResultCode KProcess::AllocateMainThreadStack(std::size_t stack_size) {
587 CASCADE_RESULT(main_thread_stack_top, 587 CASCADE_RESULT(main_thread_stack_top,
588 page_table->AllocateAndMapMemory( 588 page_table->AllocateAndMapMemory(
589 main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize, 589 main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize,
590 KMemoryState::Stack, KMemoryPermission::ReadAndWrite)); 590 KMemoryState::Stack, KMemoryPermission::UserReadWrite));
591 591
592 main_thread_stack_top += main_thread_stack_size; 592 main_thread_stack_top += main_thread_stack_size;
593 593
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 7f02d9471..7477668e4 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -16,17 +16,25 @@ namespace Kernel {
16PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, 16PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
17 Core::CPUInterrupts& interrupts_) 17 Core::CPUInterrupts& interrupts_)
18 : core_index{core_index_}, system{system_}, scheduler{scheduler_}, 18 : core_index{core_index_}, system{system_}, scheduler{scheduler_},
19 interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {} 19 interrupts{interrupts_}, guard{std::make_unique<Common::SpinLock>()} {
20#ifdef ARCHITECTURE_x86_64
21 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with
22 // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
23 auto& kernel = system.Kernel();
24 arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
25 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
26#else
27#error Platform not supported yet.
28#endif
29}
20 30
21PhysicalCore::~PhysicalCore() = default; 31PhysicalCore::~PhysicalCore() = default;
22 32
23void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { 33void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
24#ifdef ARCHITECTURE_x86_64 34#ifdef ARCHITECTURE_x86_64
25 auto& kernel = system.Kernel(); 35 auto& kernel = system.Kernel();
26 if (is_64_bit) { 36 if (!is_64_bit) {
27 arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( 37 // We already initialized a 64-bit core, replace with a 32-bit one.
28 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
29 } else {
30 arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( 38 arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
31 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); 39 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
32 } 40 }
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4362508a3..c7f5140f4 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1309,6 +1309,8 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces
1309 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize); 1309 R_UNLESS(Common::IsAligned(size, PageSize), ResultInvalidSize);
1310 R_UNLESS(size > 0, ResultInvalidSize); 1310 R_UNLESS(size > 0, ResultInvalidSize);
1311 R_UNLESS((address < address + size), ResultInvalidCurrentMemory); 1311 R_UNLESS((address < address + size), ResultInvalidCurrentMemory);
1312 R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
1313 R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
1312 1314
1313 // Validate the memory permission. 1315 // Validate the memory permission.
1314 R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission); 1316 R_UNLESS(IsValidProcessMemoryPermission(perm), ResultInvalidNewMemoryPermission);
@@ -1323,7 +1325,7 @@ static ResultCode SetProcessMemoryPermission(Core::System& system, Handle proces
1323 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); 1325 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
1324 1326
1325 // Set the memory permission. 1327 // Set the memory permission.
1326 return page_table.SetProcessMemoryPermission(address, size, ConvertToKMemoryPermission(perm)); 1328 return page_table.SetProcessMemoryPermission(address, size, perm);
1327} 1329}
1328 1330
1329static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle, 1331static ResultCode MapProcessMemory(Core::System& system, VAddr dst_address, Handle process_handle,
@@ -1626,7 +1628,7 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
1626 return ResultInvalidMemoryRegion; 1628 return ResultInvalidMemoryRegion;
1627 } 1629 }
1628 1630
1629 return page_table.MapProcessCodeMemory(dst_address, src_address, size); 1631 return page_table.MapCodeMemory(dst_address, src_address, size);
1630} 1632}
1631 1633
1632static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, 1634static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle,
@@ -1694,7 +1696,7 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
1694 return ResultInvalidMemoryRegion; 1696 return ResultInvalidMemoryRegion;
1695 } 1697 }
1696 1698
1697 return page_table.UnmapProcessCodeMemory(dst_address, src_address, size); 1699 return page_table.UnmapCodeMemory(dst_address, src_address, size);
1698} 1700}
1699 1701
1700/// Exits the current process 1702/// Exits the current process
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 3782703d2..9fc7bb1b1 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -14,6 +14,7 @@
14#include "core/hle/kernel/k_page_table.h" 14#include "core/hle/kernel/k_page_table.h"
15#include "core/hle/kernel/k_system_control.h" 15#include "core/hle/kernel/k_system_control.h"
16#include "core/hle/kernel/svc_results.h" 16#include "core/hle/kernel/svc_results.h"
17#include "core/hle/kernel/svc_types.h"
17#include "core/hle/service/ldr/ldr.h" 18#include "core/hle/service/ldr/ldr.h"
18#include "core/hle/service/service.h" 19#include "core/hle/service/service.h"
19#include "core/loader/nro.h" 20#include "core/loader/nro.h"
@@ -325,7 +326,7 @@ public:
325 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { 326 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
326 auto& page_table{process->PageTable()}; 327 auto& page_table{process->PageTable()};
327 const VAddr addr{GetRandomMapRegion(page_table, size)}; 328 const VAddr addr{GetRandomMapRegion(page_table, size)};
328 const ResultCode result{page_table.MapProcessCodeMemory(addr, baseAddress, size)}; 329 const ResultCode result{page_table.MapCodeMemory(addr, baseAddress, size)};
329 330
330 if (result == Kernel::ResultInvalidCurrentMemory) { 331 if (result == Kernel::ResultInvalidCurrentMemory) {
331 continue; 332 continue;
@@ -351,12 +352,12 @@ public:
351 352
352 if (bss_size) { 353 if (bss_size) {
353 auto block_guard = detail::ScopeExit([&] { 354 auto block_guard = detail::ScopeExit([&] {
354 page_table.UnmapProcessCodeMemory(addr + nro_size, bss_addr, bss_size); 355 page_table.UnmapCodeMemory(addr + nro_size, bss_addr, bss_size);
355 page_table.UnmapProcessCodeMemory(addr, nro_addr, nro_size); 356 page_table.UnmapCodeMemory(addr, nro_addr, nro_size);
356 }); 357 });
357 358
358 const ResultCode result{ 359 const ResultCode result{
359 page_table.MapProcessCodeMemory(addr + nro_size, bss_addr, bss_size)}; 360 page_table.MapCodeMemory(addr + nro_size, bss_addr, bss_size)};
360 361
361 if (result == Kernel::ResultInvalidCurrentMemory) { 362 if (result == Kernel::ResultInvalidCurrentMemory) {
362 continue; 363 continue;
@@ -397,12 +398,12 @@ public:
397 nro_header.segment_headers[DATA_INDEX].memory_size); 398 nro_header.segment_headers[DATA_INDEX].memory_size);
398 399
399 CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( 400 CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
400 text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute)); 401 text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
401 CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( 402 CASCADE_CODE(process->PageTable().SetProcessMemoryPermission(
402 ro_start, data_start - ro_start, Kernel::KMemoryPermission::Read)); 403 ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
403 404
404 return process->PageTable().SetProcessMemoryPermission( 405 return process->PageTable().SetProcessMemoryPermission(
405 data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); 406 data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite);
406 } 407 }
407 408
408 void LoadModule(Kernel::HLERequestContext& ctx) { 409 void LoadModule(Kernel::HLERequestContext& ctx) {
@@ -530,16 +531,19 @@ public:
530 ResultCode UnmapNro(const NROInfo& info) { 531 ResultCode UnmapNro(const NROInfo& info) {
531 // Each region must be unmapped separately to validate memory state 532 // Each region must be unmapped separately to validate memory state
532 auto& page_table{system.CurrentProcess()->PageTable()}; 533 auto& page_table{system.CurrentProcess()->PageTable()};
533 CASCADE_CODE(page_table.UnmapProcessCodeMemory(info.nro_address + info.text_size + 534
534 info.ro_size + info.data_size, 535 if (info.bss_size != 0) {
535 info.bss_address, info.bss_size)); 536 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size +
536 CASCADE_CODE(page_table.UnmapProcessCodeMemory( 537 info.ro_size + info.data_size,
537 info.nro_address + info.text_size + info.ro_size, 538 info.bss_address, info.bss_size));
538 info.src_addr + info.text_size + info.ro_size, info.data_size)); 539 }
539 CASCADE_CODE(page_table.UnmapProcessCodeMemory( 540
540 info.nro_address + info.text_size, info.src_addr + info.text_size, info.ro_size)); 541 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size,
541 CASCADE_CODE( 542 info.src_addr + info.text_size + info.ro_size,
542 page_table.UnmapProcessCodeMemory(info.nro_address, info.src_addr, info.text_size)); 543 info.data_size));
544 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size,
545 info.src_addr + info.text_size, info.ro_size));
546 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address, info.src_addr, info.text_size));
543 return ResultSuccess; 547 return ResultSuccess;
544 } 548 }
545 549