images.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. /* Hey EMACS -*- linux-c -*- */
  2. /* $Id: images.c 2417 2007-03-29 01:42:01Z roms $ */
  3. /* TiEmu - Tiemu Is an EMUlator
  4. *
  5. * Copyright (c) 2000-2001, Thomas Corvazier, Romain Lievin
  6. * Copyright (c) 2001-2003, Romain Lievin
  7. * Copyright (c) 2003, Julien Blache
  8. * Copyright (c) 2004, Romain Liévin
  9. * Copyright (c) 2005-2007, Romain Liévin, Kevin Kofler
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
  24. */
  25. /*
  26. This module handles loading of images or upgrades.
  27. Images can be:
  28. - ROM dump
  29. - FLASH upgrade as a ROM dump
  30. Note:0x12000 is the beginning of the system privileged part.
  31. */
  32. #include <assert.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <ctype.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <string.h>
  39. #include <sys/types.h>
  40. #include <unistd.h>
  41. #include "tifiles.h"
  42. #include "images.h"
  43. #include "macros.h"
  44. #include "hwpm.h"
  45. #include "ti68k_def.h"
  46. #include "ti68k_err.h"
  47. #include "mem_size.h"
  48. #define _(x) (x)
  49. #define tiemu_info(x...) (fprintf(stderr, x),fprintf(stderr, "\n"))
  50. #define tiemu_warning(x...) (fprintf(stderr, x),fprintf(stderr, "\n"))
  51. #define tiemu_error(x...) (fprintf(stderr, x),fprintf(stderr, "\n"))
  52. #define is_num(c) isdigit(c)
  53. #define is_alnum(c) isalnum(c)
  54. #define SPP 0x12000 // system privileged part
  55. #define BO 0x88 // offset from SPP to boot
  56. static int get_rom_version(char *ptr, int size, char *version);
  57. /*
  58. Utility functions
  59. */
  60. int ti68k_is_a_rom_file(const char *filename)
  61. {
  62. char *ext;
  63. ext = strrchr(filename, '.');
  64. if(ext == NULL)
  65. return 0;
  66. else if(!strcasecmp(ext, ".rom"))
  67. return !0;
  68. return 0;
  69. }
  70. int ti68k_is_a_tib_file(const char *filename)
  71. {
  72. return tifiles_file_is_os(filename);
  73. }
  74. int ti68k_is_a_img_file(const char *filename)
  75. {
  76. char *ext;
  77. ext = strrchr(filename, '.');
  78. if(ext == NULL)
  79. return 0;
  80. else if(!strcasecmp(ext, ".img"))
  81. return !0;
  82. return 0;
  83. }
  84. int ti68k_is_a_sav_file(const char *filename)
  85. {
  86. char *ext;
  87. ext = strrchr(filename, '.');
  88. if(ext == NULL)
  89. return 0;
  90. else if(!strcasecmp(ext, ".sav"))
  91. return !0;
  92. return 0;
  93. }
  94. /*
  95. Get some information on the ROM dump:
  96. - size
  97. - ROM base address
  98. - FLASH/EPROM
  99. - os version
  100. - calc type
  101. Note: if the data field is NULL, memory is allocated.
  102. Otherwise, data is overwritten.
  103. Thanks to Kevin for HW2 detection code.
  104. */
  105. int ti68k_get_rom_infos(const char *filename, IMG_INFO *rom, int preload)
  106. {
  107. FILE *file;
  108. HW_PARM_BLOCK hwblock;
  109. // Open file
  110. file = fopen(filename, "rb");
  111. if(file == NULL)
  112. {
  113. tiemu_info(_("Unable to open this file: <%s>"), filename);
  114. return ERR_CANT_OPEN;
  115. }
  116. // Clear infos
  117. memset(rom, 0, sizeof(IMG_INFO));
  118. // Retrieve ROM size
  119. fseek(file, 0, SEEK_END);
  120. rom->size = ftell(file);
  121. fseek(file, 0, SEEK_SET);
  122. if(rom->size < 256)
  123. return ERR_INVALID_ROM_SIZE;
  124. if (rom->size == 8*MB)
  125. {
  126. // TiLP used to dump 8 MB images for HW4, try to load them anyway.
  127. tiemu_info(_("/* Warning: truncating 8 MB image to 4 MB: <%s> */"), filename);
  128. rom->size = 4*MB;
  129. }
  130. if (rom->size > 4*MB)
  131. return ERR_INVALID_ROM_SIZE;
  132. if(rom->data == NULL)
  133. rom->data = malloc(rom->size + 4);
  134. if(rom->data == NULL)
  135. return ERR_MALLOC;
  136. memset(rom->data, 0xff, rom->size);
  137. if (fread(rom->data, 1, rom->size, file) < (size_t)rom->size)
  138. {
  139. tiemu_info(_("Failed to read from file: <%s>"), filename);
  140. fclose(file);
  141. return ERR_CANT_OPEN;
  142. }
  143. if (fclose(file))
  144. {
  145. tiemu_info(_("Failed to close file: <%s>"), filename);
  146. return ERR_CANT_OPEN;
  147. }
  148. rom->has_boot = 1;
  149. rom->rom_base = rom->data[0x05] & 0xf0;
  150. rom->flash = (rom->data[0x65] & 0x0f) ? 0 : FLASH_ROM;
  151. get_rom_version(rom->data, rom->size, rom->version);
  152. if(!rom->flash)
  153. {
  154. rom->calc_type = TI92;
  155. rom->hw_type = HW1;
  156. }
  157. else
  158. {
  159. // Get hw param block to determine calc type & hw type
  160. if(ti68k_get_hw_param_block((uint8_t*)rom->data, rom->rom_base,
  161. &hwblock) == -1)
  162. return ERR_INVALID_ROM;
  163. switch(hwblock.hardwareID)
  164. {
  165. case HWID_TI92P: rom->calc_type = TI92p; break;
  166. case HWID_TI89: rom->calc_type = TI89; break;
  167. case HWID_V200: rom->calc_type = V200; break;
  168. case HWID_TI89T: rom->calc_type = TI89t; break;
  169. default: break;
  170. }
  171. if(rom->flash)
  172. {
  173. if(hwblock.len < 24)
  174. rom->hw_type = HW1;
  175. else
  176. rom->hw_type = (char)hwblock.gateArray;
  177. }
  178. }
  179. if(!preload)
  180. free(rom->data);
  181. return 0;
  182. }
  183. /*
  184. Get some information on the FLASH upgrade:
  185. - size
  186. - ROM base address
  187. - os version
  188. - calc type
  189. */
  190. int ti68k_get_tib_infos(const char *filename, IMG_INFO *tib, int preload)
  191. {
  192. FlashContent *content;
  193. FlashContent *ptr;
  194. int nheaders = 0;
  195. int i;
  196. // Check valid file
  197. if(!tifiles_file_is_ti(filename))
  198. return ERR_NOT_TI_FILE;
  199. if(!tifiles_file_is_os(filename))
  200. return ERR_INVALID_UPGRADE;
  201. // Clear infos
  202. memset(tib, 0, sizeof(IMG_INFO));
  203. // Load file
  204. content = tifiles_content_create_flash(CALC_TI89);
  205. if(tifiles_file_read_flash(filename, content) != 0)
  206. return ERR_INVALID_UPGRADE;
  207. // count headers
  208. for (ptr = content; ptr != NULL; ptr = ptr->next)
  209. nheaders++;
  210. // keep the last one (data)
  211. for (i = 0, ptr = content; i < nheaders - 1; i++)
  212. ptr = ptr->next;
  213. // Load TIB into memory and relocate at SPP
  214. if(tib->data == NULL)
  215. tib->data = malloc(SPP + ptr->data_length + 4);
  216. if(tib->data == NULL)
  217. return ERR_MALLOC;
  218. memset(tib->data + SPP, 0xff, ptr->data_length);
  219. memcpy(tib->data + SPP, ptr->data_part, ptr->data_length);
  220. // Update current rom infos
  221. tib->rom_base = tib->data[BO+5 + SPP] & 0xf0;
  222. // libtifiles can't distinguish TI89/TI89t and 92+/V200. We need to look.
  223. switch(ptr->device_type & 0xff)
  224. {
  225. case DEVICE_TYPE_89: // can be a Titanium, too
  226. switch(tib->rom_base & 0xff)
  227. {
  228. case 0x20: tib->calc_type = TI89; break;
  229. case 0x80: tib->calc_type = TI89t; break;
  230. default: return ERR_INVALID_UPGRADE;
  231. }
  232. break;
  233. case DEVICE_TYPE_92P:
  234. switch(tib->rom_base & 0xff)
  235. {
  236. case 0x20: tib->calc_type = V200; break;
  237. case 0x40: tib->calc_type = TI92p; break;
  238. default: return ERR_INVALID_UPGRADE;
  239. }
  240. break;
  241. default:
  242. tiemu_info("TIB problem: %02x!\n", 0xff & ptr->device_type);
  243. return ERR_INVALID_UPGRADE;
  244. break;
  245. }
  246. tib->flash = FLASH_ROM;
  247. tib->has_boot = 0;
  248. tib->size = ptr->data_length + SPP;
  249. get_rom_version(tib->data, tib->size, tib->version);
  250. tifiles_content_delete_flash(content);
  251. if(!preload)
  252. free(tib->data);
  253. return 0;
  254. }
  255. /*
  256. Try to get some information on the ROM dump:
  257. - size
  258. - ROM base address
  259. - FLASH/EPROM
  260. - soft version
  261. - calc type
  262. */
  263. int ti68k_get_img_infos(const char *filename, IMG_INFO *ri)
  264. {
  265. FILE *f;
  266. // Check file
  267. if(!ti68k_is_a_img_file(filename))
  268. {
  269. tiemu_warning("Images must have '.img' extension (%s).\n",
  270. filename);
  271. return ERR_CANT_OPEN;
  272. }
  273. // Open dest file
  274. f = fopen(filename, "rb");
  275. if(f == NULL)
  276. {
  277. tiemu_warning("Unable to open this file: <%s>\n", filename);
  278. return ERR_CANT_OPEN;
  279. }
  280. // Read header
  281. if (fread(ri, sizeof(IMG_INFO), 1, f) < 1)
  282. {
  283. tiemu_warning("Failed to read from file: <%s>\n", filename);
  284. fclose(f);
  285. return ERR_CANT_OPEN;
  286. }
  287. if(strcmp(ri->signature, IMG_SIGN) || ri->size > 4*MB)
  288. {
  289. tiemu_warning("Bad image: <%s>\n", filename);
  290. return ERR_INVALID_UPGRADE;
  291. }
  292. // Close file
  293. if (fclose(f))
  294. {
  295. tiemu_warning("Failed to close file: <%s>\n", filename);
  296. return ERR_CANT_OPEN;
  297. }
  298. return 0;
  299. }
  300. const int ti_rom_sizes[] = { ROM_SIZE_TI92_I, ROM_SIZE_TI89, ROM_SIZE_TI92P, ROM_SIZE_V200, ROM_SIZE_TI89T };
  301. static int log_b2(int i)
  302. {
  303. int j, v;
  304. for(j = 0, v = i; v != 0; v >>= 1, j++);
  305. return j-1;
  306. }
  307. int ti68k_get_rom_size(int calc_type)
  308. {
  309. if(calc_type > CALC_MAX)
  310. {
  311. tiemu_error(_("Bad argument!"));
  312. exit(0);
  313. }
  314. return ti_rom_sizes[log_b2(calc_type)];
  315. }
  316. /*
  317. Convert an upgrade into an image.
  318. The image has neither boot block nor certificate.
  319. */
  320. int ti68k_convert_tib_to_image(IMG_INFO *src, unsigned char *dst)
  321. {
  322. int i, j;
  323. int num_blocks, last_block;
  324. int real_size;
  325. HW_PARM_BLOCK hwpb;
  326. // Fill header
  327. real_size = src->size - SPP;
  328. src->size = ti68k_get_rom_size(src->calc_type);
  329. // Write boot block
  330. memcpy(src->data, &src->data[SPP + BO], 256);
  331. memcpy(dst,src,256);
  332. dst+=256;
  333. // Write hardware param block
  334. // fill structure
  335. hwpb.len = 24;
  336. switch(src->calc_type)
  337. {
  338. case TI89:
  339. hwpb.hardwareID = HWID_TI89;
  340. hwpb.hardwareRevision = src->hw_type - 1;
  341. break;
  342. case TI92p:
  343. hwpb.hardwareID = HWID_TI92P;
  344. hwpb.hardwareRevision = src->hw_type - 1;
  345. break;
  346. case V200:
  347. hwpb.hardwareID = HWID_V200;
  348. hwpb.hardwareRevision = 2;
  349. break;
  350. case TI89t:
  351. hwpb.hardwareID = HWID_TI89T;
  352. hwpb.hardwareRevision = 2;
  353. break;
  354. }
  355. hwpb.bootMajor = hwpb.bootRevision = hwpb.bootBuild = 1;
  356. hwpb.gateArray = src->hw_type;
  357. ti68k_put_hw_param_block((uint8_t *)src->data, src->rom_base, &hwpb);
  358. // write filler
  359. *(dst++)=0xfe; *(dst++)=0xed; *(dst++)=0xba; *(dst++)=0xbe;
  360. //fwrite(&hwpb, 1hwpb.len+2, f);
  361. // write address (pointer)
  362. *(dst++)=0x00;
  363. *(dst++)=src->rom_base;
  364. *(dst++)=0x01;
  365. *(dst++)=0x08;
  366. // write structure
  367. *(dst++)=MSB(hwpb.len);
  368. *(dst++)=LSB(hwpb.len);
  369. *(dst++)=MSB(MSW(hwpb.hardwareID));
  370. *(dst++)=LSB(MSW(hwpb.hardwareID));
  371. *(dst++)=MSB(LSW(hwpb.hardwareID));
  372. *(dst++)=LSB(LSW(hwpb.hardwareID));
  373. *(dst++)=MSB(MSW(hwpb.hardwareRevision));
  374. *(dst++)=LSB(MSW(hwpb.hardwareRevision));
  375. *(dst++)=MSB(LSW(hwpb.hardwareRevision));
  376. *(dst++)=LSB(LSW(hwpb.hardwareRevision));
  377. *(dst++)=MSB(MSW(hwpb.bootMajor));
  378. *(dst++)=LSB(MSW(hwpb.bootMajor));
  379. *(dst++)=MSB(LSW(hwpb.bootMajor));
  380. *(dst++)=LSB(LSW(hwpb.bootMajor));
  381. *(dst++)=MSB(MSW(hwpb.hardwareRevision));
  382. *(dst++)=LSB(MSW(hwpb.hardwareRevision));
  383. *(dst++)=MSB(LSW(hwpb.hardwareRevision));
  384. *(dst++)=LSB(LSW(hwpb.hardwareRevision));
  385. *(dst++)=MSB(MSW(hwpb.bootBuild));
  386. *(dst++)=LSB(MSW(hwpb.bootBuild));
  387. *(dst++)=MSB(LSW(hwpb.bootBuild));
  388. *(dst++)=LSB(LSW(hwpb.bootBuild));
  389. *(dst++)=MSB(MSW(hwpb.gateArray));
  390. *(dst++)=LSB(MSW(hwpb.gateArray));
  391. *(dst++)=MSB(LSW(hwpb.gateArray));
  392. *(dst++)=LSB(LSW(hwpb.gateArray));
  393. // Fill with 0xff up-to System Part
  394. for(i = 0x108 + hwpb.len+2; i < SPP; i++)
  395. *(dst++)=0xff;
  396. // Copy FLASH upgrade at 0x12000 (SPP)
  397. num_blocks = real_size / 65536;
  398. for(i = 0; i < num_blocks; i++ )
  399. {
  400. memcpy(dst,&src->data[65536 * i + SPP],65536);
  401. dst+=65536;
  402. }
  403. last_block = real_size % 65536;
  404. memcpy(dst,&src->data[65536 * i + SPP],last_block);
  405. dst+=last_block;
  406. for(j = SPP + real_size; j < src->size; j++)
  407. *(dst++)=0xff;
  408. return 0;
  409. }
  410. /*
  411. This function loads an image.
  412. */
  413. int ti68k_load_image(const char *filename, IMG_INFO *img)
  414. {
  415. FILE *f;
  416. int err;
  417. // Clear infos
  418. memset(img, 0, sizeof(IMG_INFO));
  419. // Load infos
  420. err = ti68k_get_img_infos(filename, img);
  421. if(err)
  422. {
  423. tiemu_info(_("Unable to get information on image: %s"), filename);
  424. return err;
  425. }
  426. // Open file
  427. f = fopen(filename, "rb");
  428. if(f == NULL)
  429. {
  430. tiemu_warning("Unable to open this file: <%s>\n", filename);
  431. return ERR_CANT_OPEN;
  432. }
  433. // Read pure data
  434. if (fseek(f, img->header_size, SEEK_SET))
  435. {
  436. tiemu_warning("Failed to read from file: <%s>\n", filename);
  437. fclose(f);
  438. return ERR_CANT_OPEN;
  439. }
  440. img->data = malloc(img->size + 4);
  441. if(img->data == NULL)
  442. return ERR_MALLOC;
  443. if (fread(img->data, 1, img->size, f) < (size_t)img->size)
  444. {
  445. tiemu_warning("Failed to read from file: <%s>\n", filename);
  446. fclose(f);
  447. return ERR_CANT_OPEN;
  448. }
  449. #if 1
  450. {
  451. HW_PARM_BLOCK hwblock;
  452. ti68k_get_hw_param_block((uint8_t *)img->data, img->rom_base,
  453. &hwblock);
  454. }
  455. #endif
  456. if (fclose(f))
  457. {
  458. tiemu_warning("Failed to close file: <%s>\n", filename);
  459. return ERR_CANT_OPEN;
  460. }
  461. return 0;
  462. }
  463. /*
  464. Search the version string in the ROM
  465. Arguments:
  466. - ptr: a ROM or update image
  467. - size: the size of the buffer
  468. - version: the returned string version
  469. */
  470. static int get_rom_version(char *ptr, int size, char *version)
  471. {
  472. int i;
  473. strcpy(version, "?.??");
  474. for (i = SPP; i < size-16; i += 2)
  475. {
  476. if (is_num(ptr[i])&&(ptr[i+1]=='.') && is_num(ptr[i+2]) &&
  477. (ptr[i+3]==0)&&is_alnum(ptr[i+4]) && is_alnum(ptr[i+5]) &&
  478. (ptr[i+6]=='/')&&is_alnum(ptr[i+7]) && is_alnum(ptr[i+8]) &&
  479. (ptr[i+9]=='/')&&is_alnum(ptr[i+10]) && is_alnum(ptr[i+11]))
  480. break;
  481. if (is_num(ptr[i]) && (ptr[i+1]=='.') && is_num(ptr[i+2]) &&
  482. is_num(ptr[i+3]) && (ptr[i+4]==0) && is_alnum(ptr[i+5]) &&
  483. is_alnum(ptr[i+6]) && (ptr[i+7]=='/') && is_alnum(ptr[i+8]) &&
  484. is_alnum(ptr[i+9]) && (ptr[i+10]=='/') && is_alnum(ptr[i+11]) &&
  485. is_alnum(ptr[i+12]))
  486. break;
  487. if (is_num(ptr[i]) && (ptr[i+1]=='.') && is_num(ptr[i+2]) &&
  488. (ptr[i+3]==0) && is_alnum(ptr[i+4]) && is_alnum(ptr[i+5]) &&
  489. is_alnum(ptr[i+6]) && is_alnum(ptr[i+7]) && is_alnum(ptr[i+8]) &&
  490. is_alnum(ptr[i+9]) && is_alnum(ptr[i+10]) && is_alnum(ptr[i+11]))
  491. break;
  492. if (is_num(ptr[i]) && (ptr[i+1]=='.') && is_num(ptr[i+2]) &&
  493. is_alnum(ptr[i+3]) && (ptr[i+4]==0) && is_alnum(ptr[i+5]) &&
  494. is_alnum(ptr[i+6]) && is_alnum(ptr[i+7]) && is_alnum(ptr[i+8]) &&
  495. is_alnum(ptr[i+9]) && is_alnum(ptr[i+10]) && is_alnum(ptr[i+11]))
  496. break;
  497. }
  498. if (i < size-16)
  499. {
  500. int n;
  501. for(n = i; n < i+16; n++)
  502. {
  503. if (ptr[n]==0)
  504. {
  505. strcpy(version, ptr+i);
  506. (version)[n-i]=0;
  507. return 0;
  508. }
  509. }
  510. }
  511. return 0;
  512. }