/* Try to get some information on the ROM dump: - size - ROM base address - FLASH/EPROM - soft version - calc type */ int ti68k_get_img_infos(const char *filename, IMG_INFO *ri) { FILE *f; // No filename, exits if(!strcmp(g_basename(filename), "")) return ERR_CANT_OPEN; // Check file if(!ti68k_is_a_img_file(filename)) { tiemu_warning("Images must have '.img' extension (%s).\n", filename); return ERR_CANT_OPEN; } // Open dest file f = fopen(filename, "rb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", filename); return ERR_CANT_OPEN; } // Read header if (fread(ri, sizeof(IMG_INFO), 1, f) < 1) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } if(strcmp(ri->signature, IMG_SIGN) || ri->size > 4*MB) { tiemu_warning("Bad image: <%s>\n", filename); return ERR_INVALID_UPGRADE; } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", filename); return ERR_CANT_OPEN; } return 0; }
/* Returns the first found image */ int ti68k_find_image(const char *dirname, char **dst_name) { GDir *dir; GError *error = NULL; G_CONST_RETURN gchar *dirent; int ret = 0; char *filename; if(dst_name != NULL) *dst_name = NULL; // Search for *.img files and convert them dir = g_dir_open(dirname, 0, &error); if (dir == NULL) { tiemu_warning(_("Opendir error")); return ERR_CANT_OPEN_DIR; } filename = NULL; while ((dirent = g_dir_read_name(dir)) != NULL) { if (dirent[0] == '.') continue; if(!ti68k_is_a_img_file(dirent)) continue; filename = g_strconcat(dirname, dirent, NULL); ret = !0; break; } g_dir_close(dir); if(dst_name != NULL) *dst_name = filename; return ret; }
/* Print an error msg */ static void stop (int line) { tiemu_warning(_("Configuration file error at line %i."), line); }
/* Scan images in a given directory and write list into img_list.txt. */ int ti68k_scan_images(const char *dirname, const char *filename) { FILE *file; IMG_INFO img; GDir *dir; GError *error = NULL; G_CONST_RETURN gchar *dirent; gchar *path, *str; int ret; struct stat f_info; char *line[7]; tiemu_info(_("Scanning images/upgrades... ")); // Create file (and overwrite) file = fopen(filename, "wt"); if(file == NULL) { tiemu_warning(_("Unable to open this file: <%s>"), filename); return ERR_CANT_OPEN; } // List all files available in the directory dir = g_dir_open(dirname, 0, &error); if (dir == NULL) { tiemu_warning(_("Opendir error")); return ERR_CANT_OPEN_DIR; } while ((dirent = g_dir_read_name(dir)) != NULL) { if (dirent[0] == '.') continue; path = g_strconcat(dirname, dirent, NULL); ret = stat(path, &f_info); if(ret == -1) { tiemu_warning(_("Can not stat: <%s>"), dirent); perror("stat: "); } else { if(ti68k_is_a_img_file(path)) { memset(&img, 0, sizeof(IMG_INFO)); ret = ti68k_get_img_infos(path, &img); if(ret) { tiemu_warning(_("Can not get ROM/update info: <%s>"), path); break; } } else continue; str = g_strdup_printf("%iKB", (int)(img.size >> 10)); line[0] = (char *)dirent; line[1] = (char *)ti68k_calctype_to_string(img.calc_type); line[2] = img.version; line[3] = (char *)ti68k_romtype_to_string(img.flash); line[4] = str; line[5] = img.has_boot ? _("yes") : _("no"); line[6] = (char *)ti68k_hwtype_to_string(img.hw_type); fprintf(file, "%s,%s,%s,%s,%s,%s,%s\n", line[0], line[1], line[2], line[3], line[4], line[5], line[6]); g_free(str); } g_free(path); } // Close g_dir_close(dir); fclose(file); tiemu_info(_("Done.")); return 0; }
/* Search for ROM dumps or FLASH upgrades in a given directory and converts them into images (note: original file is deleted !). */ int ti68k_scan_files(const char *src_dir, const char *dst_dir, int erase) { GDir *dir; GError *error = NULL; G_CONST_RETURN gchar *dirent; gchar *path; int ret; gchar *dstname; // Search for files and convert them dir = g_dir_open(src_dir, 0, &error); if (dir == NULL) { tiemu_warning(_("Opendir error")); return ERR_CANT_OPEN_DIR; } while ((dirent = g_dir_read_name(dir)) != NULL) { if (dirent[0] == '.') continue; path = g_strconcat(src_dir, dirent, NULL); if(ti68k_is_a_rom_file(path)) { ret = ti68k_convert_rom_to_image(path, dst_dir, &dstname); if(ret) { g_free(dstname); g_free(path); return ret; } if(erase) unlink(path); g_free(dstname); } if(ti68k_is_a_tib_file(path)) { ret = ti68k_convert_tib_to_image(path, dst_dir, &dstname, -1); if(ret) { g_free(dstname); g_free(path); return ret; } if(erase) unlink(path); g_free(dstname); } g_free(path); } g_dir_close(dir); return 0; }
/* This function loads an image. */ int ti68k_load_image(const char *filename) { IMG_INFO *img = &img_infos; FILE *f; int err; // Clear infos memset(img, 0, sizeof(IMG_INFO)); // No filename, exits if(!strcmp(g_basename(filename), "")) return ERR_CANT_OPEN; // Load infos err = ti68k_get_img_infos(filename, img); if(err) { tiemu_info(_("Unable to get information on image: %s"), filename); return err; } ti68k_display_img_infos(img); // Open file f = fopen(filename, "rb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", filename); return ERR_CANT_OPEN; } // Read pure data if (fseek(f, img->header_size, SEEK_SET)) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } img->data = malloc(img->size + 4); if(img->data == NULL) return ERR_MALLOC; if (fread(img->data, 1, img->size, f) < (size_t)img->size) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } #if 1 { HW_PARM_BLOCK hwblock; ti68k_get_hw_param_block((uint8_t *)img->data, img->rom_base, &hwblock); ti68k_display_hw_param_block(&hwblock); } #endif if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", filename); return ERR_CANT_OPEN; } img_loaded = 1; img_changed = 1; return 0; }
/* Convert an romdump into image and replace SPP by upgrade. The resulting image has boot block. */ int ti68k_merge_rom_and_tib_to_image(const char *srcname1, const char *srcname2, const char *dirname, char **dstname) { FILE *f; int err; IMG_INFO img; char *ext; gchar *basename; int real_size; *dstname = NULL; // No filename, exits if(!strcmp(g_basename(srcname1), "")) return ERR_CANT_OPEN; if(!strcmp(g_basename(srcname2), "")) return ERR_CANT_OPEN; // Preload romdump memset(&img, 0, sizeof(IMG_INFO)); err = ti68k_get_rom_infos(srcname1, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on ROM dump: %s"), srcname1); return err; } ti68k_display_rom_infos(&img); // Save size real_size = img.size; // Load upgrade err = ti68k_get_tib_infos(srcname2, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on ROM dump: %s"), srcname2); return err; } ti68k_display_tib_infos(&img); // Create destination file basename = g_path_get_basename(srcname1); ext = strrchr(basename, '.'); *ext='\0'; strcat(basename, ".img"); *dstname = g_strconcat(dirname, basename, NULL); g_free(basename); // Restore size img.size = real_size; // Open dest file f = fopen(*dstname, "wb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", *dstname); return ERR_CANT_OPEN; } // Fill header strcpy(img.signature, IMG_SIGN); img.header_size = sizeof(IMG_INFO); img.revision = IMG_REV; img.has_boot = 1; // Write file if (fwrite(&img, 1, sizeof(IMG_INFO), f) < sizeof(IMG_INFO) || fwrite(img.data, sizeof(char), img.size, f) < (size_t)img.size) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", *dstname); return ERR_CANT_OPEN; } return 0; }
/* Convert an upgrade into an image. The image has neither boot block nor certificate. */ int ti68k_convert_tib_to_image(const char *srcname, const char *dirname, char **dstname, int hw_type) { FILE *f; int err; IMG_INFO img; char *ext; gchar *basename; int i, j; int num_blocks, last_block; int real_size; HW_PARM_BLOCK hwpb; *dstname = NULL; // No filename, exits if(!strcmp(g_basename(srcname), "")) return ERR_CANT_OPEN; // Preload upgrade memset(&img, 0, sizeof(IMG_INFO)); err = ti68k_get_tib_infos(srcname, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on FLASH upgrade: <%s>"), srcname); return err; } ti68k_display_tib_infos(&img); // Create destination file basename = g_path_get_basename(srcname); ext = strrchr(basename, '.'); *ext='\0'; strcat(basename, ".img"); *dstname = g_strconcat(dirname, basename, NULL); g_free(basename); // Open dest file f = fopen(*dstname, "wb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", *dstname); return ERR_CANT_OPEN; } // Fill header strcpy(img.signature, IMG_SIGN); img.header_size = sizeof(IMG_INFO); img.revision = IMG_REV; real_size = img.size - SPP; img.size = ti68k_get_rom_size(img.calc_type); img.hw_type = hw_type; if(hw_type == -1) { if(img.calc_type == TI89t) img.hw_type = HW3; //default else if(img.calc_type == TI89 || img.calc_type == TI92p || img.calc_type == V200) img.hw_type = HW2; // default } // Write header if (fwrite(&img, 1, sizeof(IMG_INFO), f) < sizeof(IMG_INFO)) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Write boot block memcpy(img.data, &img.data[SPP + BO], 256); if (fwrite(img.data, 1, 256, f) < 256) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Write hardware param block // fill structure hwpb.len = 24; switch(img.calc_type) { case TI89: hwpb.hardwareID = HWID_TI89; hwpb.hardwareRevision = img.hw_type - 1; break; case TI92p: hwpb.hardwareID = HWID_TI92P; hwpb.hardwareRevision = img.hw_type - 1; break; case V200: hwpb.hardwareID = HWID_V200; hwpb.hardwareRevision = 2; break; case TI89t: hwpb.hardwareID = HWID_TI89T; hwpb.hardwareRevision = 2; break; } hwpb.bootMajor = hwpb.bootRevision = hwpb.bootBuild = 1; hwpb.gateArray = img.hw_type; ti68k_put_hw_param_block((uint8_t *)img.data, img.rom_base, &hwpb); // write filler if (fputc(0xfe, f) < 0 || fputc(0xed, f) < 0 || fputc(0xba, f) < 0 || fputc(0xbe, f) < 0 //fwrite(&hwpb, 1hwpb.len+2, f); // write address (pointer) || fputc(0x00, f) < 0 || fputc(img.rom_base, f) < 0 || fputc(0x01, f) < 0 || fputc(0x08, f) < 0 // write structure || fputc(MSB(hwpb.len), f) < 0 || fputc(LSB(hwpb.len), f) < 0 || fputc(MSB(MSW(hwpb.hardwareID)), f) < 0 || fputc(LSB(MSW(hwpb.hardwareID)), f) < 0 || fputc(MSB(LSW(hwpb.hardwareID)), f) < 0 || fputc(LSB(LSW(hwpb.hardwareID)), f) < 0 || fputc(MSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(MSW(hwpb.bootMajor)), f) < 0 || fputc(LSB(MSW(hwpb.bootMajor)), f) < 0 || fputc(MSB(LSW(hwpb.bootMajor)), f) < 0 || fputc(LSB(LSW(hwpb.bootMajor)), f) < 0 || fputc(MSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(MSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(LSB(LSW(hwpb.hardwareRevision)), f) < 0 || fputc(MSB(MSW(hwpb.bootBuild)), f) < 0 || fputc(LSB(MSW(hwpb.bootBuild)), f) < 0 || fputc(MSB(LSW(hwpb.bootBuild)), f) < 0 || fputc(LSB(LSW(hwpb.bootBuild)), f) < 0 || fputc(MSB(MSW(hwpb.gateArray)), f) < 0 || fputc(LSB(MSW(hwpb.gateArray)), f) < 0 || fputc(MSB(LSW(hwpb.gateArray)), f) < 0 || fputc(LSB(LSW(hwpb.gateArray)), f) < 0) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Fill with 0xff up-to System Part for(i = 0x108 + hwpb.len+2; i < SPP; i++) if (fputc(0xff, f) < 0) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Copy FLASH upgrade at 0x12000 (SPP) num_blocks = real_size / 65536; for(i = 0; i < num_blocks; i++ ) { tiemu_info("."); fflush(stdout); if (fwrite(&img.data[65536 * i + SPP], sizeof(char), 65536, f) < 65536) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } } last_block = real_size % 65536; if (fwrite(&img.data[65536 * i + SPP], sizeof(char), last_block, f) < (size_t)last_block) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } tiemu_info(""); tiemu_info("Completing to %iMB size\n", img.size >> 20); for(j = SPP + real_size; j < img.size; j++) if (fputc(0xff, f) < 0) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", *dstname); return ERR_CANT_OPEN; } return 0; }
/* Convert a romdump into an image. This kind of image is complete (boot & certificate). */ int ti68k_convert_rom_to_image(const char *srcname, const char *dirname, char **dstname) { FILE *f; int err; IMG_INFO img; char *ext; gchar *basename; *dstname = NULL; // No filename, exits if(!strcmp(g_basename(srcname), "")) return ERR_CANT_OPEN; // Preload romdump memset(&img, 0, sizeof(IMG_INFO)); err = ti68k_get_rom_infos(srcname, &img, !0); if(err) { free(img.data); tiemu_info(_("Unable to get information on ROM dump: %s"), srcname); return err; } ti68k_display_rom_infos(&img); // Create destination file basename = g_path_get_basename(srcname); ext = strrchr(basename, '.'); *ext='\0'; strcat(basename, ".img"); *dstname = g_strconcat(dirname, basename, NULL); g_free(basename); // Open dest file f = fopen(*dstname, "wb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", *dstname); return ERR_CANT_OPEN; } // Some V200 and TI89 Titanium ROMs are half the size if((img.size < 4*MB) && (img.calc_type == V200 || img.calc_type == TI89t)) { img.size = 4*MB; img.data = realloc(img.data, 4*MB + 4); tiemu_info(_("Completing image to 4 MB!")); memset(img.data + 2*MB, 0xff, 2*MB); } // Fill header strcpy(img.signature, IMG_SIGN); img.header_size = sizeof(IMG_INFO); img.revision = IMG_REV; // Write file if (fwrite(&img, 1, sizeof(IMG_INFO), f) < (size_t)sizeof(IMG_INFO) || fwrite(img.data, sizeof(char), img.size, f) < (size_t)img.size) { tiemu_warning("Failed to write to file: <%s>\n", *dstname); fclose(f); return ERR_CANT_OPEN; } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", *dstname); return ERR_CANT_OPEN; } return 0; }
/* Try to get some information on the ROM dump: - size - ROM base address - FLASH/EPROM - soft version - calc type */ int ti68k_get_img_infos(const char *filename, IMG_INFO *ri) { FILE *f; IMG_INFO32 ri32; IMG_INFO64 ri64; // No filename, exits if(!strcmp(g_basename(filename), "")) return ERR_CANT_OPEN; // Check file if(!ti68k_is_a_img_file(filename)) { tiemu_warning("Images must have '.img' extension (%s).\n", filename); return ERR_CANT_OPEN; } // Open dest file f = fopen(filename, "rb"); if(f == NULL) { tiemu_warning("Unable to open this file: <%s>\n", filename); return ERR_CANT_OPEN; } // Read header if (fread(&ri32, sizeof(IMG_INFO32), 1, f) < 1) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } *ri = ri32; // below is patch from Lionel if(strcmp(ri->signature, IMG_SIGN) || ri->size > 4*MB || ri->calc_type > CALC_MAX || ri->header_size == 0 || ri->hw_type > 4 || ri->rom_base == 0) { // In addition to plain invalid files, this may happen if the image was // created on a 64-bit platform with TIEmu <= 3.03. // Try to read an IMG_INFO structure as it used to be written by those // 64-bit platforms. fseek(f, 0, SEEK_SET); if (fread(&ri64, sizeof(IMG_INFO64), 1, f) < 1) { tiemu_warning("Failed to read from file: <%s>\n", filename); fclose(f); return ERR_CANT_OPEN; } else { memcpy(ri->signature, &(ri64.signature), sizeof(ri64.signature)); ri->revision = (int32_t)(ri64.revision); ri->header_size = (int32_t)(ri64.header_size); ri->calc_type = ri64.calc_type; memcpy(ri->version, &(ri64.version), sizeof(ri64.version)); ri->flash = ri64.flash; ri->has_boot = ri64.has_boot; ri->size = (int32_t)(ri64.size); ri->hw_type = ri64.hw_type; ri->rom_base = ri64.rom_base; if(strcmp(ri->signature, IMG_SIGN) || ri->size > 4*MB || ri->calc_type > CALC_MAX || ri->header_size == 0 || ri->hw_type > 4 || ri->rom_base == 0) { // Nope, it still doesn't seem to be a TIEmu image. tiemu_warning("Bad image: <%s>\n", filename); return ERR_INVALID_UPGRADE; } else { tiemu_info("Found a reasonably valid 64-bit IMG_INFO in <%s>\n", filename); } } } // Close file if (fclose(f)) { tiemu_warning("Failed to close file: <%s>\n", filename); return ERR_CANT_OPEN; } return 0; }