Skip to content

Commit

Permalink
Adding kernel check feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasnoble committed Jan 1, 2025
1 parent 0933dcd commit 0eb0d76
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 21 deletions.
90 changes: 70 additions & 20 deletions src/core/debug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ uint32_t PCSX::Debug::normalizeAddress(uint32_t address) {
return address;
}

bool PCSX::Debug::isInKernel(uint32_t address, bool biosIsKernel) {
uint32_t base = (address >> 20) & 0xffc;
uint32_t real = address & 0x7fffff;
const bool ramExpansion = PCSX::g_emulator->settings.get<PCSX::Emulator::Setting8MB>();
if (base == 0x1fc) return biosIsKernel;
if (base == 0x9fc) return biosIsKernel;
if (base == 0xbfc) return biosIsKernel;
if ((base != 0x000) && (base != 0x800) && (base != 0xa00)) {

Check warning on line 60 in src/core/debug.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ New issue: Complex Conditional

PCSX::Debug::isInKernel has 1 complex conditionals with 2 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
return false;
}
if (ramExpansion) real &= ~0x00600000;
return real < 0x10000;
}

void PCSX::Debug::markMap(uint32_t address, int mask) {
address = normalizeAddress(address);
uint32_t base = (address >> 20) & 0xffc;
Expand Down Expand Up @@ -80,40 +94,63 @@ bool PCSX::Debug::isMapMarked(uint32_t address, int mask) {
}

void PCSX::Debug::process(uint32_t oldPC, uint32_t newPC, uint32_t oldCode, uint32_t newCode, bool linked) {
const auto& regs = g_emulator->m_cpu->m_regs;
const uint32_t basic = newCode >> 26;
const bool isAnyLoadOrStore = (basic >= 0x20) && (basic < 0x3b);
const auto& regs = g_emulator->m_cpu->m_regs;
const bool isJAL = basic == 3;
const bool isJR = (basic == 0) && ((newCode & 0x3f) == 8);
const bool isJALR = (basic == 0) && ((newCode & 0x3f) == 9);
const bool isLB = basic == 0x20;
const bool isLH = basic == 0x21;
const bool isLWL = basic == 0x22;
const bool isLW = basic == 0x23;
const bool isLBU = basic == 0x24;
const bool isLHU = basic == 0x25;
const bool isLWR = basic == 0x26;
const bool isSB = basic == 0x28;
const bool isSH = basic == 0x29;
const bool isSWL = basic == 0x2a;
const bool isSW = basic == 0x2b;
const bool isSWR = basic == 0x2e;
const bool isLWC2 = basic == 0x32;
const bool isSWC2 = basic == 0x3a;
const bool isLoad = isLB || isLBU || isLH || isLHU || isLW || isLWL || isLWR || isLWC2;
const bool isStore = isSB || isSH || isSW || isSWL || isSWR || isSWC2;
const bool wasInKernel = isInKernel(oldPC);
const bool isInKernelNow = isInKernel(newPC);
const uint32_t target = (newCode & 0x03ffffff) * 4 + (newPC & 0xf0000000);
const bool isTargetInKernel = isInKernel(target);
const uint32_t rd = (newCode >> 11) & 0x1f;
uint32_t offset = regs.GPR.r[(newCode >> 21) & 0x1f] + int16_t(newCode);
const bool offsetIsInKernel = isInKernel(offset, false);
const bool isJRToRA = isJR && (rd == 31);
const uint32_t oldPCBase = normalizeAddress(oldPC) & ~0xe0000000;
const uint32_t newPCBase = normalizeAddress(newPC) & ~0xe0000000;
const uint32_t targetBase = normalizeAddress(target) & ~0xe0000000;

checkBP(newPC, BreakpointType::Exec, 4);
if (m_breakmp_e && !isMapMarked(newPC, MAP_EXEC)) {
triggerBP(nullptr, newPC, 4, _("Execution map"));
}
if (m_mapping_e) {
const bool isJAL = basic == 3;
const bool isJALR = (basic == 0) && ((newCode & 0x3F) == 9);
const uint32_t target = (newCode & 0x03ffffff) * 4 + (newPC & 0xf0000000);
const uint32_t rd = (newCode >> 11) & 0x1f;
markMap(newPC, MAP_EXEC);
if (isJAL) markMap(target, MAP_EXEC_JAL);
if (isJALR) markMap(regs.GPR.r[rd], MAP_EXEC_JAL);
}

// Are we jumping from a non-kernel address to a kernel address which:
// - is not a jr to $ra (aka a return from a callback)
// - is not a jump to 0xa0 / 0xb0 / 0xc0 (aka the syscall gates)
// - is not going to the break or exception handler
if ((isJR || isJALR) && !wasInKernel && isTargetInKernel && !isJRToRA && (targetBase != 0x40) &&
(targetBase != 0x80) && (targetBase != 0xa0) && (targetBase != 0xb0) && (targetBase != 0xc0)) {
if (m_checkKernel) {
g_system->printf(_("Jump from 0x%08x to 0x%08x\n"), oldPC, targetBase);
g_system->pause();
}
}

if (isAnyLoadOrStore) {
const bool isLB = basic == 0x20;
const bool isLH = basic == 0x21;
const bool isLWL = basic == 0x22;
const bool isLW = (basic == 0x23) || (basic == 0x32);
const bool isLBU = basic == 0x24;
const bool isLHU = basic == 0x25;
const bool isLWR = basic == 0x26;
const bool isSB = basic == 0x28;
const bool isSH = basic == 0x29;
const bool isSWL = basic == 0x2a;
const bool isSW = (basic == 0x2b) || (basic == 0x3a);
const bool isSWR = basic == 0x2e;
const bool isLWC2 = basic == 0x32;
const bool isSWC2 = basic == 0x3a;
uint32_t offset = regs.GPR.r[(newCode >> 21) & 0x1f] + int16_t(newCode);
if (isLWL || isLWR || isSWR || isSWL) offset &= ~3;
if (isLB || isLBU) {
checkBP(offset, BreakpointType::Read, 1);
Expand Down Expand Up @@ -157,6 +194,19 @@ void PCSX::Debug::process(uint32_t oldPC, uint32_t newPC, uint32_t oldCode, uint
}
if (m_mapping_w32) markMap(offset, MAP_W32);
}
// Are we accessing a kernel address from a non-kernel address, while not in IRQ?
if (!g_emulator->m_cpu->m_inISR && offsetIsInKernel && !wasInKernel) {

Check warning on line 198 in src/core/debug.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Conditional

PCSX::Debug::process increases from 3 complex conditionals with 9 branches to 5 complex conditionals with 20 branches, threshold = 2. A complex conditional is an expression inside a branch (e.g. if, for, while) which consists of multiple, logical operators such as AND/OR. The more logical operators in an expression, the more severe the code smell.
if (m_checkKernel) {
if (isLoad) {
g_system->printf(_("Reading %08x from %08x\n"), offset, oldPC);
g_system->pause();
} else {
g_system->printf(_("Writing to %08x from %08x\n"), offset, oldPC);
g_system->pause();
}
g_system->pause();
}
}

Check warning on line 209 in src/core/debug.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::Debug::process increases in cyclomatic complexity from 60 to 88, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

Check notice on line 209 in src/core/debug.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

ℹ Getting worse: Bumpy Road Ahead

PCSX::Debug::process increases from 10 to 12 logical blocks with deeply nested code, threshold is one single block per function. The Bumpy Road code smell is a function that contains multiple chunks of nested conditional logic. The deeper the nesting and the more bumps, the lower the code health.
}

if (m_step == STEP_NONE) return;
Expand Down
4 changes: 3 additions & 1 deletion src/core/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ namespace PCSX {

class Debug {
public:
uint32_t normalizeAddress(uint32_t address);
static uint32_t normalizeAddress(uint32_t address);
static bool isInKernel(uint32_t address, bool biosIsKernel = true);
static inline std::function<const char*()> s_breakpoint_type_names[] = {l_("Exec"), l_("Read"), l_("Write")};
enum class BreakpointType { Exec, Read, Write };

Expand Down Expand Up @@ -118,6 +119,7 @@ class Debug {
bool m_breakmp_e = false;
bool m_breakmp_r8 = false, m_breakmp_r16 = false, m_breakmp_r32 = false;
bool m_breakmp_w8 = false, m_breakmp_w16 = false, m_breakmp_w32 = false;
bool m_checkKernel = false;

void clearMaps() {
memset(m_mainMemoryMap, 0, sizeof(m_mainMemoryMap));
Expand Down
7 changes: 7 additions & 0 deletions src/core/psxhw.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <stdint.h>

#include "core/cdrom.h"
#include "core/debug.h"
#include "core/gpu.h"
#include "core/logger.h"
#include "core/mdec.h"
Expand Down Expand Up @@ -117,6 +118,9 @@ uint8_t PCSX::HW::read8(uint32_t add) {
case 0x1f802083:
hard = 0x58;
break;
case 0x1f802088:
hard = g_emulator->m_debug->m_checkKernel;
break;

Check warning on line 123 in src/core/psxhw.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::HW::read8 increases in cyclomatic complexity from 17 to 18, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
default:
hard = g_emulator->m_mem->m_hard[hwadd & 0xffff];
PSXHW_LOG("*Unknown 8bit read at address %x\n", add);
Expand Down Expand Up @@ -441,6 +445,9 @@ void PCSX::HW::write8(uint32_t add, uint32_t rawvalue) {
while (top != L.gettop()) L.pop();
}
break;
case 0x1f802088:
g_emulator->m_debug->m_checkKernel = value;
break;

Check warning on line 450 in src/core/psxhw.cc

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

PCSX::HW::write8 increases in cyclomatic complexity from 22 to 23, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

default:
if (addressInRegisterSpace(hwadd)) {
Expand Down
2 changes: 2 additions & 0 deletions src/mips/common/hardware/pcsxhw.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@ static __inline__ void pcsx_debugbreak() { *((volatile char* const)0x1f802081) =
static __inline__ void pcsx_execSlot(uint8_t slot) { *((volatile uint8_t* const)0x1f802081) = slot; }
static __inline__ void pcsx_exit(int code) { *((volatile int16_t* const)0x1f802082) = code; }
static __inline__ void pcsx_message(const char* msg) { *((volatile const char** const)0x1f802084) = msg; }
static __inline__ void pcsx_checkKernel(int enable) { *((volatile char*)0x1f802088) = enable; }
static __inline__ int pcsx_isCheckingKernel() { return *((volatile char* const)0x1f802088) != 0; }

static __inline__ int pcsx_present() { return *((volatile uint32_t* const)0x1f802080) == 0x58534350; }
1 change: 1 addition & 0 deletions src/mips/psyqo/src/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ void psyqo::Kernel::Internal::prepare(Application& application) {
KernelData* const events = reinterpret_cast<KernelData*>(0x120);
__builtin_memset(handlers->data, 0, handlers->size);
__builtin_memset(events->data, 0, events->size);
pcsx_checkKernel(1);
syscall_setDefaultExceptionJmpBuf();
syscall_enqueueSyscallHandler(0);
syscall_enqueueIrqHandler(3);
Expand Down

0 comments on commit 0eb0d76

Please sign in to comment.