Skip to content

Commit cc9a1a6

Browse files
authored
Merge pull request #1866 from malucard/main
Implement DMA-msan compatibility
2 parents 830f4cb + b5f1e50 commit cc9a1a6

File tree

9 files changed

+371
-145
lines changed

9 files changed

+371
-145
lines changed

src/core/gpu.cc

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -437,29 +437,50 @@ 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 && PCSX::Memory::inMsanRange(addr)) {
450+
addr &= 0xfffffffc;
451+
switch (g_emulator->m_mem->msanGetStatus<4>(addr)) {
452+
case PCSX::MsanStatus::UNINITIALIZED:
453+
g_system->log(LogClass::GPU, _("GPU DMA went into usable but uninitialized msan memory: %8.8lx\n"), addr);
454+
g_system->pause();
455+
return size;
456+
case PCSX::MsanStatus::UNUSABLE:
457+
g_system->log(LogClass::GPU, _("GPU DMA went into unusable msan memory: %8.8lx\n"), addr);
458+
g_system->pause();
459+
return size;
460+
case PCSX::MsanStatus::OK:
461+
header = *(uint32_t *) (g_emulator->m_mem->m_msanRAM + (addr - PCSX::Memory::c_msanStart));
462+
break;
463+
}
464+
} else {
465+
addr &= g_emulator->getRamMask<4>();
466+
header = SWAP_LEu32(*g_emulator->m_mem->getPointer<uint32_t>(addr));
467+
}
448468

449469
if (DMACommandCounter++ > 2000000) break;
450470
if (CheckForEndlessLoop(addr)) break;
451471

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

457475
// 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;
476+
uint32_t nextAddr = header & 0xffffff;
477+
if (usingMsan && nextAddr == PCSX::Memory::c_msanChainMarker) {
478+
addr = g_emulator->m_mem->msanGetChainPtr(addr);
479+
continue;
480+
}
481+
addr = nextAddr;
482+
} while (!(addr & 0x800000)); // contrary to some documentation, the end-of-linked-list marker is not actually
483+
return size; // 0xFF'FFFF any pointer with bit 23 set will do.
463484
}
464485

465486
uint32_t PCSX::GPU::readStatus() {
@@ -683,30 +704,55 @@ void PCSX::GPU::directDMARead(uint32_t *dest, int transferSize, uint32_t hwAddr)
683704
void PCSX::GPU::chainedDMAWrite(const uint32_t *memory, uint32_t hwAddr) {
684705
uint32_t addr = hwAddr;
685706
uint32_t DMACommandCounter = 0;
707+
bool usingMsan = g_emulator->m_mem->msanInitialized();
686708

687709
s_usedAddr[0] = s_usedAddr[1] = s_usedAddr[2] = 0xffffff;
688710

689711
do {
690-
addr &= g_emulator->getRamMask<4>();
712+
uint32_t header;
713+
const uint32_t *feed;
714+
if (usingMsan && PCSX::Memory::inMsanRange(addr)) {
715+
addr &= 0xfffffffc;
716+
const uint32_t *headerPtr = (uint32_t *) (g_emulator->m_mem->m_msanRAM + (addr - PCSX::Memory::c_msanStart));
717+
switch (g_emulator->m_mem->msanGetStatus<4>(addr)) {
718+
case PCSX::MsanStatus::UNINITIALIZED:
719+
g_system->log(LogClass::GPU, _("GPU DMA went into usable but uninitialized msan memory: %8.8lx\n"), addr);
720+
g_system->pause();
721+
return;
722+
case PCSX::MsanStatus::UNUSABLE:
723+
g_system->log(LogClass::GPU, _("GPU DMA went into unusable msan memory: %8.8lx\n"), addr);
724+
g_system->pause();
725+
return;
726+
case PCSX::MsanStatus::OK:
727+
break;
728+
}
729+
header = *headerPtr;
730+
feed = headerPtr + 1;
731+
} else {
732+
addr &= g_emulator->getRamMask<4>();
733+
header = memory[addr / 4];
734+
feed = memory + addr / 4 + 1;
735+
}
691736

692737
if (DMACommandCounter++ > 2000000) break;
693738
if (CheckForEndlessLoop(addr)) break;
694739

695740
// # 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);
741+
uint32_t transferWords = header >> 24;
742+
Buffer buf(feed, transferWords);
701743
while (!buf.isEmpty()) {
702-
m_processor->processWrite(buf, Logged::Origin::CHAIN_DMA, addr << 2, transferSize);
744+
m_processor->processWrite(buf, Logged::Origin::CHAIN_DMA, addr, transferWords);
703745
}
704746

705747
// 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-
}
748+
uint32_t nextAddr = header & 0xffffff;
749+
if (usingMsan && nextAddr == PCSX::Memory::c_msanChainMarker) {
750+
addr = g_emulator->m_mem->msanGetChainPtr(addr);
751+
continue;
752+
}
753+
addr = nextAddr;
754+
} while (!(addr & 0x800000)); // contrary to some documentation, the end-of-linked-list marker is not actually
755+
} // 0xFF'FFFF any pointer with bit 23 set will do.
710756

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

src/core/psxdma.cc

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,23 @@ 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() && PCSX::Memory::inMsanRange(madr)) {
103+
while (bcr--) {
104+
// use write32 instead of the direct pointer so that the msan memory gets marked as usable
105+
PCSX::g_emulator->m_mem->write32(madr, PCSX::Memory::c_msanChainMarker);
106+
PCSX::g_emulator->m_mem->msanSetChainPtr(madr, madr - 4, 0);
107+
madr -= 4;
108+
}
109+
madr += 4;
110+
PCSX::g_emulator->m_mem->write32(madr, 0xffffff);
111+
} else {
112+
while (bcr--) {
113+
*mem-- = SWAP_LE32((madr - 4) & 0xffffff);
114+
madr -= 4;
115+
}
116+
mem++;
117+
*mem = 0xffffff;
105118
}
106-
mem++;
107-
*mem = 0xffffff;
108119
if (PCSX::g_emulator->settings.get<PCSX::Emulator::SettingDebugSettings>()
109120
.get<PCSX::Emulator::DebugSettings::Debug>()) {
110121
PCSX::g_emulator->m_debug->checkDMAwrite(6, madr, size * 4);

src/core/psxhw.cc

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "core/psxemulator.h"
3131
#include "core/sio.h"
3232
#include "core/sio1.h"
33+
#include "supportpsx/memory.h"
3334
#include "lua/luawrapper.h"
3435
#include "spu/interface.h"
3536

@@ -371,6 +372,26 @@ uint32_t PCSX::HW::read32(uint32_t add) {
371372
hard = g_emulator->m_mem->msanRealloc(ptr, size);
372373
break;
373374
}
375+
case 0x1f802094: {
376+
uint32_t headerAddr = g_emulator->m_cpu->m_regs.GPR.n.a0;
377+
PSXAddress headerAddrInfo(headerAddr);
378+
switch (headerAddrInfo.type) {
379+
case PSXAddress::Type::RAM:
380+
case PSXAddress::Type::MSAN: {
381+
uint32_t ptr = g_emulator->m_mem->read32(headerAddr) & 0xffffff;
382+
if (ptr == PCSX::Memory::c_msanChainMarker) {
383+
return g_emulator->m_mem->msanGetChainPtr(headerAddr);
384+
} else {
385+
return ptr;
386+
}
387+
}
388+
default: {
389+
g_system->printf(_("Called msanGetChainPtr with invalid header pointer %8.8lx\n"), headerAddr);
390+
g_system->pause();
391+
return 0xffffffff;
392+
}
393+
}
394+
}
374395
default: {
375396
uint32_t *ptr = (uint32_t *)&g_emulator->m_mem->m_hard[hwadd & 0xffff];
376397
hard = SWAP_LEu32(*ptr);
@@ -656,47 +677,47 @@ void PCSX::HW::write32(uint32_t add, uint32_t value) {
656677
break;
657678
case 0x1f801080:
658679
PSXHW_LOG("DMA0 MADR 32bit write %x\n", value);
659-
g_emulator->m_mem->setMADR<0>(value & 0xffffff);
680+
g_emulator->m_mem->setMADR<0>(value);
660681
return;
661682
case 0x1f801088:
662683
PSXHW_LOG("DMA0 CHCR 32bit write %x\n", value);
663684
dmaExec<0>(value); // DMA0 chcr (MDEC in DMA)
664685
return;
665686
case 0x1f801090:
666687
PSXHW_LOG("DMA1 MADR 32bit write %x\n", value);
667-
g_emulator->m_mem->setMADR<1>(value & 0xffffff);
688+
g_emulator->m_mem->setMADR<1>(value);
668689
return;
669690
case 0x1f801098:
670691
PSXHW_LOG("DMA1 CHCR 32bit write %x\n", value);
671692
dmaExec<1>(value); // DMA1 chcr (MDEC out DMA)
672693
return;
673694
case 0x1f8010a0:
674695
PSXHW_LOG("DMA2 MADR 32bit write %x\n", value);
675-
g_emulator->m_mem->setMADR<2>(value & 0xffffff);
696+
g_emulator->m_mem->setMADR<2>(value);
676697
return;
677698
case 0x1f8010a8:
678699
PSXHW_LOG("DMA2 CHCR 32bit write %x\n", value);
679700
dmaExec<2>(value); // DMA2 chcr (GPU DMA)
680701
return;
681702
case 0x1f8010b0:
682703
PSXHW_LOG("DMA3 MADR 32bit write %x\n", value);
683-
g_emulator->m_mem->setMADR<3>(value & 0xffffff);
704+
g_emulator->m_mem->setMADR<3>(value);
684705
return;
685706
case 0x1f8010b8:
686707
PSXHW_LOG("DMA3 CHCR 32bit write %x\n", value);
687708
dmaExec<3>(value); // DMA3 chcr (CDROM DMA)
688709
return;
689710
case 0x1f8010c0:
690711
PSXHW_LOG("DMA4 MADR 32bit write %x\n", value);
691-
g_emulator->m_mem->setMADR<4>(value & 0xffffff);
712+
g_emulator->m_mem->setMADR<4>(value);
692713
return;
693714
case 0x1f8010c8:
694715
PSXHW_LOG("DMA4 CHCR 32bit write %x\n", value);
695716
dmaExec<4>(value); // DMA4 chcr (SPU DMA)
696717
return;
697718
case 0x1f8010d0:
698719
PSXHW_LOG("DMA5 MADR 32bit write %x\n", value);
699-
g_emulator->m_mem->setMADR<5>(value & 0xffffff);
720+
g_emulator->m_mem->setMADR<5>(value);
700721
return;
701722
#if 0
702723
case 0x1f8010d8:
@@ -706,7 +727,7 @@ void PCSX::HW::write32(uint32_t add, uint32_t value) {
706727
#endif
707728
case 0x1f8010e0:
708729
PSXHW_LOG("DMA6 MADR 32bit write %x\n", value);
709-
g_emulator->m_mem->setMADR<6>(value & 0xffffff);
730+
g_emulator->m_mem->setMADR<6>(value);
710731
return;
711732
case 0x1f8010e8:
712733
PSXHW_LOG("DMA6 CHCR 32bit write %x\n", value);
@@ -805,6 +826,24 @@ void PCSX::HW::write32(uint32_t add, uint32_t value) {
805826
g_emulator->m_mem->msanFree(value);
806827
break;
807828
}
829+
case 0x1f802094: {
830+
PSXAddress headerAddrInfo(value);
831+
switch (headerAddrInfo.type) {
832+
case PSXAddress::Type::RAM:
833+
case PSXAddress::Type::MSAN: {
834+
uint32_t ptrToNext = g_emulator->m_cpu->m_regs.GPR.n.a0;
835+
uint32_t wordCount = g_emulator->m_cpu->m_regs.GPR.n.a1;
836+
uint32_t markerValue = g_emulator->m_mem->msanSetChainPtr(value, ptrToNext, wordCount);
837+
g_emulator->m_mem->write32(value, markerValue);
838+
return;
839+
}
840+
default: {
841+
g_system->printf(_("Called msanSetChainPtr with invalid header pointer %8.8lx\n"), value);
842+
g_system->pause();
843+
return;
844+
}
845+
}
846+
}
808847
default: {
809848
if ((hwadd >= 0x1f801c00) && (hwadd < 0x1f801e00)) {
810849
write16(add, value & 0xffff);

src/core/psxhw.h

Lines changed: 29 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 && PCSX::Memory::inMsanRange(madr)) {
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,23 @@ class HW {
7075
uint32_t DMACommandCounter = 0;
7176

7277
do {
73-
madr &= 0x7ffffc;
78+
if (usingMsan && PCSX::Memory::inMsanRange(madr)) {
79+
madr &= 0xfffffffc;
80+
switch (g_emulator->m_mem->msanGetStatus<4>(madr)) {
81+
case PCSX::MsanStatus::UNINITIALIZED:
82+
g_system->log(LogClass::GPU, _("GPU DMA went into usable but uninitialized msan memory: %8.8lx\n"), madr);
83+
g_system->pause();
84+
return;
85+
case PCSX::MsanStatus::UNUSABLE:
86+
g_system->log(LogClass::GPU, _("GPU DMA went into unusable msan memory: %8.8lx\n"), madr);
87+
g_system->pause();
88+
return;
89+
case PCSX::MsanStatus::OK:
90+
break;
91+
}
92+
} else {
93+
madr &= 0x7ffffc;
94+
}
7495

7596
if (DMACommandCounter++ > 2000000) break;
7697
if (madr == usedAddr[1]) break;
@@ -83,7 +104,12 @@ class HW {
83104
}
84105

85106
usedAddr[0] = madr;
86-
madr = SWAP_LEu32(*mem->getPointer<uint32_t>(madr)) & 0xffffff;
107+
uint32_t nextMadr = SWAP_LEu32(*mem->getPointer<uint32_t>(madr)) & 0xffffff;
108+
if (usingMsan && nextMadr == Memory::c_msanChainMarker) {
109+
madr = g_emulator->m_mem->msanGetChainPtr(madr);
110+
continue;
111+
}
112+
madr = nextMadr;
87113
} while (!(madr & 0x800000));
88114
if ((madr & 0xffffff) != 0xffffff) {
89115
mem->dmaInterruptError();

src/core/psxinterpreter.cc

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -997,9 +997,16 @@ 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+
addr ^= shift;
1001+
uint32_t mem;
1002+
// special handling to avoid msan interpreting this as a read
1003+
if (PCSX::g_emulator->m_mem->msanInitialized() && PCSX::g_emulator->m_mem->inMsanRange(addr)) {
1004+
mem = *(uint32_t *)&PCSX::g_emulator->m_mem->m_msanRAM[addr - PCSX::Memory::c_msanStart];
1005+
} else {
1006+
mem = PCSX::g_emulator->m_mem->read32(addr);
1007+
}
10011008

1002-
PCSX::g_emulator->m_mem->write32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) | (mem & SWL_MASK[shift]));
1009+
PCSX::g_emulator->m_mem->write32(addr, (_u32(_rRt_) >> SWL_SHIFT[shift]) | (mem & SWL_MASK[shift]));
10031010
/*
10041011
Mem = 1234. Reg = abcd
10051012
0 123a (reg >> 24) | (mem & 0xffffff00)
@@ -1012,9 +1019,16 @@ void InterpretedCPU::psxSWL(uint32_t code) {
10121019
void InterpretedCPU::psxSWR(uint32_t code) {
10131020
uint32_t addr = _oB_;
10141021
uint32_t shift = addr & 3;
1015-
uint32_t mem = PCSX::g_emulator->m_mem->read32(addr & ~3);
1022+
addr ^= shift;
1023+
uint32_t mem;
1024+
// special handling to avoid msan interpreting this as a read
1025+
if (PCSX::g_emulator->m_mem->msanInitialized() && PCSX::g_emulator->m_mem->inMsanRange(addr)) {
1026+
mem = *(uint32_t *)&PCSX::g_emulator->m_mem->m_msanRAM[addr - PCSX::Memory::c_msanStart];
1027+
} else {
1028+
mem = PCSX::g_emulator->m_mem->read32(addr);
1029+
}
10161030

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

10191033
/*
10201034
Mem = 1234. Reg = abcd

0 commit comments

Comments
 (0)