Add script to build gecko code of GCI Loader
- GCI Loader: gecko-gosub + 06 bin + 04 bl to onReadOptionBlock - place GCI Loader code at 817FE800 since [817FEEA0, 81800000) is used by system - place buffer at 817F1800 (instead of 817F1000+4) since there seems to be some alignment issue - Assume file size == 0x2000*6 since fileInfo->length seems to be 0
This commit is contained in:
parent
638d27b425
commit
23e5c658ad
21 changed files with 322 additions and 77 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
*.o
|
||||
out
|
||||
__pycache__
|
||||
|
|
34
Makefile
34
Makefile
|
@ -1,3 +1,5 @@
|
|||
MAKE := make
|
||||
|
||||
CC := powerpc-eabi-gcc
|
||||
CFLAGS := -O3 -I. -Wa,-mregnames,-mgekko -Wall -fno-asynchronous-unwind-tables -fno-unwind-tables -fverbose-asm -gdwarf
|
||||
|
||||
|
@ -12,20 +14,28 @@ LD := powerpc-eabi-ld
|
|||
LDFLAGS := --unresolved-symbols=ignore-in-object-files --enable-non-contiguous-regions -EB --nmagic
|
||||
|
||||
OBJCOPY := powerpc-eabi-objcopy
|
||||
OBJCOPYFLAGS := -O binary --add-gnu-debuglink=sms.ld --gap-fill 0x00 --pad-to 0x81800000
|
||||
#OBJCOPYFLAGS = -O binary $(foreach e,$(LD_FILES),--add-gnu-debuglink=$e) --gap-fill 0x00 --pad-to 0x81800000
|
||||
OBJCOPYFLAGS = -O binary $(foreach e,$(LD_FILES),--add-gnu-debuglink=$e)
|
||||
|
||||
PY := python3
|
||||
BIN2GCT := $(PY) gecko/bin2gct.py
|
||||
|
||||
SRC_DIR := source
|
||||
INC_DIR := include
|
||||
LD_DIR := ldscript
|
||||
OUT_DIR := out
|
||||
OBJ_DIR := obj
|
||||
|
||||
LD_FILE := sms.ld
|
||||
OUT_MAP := main.map
|
||||
GECKO_DIR := gecko
|
||||
GECKO_OUT_DIR := out
|
||||
|
||||
OUT_MAP := main.map
|
||||
OUT_MAIN := main.out
|
||||
OUT_BIN := main.bin
|
||||
OUT_LST := main.lst
|
||||
OUT_ASM := main.asm
|
||||
OUT_LOADER_TXT = loader.txt
|
||||
OUT_LOADER_GCT = loader.gct
|
||||
|
||||
GMSE01 := 1
|
||||
GMSJ01 := 2
|
||||
|
@ -36,11 +46,13 @@ TARGET_VERSION = $($(GAME_VERSION))
|
|||
|
||||
SRC_FILES := $(wildcard source/*.c)
|
||||
OBJ_FILES := $(SRC_FILES:.c=.o)
|
||||
LD_FILES := $(LD_DIR)/sms.ld $(LD_DIR)/$(GAME_VERSION).ld
|
||||
GECKO_FILE_LOADER := $(GECKO_DIR)/$(GECKO_OUT_DIR)/gecko-gosub.bin
|
||||
GECKO_FILES := $(GECKO_FILE_LOADER) $(GECKO_DIR)/$(GECKO_OUT_DIR)/gecko-return.bin
|
||||
|
||||
OBJS := main.o card.o
|
||||
blockCount := 7
|
||||
|
||||
all: $(OUT_DIR)/$(OUT_BIN) $(OUT_DIR)/$(OUT_LST) $(OUT_DIR)/$(OUT_ASM)
|
||||
all: $(OUT_DIR)/$(OUT_BIN) $(OUT_DIR)/$(OUT_LST) $(OUT_DIR)/$(OUT_ASM) $(OUT_DIR)/$(OUT_LOADER_TXT)
|
||||
|
||||
$(OUT_DIR)/$(OUT_ASM): $(OUT_DIR)/$(OUT_BIN)
|
||||
$(OD) $(ODASMFLAGS) $(OUT_DIR)/$(OUT_BIN) | grep -Pe "^\t(?!Address)" | sed 's/^\t//' > $(OUT_DIR)/$(OUT_ASM)
|
||||
|
@ -51,12 +63,17 @@ $(OUT_DIR)/$(OUT_LST): $(OUT_DIR)/$(OUT_BIN)
|
|||
$(OUT_DIR)/$(OUT_BIN): $(OUT_DIR)/$(OUT_MAIN)
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
|
||||
|
||||
$(OUT_DIR)/$(OUT_MAIN): $(OBJ_FILES) $(LD_FILE) $(OUT_DIR)
|
||||
$(LD) $(LDFLAGS) -o $@ -T $(LD_FILE) -Map $(OUT_DIR)/$(OUT_MAP) $(OBJ_FILES)
|
||||
$(OUT_DIR)/$(OUT_MAIN): check-set-GAME_VERSION $(OBJ_FILES) $(LD_FILES) $(OUT_DIR)
|
||||
$(LD) $(LDFLAGS) -o $@ -T $(LD_FILES) -Map $(OUT_DIR)/$(OUT_MAP) $(OBJ_FILES)
|
||||
|
||||
$(OBJ_FILES): $(SRC_FILES) check-set-TARGET_VERSION
|
||||
$(OBJ_FILES): $(SRC_FILES) check-set-GAME_VERSION #check-set-TARGET_VERSION
|
||||
$(CC) $(CFLAGS) -D VERSION=$(TARGET_VERSION) -I $(INC_DIR) -o $@ -c $(@:.o=.c)
|
||||
|
||||
$(OUT_DIR)/$(OUT_LOADER_TXT): $(OUT_DIR)/$(OUT_BIN) $(OUT_DIR)/$(OUT_MAP) $(GECKO_FILE_LOADER) | $(OUT_DIR)
|
||||
$(BIN2GCT) hook:$(OUT_DIR)/$(OUT_MAP):$(OUT_DIR)/$(OUT_BIN):onReadOptionBlock C0:$(GECKO_FILE_LOADER) > $@
|
||||
$(GECKO_FILES):
|
||||
$(MAKE) -C$(GECKO_DIR) OUT_DIR=$(GECKO_OUT_DIR) $(patsubst $(GECKO_DIR)/%,%,$@)
|
||||
|
||||
$(OUT_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
|
@ -69,3 +86,4 @@ check-set-%:
|
|||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) -rv $(OUT_DIR) $(OBJ_FILES)
|
||||
$(MAKE) -C$(GECKO_DIR) $@
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/bash
|
||||
|
||||
make GAME_VERSION=GMSE01 OUT_DIR=out/gmse01
|
||||
make GAME_VERSION=GMSJ01 OUT_DIR=out/gmsj01
|
||||
make GAME_VERSION=GMSP01 OUT_DIR=out/gmsp01
|
||||
make GAME_VERSION=GMSJ0A OUT_DIR=out/gmsj0a
|
||||
make GAME_VERSION=GMSE01 OUT_DIR=out/GMSE01
|
||||
make GAME_VERSION=GMSJ01 OUT_DIR=out/GMSJ01
|
||||
make GAME_VERSION=GMSP01 OUT_DIR=out/GMSP01
|
||||
make GAME_VERSION=GMSJ0A OUT_DIR=out/GMSJ0A
|
||||
|
|
27
gecko/GeckoFactory.py
Normal file
27
gecko/GeckoFactory.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
def int2bytes(x):
|
||||
return x.to_bytes(4, 'big')
|
||||
|
||||
def makeC0(arg):
|
||||
## read bin file
|
||||
with open(arg, 'rb') as f:
|
||||
raw = f.read()
|
||||
## .align 2
|
||||
if len(raw) % 4:
|
||||
raw += b'\x00'*(4 - len(raw)%4)
|
||||
## add `blr` to align 3
|
||||
if len(raw) % 8:
|
||||
raw += b'\x4E\x80\x00\x20'
|
||||
## add C0 header
|
||||
raw = b'\xC0\x00\x00\x00' + int2bytes(len(raw) >> 3) + raw
|
||||
return raw
|
||||
|
||||
def make06(dst, fn):
|
||||
## read bin file
|
||||
with open(fn, 'rb') as f:
|
||||
raw = f.read()
|
||||
size06 = len(raw)
|
||||
## .align 3
|
||||
if len(raw) % 8:
|
||||
raw += b'\x00'*(8 - len(raw)%8)
|
||||
## header
|
||||
return int2bytes(0x06<<24 | dst & 0x1ffffff) + int2bytes(size06) + raw
|
40
gecko/Makefile
Normal file
40
gecko/Makefile
Normal file
|
@ -0,0 +1,40 @@
|
|||
AS := powerpc-eabi-as
|
||||
ASFLAGS := -mregnames -mgekko
|
||||
|
||||
LD := powerpc-eabi-ld
|
||||
LDFLAGS := --unresolved-symbols=ignore-in-object-files --enable-non-contiguous-regions -EB --nmagic
|
||||
|
||||
OBJCOPY := powerpc-eabi-objcopy
|
||||
OBJCOPYFLAGS = -O binary
|
||||
|
||||
PY := python3
|
||||
BIN2GCT := $(PY) bin2gct.py
|
||||
|
||||
LD_DIR := ../ldscript
|
||||
LD_FILES := $(LD_DIR)/sms.ld
|
||||
|
||||
SRC_DIR := code
|
||||
OUT_DIR := out
|
||||
|
||||
SRC_FILES := $(wildcard $(SRC_DIR)/*.s)
|
||||
OBJ_FILES := $(SRC_FILES:.s=.o)
|
||||
LDO_FILES := $(OBJ_FILES:.o=.ld.o)
|
||||
OUT_TXT := $(patsubst $(SRC_DIR)/%.s,$(OUT_DIR)/%.txt,$(SRC_FILES))
|
||||
|
||||
all: $(OUT_TXT)
|
||||
|
||||
%.o: %.s
|
||||
$(AS) $(ASFLAGS) -o $@ -c $^
|
||||
%.ld.o: %.o
|
||||
$(LD) $(LDFLAGS) -o $@ -T $(LD_FILES) $^
|
||||
$(OUT_DIR)/%.bin: $(SRC_DIR)/%.ld.o | $(OUT_DIR)
|
||||
$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
|
||||
$(OUT_DIR)/%.txt: $(OUT_DIR)/%.bin | $(OUT_DIR)
|
||||
$(BIN2GCT) C0:$^ > $@
|
||||
|
||||
$(OUT_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) -rv $(OUT_DIR) $(OBJ_FILES) $(LDO_FILES)
|
101
gecko/bin2gct.py
Normal file
101
gecko/bin2gct.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
import sys
|
||||
import os
|
||||
from GeckoFactory import int2bytes, make06, makeC0
|
||||
|
||||
validArguments = '''
|
||||
C0:{input.bin}
|
||||
hook:{input.map}:{input.bin}:{symbol=fromAddr}...
|
||||
'''[1:-1]
|
||||
|
||||
def exitInvalidSyntax(arg):
|
||||
print('Invalid argument `%s`\nValid arguments:\n%s'%(arg, validArguments))
|
||||
sys.exit(1)
|
||||
def exitMessage(msg):
|
||||
print(msg)
|
||||
sys.exit(1)
|
||||
|
||||
def printCode(raw, file=sys.stdout):
|
||||
assert len(raw)%8 == 0, \
|
||||
f'Expect code with length of multiple of 8, got {len(raw)}'
|
||||
for i in range(0, len(raw), 8):
|
||||
print(raw[i:i+4].hex().upper(), raw[i+4:i+8].hex().upper(), file=file)
|
||||
|
||||
def loadHookDB(fn):
|
||||
import csv
|
||||
with open(fn) as f:
|
||||
reader = csv.DictReader(f)
|
||||
return {
|
||||
row['symbol']: row
|
||||
for row in reader
|
||||
}
|
||||
|
||||
def parseMap(fn):
|
||||
with open(fn) as f:
|
||||
sections = {}
|
||||
symbols = {}
|
||||
for line in f:
|
||||
args = line.split()
|
||||
try:
|
||||
if line.startswith('.') and len(args) == 3:
|
||||
# .text 0x00000000817fe800 0x1dc
|
||||
sections[args[0]] = int(args[1], 16)
|
||||
elif len(args) == 2:
|
||||
# 0x00000000817fe800 loadCard
|
||||
symbols[args[1]] = int(args[0], 16)
|
||||
except: pass
|
||||
return sections, symbols
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage: %s {ARG}...\nARG:\n%s'%(sys.argv[0], validArguments))
|
||||
sys.exit(1)
|
||||
|
||||
__dirname = os.path.dirname(__file__)
|
||||
hookDB = loadHookDB(os.path.join(__dirname, './hook.csv'))
|
||||
|
||||
code = b''
|
||||
for arg0 in sys.argv[1:]:
|
||||
toks = arg0.split(':', 1)
|
||||
if len(toks) != 2: exitInvalidSyntax(arg)
|
||||
ct, arg = toks
|
||||
if ct == 'C0':
|
||||
code += makeC0(arg)
|
||||
elif ct == 'hook':
|
||||
args = arg.split(':')
|
||||
if len(args) < 3: exitInvalidSyntax(arg)
|
||||
fnMap, fnBin, *entries = args
|
||||
## parse map file
|
||||
sections, symbols = parseMap(fnMap)
|
||||
assert '.text' in sections, f'.text section does not exists in file {fnMap}'
|
||||
dst = sections['.text']
|
||||
## 06
|
||||
code += make06(dst, fnBin)
|
||||
## 04 entries
|
||||
for entry in entries:
|
||||
toks = entry.split('=')
|
||||
name = toks[0]
|
||||
if len(toks) == 1:
|
||||
version = os.environ.get('GAME_VERSION')
|
||||
if not version: exitMessage('Environment variable `GAME_VERSION` is not set. Please set the GAME_VERSION environment variable or specify the address manually')
|
||||
if name not in hookDB: exitMessage('The address for symbol `%s` is unknown. Please specify it manually\nSyntax: {name}={addr}'%name)
|
||||
hook = hookDB[name]
|
||||
if version not in hook: exitMessage(f'Invalid GAME_VERSION: {version}')
|
||||
addr0 = int(hook[version], 16)
|
||||
elif len(toks) == 2:
|
||||
try:
|
||||
addr0 = int(toks[1], 16)
|
||||
except ValueError:
|
||||
exitInvalidSyntax(arg)
|
||||
else:
|
||||
exitInvalidSyntax(arg)
|
||||
assert name in symbols, f'symbol `{name}` does not exists in file {fnMap}'
|
||||
addr1 = symbols[name]
|
||||
dis = addr1 - addr0
|
||||
assert -0x200_0000 <= dis < 0x200_0000, 'too far to branch from %s(%08X) to %08X'%(name, addr0, addr1)
|
||||
## make 04
|
||||
code += int2bytes(0x0400_0000 | addr0 & 0x1ff_ffff)
|
||||
code += int2bytes(0x4800_0001 | dis & 0x3ff_ffff)
|
||||
else:
|
||||
exitInvalidSyntax(arg)
|
||||
|
||||
printCode(code)
|
15
gecko/code/gecko-gosub.s
Normal file
15
gecko/code/gecko-gosub.s
Normal file
|
@ -0,0 +1,15 @@
|
|||
## check status
|
||||
### r3 = GCTDST
|
||||
lis r3, GCTDST@ha
|
||||
lwzu r0, GCTDST@l(r3)
|
||||
### return if not DONE(2)
|
||||
cmpwi r0, 2
|
||||
bnelr
|
||||
|
||||
## backup r15 (pointer to current gecko instruction)
|
||||
add r0, r15, r4
|
||||
stw r0, 4(r3)
|
||||
## update r15 = dst + 8(GCTDST.code-r3) - r4(this C0 code size)
|
||||
addi r15, r3, 8
|
||||
sub r15, r15, r4
|
||||
blr
|
6
gecko/code/gecko-return.s
Normal file
6
gecko/code/gecko-return.s
Normal file
|
@ -0,0 +1,6 @@
|
|||
## restore r15 (pointer to current gecko instruction)
|
||||
lis r3, GCTDST+4@ha
|
||||
lwz r15, GCTDST+4@l(r3)
|
||||
## update r15 = restored r15 - r4(this C0 code size)
|
||||
sub r15, r15, r4
|
||||
blr
|
2
gecko/hook.csv
Normal file
2
gecko/hook.csv
Normal file
|
@ -0,0 +1,2 @@
|
|||
symbol,GMSE01,GMSJ01,GMSP01,GMSJ0A
|
||||
onReadOptionBlock,802A96E0,801069F4,802A96E0,80291538
|
|
|
@ -1,11 +1,14 @@
|
|||
|
||||
|
||||
#include "gcn.h"
|
||||
#include "sms.h"
|
||||
|
||||
#ifndef __CARD_H__
|
||||
#define __CARD_H__
|
||||
|
||||
bool loadCard(TCardManager *cm, CARDFileInfo *fileInfo, char *fileName, u32 *dst);
|
||||
#define LOAD_ERR_MOUNT -1
|
||||
#define LOAD_ERR_OPEN -2
|
||||
#define LOAD_ERR_SIZE -3
|
||||
#define LOAD_ERR_FILE_NOT_EXIST -4
|
||||
#define LOAD_ERR_READ -5
|
||||
int loadCard(TCardManager *cm, CARDFileInfo *fileInfo, char *fileName, u32 *dst);
|
||||
|
||||
#endif
|
|
@ -8,8 +8,12 @@
|
|||
#define CARD_SLOT_A 0
|
||||
#define CARD_SLOT_B 1
|
||||
|
||||
#define MEM1_START 0x8000000
|
||||
#define MEM1_START 0x80000000
|
||||
#define MEM1_END 0x81800000
|
||||
// The area beyond ArenaHi is used by system
|
||||
// and should not be modified
|
||||
// TODO version?
|
||||
#define ArenaHi 0x817FEEA0
|
||||
|
||||
typedef struct CARDFileInfo
|
||||
{
|
||||
|
|
|
@ -1,20 +1,6 @@
|
|||
#ifndef __SMS_H__
|
||||
#define __SMS_H__
|
||||
|
||||
/** For NTSC-J 1.0:
|
||||
*
|
||||
* mount_ 80107b50
|
||||
* open_ 801072f4
|
||||
* CARDOpen 800a3cac
|
||||
* CARDRead 800a4640
|
||||
* CARDClose 800a3e24
|
||||
*
|
||||
* onReadOptionBlock 801069f4
|
||||
*/
|
||||
|
||||
// static void *gpApplication = (void *)0x803e9700;
|
||||
// static void *gpCardManager = (void *)0x8040a2b4;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int slot;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define __TYPEDEF_H__
|
||||
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long s64;
|
||||
|
|
5
ldscript/GMSE01.ld
Normal file
5
ldscript/GMSE01.ld
Normal file
|
@ -0,0 +1,5 @@
|
|||
mount_ = 0x802b2914;
|
||||
open_ = 0x802b20d0;
|
||||
CARDOpen = 0x8035938c;
|
||||
CARDRead = 0x80359d20;
|
||||
CARDClose = 0x80359504;
|
5
ldscript/GMSJ01.ld
Normal file
5
ldscript/GMSJ01.ld
Normal file
|
@ -0,0 +1,5 @@
|
|||
mount_ = 0x80107b50;
|
||||
open_ = 0x801072f4;
|
||||
CARDOpen = 0x800a3cac;
|
||||
CARDRead = 0x800a4640;
|
||||
CARDClose = 0x800a3e24;
|
5
ldscript/GMSJ0A.ld
Normal file
5
ldscript/GMSJ0A.ld
Normal file
|
@ -0,0 +1,5 @@
|
|||
mount_ = 0x80292634;
|
||||
open_ = 0x80291e38;
|
||||
CARDOpen = 0x80338c8c;
|
||||
CARDRead = 0x80339620;
|
||||
CARDClose = 0x80338e04;
|
5
ldscript/GMSP01.ld
Normal file
5
ldscript/GMSP01.ld
Normal file
|
@ -0,0 +1,5 @@
|
|||
mount_ = 0x802aa824;
|
||||
open_ = 0x802a9fe0;
|
||||
CARDOpen = 0x803515ac;
|
||||
CARDRead = 0x80351f40;
|
||||
CARDClose = 0x80351724;
|
14
ldscript/sms.ld
Normal file
14
ldscript/sms.ld
Normal file
|
@ -0,0 +1,14 @@
|
|||
/**
|
||||
* There seems to be an alignment issue
|
||||
* addr of GCTDST.code may need to be a multiple of 0x200 or something?
|
||||
*/
|
||||
GCTDST = 0x817F1800 - 8;
|
||||
|
||||
SECTIONS {
|
||||
. = 0x817FE800; /* TODO: Determine Best Address */
|
||||
.text : { *(.text) }
|
||||
.rodata : { *(.rodata) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss) }
|
||||
.sdata : { *(.sdata) }
|
||||
}
|
14
sms.ld
14
sms.ld
|
@ -1,14 +0,0 @@
|
|||
SECTIONS {
|
||||
. = 0x817FF000; /* TODO: Determine Best Address */
|
||||
.text : { *(.text) }
|
||||
.rodata : { *(.rodata) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss) }
|
||||
.sdata : { *(.sdata) }
|
||||
}
|
||||
|
||||
mount_ = 0x80107b50;
|
||||
open_ = 0x801072f4;
|
||||
CARDOpen = 0x800a3cac;
|
||||
CARDRead = 0x800a4640;
|
||||
CARDClose = 0x800a3e24;
|
|
@ -1,23 +1,32 @@
|
|||
#include "gcn.h"
|
||||
#include "sms.h"
|
||||
#include "card.h"
|
||||
|
||||
bool loadCard(TCardManager *cm, CARDFileInfo *fileInfo, char *fileName, u32 *dst)
|
||||
// TODO: we need to keep some space to store this loader code
|
||||
// #define DST_END ArenaHi
|
||||
#define DST_END 0x817FE800
|
||||
|
||||
int loadCard(TCardManager *cm, CARDFileInfo *fileInfo, char *fileName, u32 *dst)
|
||||
{
|
||||
int rc;
|
||||
|
||||
// Mount the card
|
||||
if (!mount_(cm, 1))
|
||||
return -1;
|
||||
if (mount_(cm, 1))
|
||||
return LOAD_ERR_MOUNT;
|
||||
|
||||
// Open the card
|
||||
if (!CARDOpen(cm->slot, fileName, fileInfo))
|
||||
return -1;
|
||||
if ((rc = CARDOpen(cm->slot, fileName, fileInfo))) {
|
||||
return rc == -4 ? LOAD_ERR_FILE_NOT_EXIST : LOAD_ERR_OPEN;
|
||||
}
|
||||
|
||||
// Too many codes
|
||||
if (fileInfo->length > (MEM1_END - (u32)dst))
|
||||
return -1;
|
||||
// TODO fileInfo->length seems to be 0?
|
||||
// int fileSize = fileInfo->length;
|
||||
int fileSize = 0x2000 * 6;
|
||||
if (fileSize > (DST_END - (u32)dst))
|
||||
return LOAD_ERR_SIZE;
|
||||
|
||||
// Read codes into destination address
|
||||
if (!CARDRead(fileInfo, dst, fileInfo->length, 0))
|
||||
return -1;
|
||||
if (CARDRead(fileInfo, dst, fileSize, 0))
|
||||
return LOAD_ERR_READ;
|
||||
|
||||
// Done
|
||||
CARDClose(fileInfo);
|
||||
|
|
|
@ -18,22 +18,33 @@
|
|||
#define ADDR_GECKO_HEAP_START 0x817F0000
|
||||
#define ADDR_GECKO_HEAP_SIZE 0x00001000
|
||||
#define ADDR_GECKO_HEAP_END (ADDR_GECKO_HEAP_START + ADDR_GECKO_HEAP_SIZE)
|
||||
#define PTR_FLG_LOADED (bool *)ADDR_GECKO_HEAP_END
|
||||
#define GECKO_CODE_START (ADDR_GECKO_HEAP_END + sizeof(*PTR_FLG_LOADED))
|
||||
// GCTDST = 0x817F1000; // in ldscripts/sms.ld
|
||||
|
||||
extern struct GCTBuffer {
|
||||
// =0: initialized
|
||||
// >0: Loading(1), Done(2)
|
||||
// <0: error
|
||||
int status;
|
||||
// return address to the original Gecko handler
|
||||
void *returnAddr;
|
||||
// actual Gecko code
|
||||
u32 code[0];
|
||||
} GCTDST;
|
||||
|
||||
#define GCT_LOAD_LOADING 1
|
||||
#define GCT_LOAD_DONE 2
|
||||
|
||||
void loadCodes(TCardManager *cm, CARDFileInfo *fileInfo)
|
||||
{
|
||||
*PTR_FLG_LOADED = -1;
|
||||
|
||||
if (loadCard(cm, fileInfo, FILENAME, (void *)GECKO_CODE_START))
|
||||
*PTR_FLG_LOADED = 0;
|
||||
GCTDST.status = GCT_LOAD_LOADING;
|
||||
// load card
|
||||
int rc = loadCard(cm, fileInfo, FILENAME, GCTDST.code);
|
||||
GCTDST.status = rc == 0 ? GCT_LOAD_DONE : rc; // DONE or Error code
|
||||
}
|
||||
|
||||
// int onReadOptionBlock(TCardManager *this, CARDFileInfo *fileInfo)
|
||||
// {
|
||||
// if (*PTR_FLG_LOADED)
|
||||
// return open_(this, fileInfo);
|
||||
|
||||
// loadCodes(this, fileInfo);
|
||||
// return open_(this, fileInfo);
|
||||
// }
|
||||
int onReadOptionBlock(TCardManager *this, CARDFileInfo *fileInfo)
|
||||
{
|
||||
if (GCTDST.status <= 0) // Initialized(=0) or Error(<0)
|
||||
loadCodes(this, fileInfo);
|
||||
return open_(this, fileInfo);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue