1 // Copyright 2008 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 // NOTE:
6 // These functions are primarily used by the interpreter versions of the LoadStore instructions.
7 // However, if a JITed instruction (for example lwz) wants to access a bad memory area that call
8 // may be redirected here (for example to Read_U32()).
9 
10 #include "Core/HW/Memmap.h"
11 
12 #include <algorithm>
13 #include <array>
14 #include <cstring>
15 #include <memory>
16 
17 #include "Common/ChunkFile.h"
18 #include "Common/CommonTypes.h"
19 #include "Common/Logging/Log.h"
20 #include "Common/MemArena.h"
21 #include "Common/Swap.h"
22 #include "Core/Config/MainSettings.h"
23 #include "Core/ConfigManager.h"
24 #include "Core/HW/AudioInterface.h"
25 #include "Core/HW/DSP.h"
26 #include "Core/HW/DVD/DVDInterface.h"
27 #include "Core/HW/EXI/EXI.h"
28 #include "Core/HW/MMIO.h"
29 #include "Core/HW/MemoryInterface.h"
30 #include "Core/HW/ProcessorInterface.h"
31 #include "Core/HW/SI/SI.h"
32 #include "Core/HW/VideoInterface.h"
33 #include "Core/HW/WII_IPC.h"
34 #include "Core/PowerPC/JitCommon/JitBase.h"
35 #include "Core/PowerPC/PowerPC.h"
36 #include "VideoCommon/CommandProcessor.h"
37 #include "VideoCommon/PixelEngine.h"
38 
39 namespace Memory
40 {
41 // =================================
42 // Init() declarations
43 // ----------------
44 // Store the MemArena here
45 u8* physical_base = nullptr;
46 u8* logical_base = nullptr;
47 static bool is_fastmem_arena_initialized = false;
48 
49 // The MemArena class
50 static Common::MemArena g_arena;
51 // ==============
52 
53 // STATE_TO_SAVE
54 static bool m_IsInitialized = false;  // Save the Init(), Shutdown() state
55 // END STATE_TO_SAVE
56 
57 u8* m_pRAM;
58 u8* m_pL1Cache;
59 u8* m_pEXRAM;
60 u8* m_pFakeVMEM;
61 
62 // s_ram_size is the amount allocated by the emulator, whereas s_ram_size_real
63 // is what will be reported in lowmem, and thus used by emulated software.
64 // Note: Writing to lowmem is done by IPL. If using retail IPL, it will
65 // always be set to 24MB.
66 static u32 s_ram_size_real;
67 static u32 s_ram_size;
68 static u32 s_ram_mask;
69 static u32 s_fakevmem_size;
70 static u32 s_fakevmem_mask;
71 static u32 s_L1_cache_size;
72 static u32 s_L1_cache_mask;
73 static u32 s_io_size;
74 // s_exram_size is the amount allocated by the emulator, whereas s_exram_size_real
75 // is what gets used by emulated software.  If using retail IOS, it will
76 // always be set to 64MB.
77 static u32 s_exram_size_real;
78 static u32 s_exram_size;
79 static u32 s_exram_mask;
80 
GetRamSizeReal()81 u32 GetRamSizeReal()
82 {
83   return s_ram_size_real;
84 }
GetRamSize()85 u32 GetRamSize()
86 {
87   return s_ram_size;
88 }
GetRamMask()89 u32 GetRamMask()
90 {
91   return s_ram_mask;
92 }
GetFakeVMemSize()93 u32 GetFakeVMemSize()
94 {
95   return s_fakevmem_size;
96 }
GetFakeVMemMask()97 u32 GetFakeVMemMask()
98 {
99   return s_fakevmem_mask;
100 }
GetL1CacheSize()101 u32 GetL1CacheSize()
102 {
103   return s_L1_cache_size;
104 }
GetL1CacheMask()105 u32 GetL1CacheMask()
106 {
107   return s_L1_cache_mask;
108 }
GetIOSize()109 u32 GetIOSize()
110 {
111   return s_io_size;
112 }
GetExRamSizeReal()113 u32 GetExRamSizeReal()
114 {
115   return s_exram_size_real;
116 }
GetExRamSize()117 u32 GetExRamSize()
118 {
119   return s_exram_size;
120 }
GetExRamMask()121 u32 GetExRamMask()
122 {
123   return s_exram_mask;
124 }
125 
126 // MMIO mapping object.
127 std::unique_ptr<MMIO::Mapping> mmio_mapping;
128 
InitMMIO()129 static std::unique_ptr<MMIO::Mapping> InitMMIO()
130 {
131   auto mmio = std::make_unique<MMIO::Mapping>();
132 
133   CommandProcessor::RegisterMMIO(mmio.get(), 0x0C000000);
134   PixelEngine::RegisterMMIO(mmio.get(), 0x0C001000);
135   VideoInterface::RegisterMMIO(mmio.get(), 0x0C002000);
136   ProcessorInterface::RegisterMMIO(mmio.get(), 0x0C003000);
137   MemoryInterface::RegisterMMIO(mmio.get(), 0x0C004000);
138   DSP::RegisterMMIO(mmio.get(), 0x0C005000);
139   DVDInterface::RegisterMMIO(mmio.get(), 0x0C006000);
140   SerialInterface::RegisterMMIO(mmio.get(), 0x0C006400);
141   ExpansionInterface::RegisterMMIO(mmio.get(), 0x0C006800);
142   AudioInterface::RegisterMMIO(mmio.get(), 0x0C006C00);
143 
144   return mmio;
145 }
146 
InitMMIOWii()147 static std::unique_ptr<MMIO::Mapping> InitMMIOWii()
148 {
149   auto mmio = InitMMIO();
150 
151   IOS::RegisterMMIO(mmio.get(), 0x0D000000);
152   DVDInterface::RegisterMMIO(mmio.get(), 0x0D006000);
153   SerialInterface::RegisterMMIO(mmio.get(), 0x0D006400);
154   ExpansionInterface::RegisterMMIO(mmio.get(), 0x0D006800);
155   AudioInterface::RegisterMMIO(mmio.get(), 0x0D006C00);
156 
157   return mmio;
158 }
159 
IsInitialized()160 bool IsInitialized()
161 {
162   return m_IsInitialized;
163 }
164 
165 struct PhysicalMemoryRegion
166 {
167   u8** out_pointer;
168   u32 physical_address;
169   u32 size;
170   enum : u32
171   {
172     ALWAYS = 0,
173     FAKE_VMEM = 1,
174     WII_ONLY = 2,
175   } flags;
176   u32 shm_position;
177 };
178 
179 struct LogicalMemoryView
180 {
181   void* mapped_pointer;
182   u32 mapped_size;
183 };
184 
185 // Dolphin allocates memory to represent four regions:
186 // - 32MB RAM (actually 24MB on hardware), available on Gamecube and Wii
187 // - 64MB "EXRAM", RAM only available on Wii
188 // - 32MB FakeVMem, allocated in GameCube mode when MMU support is turned off.
189 //   This is used to approximate the behavior of a common library which pages
190 //   memory to and from the DSP's dedicated RAM. The DSP's RAM (ARAM) isn't
191 //   directly addressable on GameCube.
192 // - 256KB Locked L1, to represent cache lines allocated out of the L1 data
193 //   cache in Locked L1 mode.  Dolphin does not emulate this hardware feature
194 //   accurately; it just pretends there is extra memory at 0xE0000000.
195 //
196 // The 4GB starting at physical_base represents access from the CPU
197 // with address translation turned off. (This is only used by the CPU;
198 // other devices, like the GPU, use other rules, approximated by
199 // Memory::GetPointer.) This memory is laid out as follows:
200 // [0x00000000, 0x02000000) - 32MB RAM
201 // [0x02000000, 0x08000000) - Mirrors of 32MB RAM (not handled here)
202 // [0x08000000, 0x0C000000) - EFB "mapping" (not handled here)
203 // [0x0C000000, 0x0E000000) - MMIO etc. (not handled here)
204 // [0x10000000, 0x14000000) - 64MB RAM (Wii-only; slightly slower)
205 // [0x7E000000, 0x80000000) - FakeVMEM
206 // [0xE0000000, 0xE0040000) - 256KB locked L1
207 //
208 // The 4GB starting at logical_base represents access from the CPU
209 // with address translation turned on.  This mapping is computed based
210 // on the BAT registers.
211 //
212 // Each of these 4GB regions is followed by 4GB of empty space so overflows
213 // in address computation in the JIT don't access the wrong memory.
214 //
215 // The neighboring mirrors of RAM ([0x02000000, 0x08000000), etc.) exist because
216 // the bus masks off the bits in question for RAM accesses; using them is a
217 // terrible idea because the CPU cache won't handle them correctly, but a
218 // few buggy games (notably Rogue Squadron 2) use them by accident. They
219 // aren't backed by memory mappings because they are used very rarely.
220 //
221 // Dolphin doesn't emulate the difference between cached and uncached access.
222 //
223 // TODO: The actual size of RAM is 24MB; the other 8MB shouldn't be backed by actual memory.
224 // TODO: Do we want to handle the mirrors of the GC RAM?
225 static std::array<PhysicalMemoryRegion, 4> physical_regions;
226 
227 static std::vector<LogicalMemoryView> logical_mapped_entries;
228 
GetFlags()229 static u32 GetFlags()
230 {
231   bool wii = SConfig::GetInstance().bWii;
232   bool bMMU = SConfig::GetInstance().bMMU;
233   bool bFakeVMEM = false;
234 #ifndef _ARCH_32
235   // If MMU is turned off in GameCube mode, turn on fake VMEM hack.
236   // The fake VMEM hack's address space is above the memory space that we
237   // allocate on 32bit targets, so disable it there.
238   bFakeVMEM = !wii && !bMMU;
239 #endif
240 
241   u32 flags = 0;
242   if (wii)
243     flags |= PhysicalMemoryRegion::WII_ONLY;
244   if (bFakeVMEM)
245     flags |= PhysicalMemoryRegion::FAKE_VMEM;
246 
247   return flags;
248 }
249 
Init()250 void Init()
251 {
252   const auto get_mem1_size = [] {
253     if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
254       return Config::Get(Config::MAIN_MEM1_SIZE);
255     return Memory::MEM1_SIZE_RETAIL;
256   };
257   const auto get_mem2_size = [] {
258     if (Config::Get(Config::MAIN_RAM_OVERRIDE_ENABLE))
259       return Config::Get(Config::MAIN_MEM2_SIZE);
260     return Memory::MEM2_SIZE_RETAIL;
261   };
262   s_ram_size_real = get_mem1_size();
263   s_ram_size = MathUtil::NextPowerOf2(GetRamSizeReal());
264   s_ram_mask = GetRamSize() - 1;
265   s_fakevmem_size = 0x02000000;
266   s_fakevmem_mask = GetFakeVMemSize() - 1;
267   s_L1_cache_size = 0x00040000;
268   s_L1_cache_mask = GetL1CacheSize() - 1;
269   s_io_size = 0x00010000;
270   s_exram_size_real = get_mem2_size();
271   s_exram_size = MathUtil::NextPowerOf2(GetExRamSizeReal());
272   s_exram_mask = GetExRamSize() - 1;
273 
274   physical_regions[0] = {&m_pRAM, 0x00000000, GetRamSize(), PhysicalMemoryRegion::ALWAYS};
275   physical_regions[1] = {&m_pL1Cache, 0xE0000000, GetL1CacheSize(), PhysicalMemoryRegion::ALWAYS};
276   physical_regions[2] = {&m_pFakeVMEM, 0x7E000000, GetFakeVMemSize(),
277                          PhysicalMemoryRegion::FAKE_VMEM};
278   physical_regions[3] = {&m_pEXRAM, 0x10000000, GetExRamSize(), PhysicalMemoryRegion::WII_ONLY};
279 
280   bool wii = SConfig::GetInstance().bWii;
281   u32 flags = GetFlags();
282   u32 mem_size = 0;
283   for (PhysicalMemoryRegion& region : physical_regions)
284   {
285     if ((flags & region.flags) != region.flags)
286       continue;
287     region.shm_position = mem_size;
288     mem_size += region.size;
289   }
290   g_arena.GrabSHMSegment(mem_size);
291 
292   // Create an anonymous view of the physical memory
293   for (PhysicalMemoryRegion& region : physical_regions)
294   {
295     if ((flags & region.flags) != region.flags)
296       continue;
297 
298     *region.out_pointer = (u8*)g_arena.CreateView(region.shm_position, region.size);
299 
300     if (!*region.out_pointer)
301     {
302       PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
303       exit(0);
304     }
305   }
306 
307   if (wii)
308     mmio_mapping = InitMMIOWii();
309   else
310     mmio_mapping = InitMMIO();
311 
312   Clear();
313 
314   INFO_LOG(MEMMAP, "Memory system initialized. RAM at %p", m_pRAM);
315   m_IsInitialized = true;
316 }
317 
InitFastmemArena()318 bool InitFastmemArena()
319 {
320   u32 flags = GetFlags();
321   physical_base = Common::MemArena::FindMemoryBase();
322 
323   if (!physical_base)
324     return false;
325 
326   for (PhysicalMemoryRegion& region : physical_regions)
327   {
328     if ((flags & region.flags) != region.flags)
329       continue;
330 
331     u8* base = physical_base + region.physical_address;
332     u8* view = (u8*)g_arena.CreateView(region.shm_position, region.size, base);
333 
334     if (base != view)
335     {
336       return false;
337     }
338   }
339 
340 #ifndef _ARCH_32
341   logical_base = physical_base + 0x200000000;
342 #endif
343 
344   is_fastmem_arena_initialized = true;
345   return true;
346 }
347 
UpdateLogicalMemory(const PowerPC::BatTable & dbat_table)348 void UpdateLogicalMemory(const PowerPC::BatTable& dbat_table)
349 {
350   if (!is_fastmem_arena_initialized)
351     return;
352 
353   for (auto& entry : logical_mapped_entries)
354   {
355     g_arena.ReleaseView(entry.mapped_pointer, entry.mapped_size);
356   }
357   logical_mapped_entries.clear();
358   for (u32 i = 0; i < dbat_table.size(); ++i)
359   {
360     if (dbat_table[i] & PowerPC::BAT_PHYSICAL_BIT)
361     {
362       u32 logical_address = i << PowerPC::BAT_INDEX_SHIFT;
363       // TODO: Merge adjacent mappings to make this faster.
364       u32 logical_size = PowerPC::BAT_PAGE_SIZE;
365       u32 translated_address = dbat_table[i] & PowerPC::BAT_RESULT_MASK;
366       for (const auto& physical_region : physical_regions)
367       {
368         u32 mapping_address = physical_region.physical_address;
369         u32 mapping_end = mapping_address + physical_region.size;
370         u32 intersection_start = std::max(mapping_address, translated_address);
371         u32 intersection_end = std::min(mapping_end, translated_address + logical_size);
372         if (intersection_start < intersection_end)
373         {
374           // Found an overlapping region; map it.
375           u32 position = physical_region.shm_position + intersection_start - mapping_address;
376           u8* base = logical_base + logical_address + intersection_start - translated_address;
377           u32 mapped_size = intersection_end - intersection_start;
378 
379           void* mapped_pointer = g_arena.CreateView(position, mapped_size, base);
380           if (!mapped_pointer)
381           {
382             PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
383             exit(0);
384           }
385           logical_mapped_entries.push_back({mapped_pointer, mapped_size});
386         }
387       }
388     }
389   }
390 }
391 
DoState(PointerWrap & p)392 void DoState(PointerWrap& p)
393 {
394   bool wii = SConfig::GetInstance().bWii;
395   p.DoArray(m_pRAM, GetRamSize());
396   p.DoArray(m_pL1Cache, GetL1CacheSize());
397   p.DoMarker("Memory RAM");
398   if (m_pFakeVMEM)
399     p.DoArray(m_pFakeVMEM, GetFakeVMemSize());
400   p.DoMarker("Memory FakeVMEM");
401   if (wii)
402     p.DoArray(m_pEXRAM, GetExRamSize());
403   p.DoMarker("Memory EXRAM");
404 }
405 
Shutdown()406 void Shutdown()
407 {
408   ShutdownFastmemArena();
409 
410   m_IsInitialized = false;
411   u32 flags = GetFlags();
412   for (PhysicalMemoryRegion& region : physical_regions)
413   {
414     if ((flags & region.flags) != region.flags)
415       continue;
416     g_arena.ReleaseView(*region.out_pointer, region.size);
417     *region.out_pointer = nullptr;
418   }
419   g_arena.ReleaseSHMSegment();
420   mmio_mapping.reset();
421   INFO_LOG(MEMMAP, "Memory system shut down.");
422 }
423 
ShutdownFastmemArena()424 void ShutdownFastmemArena()
425 {
426   if (!is_fastmem_arena_initialized)
427     return;
428 
429   u32 flags = GetFlags();
430   for (PhysicalMemoryRegion& region : physical_regions)
431   {
432     if ((flags & region.flags) != region.flags)
433       continue;
434 
435     u8* base = physical_base + region.physical_address;
436     g_arena.ReleaseView(base, region.size);
437   }
438 
439   for (auto& entry : logical_mapped_entries)
440   {
441     g_arena.ReleaseView(entry.mapped_pointer, entry.mapped_size);
442   }
443   logical_mapped_entries.clear();
444 
445   physical_base = nullptr;
446   logical_base = nullptr;
447 
448   is_fastmem_arena_initialized = false;
449 }
450 
Clear()451 void Clear()
452 {
453   if (m_pRAM)
454     memset(m_pRAM, 0, GetRamSize());
455   if (m_pL1Cache)
456     memset(m_pL1Cache, 0, GetL1CacheSize());
457   if (m_pFakeVMEM)
458     memset(m_pFakeVMEM, 0, GetFakeVMemSize());
459   if (m_pEXRAM)
460     memset(m_pEXRAM, 0, GetExRamSize());
461 }
462 
GetPointerForRange(u32 address,size_t size)463 static inline u8* GetPointerForRange(u32 address, size_t size)
464 {
465   // Make sure we don't have a range spanning 2 separate banks
466   if (size >= GetExRamSizeReal())
467     return nullptr;
468 
469   // Check that the beginning and end of the range are valid
470   u8* pointer = GetPointer(address);
471   if (!pointer || !GetPointer(address + u32(size) - 1))
472     return nullptr;
473 
474   return pointer;
475 }
476 
CopyFromEmu(void * data,u32 address,size_t size)477 void CopyFromEmu(void* data, u32 address, size_t size)
478 {
479   if (size == 0)
480     return;
481 
482   void* pointer = GetPointerForRange(address, size);
483   if (!pointer)
484   {
485     PanicAlert("Invalid range in CopyFromEmu. %zx bytes from 0x%08x", size, address);
486     return;
487   }
488   memcpy(data, pointer, size);
489 }
490 
CopyToEmu(u32 address,const void * data,size_t size)491 void CopyToEmu(u32 address, const void* data, size_t size)
492 {
493   if (size == 0)
494     return;
495 
496   void* pointer = GetPointerForRange(address, size);
497   if (!pointer)
498   {
499     PanicAlert("Invalid range in CopyToEmu. %zx bytes to 0x%08x", size, address);
500     return;
501   }
502   memcpy(pointer, data, size);
503 }
504 
Memset(u32 address,u8 value,size_t size)505 void Memset(u32 address, u8 value, size_t size)
506 {
507   if (size == 0)
508     return;
509 
510   void* pointer = GetPointerForRange(address, size);
511   if (!pointer)
512   {
513     PanicAlert("Invalid range in Memset. %zx bytes at 0x%08x", size, address);
514     return;
515   }
516   memset(pointer, value, size);
517 }
518 
GetString(u32 em_address,size_t size)519 std::string GetString(u32 em_address, size_t size)
520 {
521   const char* ptr = reinterpret_cast<const char*>(GetPointer(em_address));
522   if (ptr == nullptr)
523     return "";
524 
525   if (size == 0)  // Null terminated string.
526   {
527     return std::string(ptr);
528   }
529   else  // Fixed size string, potentially null terminated or null padded.
530   {
531     size_t length = strnlen(ptr, size);
532     return std::string(ptr, length);
533   }
534 }
535 
GetPointer(u32 address)536 u8* GetPointer(u32 address)
537 {
538   // TODO: Should we be masking off more bits here?  Can all devices access
539   // EXRAM?
540   address &= 0x3FFFFFFF;
541   if (address < GetRamSizeReal())
542     return m_pRAM + address;
543 
544   if (m_pEXRAM)
545   {
546     if ((address >> 28) == 0x1 && (address & 0x0fffffff) < GetExRamSizeReal())
547       return m_pEXRAM + (address & GetExRamMask());
548   }
549 
550   PanicAlert("Unknown Pointer 0x%08x PC 0x%08x LR 0x%08x", address, PC, LR);
551 
552   return nullptr;
553 }
554 
Read_U8(u32 address)555 u8 Read_U8(u32 address)
556 {
557   return *GetPointer(address);
558 }
559 
Read_U16(u32 address)560 u16 Read_U16(u32 address)
561 {
562   return Common::swap16(GetPointer(address));
563 }
564 
Read_U32(u32 address)565 u32 Read_U32(u32 address)
566 {
567   return Common::swap32(GetPointer(address));
568 }
569 
Read_U64(u32 address)570 u64 Read_U64(u32 address)
571 {
572   return Common::swap64(GetPointer(address));
573 }
574 
Write_U8(u8 value,u32 address)575 void Write_U8(u8 value, u32 address)
576 {
577   *GetPointer(address) = value;
578 }
579 
Write_U16(u16 value,u32 address)580 void Write_U16(u16 value, u32 address)
581 {
582   u16 swapped_value = Common::swap16(value);
583   std::memcpy(GetPointer(address), &swapped_value, sizeof(u16));
584 }
585 
Write_U32(u32 value,u32 address)586 void Write_U32(u32 value, u32 address)
587 {
588   u32 swapped_value = Common::swap32(value);
589   std::memcpy(GetPointer(address), &swapped_value, sizeof(u32));
590 }
591 
Write_U64(u64 value,u32 address)592 void Write_U64(u64 value, u32 address)
593 {
594   u64 swapped_value = Common::swap64(value);
595   std::memcpy(GetPointer(address), &swapped_value, sizeof(u64));
596 }
597 
Write_U32_Swap(u32 value,u32 address)598 void Write_U32_Swap(u32 value, u32 address)
599 {
600   std::memcpy(GetPointer(address), &value, sizeof(u32));
601 }
602 
Write_U64_Swap(u64 value,u32 address)603 void Write_U64_Swap(u64 value, u32 address)
604 {
605   std::memcpy(GetPointer(address), &value, sizeof(u64));
606 }
607 
608 }  // namespace Memory
609