diff options
| author | 2017-05-14 13:52:40 -0700 | |
|---|---|---|
| committer | 2017-05-14 13:52:40 -0700 | |
| commit | 180587bb8bd18feeb81028007556276ef4ecaafd (patch) | |
| tree | 5939bfa2c92ced9b30ade0b725ace7b7dce3d040 /src/core/hle/kernel | |
| parent | Merge pull request #2695 from JayFoxRox/gs-regs (diff) | |
| parent | Kernel: Map special regions according to ExHeader (diff) | |
| download | yuzu-180587bb8bd18feeb81028007556276ef4ecaafd.tar.gz yuzu-180587bb8bd18feeb81028007556276ef4ecaafd.tar.xz yuzu-180587bb8bd18feeb81028007556276ef4ecaafd.zip | |
Merge pull request #2687 from yuriks/address-mappings
Kernel: Map special regions according to ExHeader
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/memory.cpp | 112 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory.h | 10 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 23 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.h | 2 |
4 files changed, 102 insertions, 45 deletions
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index 33c165197..8250a90b5 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp | |||
| @@ -2,11 +2,13 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cinttypes> | ||
| 5 | #include <map> | 6 | #include <map> |
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | #include <utility> | 8 | #include <utility> |
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | #include "audio_core/audio_core.h" | 10 | #include "audio_core/audio_core.h" |
| 11 | #include "common/assert.h" | ||
| 10 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 11 | #include "common/logging/log.h" | 13 | #include "common/logging/log.h" |
| 12 | #include "core/hle/config_mem.h" | 14 | #include "core/hle/config_mem.h" |
| @@ -92,52 +94,96 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) { | |||
| 92 | UNREACHABLE(); | 94 | UNREACHABLE(); |
| 93 | } | 95 | } |
| 94 | } | 96 | } |
| 95 | } | ||
| 96 | |||
| 97 | namespace Memory { | ||
| 98 | 97 | ||
| 99 | namespace { | 98 | std::array<u8, Memory::VRAM_SIZE> vram; |
| 99 | std::array<u8, Memory::N3DS_EXTRA_RAM_SIZE> n3ds_extra_ram; | ||
| 100 | |||
| 101 | void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) { | ||
| 102 | using namespace Memory; | ||
| 103 | |||
| 104 | struct MemoryArea { | ||
| 105 | VAddr vaddr_base; | ||
| 106 | PAddr paddr_base; | ||
| 107 | u32 size; | ||
| 108 | }; | ||
| 109 | |||
| 110 | // The order of entries in this array is important. The VRAM and IO VAddr ranges overlap, and | ||
| 111 | // VRAM must be tried first. | ||
| 112 | static constexpr MemoryArea memory_areas[] = { | ||
| 113 | {VRAM_VADDR, VRAM_PADDR, VRAM_SIZE}, | ||
| 114 | {IO_AREA_VADDR, IO_AREA_PADDR, IO_AREA_SIZE}, | ||
| 115 | {DSP_RAM_VADDR, DSP_RAM_PADDR, DSP_RAM_SIZE}, | ||
| 116 | {N3DS_EXTRA_RAM_VADDR, N3DS_EXTRA_RAM_PADDR, N3DS_EXTRA_RAM_SIZE - 0x20000}, | ||
| 117 | }; | ||
| 118 | |||
| 119 | VAddr mapping_limit = mapping.address + mapping.size; | ||
| 120 | if (mapping_limit < mapping.address) { | ||
| 121 | LOG_CRITICAL(Loader, "Mapping size overflowed: address=0x%08" PRIX32 " size=0x%" PRIX32, | ||
| 122 | mapping.address, mapping.size); | ||
| 123 | return; | ||
| 124 | } | ||
| 100 | 125 | ||
| 101 | struct MemoryArea { | 126 | auto area = |
| 102 | u32 base; | 127 | std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) { |
| 103 | u32 size; | 128 | return mapping.address >= area.vaddr_base && |
| 104 | const char* name; | 129 | mapping_limit <= area.vaddr_base + area.size; |
| 105 | }; | 130 | }); |
| 131 | if (area == std::end(memory_areas)) { | ||
| 132 | LOG_ERROR(Loader, "Unhandled special mapping: address=0x%08" PRIX32 " size=0x%" PRIX32 | ||
| 133 | " read_only=%d unk_flag=%d", | ||
| 134 | mapping.address, mapping.size, mapping.read_only, mapping.unk_flag); | ||
| 135 | return; | ||
| 136 | } | ||
| 106 | 137 | ||
| 107 | // We don't declare the IO regions in here since its handled by other means. | 138 | u32 offset_into_region = mapping.address - area->vaddr_base; |
| 108 | static MemoryArea memory_areas[] = { | 139 | if (area->paddr_base == IO_AREA_PADDR) { |
| 109 | {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM) | 140 | LOG_ERROR(Loader, "MMIO mappings are not supported yet. phys_addr=0x%08" PRIX32, |
| 110 | }; | 141 | area->paddr_base + offset_into_region); |
| 111 | } | 142 | return; |
| 143 | } | ||
| 112 | 144 | ||
| 113 | void Init() { | 145 | // TODO(yuriks): Use GetPhysicalPointer when that becomes independent of the virtual |
| 114 | InitMemoryMap(); | 146 | // mappings. |
| 115 | LOG_DEBUG(HW_Memory, "initialized OK"); | 147 | u8* target_pointer = nullptr; |
| 116 | } | 148 | switch (area->paddr_base) { |
| 149 | case VRAM_PADDR: | ||
| 150 | target_pointer = vram.data(); | ||
| 151 | break; | ||
| 152 | case DSP_RAM_PADDR: | ||
| 153 | target_pointer = AudioCore::GetDspMemory().data(); | ||
| 154 | break; | ||
| 155 | case N3DS_EXTRA_RAM_PADDR: | ||
| 156 | target_pointer = n3ds_extra_ram.data(); | ||
| 157 | break; | ||
| 158 | default: | ||
| 159 | UNREACHABLE(); | ||
| 160 | } | ||
| 117 | 161 | ||
| 118 | void InitLegacyAddressSpace(Kernel::VMManager& address_space) { | 162 | // TODO(yuriks): This flag seems to have some other effect, but it's unknown what |
| 119 | using namespace Kernel; | 163 | MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO; |
| 120 | 164 | ||
| 121 | for (MemoryArea& area : memory_areas) { | 165 | auto vma = address_space |
| 122 | auto block = std::make_shared<std::vector<u8>>(area.size); | 166 | .MapBackingMemory(mapping.address, target_pointer + offset_into_region, |
| 123 | address_space | 167 | mapping.size, memory_state) |
| 124 | .MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private) | 168 | .MoveFrom(); |
| 125 | .Unwrap(); | 169 | address_space.Reprotect(vma, |
| 126 | } | 170 | mapping.read_only ? VMAPermission::Read : VMAPermission::ReadWrite); |
| 171 | } | ||
| 127 | 172 | ||
| 173 | void MapSharedPages(VMManager& address_space) { | ||
| 128 | auto cfg_mem_vma = address_space | 174 | auto cfg_mem_vma = address_space |
| 129 | .MapBackingMemory(CONFIG_MEMORY_VADDR, (u8*)&ConfigMem::config_mem, | 175 | .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, |
| 130 | CONFIG_MEMORY_SIZE, MemoryState::Shared) | 176 | reinterpret_cast<u8*>(&ConfigMem::config_mem), |
| 177 | Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared) | ||
| 131 | .MoveFrom(); | 178 | .MoveFrom(); |
| 132 | address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); | 179 | address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); |
| 133 | 180 | ||
| 134 | auto shared_page_vma = address_space | 181 | auto shared_page_vma = address_space |
| 135 | .MapBackingMemory(SHARED_PAGE_VADDR, (u8*)&SharedPage::shared_page, | 182 | .MapBackingMemory(Memory::SHARED_PAGE_VADDR, |
| 136 | SHARED_PAGE_SIZE, MemoryState::Shared) | 183 | reinterpret_cast<u8*>(&SharedPage::shared_page), |
| 184 | Memory::SHARED_PAGE_SIZE, MemoryState::Shared) | ||
| 137 | .MoveFrom(); | 185 | .MoveFrom(); |
| 138 | address_space.Reprotect(shared_page_vma, VMAPermission::Read); | 186 | address_space.Reprotect(shared_page_vma, VMAPermission::Read); |
| 139 | |||
| 140 | AudioCore::AddAddressSpace(address_space); | ||
| 141 | } | 187 | } |
| 142 | 188 | ||
| 143 | } // namespace | 189 | } // namespace Kernel |
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h index 4e1856a41..08c1a9989 100644 --- a/src/core/hle/kernel/memory.h +++ b/src/core/hle/kernel/memory.h | |||
| @@ -23,11 +23,7 @@ struct MemoryRegionInfo { | |||
| 23 | void MemoryInit(u32 mem_type); | 23 | void MemoryInit(u32 mem_type); |
| 24 | void MemoryShutdown(); | 24 | void MemoryShutdown(); |
| 25 | MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); | 25 | MemoryRegionInfo* GetMemoryRegion(MemoryRegion region); |
| 26 | } | ||
| 27 | 26 | ||
| 28 | namespace Memory { | 27 | void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping); |
| 29 | 28 | void MapSharedPages(VMManager& address_space); | |
| 30 | void Init(); | 29 | } // namespace Kernel |
| 31 | void InitLegacyAddressSpace(Kernel::VMManager& address_space); | ||
| 32 | |||
| 33 | } // namespace | ||
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index ba80fe7f8..32cb25fb7 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -35,7 +35,6 @@ SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) { | |||
| 35 | process->codeset = std::move(code_set); | 35 | process->codeset = std::move(code_set); |
| 36 | process->flags.raw = 0; | 36 | process->flags.raw = 0; |
| 37 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); | 37 | process->flags.memory_region.Assign(MemoryRegion::APPLICATION); |
| 38 | Memory::InitLegacyAddressSpace(process->vm_manager); | ||
| 39 | 38 | ||
| 40 | return process; | 39 | return process; |
| 41 | } | 40 | } |
| @@ -78,8 +77,15 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 78 | 77 | ||
| 79 | AddressMapping mapping; | 78 | AddressMapping mapping; |
| 80 | mapping.address = descriptor << 12; | 79 | mapping.address = descriptor << 12; |
| 81 | mapping.size = (end_desc << 12) - mapping.address; | 80 | VAddr end_address = end_desc << 12; |
| 82 | mapping.writable = (descriptor & (1 << 20)) != 0; | 81 | |
| 82 | if (mapping.address < end_address) { | ||
| 83 | mapping.size = end_address - mapping.address; | ||
| 84 | } else { | ||
| 85 | mapping.size = 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | mapping.read_only = (descriptor & (1 << 20)) != 0; | ||
| 83 | mapping.unk_flag = (end_desc & (1 << 20)) != 0; | 89 | mapping.unk_flag = (end_desc & (1 << 20)) != 0; |
| 84 | 90 | ||
| 85 | address_mappings.push_back(mapping); | 91 | address_mappings.push_back(mapping); |
| @@ -88,8 +94,10 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { | |||
| 88 | AddressMapping mapping; | 94 | AddressMapping mapping; |
| 89 | mapping.address = descriptor << 12; | 95 | mapping.address = descriptor << 12; |
| 90 | mapping.size = Memory::PAGE_SIZE; | 96 | mapping.size = Memory::PAGE_SIZE; |
| 91 | mapping.writable = true; // TODO: Not sure if correct | 97 | mapping.read_only = false; |
| 92 | mapping.unk_flag = false; | 98 | mapping.unk_flag = false; |
| 99 | |||
| 100 | address_mappings.push_back(mapping); | ||
| 93 | } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF | 101 | } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF |
| 94 | // Kernel version | 102 | // Kernel version |
| 95 | kernel_version = descriptor & 0xFFFF; | 103 | kernel_version = descriptor & 0xFFFF; |
| @@ -131,6 +139,12 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | |||
| 131 | misc_memory_used += stack_size; | 139 | misc_memory_used += stack_size; |
| 132 | memory_region->used += stack_size; | 140 | memory_region->used += stack_size; |
| 133 | 141 | ||
| 142 | // Map special address mappings | ||
| 143 | MapSharedPages(vm_manager); | ||
| 144 | for (const auto& mapping : address_mappings) { | ||
| 145 | HandleSpecialMapping(vm_manager, mapping); | ||
| 146 | } | ||
| 147 | |||
| 134 | vm_manager.LogLayout(Log::Level::Debug); | 148 | vm_manager.LogLayout(Log::Level::Debug); |
| 135 | Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); | 149 | Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); |
| 136 | } | 150 | } |
| @@ -138,6 +152,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | |||
| 138 | VAddr Process::GetLinearHeapAreaAddress() const { | 152 | VAddr Process::GetLinearHeapAreaAddress() const { |
| 139 | return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR; | 153 | return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR; |
| 140 | } | 154 | } |
| 155 | |||
| 141 | VAddr Process::GetLinearHeapBase() const { | 156 | VAddr Process::GetLinearHeapBase() const { |
| 142 | return GetLinearHeapAreaAddress() + memory_region->base; | 157 | return GetLinearHeapAreaAddress() + memory_region->base; |
| 143 | } | 158 | } |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index b566950b0..b52211d2a 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -20,7 +20,7 @@ struct AddressMapping { | |||
| 20 | // Address and size must be page-aligned | 20 | // Address and size must be page-aligned |
| 21 | VAddr address; | 21 | VAddr address; |
| 22 | u32 size; | 22 | u32 size; |
| 23 | bool writable; | 23 | bool read_only; |
| 24 | bool unk_flag; | 24 | bool unk_flag; |
| 25 | }; | 25 | }; |
| 26 | 26 | ||