Skip to content

Commit f1b4718

Browse files
committed
implement DMA-msan compatibility
1 parent c30393d commit f1b4718

File tree

8 files changed

+207
-83
lines changed

8 files changed

+207
-83
lines changed

src/core/gpu.cc

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -437,29 +437,38 @@ inline bool PCSX::GPU::CheckForEndlessLoop(uint32_t laddr) {
437437
uint32_t PCSX::GPU::gpuDmaChainSize(uint32_t addr) {
438438
uint32_t size;
439439
uint32_t DMACommandCounter = 0;
440+
bool usingMsan = g_emulator->m_mem->msanInitialized();
440441

441442
s_usedAddr[0] = s_usedAddr[1] = s_usedAddr[2] = 0xffffff;
442443

443444
// initial linked list s_ptr (word)
444445
size = 1;
445446

446447
do {
447-
addr &= 0x7ffffc;
448+
uint32_t header;
449+
if (usingMsan && addr >= PCSX::Memory::c_msanStart && addr < PCSX::Memory::c_msanEnd) {
450+
addr &= 0xfffffffc;
451+
header = *(uint32_t *) (g_emulator->m_mem->m_msanRAM + (addr - PCSX::Memory::c_msanStart));
452+
} else {
453+
addr &= g_emulator->getRamMask<4>();
454+
header = SWAP_LEu32(*g_emulator->m_mem->getPointer<uint32_t>(addr));
455+
}
448456

449457
if (DMACommandCounter++ > 2000000) break;
450458
if (CheckForEndlessLoop(addr)) break;
451459

452-
uint32_t head = SWAP_LEu32(*g_emulator->m_mem->getPointer<uint32_t>(addr));
453-
454460
// # 32-bit blocks to transfer
455-
size += head >> 24;
461+
size += (header >> 24) + 1;
456462

457463
// next 32-bit pointer
458-
addr = head & 0xfffffc;
459-
size += 1;
460-
} while (!(addr & 0x800000)); // contrary to some documentation, the end-of-linked-list marker is not actually
461-
// 0xFF'FFFF any pointer with bit 23 set will do.
462-
return size;
464+
uint32_t nextAddr = header & 0xfffffc;
465+
if (usingMsan && nextAddr == PCSX::Memory::c_msanChainMarker) {
466+
addr = g_emulator->m_mem->msanGetChainPtr(addr);
467+
continue;
468+
}
469+
addr = nextAddr;
470+
} while (!(addr & 0x800000)); // contrary to some documentation, the end-of-linked-list marker is not actually
471+
return size; // 0xFF'FFFF any pointer with bit 23 set will do.
463472
}
464473

465474
uint32_t PCSX::GPU::readStatus() {
@@ -683,30 +692,43 @@ void PCSX::GPU::directDMARead(uint32_t *dest, int transferSize, uint32_t hwAddr)
683692
void PCSX::GPU::chainedDMAWrite(const uint32_t *memory, uint32_t hwAddr) {
684693
uint32_t addr = hwAddr;
685694
uint32_t DMACommandCounter = 0;
695+
bool usingMsan = g_emulator->m_mem->msanInitialized();
686696

687697
s_usedAddr[0] = s_usedAddr[1] = s_usedAddr[2] = 0xffffff;
688698

689699
do {
690-
addr &= g_emulator->getRamMask<4>();
700+
uint32_t header;
701+
const uint32_t *feed;
702+
if (usingMsan && addr >= PCSX::Memory::c_msanStart && addr < PCSX::Memory::c_msanEnd) {
703+
addr &= 0xfffffffc;
704+
const uint32_t *headerPtr = (uint32_t *) (g_emulator->m_mem->m_msanRAM + (addr - PCSX::Memory::c_msanStart));
705+
header = *headerPtr;
706+
feed = headerPtr + 1;
707+
} else {
708+
addr &= g_emulator->getRamMask<4>();
709+
header = memory[addr / 4];
710+
feed = memory + addr / 4 + 1;
711+
}
691712

692713
if (DMACommandCounter++ > 2000000) break;
693714
if (CheckForEndlessLoop(addr)) break;
694715

695716
// # 32-bit blocks to transfer
696-
addr >>= 2;
697-
uint32_t header = memory[addr];
698-
uint32_t transferSize = header >> 24;
699-
const uint32_t *feed = memory + addr + 1;
700-
Buffer buf(feed, transferSize);
717+
uint32_t transferWords = header >> 24;
718+
Buffer buf(feed, transferWords);
701719
while (!buf.isEmpty()) {
702-
m_processor->processWrite(buf, Logged::Origin::CHAIN_DMA, addr << 2, transferSize);
720+
m_processor->processWrite(buf, Logged::Origin::CHAIN_DMA, addr, transferWords);
703721
}
704722

705723
// next 32-bit pointer
706-
addr = header & 0xfffffc;
707-
} while (!(addr & 0x800000)); // contrary to some documentation, the end-of-linked-list marker is not actually
708-
// 0xFF'FFFF any pointer with bit 23 set will do.
709-
}
724+
uint32_t nextAddr = header & 0xfffffc;
725+
if (usingMsan && nextAddr == PCSX::Memory::c_msanChainMarker) {
726+
addr = g_emulator->m_mem->msanGetChainPtr(addr);
727+
continue;
728+
}
729+
addr = nextAddr;
730+
} while (!(addr & 0x800000)); // contrary to some documentation, the end-of-linked-list marker is not actually
731+
} // 0xFF'FFFF any pointer with bit 23 set will do.
710732

711733
void PCSX::GPU::Command::processWrite(Buffer &buf, Logged::Origin origin, uint32_t originValue, uint32_t length) {
712734
while (!buf.isEmpty()) {

src/core/psxdma.cc

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,24 @@ void dma6(uint32_t madr, uint32_t bcr, uint32_t chcr) {
9999
// already 32-bit size
100100
size = bcr;
101101

102-
while (bcr--) {
103-
*mem-- = SWAP_LE32((madr - 4) & 0xffffff);
104-
madr -= 4;
102+
if (PCSX::g_emulator->m_mem->msanInitialized() && madr >= PCSX::Memory::c_msanStart && madr < PCSX::Memory::c_msanEnd) {
103+
uint32_t msanAddress = madr - PCSX::Memory::c_msanStart;
104+
while (bcr--) {
105+
// use write32 instead of the direct pointer so that the msan memory gets marked as usable
106+
PCSX::g_emulator->m_mem->write32(madr, PCSX::Memory::c_msanChainMarker);
107+
PCSX::g_emulator->m_mem->msanSetChainPtr(madr, madr - 4, 0);
108+
madr -= 4;
109+
}
110+
madr += 4;
111+
PCSX::g_emulator->m_mem->write32(madr, 0xffffff);
112+
} else {
113+
while (bcr--) {
114+
*mem-- = SWAP_LE32((madr - 4) & 0xffffff);
115+
madr -= 4;
116+
}
117+
mem++;
118+
*mem = 0xffffff;
105119
}
106-
mem++;
107-
*mem = 0xffffff;
108120
if (PCSX::g_emulator->settings.get<PCSX::Emulator::SettingDebugSettings>()
109121
.get<PCSX::Emulator::DebugSettings::Debug>()) {
110122
PCSX::g_emulator->m_debug->checkDMAwrite(6, madr, size * 4);

src/core/psxhw.cc

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,20 @@ uint32_t PCSX::HW::read32(uint32_t add) {
371371
hard = g_emulator->m_mem->msanRealloc(ptr, size);
372372
break;
373373
}
374+
case 0x1f802094: {
375+
uint32_t headerAddr = g_emulator->m_cpu->m_regs.GPR.n.a0;
376+
if (headerAddr == 0x1f802094) {
377+
g_system->printf(_("Recursive msanGetChainPtr\n"));
378+
g_system->pause();
379+
return 0xffffffff;
380+
}
381+
uint32_t ptr = g_emulator->m_mem->read32(headerAddr) & 0xfffffc;
382+
if (ptr == PCSX::Memory::c_msanChainMarker) {
383+
return g_emulator->m_mem->msanGetChainPtr(headerAddr);
384+
} else {
385+
return ptr;
386+
}
387+
}
374388
default: {
375389
uint32_t *ptr = (uint32_t *)&g_emulator->m_mem->m_hard[hwadd & 0xffff];
376390
hard = SWAP_LEu32(*ptr);
@@ -656,47 +670,47 @@ void PCSX::HW::write32(uint32_t add, uint32_t value) {
656670
break;
657671
case 0x1f801080:
658672
PSXHW_LOG("DMA0 MADR 32bit write %x\n", value);
659-
g_emulator->m_mem->setMADR<0>(value & 0xffffff);
673+
g_emulator->m_mem->setMADR<0>(value);
660674
return;
661675
case 0x1f801088:
662676
PSXHW_LOG("DMA0 CHCR 32bit write %x\n", value);
663677
dmaExec<0>(value); // DMA0 chcr (MDEC in DMA)
664678
return;
665679
case 0x1f801090:
666680
PSXHW_LOG("DMA1 MADR 32bit write %x\n", value);
667-
g_emulator->m_mem->setMADR<1>(value & 0xffffff);
681+
g_emulator->m_mem->setMADR<1>(value);
668682
return;
669683
case 0x1f801098:
670684
PSXHW_LOG("DMA1 CHCR 32bit write %x\n", value);
671685
dmaExec<1>(value); // DMA1 chcr (MDEC out DMA)
672686
return;
673687
case 0x1f8010a0:
674688
PSXHW_LOG("DMA2 MADR 32bit write %x\n", value);
675-
g_emulator->m_mem->setMADR<2>(value & 0xffffff);
689+
g_emulator->m_mem->setMADR<2>(value);
676690
return;
677691
case 0x1f8010a8:
678692
PSXHW_LOG("DMA2 CHCR 32bit write %x\n", value);
679693
dmaExec<2>(value); // DMA2 chcr (GPU DMA)
680694
return;
681695
case 0x1f8010b0:
682696
PSXHW_LOG("DMA3 MADR 32bit write %x\n", value);
683-
g_emulator->m_mem->setMADR<3>(value & 0xffffff);
697+
g_emulator->m_mem->setMADR<3>(value);
684698
return;
685699
case 0x1f8010b8:
686700
PSXHW_LOG("DMA3 CHCR 32bit write %x\n", value);
687701
dmaExec<3>(value); // DMA3 chcr (CDROM DMA)
688702
return;
689703
case 0x1f8010c0:
690704
PSXHW_LOG("DMA4 MADR 32bit write %x\n", value);
691-
g_emulator->m_mem->setMADR<4>(value & 0xffffff);
705+
g_emulator->m_mem->setMADR<4>(value);
692706
return;
693707
case 0x1f8010c8:
694708
PSXHW_LOG("DMA4 CHCR 32bit write %x\n", value);
695709
dmaExec<4>(value); // DMA4 chcr (SPU DMA)
696710
return;
697711
case 0x1f8010d0:
698712
PSXHW_LOG("DMA5 MADR 32bit write %x\n", value);
699-
g_emulator->m_mem->setMADR<5>(value & 0xffffff);
713+
g_emulator->m_mem->setMADR<5>(value);
700714
return;
701715
#if 0
702716
case 0x1f8010d8:
@@ -706,7 +720,7 @@ void PCSX::HW::write32(uint32_t add, uint32_t value) {
706720
#endif
707721
case 0x1f8010e0:
708722
PSXHW_LOG("DMA6 MADR 32bit write %x\n", value);
709-
g_emulator->m_mem->setMADR<6>(value & 0xffffff);
723+
g_emulator->m_mem->setMADR<6>(value);
710724
return;
711725
case 0x1f8010e8:
712726
PSXHW_LOG("DMA6 CHCR 32bit write %x\n", value);
@@ -805,6 +819,18 @@ void PCSX::HW::write32(uint32_t add, uint32_t value) {
805819
g_emulator->m_mem->msanFree(value);
806820
break;
807821
}
822+
case 0x1f802094: {
823+
if (value == 0x1f802094) {
824+
g_system->printf(_("Recursive msanSetChainPtr\n"));
825+
g_system->pause();
826+
return;
827+
}
828+
uint32_t ptrToNext = g_emulator->m_cpu->m_regs.GPR.n.a0;
829+
uint32_t wordCount = g_emulator->m_cpu->m_regs.GPR.n.a1;
830+
uint32_t markerValue = g_emulator->m_mem->msanSetChainPtr(value, ptrToNext, wordCount);
831+
g_emulator->m_mem->write32(value, markerValue);
832+
return;
833+
}
808834
default: {
809835
if ((hwadd >= 0x1f801c00) && (hwadd < 0x1f801e00)) {
810836
write16(add, value & 0xffff);

src/core/psxhw.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ class HW {
4949
mem->setCHCR<n>(chcr);
5050
if ((chcr & 0x01000000) && mem->template isDMAEnabled<n>()) {
5151
uint32_t madr = mem->template getMADR<n>();
52-
madr &= 0x7ffffc;
52+
bool usingMsan = g_emulator->m_mem->msanInitialized();
53+
if (usingMsan && madr >= Memory::c_msanStart && madr < Memory::c_msanEnd) {
54+
madr &= 0xfffffffc;
55+
} else {
56+
madr &= 0x7ffffc;
57+
}
5358
uint32_t bcr = mem->template getBCR<n>();
5459
uint32_t mode = (chcr & 0x00000600) >> 9;
5560
if constexpr (n == 0) {
@@ -70,7 +75,12 @@ class HW {
7075
uint32_t DMACommandCounter = 0;
7176

7277
do {
73-
madr &= 0x7ffffc;
78+
uint32_t *madrAsPtr;
79+
if (usingMsan && madr >= Memory::c_msanStart && madr < Memory::c_msanEnd) {
80+
madr &= 0xfffffffc;
81+
} else {
82+
madr &= 0x7ffffc;
83+
}
7484

7585
if (DMACommandCounter++ > 2000000) break;
7686
if (madr == usedAddr[1]) break;
@@ -83,7 +93,12 @@ class HW {
8393
}
8494

8595
usedAddr[0] = madr;
86-
madr = SWAP_LEu32(*mem->getPointer<uint32_t>(madr)) & 0xffffff;
96+
uint32_t nextMadr = SWAP_LEu32(*mem->getPointer<uint32_t>(madr)) & 0xffffff;
97+
if (usingMsan && nextMadr == Memory::c_msanChainMarker) {
98+
madr = g_emulator->m_mem->msanGetChainPtr(madr);
99+
continue;
100+
}
101+
madr = nextMadr;
87102
} while (!(madr & 0x800000));
88103
if ((madr & 0xffffff) != 0xffffff) {
89104
mem->dmaInterruptError();

src/core/psxinterpreter.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,9 @@ void InterpretedCPU::psxSW(uint32_t code) {
997997
void InterpretedCPU::psxSWL(uint32_t code) {
998998
uint32_t addr = _oB_;
999999
uint32_t shift = addr & 3;
1000-
uint32_t mem = PCSX::g_emulator->m_mem->read32(addr & ~3);
1000+
// the check avoids msan interpreting a fully aligned store as a read
1001+
// however it may still interpret misaligned stores as reads
1002+
uint32_t mem = shift != 3? PCSX::g_emulator->m_mem->read32(addr & ~3): 0;
10011003

10021004
PCSX::g_emulator->m_mem->write32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) | (mem & SWL_MASK[shift]));
10031005
/*
@@ -1012,7 +1014,9 @@ void InterpretedCPU::psxSWL(uint32_t code) {
10121014
void InterpretedCPU::psxSWR(uint32_t code) {
10131015
uint32_t addr = _oB_;
10141016
uint32_t shift = addr & 3;
1015-
uint32_t mem = PCSX::g_emulator->m_mem->read32(addr & ~3);
1017+
// the check avoids msan interpreting a fully aligned store as a read
1018+
// however it may still interpret misaligned stores as reads
1019+
uint32_t mem = shift != 0? PCSX::g_emulator->m_mem->read32(addr & ~3): 0;
10161020

10171021
PCSX::g_emulator->m_mem->write32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) | (mem & SWR_MASK[shift]));
10181022

0 commit comments

Comments
 (0)