Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
eeffcd5
jakx: initial decompiler and project support
VodBox Aug 11, 2024
daa8693
jakx: begin all-types.gc definition work
VodBox Aug 11, 2024
12c8b7b
jakx: parse text extraction
VodBox Aug 21, 2024
050ce96
jakx: correct level max
VodBox Aug 22, 2024
8433ce1
jakx: more type definition work
VodBox Aug 22, 2024
dc24fb6
jakx: audio extraction
VodBox Aug 23, 2024
cc5f423
jakx: update sparticle decomp fields
VodBox Aug 24, 2024
fa3d75b
refactor: Add jakx stub code
yodaxtah Jun 21, 2025
246fb8f
Merge branch 'master' into jakx-ckernel
yodaxtah Jun 21, 2025
acf3b4b
[jakx] Edit game/kernel/fileio.cpp
yodaxtah Jun 22, 2025
7ab238a
[jakx] Edit game/kernel/jakx/kboot.cpp
yodaxtah Jun 22, 2025
713eed9
[jakx] Edit game/kernel/jakx/kdgo.cpp
yodaxtah Jun 22, 2025
fe35467
[jakx] Edit game/kernel/common/fileio.cpp
yodaxtah Jun 22, 2025
54754fd
[jakx] Edit game/kernel/common/kdgo.cpp
yodaxtah Jun 22, 2025
e6e6401
[jakx] Edit game/kernel/common/kdsnetm.cpp
yodaxtah Jun 22, 2025
cb47c8e
[jakx] Edit game/kernel/common/klisten.cpp
yodaxtah Jun 22, 2025
e0bbc40
[jakx] Edit game/kernel/common/kmachine.cpp
yodaxtah Jun 28, 2025
9c4681a
[jakx] Edit game/kernel/common/kmalloc.cpp
yodaxtah Jun 28, 2025
ca78701
[jakx] Edit game/kernel/common/kscheme.cpp
yodaxtah Jun 28, 2025
061c2f3
[jakx] Edit game/kernel/common/klisten.cpp
yodaxtah Jun 29, 2025
d817f6b
[jakx] Define kmkdir
yodaxtah Jul 5, 2025
3fc990f
[jakx] Define USE_OVERLORD2_W
yodaxtah Jul 5, 2025
6106da8
[jakx] Edit game/kernel/jakx/kmachine.cpp
yodaxtah Jul 5, 2025
4414e1d
[jakx] Define missing sceMkDir
yodaxtah Jul 5, 2025
efa4654
[jakx] Dirty fix compilation for Ubuntu setup
yodaxtah Sep 14, 2025
496e992
Merge branch 'master' into jakx-ckernel
yodaxtah Sep 14, 2025
100c949
Merge branch 'master' into jakx-ckernel
xTVaser Dec 30, 2025
66d80b3
Merge remote-tracking branch 'origin/master' into jakx-ckernel
xTVaser Jan 1, 2026
723a537
jakx: remove fontutils and PAL decompilation type cast files
xTVaser Jan 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions game/kernel/common/fileio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,16 +327,23 @@ Ptr<u8> FileLoad(char* name, Ptr<kheapinfo> heap, Ptr<u8> memory, u32 malloc_fla
s32 FileSave(char* name, u8* data, s32 size) {
s32 fd = sceOpen(name, SCE_WRONLY | SCE_TRUNC | SCE_CREAT);
if (fd < 0) {
MsgErr("dkernel: file write !open '%s'\n", name);
MsgErr("dkernel: file write !open: '%s'\n", name);
sceClose(fd);
return 0xfffffffa;
}

if (size != 0) {
int writeOffset = 0;
while (size != 0) {
// in jak 3, this became a loop over smaller writes for some reason.
s32 written = sceWrite(fd, data, size);
if (written != size) {
MsgErr("dkernel: can't write full file '%s'\n", name);
s32 chunkSize = 0x1000000;
if (size < 0x1000000) {
chunkSize = size; // one or final write
}
s32 written = sceWrite(fd, data + writeOffset, chunkSize);
writeOffset += written;
size -= written;
if (written != chunkSize) {
MsgErr("dkernel: can't write full file: '%s'\n", name);
sceClose(fd);
return 0xfffffffa;
}
Expand Down
6 changes: 6 additions & 0 deletions game/kernel/common/kboot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ char DebugBootLevel[64];
// Pass to GOAL kernel on boot
char DebugBootMessage[64];

// Added in Jak X, set to true in InitIOP
bool POWERING_OFF_W;

// game configuration
MasterConfig masterConfig;

// Added in Jak X
bool USE_OVERLORD2_W;

void kboot_init_globals_common() {
MasterExit = RuntimeExitStatus::RUNNING;
DiskBoot = 0;
Expand Down
6 changes: 6 additions & 0 deletions game/kernel/common/kboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,15 @@ extern char DebugBootLevel[64];
// Pass to GOAL kernel on boot
extern char DebugBootMessage[64];

// Added in Jak X, set to false by Sce callback
extern bool POWERING_OFF_W;

// Added in PC port, option to run listener functions without the kernel for debugging
extern u32 MasterUseKernel;

// Added in Jak X
extern bool USE_OVERLORD2_W;

struct MasterConfig {
u16 language; //! GOAL language 0
u16 aspect; //! SCE_ASPECT 2
Expand Down
223 changes: 166 additions & 57 deletions game/kernel/common/kdgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,81 @@
u32 sShowStallMsg; //! setting to show a "stalled on iop" message
u16 x[8]; //! stupid temporary for storing a message
u32 sMsgNum; //! Toggle for double buffered message sending.
bool IOP_RUNNING_W;
bool RPC_Initialized_G;

const s32 NUMBER_OF_RPC_CHANNELS = 7;
struct RpcCallEndFunctionArg_W {
int sema_id;
void *callback;
int third;
int fourth;
};
RpcCallEndFunctionArg_W RpcCallEndFunctionArgs_W[NUMBER_OF_RPC_CHANNELS];

const s32 NUMBER_OF_RPC_CHANNEL_PAIRS = 6; // FIXME: Why is this 6 and not 7?
struct RpcChannelIdPair_W {
int channel;
int id;
};
RpcChannelIdPair_W RpcChannels_W[NUMBER_OF_RPC_CHANNEL_PAIRS];

typedef void EndFunctionType(int idk1, int idk2);

void kdgo_init_globals() {
memset(x, 0, sizeof(x));
memset(cd, 0, sizeof(cd));
sShowStallMsg = 1;
}

int RpcCallEndFunction_W(long param_1) {
if (param_1 != 0) {
int* args = (int*)param_1;
if ((void*)(args[1]) != nullptr) {
((EndFunctionType*)(args[1]))(args[2], args[3]);
}
// FIXME: What to do with this?
// return iSignalSema(*args);
return 0;
} else {
int in_v0_lo;

Check warning on line 58 in game/kernel/common/kdgo.cpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

game/kernel/common/kdgo.cpp#L58

Variable 'in_v0_lo' is not assigned a value.
return in_v0_lo;
}
}

/*!
* Call the given RPC with the given function number and buffers.
* In Jak X, errors are written out. The conditions have been negated.
*/
s32 RpcCall(s32 rpcChannel,
u32 fno,
bool async,
void* sendBuff,
s32 sendSize,
void* recvBuff,
s32 recvSize) {
return sceSifCallRpc(&cd[rpcChannel], fno, async, sendBuff, sendSize, recvBuff, recvSize, nullptr,
nullptr);
s32 recvSize,
void* callback) {
if (rpcChannel >= NUMBER_OF_RPC_CHANNELS) {
MsgErr("dkernel: RpcCall() error; invalid port id %d\n", rpcChannel);
} else if (sendSize >= 0xffff1) {
MsgErr("dkernel: RpcCall() error; invalid send/receive sizes (ssize=%d rsize=%d)\n", (s32)sendSize, recvSize);
} else if (!((((u32)sendSize < 0xffff1) && (-1 < recvSize)) && (recvSize < 0xffff1))) {
MsgErr("dkernel: RpcCall() error; NULL send buffer (secv=0x%08x ssize=%d)\n", nullptr, sendSize);
} else if (!(recvSize < 1) || (recvBuff != nullptr)) {
MsgErr("dkernel: RpcCall() error; NULL receive buffer (recv=0x%08x rsize=%d)\n", nullptr, recvSize);
} else if ((uintptr_t)sendBuff & 0xf) {
MsgErr("dkernel: RpcCall() error; misaligned send buffer (send=0x%08x ssize=%d)\n", sendBuff, sendSize); // added missing parenthesis
} else if ((uintptr_t)recvBuff & 0xf) {

Check warning on line 85 in game/kernel/common/kdgo.cpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

game/kernel/common/kdgo.cpp#L85

Condition '(unsigned long)recvBuff&0xf' is always false
MsgErr("dkernel: RpcCall() error; misaligned receive buffer (recv=0x%08x rsize=%d\n", recvBuff, recvSize);
} else {
// FIXME: What to do with this?
// WaitSema(RpcCallEndFunctionArgs_W[rpcChannel].sema_id);
RpcCallEndFunctionArgs_W[rpcChannel].callback = callback;
RpcCallEndFunctionArgs_W[rpcChannel].fourth = 0; // in_stack_00000008;
RpcCallEndFunctionArgs_W[rpcChannel].third = 0; // in_stack_00000000;
return sceSifCallRpc(&cd[rpcChannel], fno, (int)async, sendBuff, sendSize, recvBuff, recvSize, (void*)RpcCallEndFunction_W, &RpcCallEndFunctionArgs_W[rpcChannel]);
}
return -1;
}

namespace {
Expand Down Expand Up @@ -64,6 +120,7 @@
auto send_size = args->get_as<s32>(4);
auto recv_buff = args->get_as<u64>(5);
auto recv_size = args->get_as<s32>(6);
// FIXME: Pass to RpcCall?
return sceSifCallRpc(&cd[rpcChannel], fno, async, Ptr<u8>(send_buff).c(), send_size,
Ptr<u8>(recv_buff).c(), recv_size, nullptr, nullptr);
}
Expand All @@ -72,87 +129,126 @@
* Check if the given RPC is busy, by channel.
*/
u32 RpcBusy(s32 channel) {
return sceSifCheckStatRpc(&cd[channel].rpcd);
if (channel < NUMBER_OF_RPC_CHANNELS) {
return sceSifCheckStatRpc(&cd[channel].rpcd);
} else {
return 1;
}
}

/*!
* Wait for an RPC to not be busy. Prints a stall message if sShowStallMsg is true and we have
* to wait on the IOP. Stalling here is bad because it means the rest of the game can't run.
*/
void RpcSync(s32 channel) {
if (6 < channel) {
MsgErr("dkernel: RpcSync() error; invalid port id %d\n", channel);
}
if (RpcBusy(channel)) {
if (sShowStallMsg) {
Msg(6, "STALL: [kernel] waiting for IOP on RPC port #%d\n", channel);
Msg(6, "dkernel: RpcSync() warning; port #%d stalled; waiting...\n", channel);
}
// FIXME: What to do with this?
// WaitSema(RpcCallEndFunctionArgs_W[channel].sema_id);
// FIXME: What to do with this?
// SignalSema(RpcCallEndFunctionArgs_W[channel].sema_id);
while (RpcBusy(channel)) {
// an attempt to avoid spamming SIF?
u32 i = 0;
while (i < 1000) {
i++;
}
// FIXME: What to do with this?
// DelayThread(10000);
}
if (sShowStallMsg) {
Msg(6, "dkernel: RpcSync(); port #%d acquired\n", channel);
}
}
}

/*!
* Setup an RPC.
*/
u32 RpcBind(s32 channel, s32 id) {
while (true) {
if (sceSifBindRpc(&cd[channel], id, 1) < 0) {
MsgErr("Error: RpcBind failed on port #%d [%4.4X]\n", channel, id);
return 1;
}
Msg(6, "kernel: RPC port #%d started [%4.4X]\n", channel, id);
// FlushCache(0);
// In Jak 2 they do a sceSifCheckStatRpc, but we can just skip that.

// this was not optimized out in Jak 1, but is _almost_ optimized out in Jak 2 and later.
u32 i = 0;
while (i < 10000) {
i++;
}

if (cd[channel].serve) {
break;
s32 RpcBind(s32 channel, s32 id) {
if (channel < NUMBER_OF_RPC_CHANNELS) {
bool displayedWarning = false;
while (true) {
if (sceSifBindRpc(&cd[channel], id, 0) < 0) {
MsgErr("dkernel: RpcBind() error; bind failed on port #%d id 0x%08x\n", channel, id);
return -1;
} else if (cd[channel].serve) {
MsgErr("dkernel: RpcBind() port #%d id 0x%08x bound\n", channel, id);
// In Jak 2 they do a sceSifCheckStatRpc, but we can just skip that.
return 0;
} else if (!displayedWarning) {
displayedWarning = true;
MsgErr("dkernel: RpcBind() warning; port #%d id 0x%08x not responding; retrying...\n", channel, id);
}
// FIXME: What to do with this?
// DelayThread(10000);
// it might seem like looping here is a bad idea (unclear if sceSifBindRpc can be called
// multiple times!) but this actually happens sometimes, at least on development hardware!
// (also, it's not clear that the "serve" field having data in it really means anything - maybe
// the sceSifBindRpc doesn't wait for the connection to be fully set up? This seems likely
// because they had to put that little delay in there before checking.)
}
Msg(6, "kernel: RPC port #%d not responding.\n", channel);
// it might seem like looping here is a bad idea (unclear if sceSifBindRpc can be called
// multiple times!) but this actually happens sometimes, at least on development hardware!
// (also, it's not clear that the "serve" field having data in it really means anything - maybe
// the sceSifBindRpc doesn't wait for the connection to be fully set up? This seems likely
// because they had to put that little delay in there before checking.)
} else {
MsgErr("dkernel: RpcBind() error; invalid port id %d\n", channel);
return -1;
}
return 0;
}

/*!
* Setup all RPCs
*/
u32 InitRPC() {
if (!RpcBind(PLAYER_RPC_CHANNEL, PLAYER_RPC_ID[g_game_version]) &&
!RpcBind(LOADER_RPC_CHANNEL, LOADER_RPC_ID[g_game_version]) &&
!RpcBind(RAMDISK_RPC_CHANNEL, RAMDISK_RPC_ID[g_game_version]) &&
!RpcBind(DGO_RPC_CHANNEL, DGO_RPC_ID[g_game_version]) &&
!RpcBind(STR_RPC_CHANNEL, STR_RPC_ID[g_game_version]) &&
!RpcBind(PLAY_RPC_CHANNEL, PLAY_RPC_ID[g_game_version])) {
s32 InitRPC() {
if (RPC_Initialized_G) {
MsgErr("dkernel: InitRPC() error; multiple initializations attempted");
return -1;
} else {
for (int i = 0; i < NUMBER_OF_RPC_CHANNELS; i++) {
RpcCallEndFunctionArgs_W[i].fourth = 0;
RpcCallEndFunctionArgs_W[i].sema_id = -1;
RpcCallEndFunctionArgs_W[i].callback = nullptr;
RpcCallEndFunctionArgs_W[i].third = 0;
}
for (int i = 0; i < NUMBER_OF_RPC_CHANNEL_PAIRS; i++) {
if (!RpcBind(RpcChannels_W[i].channel, RpcChannels_W[i].id)) {
return -1;
}
}
for (int i = 0; i < NUMBER_OF_RPC_CHANNELS; i++) {
// FIXME: What to do with this?
// ee_sema_t someSema;
// memset(&someSema, 0, 0x18); // MACRO
// someSema.init_count = 1;
// someSema.max_count = 1;
// int semaId = CreateSema(&someSema);
// RpcCallEndFunctionArgs_W[i].sema_id = semaId;
// if (semaId < 0) {
// for (int j = i; j > 0; --j) {
// DeleteSema(RpcCallEndFunctionArgs_W[j].sema_id);
// RpcCallEndFunctionArgs_W[j].sema_id = -1;
// }
// return -1;
// }
}
RPC_Initialized_G = true;
return 0;
}
lg::print("Entering endless loop ... please wait\n");
for (;;) {
}
}

/*!
* Send a message to the IOP to stop it.
*/
void StopIOP() {
x[2] = 0x14; // todo - this type and message
// RpcSync(PLAYER_RPC_CHANNEL);
// RpcCall(PLAYER_RPC_CHANNEL, 0, false, x, 0x50, nullptr, 0);
lg::print("IOP shut down\n");
// sceDmaSync(0x10009000, 0, 0);
lg::print("DMA shut down\n");
int StopIOP() {
if (Is_RPC_Initialized_G() && IOP_RUNNING_W) {
x[2] = 0x10;
x[3] = 0; // todo - this type and message
// RpcSync(1); // FIXME: PLAYER_RPC_CHANNEL at 1? Previously at 0.
IOP_RUNNING_W = false;
// return RpcCall(1, 0, false, x, 0x30, nullptr, 0);
lg::print("IOP shut down\n");
return 0;
} else {
return 0;
}
}

/*!
Expand All @@ -172,8 +268,7 @@
// backup show stall message and set it to false
// EE will be loading DGO in a loop, so it will always be stalling
// no need to print it.
u32 lastShowStall = sShowStallMsg;
sShowStallMsg = 0;
bool lastShowStall = setStallMsg_G(false);

// pick somewhat arbitrary memory to load the DGO into
BeginLoadingDGO("TEST.DGO", Ptr<u8>(0x4800000), Ptr<u8>(0x4c00000), Ptr<u8>(0x4000000));
Expand All @@ -194,9 +289,23 @@
// okay to load the next one
ASSERT(false); // this is different per version, annoyingly. This function is unused though,
// so let's be lazy for now...
// ContinueLoadingDGO(Ptr<u8>(0x4000000));
// ContinueLoadingDGO(Ptr<u8>(0x4800000));
}

sShowStallMsg = lastShowStall;
*/
setStallMsg_G(lastShowStall);
*/
}

bool setStallMsg_GW(bool show)
{
bool oldShowStallMsg;

oldShowStallMsg = sShowStallMsg;
sShowStallMsg = show;
return oldShowStallMsg;
}

bool Is_RPC_Initialized_G(void)
{
return RPC_Initialized_G;
}
15 changes: 11 additions & 4 deletions game/kernel/common/kdgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@
#include "game/kernel/common/Ptr.h"

extern u32 sMsgNum;

extern bool IOP_RUNNING_W;

extern u32 sShowStallMsg;

s32 RpcCall(s32 rpcChannel,
u32 fno,
bool async,
void* sendBuff,
s32 sendSize,
void* recvBuff,
s32 recvSize);
s32 recvSize,
void* callback = nullptr);
u64 RpcCall_wrapper(void* _args);
u32 RpcBusy(s32 channel);
void RpcSync(s32 channel);
void LoadDGOTest();
void kdgo_init_globals();
u32 InitRPC();
void StopIOP();
s32 InitRPC();
int StopIOP();

extern u32 sShowStallMsg;
bool setStallMsg_GW(bool show);
bool Is_RPC_Initialized_G();
Loading
Loading