@@ -85,6 +85,18 @@ static const std::map<uint32_t, std::string_view> s_knownBioses = {
8585#endif
8686};
8787
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+
88100int PCSX::Memory::init () {
89101 m_readLUT = (uint8_t **)calloc (0x10000 , sizeof (void *));
90102 m_writeLUT = (uint8_t **)calloc (0x10000 , sizeof (void *));
@@ -140,7 +152,7 @@ bool PCSX::Memory::loadEXP1FromFile(std::filesystem::path rom_path) {
140152 memset (m_exp1, 0xff , exp1_size);
141153 f->read (m_exp1, rom_size);
142154 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 ());
144156 result = true ;
145157 }
146158 } else {
@@ -222,7 +234,7 @@ The distributed OpenBIOS.bin file can be an appropriate BIOS replacement.
222234 f->read (m_bios, bios_size);
223235 }
224236 f->close ();
225- PCSX:: g_system->printf (_ (" Loaded BIOS: %s\n " ), biosPath.string ());
237+ g_system->printf (_ (" Loaded BIOS: %s\n " ), biosPath.string ());
226238 }
227239 }
228240
@@ -250,6 +262,14 @@ void PCSX::Memory::shutdown() {
250262
251263 free (m_readLUT);
252264 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 ();
253273}
254274
255275uint8_t PCSX::Memory::read8 (uint32_t address) {
@@ -261,6 +281,20 @@ uint8_t PCSX::Memory::read8(uint32_t address) {
261281 if (pointer != nullptr ) {
262282 const uint32_t offset = address & 0xffff ;
263283 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+ }
264298 } else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
265299 if ((address & 0xffff ) < 0x400 ) {
266300 return m_hard[address & 0x3ff ];
@@ -296,6 +330,23 @@ uint16_t PCSX::Memory::read16(uint32_t address) {
296330 if (pointer != nullptr ) {
297331 const uint32_t offset = address & 0xffff ;
298332 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+ }
299350 } else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
300351 if ((address & 0xffff ) < 0x400 ) {
301352 uint16_t *ptr = (uint16_t *)&m_hard[address & 0x3ff ];
@@ -328,6 +379,23 @@ uint32_t PCSX::Memory::read32(uint32_t address, ReadType readType) {
328379 if (pointer != nullptr ) {
329380 const uint32_t offset = address & 0xffff ;
330381 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+ }
331399 } else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
332400 if ((address & 0xffff ) < 0x400 ) {
333401 uint32_t *ptr = (uint32_t *)&m_hard[address & 0x3ff ];
@@ -437,6 +505,15 @@ void PCSX::Memory::write8(uint32_t address, uint32_t value) {
437505 const uint32_t offset = address & 0xffff ;
438506 *(pointer + offset) = static_cast <uint8_t >(value);
439507 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+ }
440517 } else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
441518 if ((address & 0xffff ) < 0x400 ) {
442519 m_hard[address & 0x3ff ] = value;
@@ -465,6 +542,17 @@ void PCSX::Memory::write16(uint32_t address, uint32_t value) {
465542 const uint32_t offset = address & 0xffff ;
466543 *(uint16_t *)(pointer + offset) = SWAP_LEu16 (static_cast <uint16_t >(value));
467544 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+ }
468556 } else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
469557 if ((address & 0xffff ) < 0x400 ) {
470558 uint16_t *ptr = (uint16_t *)&m_hard[address & 0x3ff ];
@@ -494,6 +582,17 @@ void PCSX::Memory::write32(uint32_t address, uint32_t value) {
494582 const uint32_t offset = address & 0xffff ;
495583 *(uint32_t *)(pointer + offset) = SWAP_LEu32 (value);
496584 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+ }
497596 } else if (page == 0x1f80 || page == 0x9f80 || page == 0xbf80 ) {
498597 if ((address & 0xffff ) < 0x400 ) {
499598 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
717816 auto toCopy = std::min (size, c_blockSize - offset);
718817 memcpy (block + offset, src, toCopy);
719818}
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