Skip to content

Commit bc27560

Browse files
committed
init chowloader nx binary code
0 parents  commit bc27560

25 files changed

Lines changed: 1449 additions & 0 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
chowloader.o.dSYM/
2+
chowloader.o
3+
transformer/main.pchtxt

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# ChowLoader Nintendo Switch Binary
2+
3+
This repo contain the source of the code in the patch of the console version and the transformer that convert the Mach-O output of the build (build made on Apple Silicon Mac) to ipswitch patch compatible file.
4+
5+
The build command is
6+
7+
```console
8+
clang -O0 -g ./**/*.c -o chowloader.o
9+
```

chowloader.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include "lib/imports.h"
2+
#include "utils.h"
3+
4+
#include "chowloader/assets.h"
5+
#include "chowloader/aot.h"
6+
#include "chowloader/renderer.h"
7+
8+
#include "chowloader.h"
9+
10+
int initChowLoaderObject(JSContext *ctx, JSValueConst this_obj, const char *prop, JSValue val){
11+
JS_SetPropertyStr(ctx, this_obj, prop, val);
12+
13+
JSValue chowloader = JS_NewObject(ctx);
14+
JS_SetPropertyStr(ctx, this_obj, "chowloader", chowloader);
15+
16+
JSValue _executeJobs = JS_NewCFunction2(ctx, &executeJobs, "executeJobs", 1, JS_CFUNC_generic, 0);
17+
JS_SetPropertyStr(ctx, chowloader, "executeJobs", _executeJobs);
18+
19+
JS_SetPropertyStr(ctx, chowloader, "assets", createAssetsObject(ctx));
20+
21+
JS_SetPropertyStr(ctx, chowloader, "renderer", createRendererObject(ctx));
22+
23+
JS_SetPropertyStr(ctx, chowloader, "aot", createAOTObject(ctx));
24+
25+
#ifdef __CHOWLOADER_THREAD_H
26+
JSValue _launchThread = JS_NewCFunction2(ctx, &launchThread, "launchThread", 1, JS_CFUNC_generic, 0);
27+
JS_SetPropertyStr(ctx, chowloader, "launchThread", _launchThread);
28+
#endif
29+
30+
#ifdef CHOWLOADER_DEBUG
31+
JSValue _debugger = JS_NewCFunction2(ctx, &debugger, "debugger", 1, JS_CFUNC_generic, 0);
32+
JS_SetPropertyStr(ctx, chowloader, "debugger", _debugger);
33+
#endif
34+
35+
return 1;
36+
}
37+
38+
#ifdef CHOWLOADER_DEBUG
39+
JSValue debugger(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv){
40+
__builtin_debugtrap();
41+
return JS_UNDEFINED;
42+
}
43+
#endif
44+
45+
JSValue executeJobs(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv){
46+
JS_ExecutePendingJob(ctx->rt, &ctx);
47+
return JS_UNDEFINED;
48+
}
49+
50+
int main(){
51+
return 0;
52+
}

chowloader.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#ifndef __CHOWLOADER_H
2+
#define __CHOWLOADER_H
3+
4+
#define CHOWLOADER_DEBUG
5+
6+
int initChowLoaderObject(JSContext *ctx, JSValueConst this_obj, const char *prop, JSValue val);
7+
JSValue debugger(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
8+
JSValue cacheImage(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
9+
JSValue executeJobs(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
10+
11+
#endif

chowloader/aot.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#include "../lib/imports.h"
2+
#include "../utils.h"
3+
#include "aot.h"
4+
5+
JSValue getAOTObject(JSContext *ctx, const char* type, int count, void *va_list){
6+
JSValue array = JS_NewArray(ctx);
7+
8+
int offset = ((int*)va_list)[6];
9+
10+
const char **list = va_list + offset;
11+
const char **overflow_list = ((const char ***)va_list)[0];
12+
13+
int c = -offset / 8;
14+
15+
int first_count = count;
16+
if(first_count > c) first_count = c;
17+
18+
for(uint32_t i = 0; i < first_count; ++i){
19+
const char* str = list[i];
20+
JS_DefinePropertyValueUint32(ctx, array, i, JS_NewStringLen(ctx, str, strlen(str)), 7);
21+
}
22+
23+
if(count > 5){
24+
for(uint32_t i = 0; i < count - c; ++i){
25+
const char* str = overflow_list[i];
26+
JS_DefinePropertyValueUint32(ctx, array, i+c, JS_NewStringLen(ctx, str, strlen(str)), 7);
27+
}
28+
}
29+
30+
JSValue aot_object = get_aot_object(ctx, count, va_list);
31+
32+
JSValue object = JS_NewObject(ctx);
33+
34+
JS_SetPropertyStr(ctx, object, "type", JS_NewStringLen(ctx, type, strlen(type)));
35+
JS_SetPropertyStr(ctx, object, "object", aot_object);
36+
37+
JSValue joinstr = JS_NewStringLen(ctx, ".", 1);
38+
JSValue path = js_array_join(ctx, array, 1, &joinstr, 0);
39+
40+
JS_SetPropertyStr(ctx, object, "path", path);
41+
42+
emitChowloaderEventValue(ctx, "aot_object", object);
43+
44+
return aot_object;
45+
}
46+
47+
JSValue hookJSAOT(JSContext *ctx, int count, void *va_list){
48+
return getAOTObject(ctx, "jsaot", count, va_list);
49+
}
50+
51+
JSValue hookJSVAL(JSContext *ctx, int count, void *va_list){
52+
return getAOTObject(ctx, "jsval", count, va_list);
53+
}
54+
55+
JSValue hookJSVARREF(JSContext *ctx, int count, void *va_list){
56+
return getAOTObject(ctx, "jsval", count, va_list);
57+
}
58+
59+
void initAOT(JSContext *ctx){
60+
emitChowloaderEvent(ctx, "omori_loaded");
61+
init_aot(ctx);
62+
emitChowloaderEvent(ctx, "aot_loaded");
63+
}
64+
65+
// AOT Patching
66+
67+
JSValue createAOTObject(JSContext *ctx){
68+
JSValue aot = JS_NewObject(ctx);
69+
70+
JSValue _findJSVALNative = JS_NewCFunction2(ctx, &findJSVALNative, "find", 1, JS_CFUNC_generic, 0);
71+
JS_SetPropertyStr(ctx, aot, "find", _findJSVALNative);
72+
73+
JSValue _patchJSVALNative = JS_NewCFunction2(ctx, &patchJSVALNative, "patch", 1, JS_CFUNC_generic, 0);
74+
JS_SetPropertyStr(ctx, aot, "patch", _patchJSVALNative);
75+
76+
return aot;
77+
}
78+
79+
JSValue JSVALOffset = 0;
80+
81+
JSValue findJSVALNative(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv){
82+
JSValue* offset = &JSVALOffset;
83+
84+
for(size_t i = 0; i < JS_VALUE_GET_UINT(argv[0]); i++){
85+
if(offset[i] == argv[1]){
86+
return JS_MKVAL(JS_TAG_INT, (uintptr_t)(offset + i));
87+
}
88+
}
89+
90+
return JS_MKVAL(JS_TAG_INT, 0xFFFFFFFF);
91+
}
92+
93+
JSValue patchJSVALNative(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv){
94+
JSValue* val = (JSValue*)JS_VALUE_GET_UINT(argv[0]);
95+
val[0] = argv[1];
96+
return JS_TRUE;
97+
}

chowloader/aot.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef __CHOWLOADER_AOT_H
2+
#define __CHOWLOADER_AOT_H
3+
4+
JSValue getAOTObject(JSContext *ctx, const char* type, int count, void *va_list);
5+
JSValue hookJSAOT(JSContext *ctx, int count, void *va_list);
6+
JSValue hookJSVAL(JSContext *ctx, int count, void *va_list);
7+
JSValue hookJSVARREF(JSContext *ctx, int count, void *va_list);
8+
void initAOT(JSContext *ctx);
9+
10+
JSValue createAOTObject(JSContext *ctx);
11+
JSValue findJSVALNative(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
12+
JSValue patchJSVALNative(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
13+
14+
#endif

chowloader/assets.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include "../lib/imports.h"
2+
#include "../utils.h"
3+
#include "assets.h"
4+
5+
JSValue createAssetsObject(JSContext *ctx){
6+
JSValue renderer = JS_NewObject(ctx);
7+
8+
JSValue _loadImage = JS_NewCFunction2(ctx, &loadImage, "loadImage", 1, JS_CFUNC_generic, 0);
9+
JS_SetPropertyStr(ctx, renderer, "loadImage", _loadImage);
10+
11+
JSValue _loadAudio = JS_NewCFunction2(ctx, &loadAudio, "loadAudio", 1, JS_CFUNC_generic, 0);
12+
JS_SetPropertyStr(ctx, renderer, "loadAudio", _loadAudio);
13+
14+
return renderer;
15+
}
16+
17+
JSValue loadImage(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv){
18+
const char *path = convertPathJS(ctx, argv[0]);
19+
if(!path) return JS_FALSE;
20+
size_t size;
21+
void *image_buf = readFile(ctx, path, &size);
22+
int width;
23+
int height;
24+
stbi_info_from_memory(image_buf, size, &width, &height, NULL);
25+
operator_delete(image_buf);
26+
ChowdrenCacheImage(path, width, height);
27+
return JS_TRUE;
28+
}
29+
30+
JSValue loadAudio(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv){
31+
const char *path = convertPathJS(ctx, argv[0]);
32+
if(!path) return JS_FALSE;
33+
size_t size;
34+
void *audio_buf = readFile(ctx, path, &size);
35+
int error;
36+
stb_vorbis *vorbis = stb_vorbis_open_memory(audio_buf, size, &error, NULL);
37+
if(!vorbis) return JS_FALSE;
38+
char *end_audio_buf = (char *)audio_buf + size - 6;
39+
while(end_audio_buf[0] != 'O' || end_audio_buf[1] != 'g' || end_audio_buf[2] != 'g' || end_audio_buf[3] != 'S' || end_audio_buf[4] || (end_audio_buf[5] & 0x4) == 0){
40+
if((uintptr_t)(--end_audio_buf) < (uintptr_t)audio_buf)
41+
return JS_FALSE;
42+
}
43+
uint32_t granulepos = *(uint32_t*)(end_audio_buf + 6);
44+
operator_delete(audio_buf);
45+
ChowdrenPreloadAudio(path+2, path, size, granulepos * vorbis->channels, vorbis->sample_rate, vorbis->channels);
46+
return JS_TRUE;
47+
}
48+
49+
50+
std_string *hookFonts(std_string *path, const char *ext){
51+
const char *str = to_char_string(path);
52+
if(str[8] == '.' && str[9] == '/'){
53+
str += 8;
54+
}
55+
size_t len = strlen(str);
56+
std_string *s;
57+
if(str[len - 4] == '.' && str[len - 3] == 't' && str[len - 2] == 't' && str[len - 1] == 'f'){
58+
s = to_std_string(str);
59+
} else {
60+
char *tmp = operator_new(len + 5);
61+
strcpy(tmp, str);
62+
strcpy(tmp + len, ext);
63+
s = to_std_string(tmp);
64+
operator_delete(tmp);
65+
}
66+
return s;
67+
}

chowloader/assets.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef __CHOWLOADER_ASSETS_H
2+
#define __CHOWLOADER_ASSETS_H
3+
4+
JSValue createAssetsObject(JSContext *ctx);
5+
JSValue loadImage(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
6+
JSValue loadAudio(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);
7+
std_string *hookFonts(std_string *str1, const char *str2);
8+
9+
#endif

chowloader/error.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "../lib/imports.h"
2+
#include "../utils.h"
3+
#include "error.h"
4+
5+
void hookBuildBacktrace(JSContext *ctx, JSValueConst error_obj, const char *filename, int line_num, int backtrace_flags){
6+
build_backtrace(ctx, error_obj, filename, line_num, backtrace_flags);
7+
emitChowloaderEventValue(ctx, "error", error_obj);
8+
}
9+
10+
JSValue hookThrow(JSContext *ctx, JSValue obj){
11+
emitChowloaderEventValue(ctx, "error", obj);
12+
return JS_Throw(ctx, obj);
13+
}

chowloader/error.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef __CHOWLOADER_ERROR_H
2+
#define __CHOWLOADER_ERROR_H
3+
4+
void hookBuildBacktrace(JSContext *ctx, JSValueConst error_obj, const char *filename, int line_num, int backtrace_flags);
5+
JSValue hookThrow(JSContext *ctx, JSValue obj);
6+
7+
#endif

0 commit comments

Comments
 (0)