mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
Start the main thread with COP0 Status.IE set (#214)
Guest code reads COP0 Status to decide whether interrupts are enabled,
and two different bits are involved:
IE (bit 0) the architectural MIPS interrupt enable, set once by the
kernel during boot and normally left set.
EIE (bit 16) the EE-specific enable that `ei` and `di` toggle.
We never execute the boot ROM, so nothing was setting either one, and
R5900Context started with Status at zero.
That is not cosmetic. libkernel's StartThread opens with
`mfc0 Status; xori 1; andi 1` and bails out with -1 when IE is clear --
its "you must call iStartThread from an interrupt handler" guard. With
Status at zero that guard fired every time, so every StartThread failed.
Dragon Quest VIII hits this during boot: it creates its CD streaming
thread, gets -1, prints "Can't start thread for streaming." and then
deadlocks with every thread blocked and none runnable. Nothing in the
runtime logs anything, because from its point of view the guest simply
asked a question and got an answer.
EIE matters for the matching reason: DIntr reports whether it was set so
the caller knows whether to pair it with an EIntr. Starting at zero makes
DIntr always answer "already disabled", so the re-enable never happens.
Two changes, both needed:
- R5900Context's constructor now sets Status to EIE | IE rather than 0.
BEV is deliberately left clear -- that selects the boot exception
vectors, which is the pre-handoff state, not this one.
- PS2Runtime's constructor no longer memsets m_cpuContext. R5900Context
already zeroes itself before applying its reset values, so the memset
only threw those values away. Threads created later were unaffected
because EeScheduler::startThread assigns `R5900Context{}`, which is
why this presented as "the main thread cannot start threads" rather
than something more obviously global.
(cherry picked from commit 2ac2ce6320)
This commit is contained in:
@@ -150,10 +150,10 @@ struct alignas(16) R5900Context
|
||||
|
||||
// Reset COP0 registers
|
||||
cop0_random = 47; // Start at maximum value
|
||||
// cop0_status = 0x400000; // BEV set, ERL clear, kernel mode
|
||||
// 0x00400000 = BEV (Boot Exception Vectors).
|
||||
// 0x00000000 = Normal mode (after BIOS handoff).
|
||||
cop0_status = 0x00000000;
|
||||
// Status as the EE kernel leaves it at handoff. IE (bit 0) and EIE
|
||||
// (bit 16) are separate enables and guest code reads both; libkernel's
|
||||
// StartThread refuses to run while IE is clear.
|
||||
cop0_status = 0x00010001; // EIE | IE
|
||||
cop0_prid = 0x00002e20; // CPU ID for R5900
|
||||
|
||||
in_delay_slot = false;
|
||||
|
||||
@@ -491,7 +491,9 @@ PS2Runtime::PS2Runtime()
|
||||
}
|
||||
#endif
|
||||
|
||||
std::memset(&m_cpuContext, 0, sizeof(m_cpuContext));
|
||||
// Assign rather than memset: R5900Context's constructor zeroes itself and
|
||||
// then applies the COP0 reset values, which a memset here would discard.
|
||||
m_cpuContext = R5900Context{};
|
||||
|
||||
// R0 is always zero in MIPS
|
||||
m_cpuContext.r[0] = _mm_set1_epi32(0);
|
||||
|
||||
Reference in New Issue
Block a user