From 9c1ded3b0ae8e540177ee0c0baa1f9c8fcf91989 Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Wed, 18 Mar 2009 20:52:11 +0100 Subject: Initial commit of sources --- wii_tmd.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 wii_tmd.c (limited to 'wii_tmd.c') diff --git a/wii_tmd.c b/wii_tmd.c new file mode 100644 index 0000000..8f4002d --- /dev/null +++ b/wii_tmd.c @@ -0,0 +1,254 @@ +/** + * wii_tmd.c + */ + +#include +#include "wii_tmd.h" + +const char *region_names[] = { + "JAP/NTSC-J", + "NTSC-U", + "PAL", + "REGION FREE", + "UNKNOWN", + NULL +}; + +typedef struct { + u16 id; + char *name; +} group; + +static group group_names[] = { + {0x0001, "Nintendo"}, + {0x3031, "Nintendo"} +}; + +typedef struct { + u32 id; + char *name; +} title_category; + +static title_category title_category_names[] = { + {0x00000001, "System"}, + {0x00010000, "Savedata"}, + {0x00010001, "Channel"}, + {0x00010002, "System Channel"}, + {0x00010004, "Game Channel"}, + {0x00010005, "Game Content"}, + {0x00010008, "Hidden Channel"} +}; + +char *tmd_lookup_title_category_name(u32 category) { + u32 i; + const title_category *c; + + for (i = 0; i < (sizeof(title_category_names)/sizeof(title_category)); i++) { + c = &title_category_names[i]; + if (c->id == category) + return c->name; + } + + return "Unknown"; +} + +char *tmd_lookup_group_name(u16 group_id) { + u32 i; + const group *g; + for (i = 0; i < (sizeof(group_names)/sizeof(group)); i++) { + g = &group_names[i]; + if (g->id == group_id) + return g->name; + } + + return "Unknown"; +} + +typedef struct { + u32 id; + char *format; + u8 replace; +} system_title_name; + +static system_title_name system_title_names[] = { + {0x00000001, "BOOT2", 0}, + {0x00000002, "System Menu", 0}, + {0x00000100, "BC", 0}, + {0x00000101, "MIOS", 0}, + {0x00000000, "IOS%d", 1}, /* last item is default */ +}; + +int tmd_get_system_title_name(u32 title_id, char *name) { + u32 i; + const system_title_name *t; + for (i = 0; i < (sizeof(system_title_names)/sizeof(system_title_name)); i++) { + t = &system_title_names[i]; + if(t->id == title_id) { + break; + } + } + + if(t->replace == 1) + return sprintf(name, t->format, title_id); + else + return sprintf(name, t->format); +} + +typedef struct { + u8 id; + char *name; +} system_code_name; + +static system_code_name system_code_names[] = { + {'C', "Commodore 64 Virtual Console"}, + {'E', "NeoGeo Virtual Console"}, + {'F', "Nintendo Virtual Console"}, + {'H', "General channel"}, + {'J', "Super Nintendo Virtual Console"}, + {'L', "Sega Master System Virtual Console"}, + {'M', "Sega Megadrive Virtual Console"}, + {'N', "Nintendo 64 Virtual Console"}, + {'P', "TurboGraFX Virtual Console"}, + {'Q', "TurboGraFX CD Virtual Console"}, + {'R', "Wii Disc"}, + {'W', "WiiWare"} +}; + +char *tmd_lookup_system_code_name(u32 title_id) { + u32 i; + const system_code_name *s; + char *unknown = "Unknown \"?\""; + + for (i = 0; i < (sizeof(system_code_names)/sizeof(system_code_name)); i++) { + s = &system_code_names[i]; + if (s->id == (title_id & 0xff)) + return s->name; + } + + unknown[9] = (u8)(title_id & 0xff); + return unknown; +} + +void dump_tmd_raw(u8 *tmd) { + u32 i, n; + u8 *p; + + printf("issuer : %s\n", tmd + 0x140); + printf("sys_version : %016llx\n", be64(tmd + 0x0184)); + printf("title_id : %04x (%4s)\n", be16(tmd + 0x018c), tmd + 0x0190); + printf("title_type : %08x\n", be32(tmd + 0x0194)); + printf("group_id : %04x\n", be16(tmd + 0x0198)); + printf("region : %s\n", region_names[tmd[OFFSET_REGION]]); + printf("title_version: %04x\n", be16(tmd + 0x01dc)); + printf("num_contents : %04x\n", be16(tmd + 0x01de)); + printf("boot_index : %04x\n", be16(tmd + 0x01e0)); + + n = be16(tmd + 0x01de); + p = tmd + 0x01e4; + for (i = 0; i < n; i++) { + printf("cid %08x index %04x type %04x size %08llx\n", + be32(p), be16(p + 4), be16(p + 6), be64(p + 8)); + p += 0x24; + } +} + +void print_tmd(tmd_header *tmd) { + printf("- tmd_header\n"); + printf("sig_type : %08x (%s)\n", tmd->sig_type, (tmd->sig_type == RSA_2048 ? "RSA_2048": "RSA_4096")); + printf("issuer : %.64s\n", tmd->issuer); + printf("version : %x\n", tmd->version); + printf("ca_crl_version : %x\n", tmd->ca_crl_version); + printf("signer_crl_version: %x\n", tmd->signer_crl_version); + printf("sys_version : %016llx (IOS%llu)\n", tmd->sys_version, tmd->sys_version & 0xff); + printf("title_category : %08x (%s)\n", tmd->title_category, tmd_lookup_title_category_name(tmd->title_category)); + printf("title_id : %08x ", tmd->title_id); + if(tmd->title_category == TITLE_CATEGORY_SYSTEM) { + printf("(IOS%d)\n", be32((u8*)&tmd->title_id)); + } + else + { + printf("(%.4s)\n", (char*)&tmd->title_id); + printf("system : %s\n", tmd_lookup_system_code_name(tmd->title_id)); + } + + printf("title_type : %08x\n", tmd->title_type); + printf("group_id : %04x (%s)\n", tmd->group_id, tmd_lookup_group_name(tmd->group_id)); + printf("region_code : %s (%d)\n", region_names[tmd->region_code], tmd->region_code); + printf("access_rights : %08x\n", tmd->access_rights); + printf("title_version : %d (%04x)\n", tmd->title_version, tmd->title_version); + printf("num_contents : %04x\n", tmd->num_contents); + printf("boot_index : %04x\n", tmd->boot_index); +} + +void print_tmd_content_records(tmd_header *tmd, tmd_content_record *tmd_content) { + u8 i, n; + tmd_content_record *cr; + + for (i = 0; i < tmd->num_contents; i++) { + cr = &tmd_content[i]; + printf("- tmd_content_record[%d]\n", i); + printf("cid : %08x\n", cr->cid); + printf("index: %04x\n", cr->index); + printf("type : %04x\n", cr->type); + printf("size : %1$016llx (%1$llu)\n", cr->size); + printf("hash : "); + for (n = 0; n < 20; n++) + printf("%02x", cr->hash[n]); + printf("\n"); + } +} + +u32 tmd_get_block_size(tmd_header *tmd, tmd_content_record *tmd_content) { + u32 blocks = 0; + u8 i; + u64 install_size = 0; + tmd_content_record *cr; + + for (i = 0; i < tmd->num_contents; i++) { + cr = &tmd_content[i]; + if (cr->type == 1) { + install_size += cr->size; + } + } + + blocks = (install_size/WII_BLOCK_SIZE) + ((install_size % WII_BLOCK_SIZE) == 0 ? 0: 1); + + return blocks; +} + +void tmd_read(FILE *f, tmd_header *tmd) { + /* read head into struct */ + fread(tmd, sizeof(tmd_header), 1, f); + + /* convert to big endian */ + tmd->sig_type = be32((u8*)&tmd->sig_type); + tmd->title_category = be32((u8*)&tmd->title_category); + tmd->sys_version = be64((u8*)&tmd->sys_version); + tmd->title_type = be32((u8*)&tmd->title_type); + tmd->group_id = be16((u8*)&tmd->group_id); + tmd->fill4 = be16((u8*)&tmd->fill4); + tmd->region_code = be16((u8*)&tmd->region_code); + tmd->access_rights = be32((u8*)&tmd->access_rights); + tmd->title_version = be16((u8*)&tmd->title_version); + tmd->num_contents = be16((u8*)&tmd->num_contents); + tmd->boot_index = be16((u8*)&tmd->boot_index); + tmd->fill6 = be16((u8*)&tmd->fill6); +} + +void tmd_read_content_records(FILE *f, tmd_header *tmd, tmd_content_record *tmd_content) { + u8 i; + tmd_content_record *cr; + + fseek(f, OFFSET_TMD + sizeof(tmd_header), SEEK_SET); + + for (i = 0; i < tmd->num_contents; i++) { + cr = tmd_content + i; + fread(cr, sizeof(tmd_content_record), 1, f); + + /* convert to big endian */ + cr->cid = be32((u8*)&cr->cid); + cr->index = be16((u8*)&cr->index); + cr->type = be16((u8*)&cr->type); + cr->size = be64((u8*)&cr->size); + } +} -- cgit v1.1-32-gdbae