@@ -85,6 +85,18 @@ static const std::map<uint32_t, std::string_view> s_knownBioses = {
85
85
#endif
86
86
};
87
87
88
+ PCSX::Memory::Memory () : m_listener(g_system->m_eventBus) {
89
+ m_listener.listen <Events::ExecutionFlow::Reset>([this ](auto &) {
90
+ free (m_msanRAM);
91
+ free (m_msanBitmap);
92
+ free (m_msanWrittenBitmap);
93
+ m_msanRAM = nullptr ;
94
+ m_msanBitmap = nullptr ;
95
+ m_msanWrittenBitmap = nullptr ;
96
+ m_msanAllocs.clear ();
97
+ });
98
+ }
99
+
88
100
int PCSX::Memory::init () {
89
101
m_readLUT = (uint8_t **)calloc (0x10000 , sizeof (void *));
90
102
m_writeLUT = (uint8_t **)calloc (0x10000 , sizeof (void *));
@@ -140,7 +152,7 @@ bool PCSX::Memory::loadEXP1FromFile(std::filesystem::path rom_path) {
140
152
memset (m_exp1, 0xff , exp1_size);
141
153
f->read (m_exp1, rom_size);
142
154
f->close ();
143
- PCSX:: g_system->printf (_ (" Loaded %i bytes to EXP1 from file: %s\n " ), rom_size, exp1Path.string ());
155
+ g_system->printf (_ (" Loaded %i bytes to EXP1 from file: %s\n " ), rom_size, exp1Path.string ());
144
156
result = true ;
145
157
}
146
158
} else {
@@ -222,7 +234,7 @@ The distributed OpenBIOS.bin file can be an appropriate BIOS replacement.
222
234
f->read (m_bios, bios_size);
223
235
}
224
236
f->close ();
225
- PCSX:: g_system->printf (_ (" Loaded BIOS: %s\n " ), biosPath.string ());
237
+ g_system->printf (_ (" Loaded BIOS: %s\n " ), biosPath.string ());
226
238
}
227
239
}
228
240
@@ -250,6 +262,14 @@ void PCSX::Memory::shutdown() {
250
262
251
263
free (m_readLUT);
252
264
free (m_writeLUT);
265
+
266
+ free (m_msanRAM);
267
+ free (m_msanBitmap);
268
+ free (m_msanWrittenBitmap);
269
+ m_msanRAM = nullptr ;
270
+ m_msanBitmap = nullptr ;
271
+ m_msanWrittenBitmap = nullptr ;
272
+ m_msanAllocs.clear ();
253
273
}
254
274
255
275
uint8_t PCSX::Memory::read8 (uint32_t address) {
@@ -261,6 +281,20 @@ uint8_t PCSX::Memory::read8(uint32_t address) {
261
281
if (pointer != nullptr ) {
262
282
const uint32_t offset = address & 0xffff ;
263
283
return *(pointer + offset);
284
+ } else if (msanInitialized () && (address >= 0x20000000 ) && (address < (0x20000000 + c_msanSize))) {
285
+ uint32_t msanAddress = address - 0x20000000 ;
286
+ if ((m_msanWrittenBitmap[msanAddress / 8 ] & (1 << (msanAddress % 8 ))) == 0 ) {
287
+ g_system->log (LogClass::CPU, _ (" 8-bit read from usable but uninitialized msan memory: %8.8lx\n " ), address);
288
+ g_system->pause ();
289
+ return 0 ;
290
+ }
291
+ if (m_msanBitmap[msanAddress / 8 ] & (1 << (msanAddress % 8 ))) {
292
+ return m_msanRAM[msanAddress];
293
+ } else {
294
+ g_system->log (LogClass::CPU, _ (" 8-bit read from unsable msan memory: %8.8lx\n " ), address);
295
+ g_system->pause ();
296
+ return 0 ;
297
+ }
264
298
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
265
299
if ((address & 0xffff ) < 0x400 ) {
266
300
return m_hard[address & 0x3ff ];
@@ -296,6 +330,23 @@ uint16_t PCSX::Memory::read16(uint32_t address) {
296
330
if (pointer != nullptr ) {
297
331
const uint32_t offset = address & 0xffff ;
298
332
return SWAP_LEu16 (*(uint16_t *)(pointer + offset));
333
+ } else if (msanInitialized () && (address >= 0x20000000 ) && (address < (0x20000000 + c_msanSize))) {
334
+ uint32_t msanAddress = address - 0x20000000 ;
335
+ for (unsigned offset = 0 ; offset < 2 ; offset++) {
336
+ if ((m_msanWrittenBitmap[(msanAddress + offset) / 8 ] & (1 << ((msanAddress + offset) % 8 ))) == 0 ) {
337
+ g_system->log (LogClass::CPU, _ (" 16-bit read from usable but uninitialized msan memory: %8.8lx\n " ),
338
+ address);
339
+ g_system->pause ();
340
+ return 0 ;
341
+ }
342
+ }
343
+ if (m_msanBitmap[msanAddress / 8 ] & (1 << (msanAddress % 8 ))) {
344
+ return *(uint16_t *)&m_msanRAM[msanAddress];
345
+ } else {
346
+ g_system->log (LogClass::CPU, _ (" 16-bit read from unsable msan memory: %8.8lx\n " ), address);
347
+ g_system->pause ();
348
+ return 0 ;
349
+ }
299
350
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
300
351
if ((address & 0xffff ) < 0x400 ) {
301
352
uint16_t *ptr = (uint16_t *)&m_hard[address & 0x3ff ];
@@ -328,6 +379,23 @@ uint32_t PCSX::Memory::read32(uint32_t address, ReadType readType) {
328
379
if (pointer != nullptr ) {
329
380
const uint32_t offset = address & 0xffff ;
330
381
return SWAP_LEu32 (*(uint32_t *)(pointer + offset));
382
+ } else if (msanInitialized () && (address >= 0x20000000 ) && (address < (0x20000000 + c_msanSize))) {
383
+ uint32_t msanAddress = address - 0x20000000 ;
384
+ for (unsigned offset = 0 ; offset < 4 ; offset++) {
385
+ if ((m_msanWrittenBitmap[(msanAddress + offset) / 8 ] & (1 << ((msanAddress + offset) % 8 ))) == 0 ) {
386
+ g_system->log (LogClass::CPU, _ (" 32-bit read from usable but uninitialized msan memory: %8.8lx\n " ),
387
+ address);
388
+ g_system->pause ();
389
+ return 0 ;
390
+ }
391
+ }
392
+ if (m_msanBitmap[msanAddress / 8 ] & (1 << (msanAddress % 8 ))) {
393
+ return *(uint32_t *)&m_msanRAM[msanAddress];
394
+ } else {
395
+ g_system->log (LogClass::CPU, _ (" 32-bit read from unsable msan memory: %8.8lx\n " ), address);
396
+ g_system->pause ();
397
+ return 0 ;
398
+ }
331
399
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
332
400
if ((address & 0xffff ) < 0x400 ) {
333
401
uint32_t *ptr = (uint32_t *)&m_hard[address & 0x3ff ];
@@ -437,6 +505,15 @@ void PCSX::Memory::write8(uint32_t address, uint32_t value) {
437
505
const uint32_t offset = address & 0xffff ;
438
506
*(pointer + offset) = static_cast <uint8_t >(value);
439
507
g_emulator->m_cpu ->Clear ((address & (~3 )), 1 );
508
+ } else if (msanInitialized () && (address >= 0x20000000 ) && (address < (0x20000000 + c_msanSize))) {
509
+ uint32_t msanAddress = address - 0x20000000 ;
510
+ if (m_msanBitmap[msanAddress / 8 ] & (1 << (msanAddress % 8 ))) {
511
+ m_msanWrittenBitmap[msanAddress / 8 ] |= (1 << (msanAddress % 8 ));
512
+ m_msanRAM[msanAddress] = value;
513
+ } else {
514
+ g_system->log (LogClass::CPU, _ (" 8-bit write to unsable msan memory: %8.8lx\n " ), address);
515
+ g_system->pause ();
516
+ }
440
517
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
441
518
if ((address & 0xffff ) < 0x400 ) {
442
519
m_hard[address & 0x3ff ] = value;
@@ -465,6 +542,17 @@ void PCSX::Memory::write16(uint32_t address, uint32_t value) {
465
542
const uint32_t offset = address & 0xffff ;
466
543
*(uint16_t *)(pointer + offset) = SWAP_LEu16 (static_cast <uint16_t >(value));
467
544
g_emulator->m_cpu ->Clear ((address & (~3 )), 1 );
545
+ } else if (msanInitialized () && (address >= 0x20000000 ) && (address < (0x20000000 + c_msanSize))) {
546
+ uint32_t msanAddress = address - 0x20000000 ;
547
+ if (m_msanBitmap[msanAddress / 8 ] & (1 << (msanAddress % 8 ))) {
548
+ for (unsigned offset = 0 ; offset < 2 ; offset++) {
549
+ m_msanWrittenBitmap[(msanAddress + offset) / 8 ] |= (1 << ((msanAddress + offset) % 8 ));
550
+ }
551
+ *(uint16_t *)&m_msanRAM[msanAddress] = value;
552
+ } else {
553
+ g_system->log (LogClass::CPU, _ (" 16-bit write to unsable msan memory: %8.8lx\n " ), address);
554
+ g_system->pause ();
555
+ }
468
556
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
469
557
if ((address & 0xffff ) < 0x400 ) {
470
558
uint16_t *ptr = (uint16_t *)&m_hard[address & 0x3ff ];
@@ -494,6 +582,17 @@ void PCSX::Memory::write32(uint32_t address, uint32_t value) {
494
582
const uint32_t offset = address & 0xffff ;
495
583
*(uint32_t *)(pointer + offset) = SWAP_LEu32 (value);
496
584
g_emulator->m_cpu ->Clear ((address & (~3 )), 1 );
585
+ } else if (msanInitialized () && (address >= 0x20000000 ) && (address < (0x20000000 + c_msanSize))) {
586
+ uint32_t msanAddress = address - 0x20000000 ;
587
+ if (m_msanBitmap[msanAddress / 8 ] & (1 << (msanAddress % 8 ))) {
588
+ for (unsigned offset = 0 ; offset < 4 ; offset++) {
589
+ m_msanWrittenBitmap[(msanAddress + offset) / 8 ] |= (1 << ((msanAddress + offset) % 8 ));
590
+ }
591
+ *(uint32_t *)&m_msanRAM[msanAddress] = value;
592
+ } else {
593
+ g_system->log (LogClass::CPU, _ (" 32-bit write to unsable msan memory: %8.8lx\n " ), address);
594
+ g_system->pause ();
595
+ }
497
596
} else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
498
597
if ((address & 0xffff ) < 0x400 ) {
499
598
uint32_t *ptr = (uint32_t *)&m_hard[address & 0x3ff ];
@@ -717,3 +816,123 @@ void PCSX::Memory::MemoryAsFile::writeBlock(const void *src, size_t size, size_t
717
816
auto toCopy = std::min (size, c_blockSize - offset);
718
817
memcpy (block + offset, src, toCopy);
719
818
}
819
+
820
+ void PCSX::Memory::initMsan (bool reset) {
821
+ if (reset) {
822
+ free (m_msanRAM);
823
+ free (m_msanBitmap);
824
+ free (m_msanWrittenBitmap);
825
+ m_msanRAM = nullptr ;
826
+ m_msanBitmap = nullptr ;
827
+ m_msanWrittenBitmap = nullptr ;
828
+ m_msanAllocs.clear ();
829
+ }
830
+ if (msanInitialized ()) {
831
+ g_system->printf (_ (" MSAN system was already initialized.\n " ));
832
+ g_system->pause ();
833
+ return ;
834
+ }
835
+
836
+ // 1.5GB of RAM, with 384MB worth of bitmap, between 0x20000000 and 0x80000000
837
+ m_msanRAM = (uint8_t *)calloc (c_msanSize, 1 );
838
+ m_msanBitmap = (uint8_t *)calloc (c_msanSize / 8 , 1 );
839
+ m_msanWrittenBitmap = (uint8_t *)calloc (c_msanSize / 8 , 1 );
840
+ m_msanPtr = 1024 ;
841
+ }
842
+
843
+ uint32_t PCSX::Memory::msanAlloc (uint32_t size) {
844
+ // Allocate 1kB more than requested, to redzone the allocation.
845
+ // This is to detect out-of-bounds accesses.
846
+ uint32_t actualSize = size + 1 * 1024 ;
847
+ // Then round up to the next 16-byte boundary.
848
+ actualSize = actualSize + 15 & ~15 ;
849
+
850
+ // Check if we still have enough memory.
851
+ if (m_msanPtr + actualSize > c_msanSize) {
852
+ g_system->printf (_ (" Out of memory in MsanAlloc\n " ));
853
+ g_system->pause ();
854
+ return 0 ;
855
+ }
856
+
857
+ // Allocate the memory.
858
+ uint32_t ptr = m_msanPtr;
859
+ m_msanPtr += actualSize;
860
+ // Mark the allocation as usable.
861
+ for (uint32_t i = 0 ; i < size; i++) {
862
+ m_msanBitmap[(ptr + i) / 8 ] |= 1 << ((ptr + i) % 8 );
863
+ }
864
+
865
+ // Insert the allocation into the list of allocations.
866
+ m_msanAllocs.insert ({ptr, size});
867
+ return ptr + 0x20000000 ;
868
+ }
869
+
870
+ void PCSX::Memory::msanFree (uint32_t ptr) {
871
+ if (ptr == 0 ) {
872
+ return ;
873
+ }
874
+ // Check if the pointer is valid.
875
+ if (ptr < 0x20000000 || ptr >= 0x20000000 + c_msanSize) {
876
+ g_system->printf (_ (" Invalid pointer passed to MsanFree: %08x\n " ), ptr);
877
+ g_system->pause ();
878
+ return ;
879
+ }
880
+ ptr -= 0x20000000 ;
881
+ auto it = m_msanAllocs.find (ptr);
882
+ if (it == m_msanAllocs.end ()) {
883
+ g_system->printf (_ (" Invalid pointer passed to MsanFree: %08x\n " ), ptr);
884
+ g_system->pause ();
885
+ return ;
886
+ }
887
+ // Mark the allocation as unusable.
888
+ for (uint32_t i = 0 ; i < m_msanAllocs[ptr]; i++) {
889
+ m_msanBitmap[(ptr + i) / 8 ] &= ~(1 << ((ptr + i) % 8 ));
890
+ }
891
+ // Remove the allocation from the list of allocations.
892
+ m_msanAllocs.erase (ptr);
893
+ }
894
+
895
+ uint32_t PCSX::Memory::msanRealloc (uint32_t ptr, uint32_t size) {
896
+ if (ptr == 0 ) {
897
+ return msanAlloc (size);
898
+ }
899
+ if (size == 0 ) {
900
+ msanFree (ptr);
901
+ return 0 ;
902
+ }
903
+ // Check if the pointer is valid.
904
+ if (ptr < 0x20000000 || ptr >= 0x20000000 + c_msanSize) {
905
+ g_system->printf (_ (" Invalid pointer passed to MsanRealloc: %08x\n " ), ptr);
906
+ g_system->pause ();
907
+ return 0 ;
908
+ }
909
+ ptr -= 0x20000000 ;
910
+ auto it = m_msanAllocs.find (ptr);
911
+ if (it == m_msanAllocs.end ()) {
912
+ g_system->printf (_ (" Invalid pointer passed to MsanRealloc: %08x\n " ), ptr);
913
+ g_system->pause ();
914
+ return 0 ;
915
+ }
916
+ auto oldSize = it->second ;
917
+
918
+ // Allocate new memory.
919
+ uint32_t newPtr = msanAlloc (size);
920
+ if (!newPtr) return 0 ;
921
+ newPtr -= 0x20000000 ;
922
+
923
+ // Copy the old memory to the new memory.
924
+ memcpy (m_msanRAM + newPtr, m_msanRAM + ptr, std::min (size, oldSize));
925
+
926
+ // Mark the old allocation as unusable
927
+ for (uint32_t i = 0 ; i < oldSize; i++) {
928
+ m_msanBitmap[(ptr + i) / 8 ] &= ~(1 << ((ptr + i) % 8 ));
929
+ }
930
+ // Mark the new allocation as written to
931
+ auto toCopy = std::min (size, oldSize);
932
+ for (uint32_t i = 0 ; i < toCopy; i++) {
933
+ m_msanWrittenBitmap[(newPtr + i) / 8 ] |= 1 << ((newPtr + i) % 8 );
934
+ }
935
+ // Remove the allocation from the list of allocations.
936
+ m_msanAllocs.erase (ptr);
937
+ return newPtr + 0x20000000 ;
938
+ }
0 commit comments