//-------------------------------------------------------------------------- int get_aout_file_format_index(linput_t *li) { exec ex; register int i = 0; if(qlread(li, &ex, sizeof(ex)) != sizeof(ex)) return false; if(N_BADMAG(ex)) { ex.a_info = swap32(ex.a_info); switch(N_MACHTYPE(ex)) { case M_386_NETBSD: case M_68K_NETBSD: case M_68K4K_NETBSD: case M_532_NETBSD: case M_SPARC_NETBSD: case M_PMAX_NETBSD: case M_VAX_NETBSD: case M_ALPHA_NETBSD: case M_ARM6_NETBSD: break; default: return false; } } switch(N_MAGIC(ex)) { case NMAGIC: ++i; case CMAGIC: ++i; case ZMAGIC: ++i; case OMAGIC: ++i; case QMAGIC: // msg("text=%d data=%d symsize=%d txtoff=%d sum=%d\n", ex.a_text, ex.a_data, // N_SYMSIZE(ex), N_TXTOFF(ex), ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex)); if ( qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) + N_TXTOFF(ex) ) break; if ( N_MAGIC(ex) == ZMAGIC && qlsize(li) >= ex.a_text + ex.a_data + N_SYMSIZE(ex) ) { i = 5; // OpenBSD demand-paged break; } default: return false; } return i+1; }
static int copy_to_remote(const char *lname, const char *rname) { int code = 0; int fn = s_open_file(rname, NULL, false); if ( fn != -1 ) { linput_t *li = open_linput(lname, false); if ( li != NULL ) { size_t size = qlsize(li); if ( size > 0 ) { char *buf = (char *)qalloc(size); qlread(li, buf, size); if ( s_write_file(fn, 0, buf, size) != ssize_t(size) ) code = qerrcode(); } close_linput(li); } else { code = qerrcode(); } s_close_file(fn); #if DEBUGGER_ID == DEBUGGER_ID_X86_IA32_LINUX_USER // chmod +x s_ioctl(0, rname, strlen(rname)+1, NULL, 0); #endif } else { code = qerrcode(); } return code; }
//------------------------------------------------------------------------- // Since the Palm Pilot programs are really poorly recognized by usual // methods, we are forced to read the resource tablee to determine // if everying is ok //return 0 if not a PRC, 2 if has ARM code segments, 1 otherwise int is_prc_file(linput_t *li) { DatabaseHdrType h; if ( qlread(li,&h,sizeof(h)) != sizeof(h) ) return 0; swap_prc(h); if ( (h.attributes & dmHdrAttrResDB) == 0 ) return 0; if ( short(h.numRecords) <= 0 ) return 0; const uint32 filesize = qlsize(li); const uint32 lowestpos = h.numRecords*sizeof(ResourceMapEntry) + sizeof(h); if ( lowestpos > filesize ) return 0; // the dates can be plain wrong, so don't check them: //uint32 now = time(NULL); //&& uint32(h.lastBackupDate) <= now // use unsigned comparition! //&& uint32(h.creationDate) <= now // use unsigned comparition! //&& uint32(h.modificationDate) <= now // use unsigned comparition! size_t size = sizeof(ResourceMapEntry) * h.numRecords; ResourceMapEntry *re = (ResourceMapEntry *)alloca(size); if ( re == NULL ) return 0; if ( qlread(li,re,size) != size ) return 0; bool hasArmCode = false; for ( int i=0; i < h.numRecords; i++ ) { swap_resource_map_entry(re[i]); if ( re[i].ulOffset >= filesize || re[i].ulOffset < lowestpos ) return 0; if ( re[i].fcType == PILOT_RSC_ARMC || re[i].fcType == PILOT_RSC_ARMCL ) hasArmCode = true; } return hasArmCode ? 2 : 1; }
bool load_header(linput_t *li) { int headerversion; int size; qlseek(li, 3); if (qlread(li, &yssEndian, 1) != 1) { error("Truncated file"); return false; } qlread(li, &headerversion, 4); qlread(li, &size, 4); int headersize=0xC; if (headerversion == 2) { qlseek(li, 8, SEEK_CUR); headersize+=8; } // Make sure size variable matches actual size minus header if (size != (qlsize(li) - headersize)) { error("Header size isn't valid"); return false; } return true; }
//---------------------------------------------------------------------------- int idaapi accept_file( linput_t *li, char fileformatname[MAX_FILE_FORMAT_NAME], int n) { if ( n > 0 ) return 0; int32 spc_file_size = qlsize(li); if ( spc_file_size < 0x10200 ) return 0; spc_file_t spc_info; if ( qlseek(li, 0) != 0 ) return 0; if ( qlread(li, &spc_info, sizeof(spc_file_t)) != sizeof(spc_file_t) ) return 0; if (memcmp(spc_info.signature, "SNES-SPC700 Sound File Data", 27) != 0 || spc_info.signature[0x21] != 0x1a || spc_info.signature[0x22] != 0x1a) return 0; qstrncpy(fileformatname, "SNES-SPC700 Sound File Data", MAX_FILE_FORMAT_NAME); return 1; }
//---------------------------------------------------------------------- // // check input file format. if recognized, then return 1 // and fill 'fileformatname'. // otherwise return 0 // int accept_file(linput_t *li, char fileformatname[MAX_FILE_FORMAT_NAME], int n) { if( n!= 0 ) return 0; // quit if file is smaller than size of iNes header if (qlsize(li) < sizeof(ines_hdr)) return 0; // set filepos to offset 0 qlseek(li, 0, SEEK_SET); // read NES header if(qlread(li, &hdr, INES_HDR_SIZE) != INES_HDR_SIZE) return 0; // is it a valid ROM image in iNes format? if( memcmp("NES", &hdr.id, sizeof(hdr.id)) != 0 || hdr.term != 0x1A ) return 0; // this is the name of the file format which will be // displayed in IDA's dialog qstrncpy(fileformatname, "Nintendo Entertainment System ROM", MAX_FILE_FORMAT_NAME); // set processor to 6502 if ( ph.id != PLFM_6502 ) { msg("Nintendo Entertainment System ROM detected: setting processor type to M6502.\n"); set_processor_type("M6502", SETPROC_ALL|SETPROC_FATAL); } return (1 | ACCEPT_FIRST); }
//----------------------------------------------------------------------- bool is_intelomf_file(linput_t *li) { uchar magic; lmh h; qlseek(li, 0); if ( qlread(li, &magic, sizeof(magic)) != sizeof(magic) || qlread(li, &h, sizeof(h)) != sizeof(h) ) return false; int fsize = qlsize(li); return magic == INTELOMF_MAGIC_BYTE && h.tot_length < fsize; }
//------------------------------------------------------------------------ // process all imports of a pe file // returns: -1:could not read an impdir; 0-ok; // other values can be returned by the visitor inline int pe_loader_t::process_imports(linput_t *li, pe_import_visitor_t &piv) { if ( pe.impdir.rva == 0 ) return 0; if ( transvec.empty() ) process_sections(li); int code = 0; bool is_memory_linput = get_linput_type(li) == LINPUT_PROCMEM; for ( int ni=0; ; ni++ ) { off_t off = pe.impdir.rva + ni*sizeof(peimpdir_t); peimpdir_t &id = piv.id; if ( !vmread(li, off, &id, sizeof(id)) ) { int code = piv.impdesc_error(off); if ( code != 0 ) break; // we continue if the import descriptor is within the page belonging // to the program if ( !is_memory_linput ) { uint32 fsize = pe.align_up_in_file(qlsize(li)); if ( map_ea(off)+sizeof(id) > fsize ) return -1; } } if ( id.dllname == 0 && id.table1 == 0 ) break; ea_t ltable = id.table1; //OriginalFirstThunk ea_t atable = id.looktab; //FirstThunk bool ok = true; char dll[MAXSTR]; asciiz(li, id.dllname, dll, sizeof(dll), &ok); if ( !ok || dll[0] == '\0' ) break; ansi2idb(dll); if ( !is_memory_linput && (map_ea(ltable) == BADADDR || ltable < pe.hdrsize) ) ltable = atable; atable += get_imagebase(); int code = piv.visit_module(dll, atable, ltable); if ( code != 0 ) break; code = process_import_table(li, pe, atable, ltable, piv); if ( code != 0 ) break; } return code; }
//------------------------------------------------------------------------ inline int pe_loader_t::process_sections(linput_t *li, off_t first_sec_pos, int nobjs, pe_section_visitor_t &psv) { transvec.qclear(); qvector <pesection_t> sec_headers; // does the file layout match memory layout? bool alt_align = pe.objalign == pe.filealign && pe.objalign < PAGE_SIZE; for ( int i=0; i < nobjs; i++ ) { pesection_t& sh = sec_headers.push_back(); qlseek(li, first_sec_pos + i*sizeof(pesection_t)); lread(li, &sh, sizeof(sh)); if ( sh.s_vaddr != uint32(sh.s_scnptr) || sh.s_vsize > sh.s_psize ) alt_align = false; } if ( alt_align ) // according to Ivan Teblin from AVERT Labs, such files are // mapped by Windows as-is and not section by section // we mimic that behaviour psv.load_all(); int off_align = alt_align ? pe.filealign : FILEALIGN; if ( pe.is_efi() ) off_align = 1; for ( int i=0; i < nobjs; i++ ) { pesection_t &sh = sec_headers[i]; uint32 scnptr = align_down(sh.s_scnptr, off_align);//pe.align_down_in_file(sh.s_scnptr); transl_t &tr = transvec.push_back(); tr.start = sh.s_vaddr; tr.psize = sh.get_psize(pe); tr.end = pe.align_up_in_file(uint32(sh.s_vaddr + tr.psize)); tr.pos = scnptr; int code = psv.visit_section(sh, scnptr); if ( code != 0 ) return code; } if ( nobjs == 0 ) { // add mapping for the header transl_t &tr = transvec.push_back(); tr.start = 0; tr.psize = qlsize(li); tr.end = pe.align_up_in_file(pe.imagesize); tr.pos = 0; } return 0; }
//-------------------------------------------------------------------------- bool macho_file_t::parse_fat_header() { qlseek(li, start_offset); if ( qlread(li, &fheader, sizeof(fheader)) != sizeof(fheader) ) return false; int code = (fheader.magic == FAT_MAGIC); if ( fheader.magic == FAT_CIGAM ) { swap_fat_header(&fheader); code = 2; } if ( code == 0 || fheader.nfat_arch > 16 ) return false; uint32 fsize = qlsize(li); uint32 archs_size = fheader.nfat_arch * sizeof(fat_arch); if ( sizeof(fat_header) + archs_size >= fsize ) return false; fat_archs.resize(fheader.nfat_arch); if ( qlread(li, fat_archs.begin(), archs_size) != archs_size ) { fat_archs.clear(); return false; } for ( uint32_t i=0; i < fheader.nfat_arch; i++ ) { fat_arch *parch = &fat_archs[i]; if ( code == 2 ) swap_fat_arch(parch); if ( parch->size <= sizeof(mach_header) || parch->size >= fsize || parch->offset < sizeof(fat_header) + archs_size || parch->offset + parch->size > fsize ) { fat_archs.clear(); return false; } } return true; }
//-------------------------------------------------------------------------- // check and send to the remote server the specified stub // do it only if its crc does not match the specified crc // this function runs on the local machine with ida interface static uchar *sync_stub(const char *fname, uint32 crc, size_t *psize) { char path[QMAXPATH]; bool told = false; if ( getsysfile(path, sizeof(path), fname, NULL) != NULL ) { linput_t *li = open_linput(path, false); if ( li != NULL ) { int32 size = qlsize(li); if ( size > 0 ) { uchar *buf = qnewarray(uchar, size); if ( buf != NULL ) { if ( qlread(li, buf, size) == size ) { if ( calc_crc32(0, buf, size) != crc ) { close_linput(li); *psize = size; return buf; } else { msg("Kernel debugger stub is up to date...\n"); told = true; *psize = 1; // signal ok } } qfree(buf); } } close_linput(li); } } if ( !told ) warning("AUTOHIDE NONE\nCould not find/read debugger stub %s", fname); return NULL; }
//----------------------------------------------------------------------------- // process a file record according to its "record_type". // return true if there is no more records to process. static bool process_record(linput_t *li, const uchar record_type, bool load) { bool finished = false; switch (record_type) { // A record with a header byte of $81 is a record that may contain code or // data from arbitrary segments. // // header : 1 byte // segment : 1 byte // gran : 1 byte // start_addr : 4 bytes (entry point) // length : 2 bytes // data : length bytes case 0x81: { mas_header_t header; memset(&header, 0, sizeof header); // read the header if (qlread(li, &header, sizeof header) != sizeof header) mas_error("unable to read header (%d bytes)", sizeof header); // granularities that differ from 1 are rare and mostly appear // in DSP CPU's that are not designed for byte processing. if (header.gran != 1) mas_error("unsupported granularity (%d)", header.gran); // set processor if (!mas_set_cpu(header.header)) mas_error("processor type '0x%X' is currently unsupported", header.header); if (!load) // we have the processor, nothing else to do { finished = true; break; } // get segment name const char *segname = mas_get_segname(header.segment); if (segname == NULL) mas_error("invalid segment '0x%X'", header.segment); #if defined(DEBUG) msg("MAS: ready to read %d bytes (0x%X -> 0x%X)\n", header.length, header.start_addr, header.start_addr + header.length); #endif // send code in the database file2base(li, qltell(li), header.start_addr, header.start_addr + header.length, FILEREG_PATCHABLE); // set selector sel_t selector = allocate_selector(0); // create segment add_segm(selector, header.start_addr, header.start_addr + header.length, segname, segname); } break; // The last record in a file bears the Header $00 and has only a string as // data field. This string does not have an explicit length specification; // its end is equal to the file's end. // // The string contains only the name of the program that created the file // and has no further meaning. // // creator : x bytes case 0x00: { ulong length = qlsize(li) - qltell(li); #if defined(DEBUG) msg("MAS: creator length : %ld bytes\n", length); #endif if (length >= sizeof creator) mas_error("creator length is too large (%ld >= %ld", length, sizeof creator); int tmp; if ((tmp = qlread(li, creator, length)) != length) mas_error("unable to read creator string (i read %d)", tmp); creator[tmp] = '\0'; } finished = true; break; // entry_point : 4 bytes case 0x80: { if (qlread(li, &entry_point, 4) != 4) mas_error("unable to read entry_point"); if (load) { #if defined(DEBUG) msg("MAS: detected entry point : 0x%X\n", entry_point); #endif inf.startIP = entry_point; // entry point segment_t *s = getseg(entry_point); inf.start_cs = s ? s->sel : 0; // selector of code } } break; default: // start_addr : 4 bytes // length : 2 bytes // data : length bytes if (record_type >= 0x01 && record_type <= 0x7F) { struct header { int start_addr; short length; } header; memset(&header, 0, sizeof header); // read the header if (qlread(li, &header, sizeof header) != sizeof header) mas_error("unable to read header (%d bytes)", sizeof header); if (load) { // send code in the database file2base(li, qltell(li), header.start_addr, header.start_addr + header.length, FILEREG_PATCHABLE); #if defined(DEBUG) msg("MAS: i've read %d DATA bytes (0x%X -> 0x%X)\n", header.length, header.start_addr, header.start_addr + header.length); #endif // set selector sel_t selector = allocate_selector(0); // create data segment add_segm(selector, header.start_addr, header.start_addr + header.length, "DATA", "DATA"); } else qlseek(li, qltell(li)+header.length); } else mas_error("invalid record type '0x%X'\n", record_type); } return finished; }
unsigned SuperFamicomCartridge::score_header(linput_t *li, unsigned addr) { int32 size = qlsize(li); if(size < 0x8000) return 0; //skip copier header uint32 start = 0; if((size & 0x7fff) == 512) start += 512, size -= 512; if((uint32)size < addr + 64) return 0; //image too small to contain header at this location? int score = 0; uint8 header[64]; qlseek(li, start + addr); qlread(li, header, 64); uint16 resetvector = header[ResetVector] | (header[ResetVector + 1] << 8); uint16 checksum = header[Checksum ] | (header[Checksum + 1] << 8); uint16 complement = header[Complement ] | (header[Complement + 1] << 8); uint32 resetop_addr = (addr & ~0x7fff) | (resetvector & 0x7fff); if(qlseek(li, start + resetop_addr) != (start + resetop_addr)) return 0; uint8 resetop; if(qlread(li, &resetop, sizeof(uint8)) != sizeof(uint8)) return 0; //first opcode executed upon reset uint8 mapper = header[Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit //$00:[000-7fff] contains uninitialized RAM and MMIO. //reset vector must point to ROM at $00:[8000-ffff] to be considered valid. if(resetvector < 0x8000) return 0; //some images duplicate the header in multiple locations, and others have completely //invalid header information that cannot be relied upon. //below code will analyze the first opcode executed at the specified reset vector to //determine the probability that this is the correct header. //most likely opcodes if(resetop == 0x78 //sei || resetop == 0x18 //clc (clc; xce) || resetop == 0x38 //sec (sec; xce) || resetop == 0x9c //stz $nnnn (stz $4200) || resetop == 0x4c //jmp $nnnn || resetop == 0x5c //jml $nnnnnn ) score += 8; //plausible opcodes if(resetop == 0xc2 //rep #$nn || resetop == 0xe2 //sep #$nn || resetop == 0xad //lda $nnnn || resetop == 0xae //ldx $nnnn || resetop == 0xac //ldy $nnnn || resetop == 0xaf //lda $nnnnnn || resetop == 0xa9 //lda #$nn || resetop == 0xa2 //ldx #$nn || resetop == 0xa0 //ldy #$nn || resetop == 0x20 //jsr $nnnn || resetop == 0x22 //jsl $nnnnnn ) score += 4; //implausible opcodes if(resetop == 0x40 //rti || resetop == 0x60 //rts || resetop == 0x6b //rtl || resetop == 0xcd //cmp $nnnn || resetop == 0xec //cpx $nnnn || resetop == 0xcc //cpy $nnnn ) score -= 4; //least likely opcodes if(resetop == 0x00 //brk #$nn || resetop == 0x02 //cop #$nn || resetop == 0xdb //stp || resetop == 0x42 //wdm || resetop == 0xff //sbc $nnnnnn,x ) score -= 8; //at times, both the header and reset vector's first opcode will match ... //fallback and rely on info validity in these cases to determine more likely header. //a valid checksum is the biggest indicator of a valid header. if((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4; if(addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM if(addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM if(header[Company] == 0x33) score += 2; //0x33 indicates extended header if(header[RomType] < 0x08) score++; if(header[RomSize] < 0x10) score++; if(header[RamSize] < 0x08) score++; if(header[CartRegion] < 14) score++; if(score < 0) score = 0; return score; }
void SuperFamicomCartridge::read_header(linput_t *li) { int32 size = qlsize(li); if(size < 0) return; //skip copier header uint32 start = 0; has_copier_header = (size & 0x7fff) == 512; if(has_copier_header) start += 512, size -= 512; type = TypeUnknown; mapper = LoROM; dsp1_mapper = DSP1Unmapped; region = NTSC; rom_size = size; ram_size = 0; has_bsx_slot = false; has_superfx = false; has_sa1 = false; has_sharprtc = false; has_epsonrtc = false; has_sdd1 = false; has_spc7110 = false; has_cx4 = false; has_dsp1 = false; has_dsp2 = false; has_dsp3 = false; has_dsp4 = false; has_obc1 = false; has_st010 = false; has_st011 = false; has_st018 = false; //===================== //detect Game Boy carts //===================== if(size >= 0x0140) { uint8 data[0x140]; qlseek(li, start); qlread(li, data, 0x140); if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66 && data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) { type = TypeGameBoy; return; } } if(size < 32768) { type = TypeUnknown; return; } const unsigned index = find_header(li); header_offset = index; uint8 extended_header[16 + 64]; qlseek(li, start + index - 16); qlread(li, extended_header, 16 + 64); uint8 * header = &extended_header[16]; const uint8 mapperid = header[Mapper]; const uint8 rom_type = header[RomType]; const uint8 lrom_size = header[RomSize]; const uint8 company = header[Company]; const uint8 regionid = header[CartRegion] & 0x7f; ram_size = 1024 << (header[RamSize] & 7); if(ram_size == 1024) ram_size = 0; //no RAM present if(lrom_size == 0 && ram_size) ram_size = 0; //fix for Bazooka Blitzkrieg's malformed header (swapped ROM and RAM sizes) //0, 1, 13 = NTSC; 2 - 12 = PAL region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL; //======================= //detect BS-X flash carts //======================= if(header[0x13] == 0x00 || header[0x13] == 0xff) { if(header[0x14] == 0x00) { const uint8 n15 = header[0x15]; if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) { if(header[0x1a] == 0x33 || header[0x1a] == 0xff) { type = TypeBsx; mapper = BSXROM; region = NTSC; //BS-X only released in Japan return; } } } } //========================= //detect Sufami Turbo carts //========================= uint8 data[32]; qlseek(li, start); qlread(li, data, 32); if(!memcmp(data, "BANDAI SFC-ADX", 14)) { if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) { type = TypeSufamiTurboBios; } else { type = TypeSufamiTurbo; } mapper = STROM; region = NTSC; //Sufami Turbo only released in Japan return; //RAM size handled outside this routine } //========================== //detect Super Game Boy BIOS //========================== if(!memcmp(header, "Super GAMEBOY2", 14)) { type = TypeSuperGameBoy2Bios; return; } if(!memcmp(header, "Super GAMEBOY", 13)) { type = TypeSuperGameBoy1Bios; return; } //===================== //detect standard carts //===================== //detect presence of BS-X flash cartridge connector (reads extended header information) if(header[-14] == 'Z') { if(header[-11] == 'J') { uint8 n13 = header[-13]; if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) { if(company == 0x33 || (header[-10] == 0x00 && header[-4] == 0x00)) { has_bsx_slot = true; } } } } if(has_bsx_slot) { if(!memcmp(header, "Satellaview BS-X ", 21)) { //BS-X base cart type = TypeBsxBios; mapper = BSXROM; region = NTSC; //BS-X only released in Japan return; //RAM size handled internally by load_cart_bsx() -> BSXCart class } else { type = TypeBsxSlotted; mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM); region = NTSC; //BS-X slotted cartridges only released in Japan } } else { //standard cart type = TypeNormal; if(index == 0x7fc0 && size >= 0x401000) { mapper = ExLoROM; } else if(index == 0x7fc0 && mapperid == 0x32) { mapper = ExLoROM; } else if(index == 0x7fc0) { mapper = LoROM; } else if(index == 0xffc0) { mapper = HiROM; } else { //index == 0x40ffc0 mapper = ExHiROM; } } if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { has_superfx = true; mapper = SuperFXROM; ram_size = 1024 << (header[-3] & 7); if(ram_size == 1024) ram_size = 0; } if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) { has_sa1 = true; mapper = SA1ROM; } if(mapperid == 0x35 && rom_type == 0x55) { has_sharprtc = true; } if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) { has_sdd1 = true; } if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) { has_spc7110 = true; has_epsonrtc = (rom_type == 0xf9); mapper = SPC7110ROM; } if(mapperid == 0x20 && rom_type == 0xf3) { has_cx4 = true; } if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) { has_dsp1 = true; } if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) { has_dsp1 = true; } if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) { has_dsp1 = true; } if(has_dsp1 == true) { if((mapperid & 0x2f) == 0x20 && size <= 0x100000) { dsp1_mapper = DSP1LoROM1MB; } else if((mapperid & 0x2f) == 0x20) { dsp1_mapper = DSP1LoROM2MB; } else if((mapperid & 0x2f) == 0x21) { dsp1_mapper = DSP1HiROM; } } if(mapperid == 0x20 && rom_type == 0x05) { has_dsp2 = true; } if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) { has_dsp3 = true; } if(mapperid == 0x30 && rom_type == 0x03) { has_dsp4 = true; } if(mapperid == 0x30 && rom_type == 0x25) { has_obc1 = true; } if(mapperid == 0x30 && rom_type == 0xf6 && lrom_size >= 10) { has_st010 = true; } if(mapperid == 0x30 && rom_type == 0xf6 && lrom_size < 10) { has_st011 = true; } if(mapperid == 0x30 && rom_type == 0xf5) { has_st018 = true; } }
SuperFamicomCartridge::SuperFamicomCartridge(linput_t *li) { int32 size = qlsize(li); if(size < 0) { loader_failure("Failed retrieving rom size.\n"); return; } firmware_appended = false; //skip copier header if((size & 0x7fff) == 512) size -= 512; if(size < 0x8000) return; read_header(li); if(type == TypeGameBoy) return; if(type == TypeBsx) return; if(type == TypeSufamiTurbo) return; if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) { if((rom_size & 0x7fff) == 0x100) { firmware_appended = true; rom_size -= 0x100; } } else if(has_cx4) { if((rom_size & 0x7fff) == 0xc00) { firmware_appended = true; rom_size -= 0xc00; } } if(has_dsp1) { if((size & 0x7fff) == 0x2000) { firmware_appended = true; rom_size -= 0x2000; } } if(has_dsp2) { if((size & 0x7fff) == 0x2000) { firmware_appended = true; rom_size -= 0x2000; } } if(has_dsp3) { if((size & 0x7fff) == 0x2000) { firmware_appended = true; rom_size -= 0x2000; } } if(has_dsp4) { if((size & 0x7fff) == 0x2000) { firmware_appended = true; rom_size -= 0x2000; } } if(has_st010) { if((size & 0xffff) == 0xd000) { firmware_appended = true; rom_size -= 0xd000; } } if(has_st011) { if((size & 0xffff) == 0xd000) { firmware_appended = true; rom_size -= 0xd000; } } if(has_st018) { if((size & 0x3ffff) == 0x28000) { firmware_appended = true; rom_size -= 0x28000; } } }