mirror of
https://github.com/open-goal/jak-project
synced 2026-08-22 07:04:29 -04:00
[Runtime] misc fixes to runtime and listener (#170)
* misc runtime fixes * clang format
This commit is contained in:
@@ -41,7 +41,9 @@ enum ListenerToTargetMsgKind : u16 {
|
||||
LTT_MSG_PRINT = 6, //! Print an object
|
||||
LTT_MSG_PRINT_SYMBOLS = 7, //! Print all symbols
|
||||
LTT_MSG_RESET = 8, //! Reset the game
|
||||
LTT_MSG_CODE = 9 //! Send code to patch into the game
|
||||
LTT_MSG_CODE = 9, //! Send code to patch into the game
|
||||
// below here are added
|
||||
LTT_MSG_SHUTDOWN = 10 //! Shut down the runtime.
|
||||
};
|
||||
|
||||
/*!
|
||||
|
||||
+7
-13
@@ -8,7 +8,7 @@
|
||||
#ifndef JAK_PTR_H
|
||||
#define JAK_PTR_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include "game/runtime.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -36,25 +36,19 @@ struct Ptr {
|
||||
explicit Ptr(u32 v) { offset = v; }
|
||||
|
||||
/*!
|
||||
* Dereference a pointer. Will throw if you do this on a null pointer.
|
||||
* Dereference a pointer. Will error if you do this on a null pointer.
|
||||
*/
|
||||
T* operator->() {
|
||||
if (offset) {
|
||||
return (T*)(g_ee_main_mem + offset);
|
||||
} else {
|
||||
throw std::runtime_error("Ptr null dereference!");
|
||||
}
|
||||
assert(offset);
|
||||
return (T*)(g_ee_main_mem + offset);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Dereference a pointer. Will throw if you do this on a null pointer.
|
||||
* Dereference a pointer. Will error if you do this on a null pointer.
|
||||
*/
|
||||
T& operator*() {
|
||||
if (offset) {
|
||||
return *(T*)(g_ee_main_mem + offset);
|
||||
} else {
|
||||
throw std::runtime_error("Ptr null dereference!");
|
||||
}
|
||||
assert(offset);
|
||||
return *(T*)(g_ee_main_mem + offset);
|
||||
}
|
||||
|
||||
// pointer math
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "common/cross_os_debug/xdbg.h"
|
||||
#include "common/common_types.h"
|
||||
#include "game/sce/libscf.h"
|
||||
#include "kboot.h"
|
||||
@@ -77,9 +76,6 @@ void kboot_init_globals() {
|
||||
* Add call to sceDeci2Reset when GOAL shuts down.
|
||||
*/
|
||||
s32 goal_main(int argc, const char* const* argv) {
|
||||
// Added for OpenGOAL's debugger
|
||||
xdbg::allow_debugging();
|
||||
|
||||
// Initialize global variables based on command line parameters
|
||||
// This call is not present in the retail version of the game
|
||||
// but the function is, and it likely goes here.
|
||||
|
||||
@@ -161,7 +161,7 @@ void GoalProtoHandler(int event, int param, void* opt) {
|
||||
* DONE, original version used an uncached address and had a FlushCache call, which were both
|
||||
* removed
|
||||
*/
|
||||
s32 SendFromBufferD(s32 msg_kind, u64 p2, char* data, s32 size) {
|
||||
s32 SendFromBufferD(s32 msg_kind, u64 msg_id, char* data, s32 size) {
|
||||
// wait for send to finish or error first...
|
||||
while (protoBlock.send_status > 0) {
|
||||
// on actual PS2, the kernel will run this in another thread.
|
||||
@@ -190,7 +190,7 @@ s32 SendFromBufferD(s32 msg_kind, u64 p2, char* data, s32 size) {
|
||||
header->msg_kind = (ListenerMessageKind)msg_kind;
|
||||
header->u6 = 0;
|
||||
header->msg_size = size;
|
||||
header->msg_id = p2;
|
||||
header->msg_id = msg_id;
|
||||
|
||||
// start send!
|
||||
auto rv = sceDeci2ReqSend(protoBlock.socket, header->deci2_header.dst);
|
||||
|
||||
@@ -68,7 +68,7 @@ void GoalProtoHandler(int event, int param, void* data);
|
||||
* DONE, original version used an uncached address and had a FlushCache call, which were both
|
||||
* removed
|
||||
*/
|
||||
s32 SendFromBufferD(s32 p1, u64 p2, char* data, s32 size);
|
||||
s32 SendFromBufferD(s32 p1, u64 msg_id, char* data, s32 size);
|
||||
|
||||
/*!
|
||||
* Print GOAL Protocol status
|
||||
|
||||
+43
-31
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <common/versions.h>
|
||||
#include "klink.h"
|
||||
#include "fileio.h"
|
||||
@@ -81,7 +82,7 @@ void link_control::begin(Ptr<uint8_t> object_file,
|
||||
"VERSION ERROR: C Kernel built from GOAL %d.%d, but object file %s is from GOAL %d.%d\n",
|
||||
versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR, name, ofh->goal_version_major,
|
||||
ofh->goal_version_minor);
|
||||
exit(0);
|
||||
assert(false);
|
||||
}
|
||||
if (link_debug_printfs) {
|
||||
printf("Object file header:\n");
|
||||
@@ -352,11 +353,20 @@ uint32_t cross_seg_dist_link_v3(Ptr<uint8_t> link,
|
||||
// target seg, dist into mine, dist into target, patch loc in mine
|
||||
uint8_t target_seg = *link;
|
||||
assert(target_seg < ofh->segment_count);
|
||||
|
||||
uint32_t* link_data = (link + 1).cast<uint32_t>().c();
|
||||
int32_t mine = link_data[0] + ofh->code_infos[current_seg].offset;
|
||||
int32_t tgt = link_data[1] + ofh->code_infos[target_seg].offset;
|
||||
int32_t diff = tgt - mine;
|
||||
uint32_t offset_of_patch = link_data[2] + ofh->code_infos[current_seg].offset;
|
||||
|
||||
if (!ofh->code_infos[target_seg].offset) {
|
||||
// we want to address GOAL 0. In the case where this is a rip-relative load or store, this
|
||||
// will crash, which is what we want. If it's an lea and just getting an address, this will get
|
||||
// us a nullptr. If you do a method-set! with a null pointer it does nothing, so it's safe to
|
||||
// method-set! to things that are in unloaded segments and it'll just keep the old method.
|
||||
diff = -mine;
|
||||
}
|
||||
// printf("link object in seg %d diff %d at %d (%d + %d)\n", target_seg, diff, offset_of_patch,
|
||||
// link_data[2], ofh->code_infos[current_seg].offset);
|
||||
|
||||
@@ -367,7 +377,7 @@ uint32_t cross_seg_dist_link_v3(Ptr<uint8_t> link,
|
||||
} else if (size == 8) {
|
||||
*Ptr<int64_t>(offset_of_patch).c() = diff;
|
||||
} else {
|
||||
throw std::runtime_error("unknown size in cross_seg_dist_link_v3");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return 1 + 3 * 4;
|
||||
@@ -463,36 +473,38 @@ uint32_t link_control::work_v3() {
|
||||
// state 1: linking. For now all links are done at once. This is probably going to be fine on a
|
||||
// modern computer. But the game broke this into multiple steps.
|
||||
if (m_segment_process < ofh->segment_count) {
|
||||
Ptr<u8> lp(ofh->link_infos[m_segment_process].offset);
|
||||
if (ofh->code_infos[m_segment_process].offset) {
|
||||
Ptr<u8> lp(ofh->link_infos[m_segment_process].offset);
|
||||
|
||||
while (*lp) {
|
||||
switch (*lp) {
|
||||
case LINK_TABLE_END:
|
||||
break;
|
||||
case LINK_SYMBOL_OFFSET:
|
||||
lp = lp + 1;
|
||||
lp = lp + symlink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
|
||||
break;
|
||||
case LINK_TYPE_PTR:
|
||||
lp = lp + 1; // seek past id
|
||||
lp = lp + typelink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
|
||||
break;
|
||||
case LINK_DISTANCE_TO_OTHER_SEG_64:
|
||||
lp = lp + 1;
|
||||
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 8);
|
||||
break;
|
||||
case LINK_DISTANCE_TO_OTHER_SEG_32:
|
||||
lp = lp + 1;
|
||||
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 4);
|
||||
break;
|
||||
case LINK_PTR:
|
||||
lp = lp + 1;
|
||||
lp = lp + ptr_link_v3(lp, ofh, m_segment_process);
|
||||
break;
|
||||
default:
|
||||
printf("unknown link table thing %d\n", *lp);
|
||||
exit(0);
|
||||
break;
|
||||
while (*lp) {
|
||||
switch (*lp) {
|
||||
case LINK_TABLE_END:
|
||||
break;
|
||||
case LINK_SYMBOL_OFFSET:
|
||||
lp = lp + 1;
|
||||
lp = lp + symlink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
|
||||
break;
|
||||
case LINK_TYPE_PTR:
|
||||
lp = lp + 1; // seek past id
|
||||
lp = lp + typelink_v3(lp, Ptr<u8>(ofh->code_infos[m_segment_process].offset));
|
||||
break;
|
||||
case LINK_DISTANCE_TO_OTHER_SEG_64:
|
||||
lp = lp + 1;
|
||||
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 8);
|
||||
break;
|
||||
case LINK_DISTANCE_TO_OTHER_SEG_32:
|
||||
lp = lp + 1;
|
||||
lp = lp + cross_seg_dist_link_v3(lp, ofh, m_segment_process, 4);
|
||||
break;
|
||||
case LINK_PTR:
|
||||
lp = lp + 1;
|
||||
lp = lp + ptr_link_v3(lp, ofh, m_segment_process);
|
||||
break;
|
||||
default:
|
||||
printf("unknown link table thing %d\n", *lp);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include "klisten.h"
|
||||
#include "kboot.h"
|
||||
#include "kprint.h"
|
||||
@@ -133,9 +135,9 @@ void ProcessListenerMessage(Ptr<char> msg) {
|
||||
break;
|
||||
case LTT_MSG_RESET:
|
||||
MasterExit = 1;
|
||||
if (protoBlock.msg_id == UINT64_MAX) {
|
||||
MasterExit = 2;
|
||||
}
|
||||
break;
|
||||
case LTT_MSG_SHUTDOWN:
|
||||
MasterExit = 2;
|
||||
break;
|
||||
case LTT_MSG_CODE: {
|
||||
auto buffer = kmalloc(kdebugheap, MessCount, 0, "listener-link-block");
|
||||
|
||||
@@ -366,7 +366,7 @@ int ShutdownMachine() {
|
||||
CloseListener();
|
||||
ShutdownSound();
|
||||
ShutdownGoalProto();
|
||||
Msg(6, "kernel: machine shutdown");
|
||||
Msg(6, "kernel: machine shutdown\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include "common/goal_constants.h"
|
||||
#include "kmalloc.h"
|
||||
#include "kprint.h"
|
||||
|
||||
+15
-18
@@ -7,6 +7,7 @@
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
#include "common/goal_constants.h"
|
||||
#include "common/common_types.h"
|
||||
@@ -348,10 +349,9 @@ s32 cvt_float(float x, s32 precision, s32* lead_char, char* buff_start, char* bu
|
||||
value = (char)rounder;
|
||||
} else if (!(ru32 >> 31)) { // sign bit
|
||||
value = 0;
|
||||
throw std::runtime_error("got very large exponent in rounding calculation");
|
||||
assert(false); // not sure what happens here.
|
||||
} else {
|
||||
value = -1; // happens on NaN's
|
||||
// throw std::runtime_error("got negative sign bit in rounding calculation");
|
||||
}
|
||||
|
||||
// place number at the end of the buffer and move pointer back
|
||||
@@ -396,10 +396,9 @@ s32 cvt_float(float x, s32 precision, s32* lead_char, char* buff_start, char* bu
|
||||
value = (char)next_int;
|
||||
} else if (!(ru32 >> 0x1f)) {
|
||||
value = 0;
|
||||
throw std::runtime_error("got very large exponent in rounding calculation");
|
||||
assert(false); // not sure what happens here.
|
||||
} else {
|
||||
value = -1; // happens on NaN's
|
||||
// throw std::runtime_error("got negative sign bit in rounding calculation");
|
||||
}
|
||||
*count_chrp = value + '0';
|
||||
count_chrp++;
|
||||
@@ -411,7 +410,7 @@ s32 cvt_float(float x, s32 precision, s32* lead_char, char* buff_start, char* bu
|
||||
// however, the rounding flag is always disabled and the rounding code doesn't work.
|
||||
if ((fraction_part != 0.f) && ((flags & 1) != 0)) {
|
||||
start_ptr = round(fraction_part, nullptr, start_ptr, count_chrp - 1, 0, lead_char);
|
||||
throw std::runtime_error("cvt_float called round!");
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,7 +562,7 @@ char* kitoa(char* buffer, s64 value, u64 base, s32 length, char pad, u32 flag) {
|
||||
* uses C varags, but 128-bit varags don't work, so "format" always passes 0 for quadword printing.
|
||||
*/
|
||||
void kqtoa() {
|
||||
throw std::runtime_error("kqtoa not implemented");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
struct format_struct {
|
||||
@@ -801,7 +800,7 @@ s32 format_impl(uint64_t* args) {
|
||||
}
|
||||
kstrinsert(output_ptr, pad, desired_length - print_len);
|
||||
} else {
|
||||
throw std::runtime_error("unsupported justify in format");
|
||||
assert(false);
|
||||
// output_ptr = strend(output_ptr);
|
||||
// while(0 < (desired_length - print_len)) {
|
||||
// char pad = ' ';
|
||||
@@ -852,7 +851,7 @@ s32 format_impl(uint64_t* args) {
|
||||
kstrinsert(output_ptr, pad, desired_length - print_len);
|
||||
|
||||
} else {
|
||||
throw std::runtime_error("unsupported justify in format");
|
||||
assert(false);
|
||||
// output_ptr = strend(output_ptr);
|
||||
// u32 l140 = 0;
|
||||
// while(l140 < (desired_length - print_len)) {
|
||||
@@ -893,9 +892,7 @@ s32 format_impl(uint64_t* args) {
|
||||
call_method_of_type(in, type, GOAL_PRINT_METHOD);
|
||||
}
|
||||
} else {
|
||||
// TODO - if we can't throw exceptions, what is the option?
|
||||
// log, break and continue?
|
||||
throw std::runtime_error("failed to find symbol in format!");
|
||||
assert(false); // bad type.
|
||||
}
|
||||
}
|
||||
output_ptr = strend(output_ptr);
|
||||
@@ -916,7 +913,7 @@ s32 format_impl(uint64_t* args) {
|
||||
call_method_of_type(in, type, GOAL_INSPECT_METHOD);
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("failed to find symbol in format!");
|
||||
assert(false); // bad type
|
||||
}
|
||||
}
|
||||
output_ptr = strend(output_ptr);
|
||||
@@ -924,7 +921,7 @@ s32 format_impl(uint64_t* args) {
|
||||
|
||||
case 'Q': // not yet implemented. hopefully andy gavin finishes this one soon.
|
||||
case 'q':
|
||||
throw std::runtime_error("nyi q format string");
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
case 'X': // hex, 64 bit, pad padchar
|
||||
@@ -1021,7 +1018,7 @@ s32 format_impl(uint64_t* args) {
|
||||
precision = 4;
|
||||
float value;
|
||||
if (in < 0) {
|
||||
throw std::runtime_error("time seconds format error negative.\n");
|
||||
assert(false); // i don't get this one
|
||||
} else {
|
||||
value = in;
|
||||
}
|
||||
@@ -1037,7 +1034,7 @@ s32 format_impl(uint64_t* args) {
|
||||
|
||||
default:
|
||||
MsgErr("format: unknown code 0x%02x\n", format_ptr[1]);
|
||||
throw std::runtime_error("format error");
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
format_ptr++;
|
||||
@@ -1079,13 +1076,13 @@ s32 format_impl(uint64_t* args) {
|
||||
*PrintPendingLocal3 = 0;
|
||||
return 0;
|
||||
} else if (type == *Ptr<Ptr<Type>>(s7.offset + FIX_SYM_FILE_STREAM_TYPE)) {
|
||||
throw std::runtime_error("FORMAT into a file stream not supported");
|
||||
assert(false); // file stream nyi
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("unknown format destination");
|
||||
assert(false); // unknown destination
|
||||
return 0;
|
||||
}
|
||||
|
||||
throw std::runtime_error("how did we get here?");
|
||||
assert(false); // ??????
|
||||
return 7;
|
||||
}
|
||||
@@ -126,9 +126,7 @@ u64 goal_malloc(u32 heap, u32 size, u32 flags, u32 name) {
|
||||
* completely defined.
|
||||
*/
|
||||
u64 alloc_from_heap(u32 heapSymbol, u32 type, s32 size) {
|
||||
if (size <= 0) {
|
||||
throw std::runtime_error("got <= 0 size allocation in alloc_from_heap!");
|
||||
}
|
||||
assert(size > 0);
|
||||
|
||||
// align to 16 bytes (part one)
|
||||
s32 alignedSize = size + 0xf;
|
||||
@@ -165,7 +163,7 @@ u64 alloc_from_heap(u32 heapSymbol, u32 type, s32 size) {
|
||||
|
||||
return kmalloc(*Ptr<Ptr<kheapinfo>>(heapSymbol), size, KMALLOC_MEMSET, gstr->data()).offset;
|
||||
} else if (heapOffset == FIX_SYM_PROCESS_TYPE) {
|
||||
throw std::runtime_error("this type of process allocation is not supported yet!\n");
|
||||
assert(false); // nyi
|
||||
// allocate on current process heap
|
||||
// Ptr start = *ptr<Ptr>(getS6() + 0x4c + 8);
|
||||
// Ptr heapEnd = *ptr<Ptr>(getS6() + 0x4c + 4);
|
||||
@@ -181,7 +179,7 @@ u64 alloc_from_heap(u32 heapSymbol, u32 type, s32 size) {
|
||||
// alignedSize); return 0;
|
||||
// }
|
||||
} else if (heapOffset == FIX_SYM_SCRATCH) {
|
||||
throw std::runtime_error("this type of scratchpad allocation is not used!\n");
|
||||
assert(false); // nyi, I think unused.
|
||||
} else {
|
||||
memset(Ptr<u8>(heapSymbol).c(), 0, (size_t)alignedSize); // treat it as a stack address
|
||||
return heapSymbol;
|
||||
@@ -1122,8 +1120,8 @@ u64 call_method_of_type(u32 arg, Ptr<Type> type, u32 method_id) {
|
||||
(*type_tag).offset);
|
||||
}
|
||||
}
|
||||
// throw std::runtime_error("call_method_of_type failed!\n");
|
||||
printf("[ERROR] call_method_of_type failed!\n");
|
||||
assert(false);
|
||||
return arg;
|
||||
}
|
||||
|
||||
@@ -1159,7 +1157,8 @@ u64 call_method_of_type_arg2(u32 arg, Ptr<Type> type, u32 method_id, u32 a1, u32
|
||||
(*type_tag).offset);
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("call_method_of_type failed!\n");
|
||||
printf("[ERROR] call_method_of_type_arg2 failed!\n");
|
||||
assert(false);
|
||||
return arg;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ void setup_logging(bool verbose) {
|
||||
auto game_logger = spdlog::stdout_color_mt("GOAL Runtime");
|
||||
spdlog::set_default_logger(game_logger);
|
||||
spdlog::flush_on(spdlog::level::info);
|
||||
spdlog::set_pattern("%v");
|
||||
spdlog::info("Verbose logging enabled");
|
||||
} else {
|
||||
auto game_logger = spdlog::basic_logger_mt("GOAL Runtime", "logs/runtime.log");
|
||||
|
||||
@@ -273,6 +273,9 @@ uint32_t FS_BeginRead(LoadStackEntry* fd, void* buffer, int32_t len) {
|
||||
|
||||
const char* path = get_file_path(fd->fr);
|
||||
FILE* fp = fopen(path, "rb");
|
||||
if (!fp) {
|
||||
spdlog::error("[OVERLORD] fake iso could not open the file \"{}\"", path);
|
||||
}
|
||||
assert(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint32_t file_len = ftell(fp);
|
||||
|
||||
+5
-1
@@ -47,6 +47,7 @@
|
||||
#include "game/overlord/stream.h"
|
||||
|
||||
#include "common/goal_constants.h"
|
||||
#include "common/cross_os_debug/xdbg.h"
|
||||
|
||||
u8* g_ee_main_mem = nullptr;
|
||||
|
||||
@@ -75,7 +76,7 @@ void deci2_runner(SystemThreadInterface& iface) {
|
||||
server.wait_for_protos_ready();
|
||||
// then allow the server to accept connections
|
||||
if (!server.init()) {
|
||||
throw std::runtime_error("DECI2 server init failed");
|
||||
assert(false);
|
||||
}
|
||||
|
||||
spdlog::debug("[DECI2] Waiting for listener...");
|
||||
@@ -148,6 +149,9 @@ void ee_runner(SystemThreadInterface& iface) {
|
||||
kmemcard_init_globals();
|
||||
kprint_init_globals();
|
||||
|
||||
// Added for OpenGOAL's debugger
|
||||
xdbg::allow_debugging();
|
||||
|
||||
goal_main(g_argc, g_argv);
|
||||
spdlog::debug("[EE] Done!");
|
||||
|
||||
|
||||
+4
-2
@@ -203,12 +203,14 @@ s32 CreateSema(SemaParam* param) {
|
||||
|
||||
s32 WaitSema(s32 sema) {
|
||||
(void)sema;
|
||||
throw std::runtime_error("NYI");
|
||||
assert(false); // nyi
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 SignalSema(s32 sema) {
|
||||
(void)sema;
|
||||
throw std::runtime_error("NYI");
|
||||
assert(false); // nyi
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 WakeupThread(s32 thid) {
|
||||
|
||||
@@ -217,7 +217,6 @@ void Deci2Server::run() {
|
||||
printf("[DECI2] Warning: no handler for this message, ignoring...\n");
|
||||
unlock();
|
||||
return;
|
||||
// throw std::runtime_error("no handler!");
|
||||
}
|
||||
|
||||
auto& driver = d2_drivers[handler];
|
||||
|
||||
+14
-21
@@ -7,17 +7,17 @@
|
||||
* Create a new thread. Will not run the thread.
|
||||
*/
|
||||
s32 IOP_Kernel::CreateThread(std::string name, u32 (*func)()) {
|
||||
if (_currentThread != -1)
|
||||
throw std::runtime_error("tried to create thread from thread");
|
||||
assert(_currentThread == -1); // can only create thread from kernel thread.
|
||||
|
||||
u32 ID = (u32)_nextThID++;
|
||||
if (threads.size() != ID)
|
||||
throw std::runtime_error("thread number error?");
|
||||
assert(ID == threads.size());
|
||||
|
||||
// add entry
|
||||
threads.emplace_back(name, func, ID, this);
|
||||
// setup the thread!
|
||||
// printf("[IOP Kernel] SetupThread %s...\n", name.c_str());
|
||||
|
||||
// hack to allow creating a "null thread" which doesn't/can't run but occupies slot 0.
|
||||
// allow creating a "null thread" which doesn't/can't run but occupies slot 0.
|
||||
if (func) {
|
||||
_currentThread = ID;
|
||||
// create OS thread, will run the setupThread function
|
||||
@@ -47,11 +47,9 @@ void IOP_Kernel::setupThread(s32 id) {
|
||||
returnToKernel();
|
||||
threads.at(id).waitForDispatch();
|
||||
// printf("[IOP Kernel] Thread %s first dispatch!\n", threads.at(id).name.c_str());
|
||||
if (_currentThread != id) {
|
||||
throw std::runtime_error("the wrong thread has run!\n");
|
||||
}
|
||||
assert(_currentThread == id); // should run in the thread.
|
||||
(threads.at(id).function)();
|
||||
printf("Thread %s has returned!\n", threads.at(id).name.c_str());
|
||||
// printf("Thread %s has returned!\n", threads.at(id).name.c_str());
|
||||
threads.at(id).done = true;
|
||||
returnToKernel();
|
||||
}
|
||||
@@ -60,8 +58,7 @@ void IOP_Kernel::setupThread(s32 id) {
|
||||
* Run a thread (call from kernel)
|
||||
*/
|
||||
void IOP_Kernel::runThread(s32 id) {
|
||||
if (_currentThread != -1)
|
||||
throw std::runtime_error("tried to runThread in a thread");
|
||||
assert(_currentThread == -1); // should run in the kernel thread
|
||||
_currentThread = id;
|
||||
threads.at(id).dispatch();
|
||||
threads.at(id).waitForReturnToKernel();
|
||||
@@ -77,9 +74,8 @@ void IOP_Kernel::SuspendThread() {
|
||||
s32 oldThread = getCurrentThread();
|
||||
threads.at(oldThread).returnToKernel();
|
||||
threads.at(oldThread).waitForDispatch();
|
||||
if (_currentThread != oldThread) {
|
||||
throw std::runtime_error("bad resume");
|
||||
}
|
||||
// check kernel resumed us correctly
|
||||
assert(_currentThread == oldThread);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -130,8 +126,8 @@ void IOP_Kernel::dispatchAll() {
|
||||
*/
|
||||
void IopThreadRecord::returnToKernel() {
|
||||
runThreadReady = false;
|
||||
if (kernel->getCurrentThread() != thID)
|
||||
throw std::runtime_error("tried to sleep the wrong thread!");
|
||||
// should be called from the correct thread
|
||||
assert(kernel->getCurrentThread() == thID);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(*threadToKernelMutex);
|
||||
@@ -145,8 +141,8 @@ void IopThreadRecord::returnToKernel() {
|
||||
*/
|
||||
void IopThreadRecord::dispatch() {
|
||||
syscallReady = false;
|
||||
if (kernel->getCurrentThread() != thID)
|
||||
throw std::runtime_error("tried to dispatch the wrong thread!");
|
||||
assert(kernel->getCurrentThread() == thID);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(*kernelToThreadMutex);
|
||||
runThreadReady = true;
|
||||
@@ -160,17 +156,14 @@ void IopThreadRecord::dispatch() {
|
||||
void IopThreadRecord::waitForReturnToKernel() {
|
||||
std::unique_lock<std::mutex> lck(*threadToKernelMutex);
|
||||
threadToKernelCV->wait(lck, [this] { return syscallReady; });
|
||||
// syscallReady = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Thread waits for kernel to dispatch it.
|
||||
*/
|
||||
void IopThreadRecord::waitForDispatch() {
|
||||
// if(kernel->getCurrentThread() == -1) throw std::runtime_error("tried to suspend main!\n");
|
||||
std::unique_lock<std::mutex> lck(*kernelToThreadMutex);
|
||||
kernelToThreadCV->wait(lck, [this] { return runThreadReady; });
|
||||
// runThreadReady = false;
|
||||
}
|
||||
|
||||
void IOP_Kernel::set_rpc_queue(iop::sceSifQueueData* qd, u32 thread) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include "common/common_types.h"
|
||||
|
||||
class IOP_Kernel;
|
||||
@@ -98,8 +99,7 @@ class IOP_Kernel {
|
||||
* Resume the kernel.
|
||||
*/
|
||||
void returnToKernel() {
|
||||
if (_currentThread < 0)
|
||||
throw std::runtime_error("tried to return to kernel not in a thread");
|
||||
assert(_currentThread >= 0); // must be in a thread
|
||||
threads[_currentThread].returnToKernel();
|
||||
}
|
||||
|
||||
@@ -126,15 +126,16 @@ class IOP_Kernel {
|
||||
// total hack - returning this value causes the ISO thread to error out and quit.
|
||||
return -0x1a9;
|
||||
}
|
||||
// printf("poll %d %ld\n", mbx, mbxs.size());
|
||||
if (mbx >= (s32)mbxs.size())
|
||||
throw std::runtime_error("invalid PollMbx");
|
||||
|
||||
assert(mbx < (s32)mbxs.size());
|
||||
s32 gotSomething = mbxs[mbx].empty() ? 0 : 1;
|
||||
if (gotSomething) {
|
||||
void* thing = mbxs[mbx].front();
|
||||
// printf("pop from msgbox %d %p\n", mbx, thing);
|
||||
if (msg)
|
||||
|
||||
if (msg) {
|
||||
*msg = thing;
|
||||
}
|
||||
|
||||
mbxs[mbx].pop();
|
||||
}
|
||||
|
||||
@@ -145,11 +146,8 @@ class IOP_Kernel {
|
||||
* Push something into a mbx
|
||||
*/
|
||||
s32 SendMbx(s32 mbx, void* value) {
|
||||
if (mbx >= (s32)mbxs.size())
|
||||
throw std::runtime_error("invalid SendMbx");
|
||||
assert(mbx < (s32)mbxs.size());
|
||||
mbxs[mbx].push(value);
|
||||
// printf("push into messagebox %d %p\n", mbx, value);
|
||||
// printf("mbx size %ld\n", mbxs.size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
SystemThread& SystemThreadManager::create_thread(const std::string& name) {
|
||||
if (thread_count >= MAX_SYSTEM_THREADS) {
|
||||
spdlog::critical("Out of System Threads! MAX_SYSTEM_THREADS is ", MAX_SYSTEM_THREADS);
|
||||
throw std::runtime_error("Out of System Threads! Please increase MAX_SYSTEM_THREADS");
|
||||
assert(false);
|
||||
}
|
||||
auto& thread = threads[thread_count];
|
||||
|
||||
|
||||
@@ -182,6 +182,9 @@ bool Listener::connect_to_target(int n_tries, const std::string& ip, int port) {
|
||||
listen_socket = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
last_recvd_id = 0;
|
||||
last_sent_id = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -218,7 +221,17 @@ void Listener::receive_func() {
|
||||
case ListenerMessageKind::MSG_ACK:
|
||||
// an "ack" message, sent by the target to indicate it got something.
|
||||
if (!waiting_for_ack) {
|
||||
printf("[Listener] Got an ack message when we weren't expecting one.");
|
||||
if (hdr->msg_id == last_sent_id) {
|
||||
printf("[Listener] Received ACK for most recent message late.\n");
|
||||
if (last_recvd_id != hdr->msg_id - 1) {
|
||||
printf(
|
||||
"[Listener] WARNING: message ID jumped from %ld to %ld. Some messages may have "
|
||||
"been lost. You must wait for an ACK before sending the next message.\n",
|
||||
last_recvd_id, hdr->msg_id);
|
||||
}
|
||||
} else {
|
||||
printf("[Listener] Got an unexpcted ACK message.");
|
||||
}
|
||||
}
|
||||
|
||||
if (hdr->deci2_header.len < 512) {
|
||||
@@ -236,6 +249,13 @@ void Listener::receive_func() {
|
||||
ack_recv_buff[ack_recv_prog] = '\0';
|
||||
assert(ack_recv_prog < 512);
|
||||
got_ack = true;
|
||||
last_recvd_id = hdr->msg_id;
|
||||
if (last_recvd_id > last_sent_id) {
|
||||
printf(
|
||||
"[Listener] ERROR: Got an ack message with id of %ld, but the last message sent "
|
||||
"had an ID of %ld.\n",
|
||||
last_recvd_id, last_sent_id);
|
||||
}
|
||||
} else {
|
||||
printf("[Listener] got invalid ack!\n");
|
||||
}
|
||||
@@ -245,6 +265,7 @@ void Listener::receive_func() {
|
||||
case ListenerMessageKind::MSG_PRINT: {
|
||||
auto* str_buff = new char[hdr->msg_size + 1]; // plus one for the null terminator
|
||||
int msg_prog = 0;
|
||||
assert(hdr->msg_id == 0);
|
||||
while (rcvd < hdr->deci2_header.len) {
|
||||
if (!m_connected) {
|
||||
return;
|
||||
@@ -338,7 +359,8 @@ void Listener::send_code(std::vector<uint8_t>& code) {
|
||||
header->msg_size = code.size();
|
||||
header->ltt_msg_kind = LTT_MSG_CODE;
|
||||
header->u6 = 0;
|
||||
header->msg_id = 0;
|
||||
last_sent_id++;
|
||||
header->msg_id = last_sent_id;
|
||||
memcpy(buffer_data, code.data(), code.size());
|
||||
send_buffer(total_size);
|
||||
}
|
||||
@@ -365,9 +387,10 @@ void Listener::send_reset(bool shutdown) {
|
||||
header->deci2_header.src = 'H';
|
||||
header->deci2_header.dst = 'E';
|
||||
header->msg_size = 0;
|
||||
header->ltt_msg_kind = LTT_MSG_RESET;
|
||||
header->ltt_msg_kind = shutdown ? LTT_MSG_SHUTDOWN : LTT_MSG_RESET;
|
||||
header->u6 = 0;
|
||||
header->msg_id = shutdown ? UINT64_MAX : 0;
|
||||
last_sent_id++;
|
||||
header->msg_id = last_sent_id;
|
||||
send_buffer(sizeof(ListenerMessageHeader));
|
||||
disconnect();
|
||||
close_socket(listen_socket);
|
||||
@@ -392,7 +415,8 @@ void Listener::send_poke() {
|
||||
header->msg_size = 0;
|
||||
header->ltt_msg_kind = LTT_MSG_POKE;
|
||||
header->u6 = 0;
|
||||
header->msg_id = 0;
|
||||
last_sent_id++;
|
||||
header->msg_id = last_sent_id;
|
||||
send_buffer(sizeof(ListenerMessageHeader));
|
||||
}
|
||||
|
||||
@@ -426,8 +450,7 @@ void Listener::send_buffer(int sz) {
|
||||
printf(" OK\n");
|
||||
}
|
||||
} else {
|
||||
printf(
|
||||
" Error - target has timed out. If it is stuck in a loop, it must be manually killed.\n");
|
||||
printf(" Timed out waiting for ack.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ class Listener {
|
||||
std::vector<std::string> message_record;
|
||||
std::unordered_map<std::string, LoadEntry> m_load_entries;
|
||||
char ack_recv_buff[512];
|
||||
uint64_t last_sent_id = 0;
|
||||
uint64_t last_recvd_id = 0;
|
||||
};
|
||||
} // namespace listener
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
set(GOALC_TEST_CASES
|
||||
"goalc/all_goalc_template_tests.cpp"
|
||||
goalc/test_debugger.cpp
|
||||
goalc/test_game_no_debug.cpp
|
||||
)
|
||||
|
||||
set(GOALC_TEST_FRAMEWORK_SOURCES
|
||||
|
||||
@@ -102,6 +102,12 @@ void runtime_with_kernel() {
|
||||
exec_runtime(argc, const_cast<char**>(argv));
|
||||
}
|
||||
|
||||
void runtime_with_kernel_no_debug_segment() {
|
||||
constexpr int argc = 3;
|
||||
const char* argv[argc] = {"", "-fakeiso", "-debug-mem"};
|
||||
exec_runtime(argc, const_cast<char**>(argv));
|
||||
}
|
||||
|
||||
void createDirIfAbsent(const std::string& path) {
|
||||
if (!std::filesystem::is_directory(path) || !std::filesystem::exists(path)) {
|
||||
std::filesystem::create_directory(path);
|
||||
|
||||
@@ -41,6 +41,7 @@ struct CompilerTestRunner {
|
||||
|
||||
void runtime_no_kernel();
|
||||
void runtime_with_kernel();
|
||||
void runtime_with_kernel_no_debug_segment();
|
||||
|
||||
void createDirIfAbsent(const std::string& path);
|
||||
std::string getTemplateDir(const std::string& category);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Test the game running without loading debug segments.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "goalc/compiler/Compiler.h"
|
||||
#include "test/goalc/framework/test_runner.h"
|
||||
|
||||
TEST(GameNoDebugSegment, Init) {
|
||||
Compiler compiler;
|
||||
compiler.run_front_end_on_string("(build-kernel)");
|
||||
std::thread runtime_thread = std::thread(GoalTest::runtime_with_kernel_no_debug_segment);
|
||||
|
||||
// this shouldn't crash
|
||||
compiler.run_test_from_string("(inspect *kernel-context*)");
|
||||
|
||||
// these should be equal, both the fallback inspect method
|
||||
EXPECT_TRUE(compiler.run_test_from_string(
|
||||
"(print (eq? (method kernel-context inspect) (method cpu-thread inspect))) 0") ==
|
||||
std::vector<std::string>{"#t\n0\n"});
|
||||
|
||||
// should be below the debug heap.
|
||||
EXPECT_TRUE(
|
||||
compiler.run_test_from_string(
|
||||
"(print (< (the uint (method kernel-context inspect)) (the uint (-> debug base)))) 0") ==
|
||||
std::vector<std::string>{"#t\n0\n"});
|
||||
|
||||
// debug segment flag should be disabled.
|
||||
EXPECT_TRUE(compiler.run_test_from_string("(print *debug-segment*) 0") ==
|
||||
std::vector<std::string>{"#f\n0\n"});
|
||||
|
||||
compiler.shutdown_target();
|
||||
runtime_thread.join();
|
||||
}
|
||||
Reference in New Issue
Block a user