mirror of
https://github.com/radareorg/radare2.git
synced 2024-10-07 10:33:30 +00:00
Implemented a sort-of-working SNES/SFC file format
This commit is contained in:
parent
5fc6dc30a8
commit
6d9db7e891
@ -152,7 +152,7 @@ static int snes_anop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int l
|
||||
break;
|
||||
case 0x4c: // jmp addr
|
||||
op->eob = true;
|
||||
op->jump = ut8p_bw (data+1);
|
||||
op->jump = (addr & 0xFF0000) | ut8p_bw (data+1);
|
||||
op->type = R_ANAL_OP_TYPE_JMP;
|
||||
break;
|
||||
case 0x5c: // jmp long
|
||||
@ -202,7 +202,7 @@ static int snes_anop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int l
|
||||
op->type = R_ANAL_OP_TYPE_CJMP;
|
||||
break;
|
||||
case 0x20: // jsr addr
|
||||
op->jump = ut8p_bw (data+1);
|
||||
op->jump = (addr & 0xFF0000) | ut8p_bw (data+1);
|
||||
op->type = R_ANAL_OP_TYPE_CALL;
|
||||
break;
|
||||
case 0x22: // jsr long
|
||||
|
@ -19,7 +19,6 @@ static bool snes_asm_fini (void* user) {
|
||||
free(snesflags);
|
||||
snesflags = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) {
|
||||
int dlen = snesDisass (snesflags->M, snesflags->X, a->pc, op, buf, len);
|
||||
|
58
libr/bin/format/sfc/sfc_specs.h
Normal file
58
libr/bin/format/sfc/sfc_specs.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* radare - LGPL - 2015 - maijin */
|
||||
|
||||
//CPU_memory_map: http://wiki.nesdev.com/w/index.php/CPU_memory_map
|
||||
|
||||
#ifndef _SFC_SPECS_H
|
||||
#define _SFC_SPECS_H
|
||||
|
||||
#define LOROM_PAGE_SIZE 0x8000
|
||||
#define HIROM_PAGE_SIZE 0x10000
|
||||
#define BANK_SIZE 0x10000
|
||||
|
||||
#define SFC_HDR_SIZE sizeof (sfc_int_hdr)
|
||||
#define LOROM_HDR_LOC 0x7FC0
|
||||
#define HIROM_HDR_LOC 0xFFC0
|
||||
|
||||
#define ADDMEM_START_ADDRESS 0x6000
|
||||
#define ADDMEM_SIZE 0x2000
|
||||
|
||||
//identical for both LoROM and HiROM
|
||||
|
||||
#define PPU1_REG_ADDRESS 0x2100
|
||||
#define PPU1_REG_SIZE 0x0100
|
||||
|
||||
#define DSP_REG_ADDRESS 0x3000
|
||||
#define DSP_REG_SIZE 0x1000
|
||||
|
||||
#define OLDJOY_REG_ADDRESS 0x4000
|
||||
#define OLDJOY_REG_SIZE 0x0100
|
||||
|
||||
#define PPU2_REG_ADDRESS 0x4200
|
||||
#define PPU2_REG_SIZE 0x0300
|
||||
|
||||
#define LOWRAM_START_ADDRESS 0x7E0000
|
||||
#define LOWRAM_SIZE 0x2000
|
||||
|
||||
#define LOWRAM_MIRROR_START_ADDRESS 0x0000
|
||||
#define LOWRAM_MIRROR_SIZE 0x2000
|
||||
|
||||
#define HIRAM_START_ADDRESS 0x7E2000
|
||||
#define HIRAM_SIZE 0x6000
|
||||
|
||||
#define EXTRAM_START_ADDRESS 0x7E8000
|
||||
#define EXTRAM_SIZE 0x18000
|
||||
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
char name[0x15]; //game title.
|
||||
ut8 rom_setup; //ROM setup (LoROM/HiROM, etc.)
|
||||
ut8 rom_type;
|
||||
ut8 rom_size; //in 1kb chunks
|
||||
ut8 sram_size; //in 1kb chunks
|
||||
ut8 dest_code;
|
||||
ut8 fixed_0x33; //should be equal to 0x33
|
||||
ut8 rom_version;
|
||||
ut16 comp_check; //should be equal to ~checksum
|
||||
ut16 checksum;
|
||||
} sfc_int_hdr;
|
||||
|
||||
#endif // _SFC_SPECS_H
|
@ -14,7 +14,7 @@ FORMATS=any.mk elf.mk elf64.mk pe.mk pe64.mk te.mk mach0.mk
|
||||
FORMATS+=bios.mk mach064.mk fatmach0.mk dyldcache.mk java.mk
|
||||
FORMATS+=dex.mk fs.mk ningb.mk coff.mk ningba.mk xbe.mk zimg.mk
|
||||
FORMATS+=omf.mk cgc.mk dol.mk nes.mk mbn.mk psxexe.mk spc700.mk
|
||||
FORMATS+=vsf.mk nin3ds.mk xtr_dyldcache.mk bflt.mk wasm.mk
|
||||
FORMATS+=vsf.mk nin3ds.mk xtr_dyldcache.mk bflt.mk wasm.mk sfk.mk
|
||||
include $(FORMATS)
|
||||
|
||||
all: ${ALL_TARGETS}
|
||||
|
301
libr/bin/p/bin_sfc.c
Normal file
301
libr/bin/p/bin_sfc.c
Normal file
@ -0,0 +1,301 @@
|
||||
/* radare - LGPL3 - 2015-2016 - maijin */
|
||||
|
||||
#include <r_bin.h>
|
||||
#include <r_lib.h>
|
||||
#include "sfc/sfc_specs.h"
|
||||
#include <r_endian.h>
|
||||
|
||||
static bool check_bytes(const ut8 *buf, ut64 length) {
|
||||
|
||||
const ut8* buf_hdr = buf;
|
||||
ut16 cksum1, cksum2;
|
||||
|
||||
if ((length & 0x8000) == 0x200) buf_hdr += 0x200;
|
||||
|
||||
//determine if ROM is headered, and add a 0x200 gap if so.
|
||||
cksum1 = r_read_le16(buf_hdr + 0x7FDC);
|
||||
cksum2 = r_read_le16(buf_hdr + 0x7FDE);
|
||||
|
||||
if (cksum1 == (ut16)~cksum2) return true;
|
||||
|
||||
cksum1 = r_read_le16(buf_hdr + 0xFFDC);
|
||||
cksum2 = r_read_le16(buf_hdr + 0xFFDE);
|
||||
|
||||
if (cksum1 == (ut16)~cksum2) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool check(RBinFile *arch) {
|
||||
const ut8 *bytes = arch ? r_buf_buffer (arch->buf) : NULL;
|
||||
ut64 sz = arch ? r_buf_size (arch->buf): 0;
|
||||
return check_bytes (bytes, sz);
|
||||
}
|
||||
|
||||
static void * load_bytes(RBinFile *arch, const ut8 *buf, ut64 sz, ut64 loadaddr, Sdb *sdb){
|
||||
check_bytes (buf, sz);
|
||||
return R_NOTNULL;
|
||||
}
|
||||
|
||||
static RBinInfo* info(RBinFile *arch) {
|
||||
RBinInfo *ret = NULL;
|
||||
|
||||
int hdroffset = 0;
|
||||
if ((arch->size & 0x8000) == 0x200) hdroffset = 0x200;
|
||||
|
||||
sfc_int_hdr sfchdr;
|
||||
memset (&sfchdr, 0, SFC_HDR_SIZE);
|
||||
|
||||
int reat = r_buf_read_at (arch->buf, 0x7FC0 + hdroffset, (ut8*)&sfchdr, SFC_HDR_SIZE);
|
||||
if (reat != SFC_HDR_SIZE) {
|
||||
eprintf ("Unable to read SFC/SNES header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (sfchdr.comp_check != (ut16)~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 0) ){
|
||||
|
||||
// if the fixed 0x33 byte or the LoROM indication are not found, then let's try interpreting the ROM as HiROM
|
||||
|
||||
reat = r_buf_read_at (arch->buf, 0xFFC0 + hdroffset, (ut8*)&sfchdr, SFC_HDR_SIZE);
|
||||
if (reat != SFC_HDR_SIZE) {
|
||||
eprintf ("Unable to read SFC/SNES header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (sfchdr.comp_check != (ut16)~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 1) ) {
|
||||
|
||||
eprintf ("Cannot determine if this is a LoROM or HiROM file\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ret = R_NEW0 (RBinInfo)))
|
||||
return NULL;
|
||||
|
||||
ret->file = strdup (arch->file);
|
||||
ret->type = strdup ("ROM");
|
||||
ret->machine = strdup ("Super NES / Super Famicom");
|
||||
ret->os = strdup ("snes");
|
||||
ret->arch = strdup ("snes");
|
||||
ret->bits = 16;
|
||||
ret->has_va = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void addrom(RList *ret, const char *name, int i, ut64 paddr, ut64 vaddr, ut32 size) {
|
||||
RBinSection *ptr = R_NEW0 (RBinSection);
|
||||
if (!ptr) return;
|
||||
sprintf(ptr->name,"%s_%02x",name,i);
|
||||
ptr->paddr = paddr;
|
||||
ptr->vaddr = vaddr;
|
||||
ptr->size = ptr->vsize = size;
|
||||
ptr->srwx = R_BIN_SCN_READABLE | R_BIN_SCN_EXECUTABLE | R_BIN_SCN_MAP;
|
||||
ptr->add = true;
|
||||
r_list_append (ret, ptr);
|
||||
}
|
||||
|
||||
static void addsym(RList *ret, const char *name, ut64 addr, ut32 size) {
|
||||
RBinSymbol *ptr = R_NEW0 (RBinSymbol);
|
||||
if (!ptr) return;
|
||||
ptr->name = strdup (name? name: "");
|
||||
ptr->paddr = ptr->vaddr = addr;
|
||||
ptr->size = size;
|
||||
ptr->ordinal = 0;
|
||||
r_list_append (ret, ptr);
|
||||
}
|
||||
|
||||
static RList* symbols(RBinFile *arch) {
|
||||
RList *ret = NULL;
|
||||
if (!(ret = r_list_new ()))
|
||||
return NULL;
|
||||
ret->free = free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RList* sections(RBinFile *arch) {
|
||||
RList *ret = NULL;
|
||||
RBinSection *ptr = NULL;
|
||||
int hdroffset = 0;
|
||||
ut8 is_hirom = 0;
|
||||
int i=0; //0x8000-long bank number for loops
|
||||
|
||||
if ((arch->size & 0x8000) == 0x200) hdroffset = 0x200;
|
||||
|
||||
sfc_int_hdr sfchdr;
|
||||
memset (&sfchdr, 0, SFC_HDR_SIZE);
|
||||
|
||||
int reat = r_buf_read_at (arch->buf, 0x7FC0 + hdroffset, (ut8*)&sfchdr, SFC_HDR_SIZE);
|
||||
if (reat != SFC_HDR_SIZE) {
|
||||
eprintf ("Unable to read SFC/SNES header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (sfchdr.comp_check != (ut16)~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 0) ){
|
||||
|
||||
// if the fixed 0x33 byte or the LoROM indication are not found, then let's try interpreting the ROM as HiROM
|
||||
|
||||
reat = r_buf_read_at (arch->buf, 0xFFC0 + hdroffset, (ut8*)&sfchdr, SFC_HDR_SIZE);
|
||||
if (reat != SFC_HDR_SIZE) {
|
||||
eprintf ("Unable to read SFC/SNES header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (sfchdr.comp_check != (ut16)~(sfchdr.checksum)) || ((sfchdr.rom_setup & 0x1) != 1) ) {
|
||||
|
||||
eprintf ("Cannot determine if this is a LoROM or HiROM file\n");
|
||||
return NULL;
|
||||
}
|
||||
is_hirom = 1;
|
||||
}
|
||||
|
||||
if (!(ret = r_list_new ()))
|
||||
return NULL;
|
||||
|
||||
|
||||
if (is_hirom) {
|
||||
|
||||
for (i=0; i < ((arch->size - hdroffset)/ 0x8000) ; i++) {
|
||||
|
||||
addrom(ret,"ROM",i,hdroffset + i*0x8000,0x400000 + (i*0x8000), 0x8000);
|
||||
if (i % 2) addrom(ret,"ROM_MIRROR",i,hdroffset + i*0x8000,(i*0x8000), 0x8000);
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i=0; i < ((arch->size - hdroffset)/ 0x8000) ; i++) {
|
||||
|
||||
addrom(ret,"ROM",i,hdroffset + i*0x8000,0x8000 + (i*0x10000), 0x8000);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RList *mem (RBinFile *arch) {
|
||||
RList *ret;
|
||||
RBinMem *m, *n;
|
||||
if (!(ret = r_list_new()))
|
||||
return NULL;
|
||||
ret->free = free;
|
||||
if (!(m = R_NEW0 (RBinMem))) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m->name = strdup ("LOWRAM");
|
||||
m->addr = LOWRAM_START_ADDRESS;
|
||||
m->size = LOWRAM_SIZE;
|
||||
m->perms = r_str_rwx ("rwx");
|
||||
r_list_append (ret, m);
|
||||
if (!(n = R_NEW0 (RBinMem)))
|
||||
return ret;
|
||||
|
||||
m->mirrors = r_list_new();
|
||||
|
||||
n->name = strdup ("LOWRAM_MIRROR");
|
||||
n->addr = LOWRAM_MIRROR_START_ADDRESS;
|
||||
n->size = LOWRAM_MIRROR_SIZE;
|
||||
n->perms = r_str_rwx ("rwx");
|
||||
r_list_append (m->mirrors, n);
|
||||
if (!(n = R_NEW0 (RBinMem))) {
|
||||
r_list_free (m->mirrors);
|
||||
m->mirrors = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
m->name = strdup ("HIRAM");
|
||||
m->addr = HIRAM_START_ADDRESS;
|
||||
m->size = HIRAM_SIZE;
|
||||
m->perms = r_str_rwx ("rwx");
|
||||
r_list_append (ret, m);
|
||||
if (!(n = R_NEW0 (RBinMem)))
|
||||
return ret;
|
||||
|
||||
m->name = strdup ("EXTRAM");
|
||||
m->addr = EXTRAM_START_ADDRESS;
|
||||
m->size = EXTRAM_SIZE;
|
||||
m->perms = r_str_rwx ("rwx");
|
||||
r_list_append (ret, m);
|
||||
if (!(n = R_NEW0 (RBinMem)))
|
||||
return ret;
|
||||
|
||||
|
||||
m->name = strdup ("PPU1_REG");
|
||||
m->addr = PPU1_REG_ADDRESS;
|
||||
m->size = PPU1_REG_SIZE;
|
||||
m->perms = r_str_rwx ("rwx");
|
||||
r_list_append (ret, m);
|
||||
if (!(m = R_NEW0 (RBinMem))) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m->name = strdup ("DSP_REG");
|
||||
m->addr = DSP_REG_ADDRESS;
|
||||
m->size = DSP_REG_SIZE;
|
||||
m->perms = r_str_rwx ("rwx");
|
||||
r_list_append (ret, m);
|
||||
if (!(m = R_NEW0 (RBinMem))) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m->name = strdup ("OLDJOY_REG");
|
||||
m->addr = OLDJOY_REG_ADDRESS;
|
||||
m->size = OLDJOY_REG_SIZE;
|
||||
m->perms = r_str_rwx ("rwx");
|
||||
r_list_append (ret, m);
|
||||
if (!(m = R_NEW0 (RBinMem))) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m->name = strdup ("PPU2_REG");
|
||||
m->addr = PPU2_REG_ADDRESS;
|
||||
m->size = PPU2_REG_SIZE;
|
||||
m->perms = r_str_rwx ("rwx");
|
||||
r_list_append (ret, m);
|
||||
if (!(m = R_NEW0 (RBinMem))) {
|
||||
r_list_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static RList* entries(RBinFile *arch) { //Should be 3 offsets pointed by NMI, RESET, IRQ after mapping && default = 1st CHR
|
||||
RList *ret;
|
||||
if (!(ret = r_list_new ())) {
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
RBinAddr *ptr = NULL;
|
||||
if (!(ptr = R_NEW0 (RBinAddr))) {
|
||||
return ret;
|
||||
}
|
||||
ptr->paddr = INES_HDR_SIZE;
|
||||
ptr->vaddr = ROM_START_ADDRESS;
|
||||
r_list_append (ret, ptr);
|
||||
*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
RBinPlugin r_bin_plugin_sfc = {
|
||||
.name = "sfc",
|
||||
.desc = "Super NES / Super Famicom ROM file",
|
||||
.license = "LGPL3",
|
||||
.load_bytes = &load_bytes,
|
||||
.check = &check,
|
||||
.check_bytes = &check_bytes,
|
||||
.entries = &entries,
|
||||
.sections = sections,
|
||||
.symbols = &symbols,
|
||||
.info = &info,
|
||||
.mem = &mem,
|
||||
};
|
||||
|
||||
#ifndef CORELIB
|
||||
RLibStruct radare_plugin = {
|
||||
.type = R_LIB_TYPE_BIN,
|
||||
.data = &r_bin_plugin_sfc,
|
||||
.version = R2_VERSION
|
||||
};
|
||||
#endif
|
10
libr/bin/p/sfc.mk
Normal file
10
libr/bin/p/sfc.mk
Normal file
@ -0,0 +1,10 @@
|
||||
OBJ_SFC=bin_sfc.o
|
||||
|
||||
STATIC_OBJ+=${OBJ_SFC}
|
||||
TARGET_SFC=bin_sfc.${EXT_SO}
|
||||
|
||||
ALL_TARGETS+=${TARGET_SFC}
|
||||
|
||||
${TARGET_SFC}: ${OBJ_SFC}
|
||||
${CC} $(call libname,bin_sfc) -shared ${CFLAGS} \
|
||||
-o ${TARGET_SFC} ${OBJ_SFC} $(LINK) $(LDFLAGS)
|
Loading…
Reference in New Issue
Block a user